feat: 添加动画速度调整功能 优化页面自适应效果

This commit is contained in:
alger
2024-12-08 21:50:58 +08:00
parent f1030d3a78
commit 17795e5da2
10 changed files with 149 additions and 77 deletions
+11 -37
View File
@@ -5,19 +5,13 @@ import { getListByCat, getListDetail, getRecommendList } from '@/api/list';
import MusicList from '@/components/MusicList.vue';
import type { IRecommendItem } from '@/type/list';
import type { IListDetail } from '@/type/listDetail';
import { formatNumber, getImgUrl, isMobile, setAnimationClass, setAnimationDelay } from '@/utils';
import { formatNumber, getImgUrl, setAnimationClass, setAnimationDelay } from '@/utils';
defineOptions({
name: 'List',
});
const ITEMS_PER_ROW = ref(6); // 每行显示的数量
const TOTAL_ITEMS = 30; // 每页数量
// 计算实际需要加载的数量,确保能被每行数量整除
const getAdjustedLimit = (perRow: number) => {
return Math.ceil(TOTAL_ITEMS / perRow) * perRow;
};
const TOTAL_ITEMS = 40; // 每数量
const recommendList = ref<any[]>([]);
const showMusic = ref(false);
@@ -25,11 +19,9 @@ const page = ref(0);
const hasMore = ref(true);
const isLoadingMore = ref(false);
// 计算每个项目在当前页面中的索引
// 计算每个项目的动画延迟
const getItemAnimationDelay = (index: number) => {
const adjustedLimit = getAdjustedLimit(ITEMS_PER_ROW.value);
const currentPageIndex = index % adjustedLimit;
return setAnimationDelay(currentPageIndex, 30);
return setAnimationDelay(index, 30);
};
const recommendItem = ref<IRecommendItem | null>();
@@ -62,11 +54,10 @@ const loadList = async (type: string, isLoadMore = false) => {
}
try {
const adjustedLimit = getAdjustedLimit(ITEMS_PER_ROW.value);
const params = {
cat: type || '',
limit: adjustedLimit,
offset: page.value * adjustedLimit,
limit: TOTAL_ITEMS,
offset: page.value * TOTAL_ITEMS,
};
const { data } = await getListByCat(params);
if (isLoadMore) {
@@ -93,35 +84,16 @@ const handleScroll = (e: any) => {
}
};
// 监听窗口大小变化,调整每行显示数量
const updateItemsPerRow = () => {
const width = window.innerWidth;
if (isMobile.value) {
ITEMS_PER_ROW.value = 2;
return;
}
if (width > 1800) ITEMS_PER_ROW.value = 8;
else if (width > 1200) ITEMS_PER_ROW.value = 8;
else if (width > 768) ITEMS_PER_ROW.value = 6;
else ITEMS_PER_ROW.value = 5;
};
onMounted(() => {
updateItemsPerRow();
window.addEventListener('resize', updateItemsPerRow);
if (route.query.type) {
loadList(route.query.type as string);
} else {
getRecommendList(getAdjustedLimit(ITEMS_PER_ROW.value)).then((res: { data: { result: any } }) => {
getRecommendList(TOTAL_ITEMS).then((res: { data: { result: any } }) => {
recommendList.value = res.data.result;
});
}
});
onUnmounted(() => {
window.removeEventListener('resize', updateItemsPerRow);
});
watch(
() => route.query,
async (newParams) => {
@@ -195,12 +167,12 @@ watch(
&-list {
@apply grid gap-x-8 gap-y-6 pb-28 pr-4;
grid-template-columns: repeat(v-bind(ITEMS_PER_ROW), minmax(0, 1fr));
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
}
&-item {
@apply flex flex-col;
&-img {
@apply rounded-xl overflow-hidden relative w-full;
@apply rounded-xl overflow-hidden relative w-full aspect-square;
&-img {
@apply block w-full h-full;
}
@@ -248,6 +220,8 @@ watch(
.mobile {
.recommend-list {
@apply px-4;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
}
</style>
+8 -12
View File
@@ -13,14 +13,7 @@
:style="getItemAnimationDelay(index)"
>
<div class="mv-item-img" @click="handleShowMv(item, index)">
<n-image
class="mv-item-img-img"
:src="getImgUrl(item.cover, '200y112')"
lazy
preview-disabled
width="200"
height="112"
/>
<n-image class="mv-item-img-img" :src="getImgUrl(item.cover, '320y180')" lazy preview-disabled />
<div class="top">
<div class="play-count">{{ formatNumber(item.playCount) }}</div>
<i class="iconfont icon-videofill"></i>
@@ -169,8 +162,8 @@ const isPrevDisabled = computed(() => currentIndex.value === 0);
}
&-content {
@apply grid gap-6 pb-28 mt-2 pr-4;
grid-template-columns: repeat(auto-fill, minmax(14%, 1fr));
@apply grid gap-4 pb-28 mt-2 pr-4;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.mv-item {
@@ -178,6 +171,7 @@ const isPrevDisabled = computed(() => currentIndex.value === 0);
background-color: #1f1f1f;
&-img {
@apply rounded-lg overflow-hidden relative;
aspect-ratio: 16/9;
line-height: 0;
&:hover img {
@@ -185,7 +179,7 @@ const isPrevDisabled = computed(() => currentIndex.value === 0);
}
&-img {
@apply w-full rounded-lg overflow-hidden;
@apply w-full h-full object-cover rounded-lg overflow-hidden;
}
.top {
@@ -224,7 +218,9 @@ const isPrevDisabled = computed(() => currentIndex.value === 0);
.mobile {
.mv-list-content {
grid-template-columns: repeat(auto-fill, minmax(30%, 1fr));
@apply px-4;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
}
+66 -12
View File
@@ -1,6 +1,6 @@
<template>
<div class="set-page">
<div class="set-item">
<div v-if="isElectron" class="set-item">
<div>
<div class="set-item-title">代理</div>
<div class="set-item-content">无法听音乐时打开</div>
@@ -9,10 +9,34 @@
</div>
<div class="set-item">
<div>
<div class="set-item-title">减轻动画效果</div>
<div class="set-item-title">关闭动画效果</div>
</div>
<n-switch v-model:value="setData.noAnimate" />
</div>
<div class="set-item">
<div>
<div class="set-item-title">动画速度</div>
<div class="set-item-content">调节动画播放速度</div>
</div>
<div class="flex items-center gap-2">
<span class="text-sm text-gray-400">{{ setData.animationSpeed }}x</span>
<div class="w-40">
<n-slider
v-model:value="setData.animationSpeed"
:min="0.1"
:max="3"
:step="0.1"
:marks="{
0.1: '极慢',
1: '正常',
3: '极快',
}"
:disabled="setData.noAnimate"
class="w-40"
/>
</div>
</div>
</div>
<div class="set-item">
<div>
<div class="set-item-title">版本</div>
@@ -20,22 +44,37 @@
</div>
<div>{{ config.version }}</div>
</div>
<div class="set-item">
<div class="set-item cursor-pointer hover:text-green-500 hover:bg-green-950 transition-all" @click="openAuthor">
<div>
<div class="set-item-title">作者</div>
<div class="set-item-content"></div>
<div class="set-item-content">algerkong github</div>
</div>
<div>{{ setData.author }}</div>
</div>
<div class="set-action">
<n-button @click="handelCancel">取消</n-button>
<n-button type="primary" @click="handleSave">保存并重启</n-button>
<n-button class="w-40 h-10" @click="handelCancel">取消</n-button>
<n-button type="primary" class="w-40 h-10" @click="handleSave">{{ isElectron ? '保存并重启' : '保存' }}</n-button>
</div>
<div class="p-6 bg-black rounded-lg shadow-lg mt-20">
<div class="text-gray-100 text-base text-center">支持作者</div>
<div class="flex gap-60">
<div class="flex flex-col items-center gap-2 cursor-pointer hover:scale-[2] transition-all z-10 bg-black">
<n-image :src="alipayQR" alt="支付宝收款码" class="w-32 h-32 rounded-lg" preview-disabled />
<span class="text-sm text-gray-100">支付宝</span>
</div>
<div class="flex flex-col items-center gap-2 cursor-pointer hover:scale-[2] transition-all z-10 bg-black">
<n-image :src="wechatQR" alt="微信收款码" class="w-32 h-32 rounded-lg" preview-disabled />
<span class="text-sm text-gray-100">微信支付</span>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useRouter } from 'vue-router';
import config from '@/../package.json';
@@ -45,20 +84,32 @@ defineOptions({
name: 'Setting',
});
const setData = ref(store.state.setData);
const alipayQR = 'https://github.com/algerkong/algerkong/blob/main/alipay.jpg?raw=true';
const wechatQR = 'https://github.com/algerkong/algerkong/blob/main/wechat.jpg?raw=true';
const isElectron = ref((window as any).electronAPI !== undefined);
const router = useRouter();
// 使用计算属性来获取和设置数据
const setData = computed({
get: () => store.state.setData,
set: (value) => store.commit('setSetData', value),
});
const handelCancel = () => {
router.back();
};
const windowData = window as any;
const handleSave = () => {
store.commit('setSetData', setData.value);
if (windowData.electronAPI) {
windowData.electronAPI.restart();
if (isElectron.value) {
(window as any).electronAPI.restart();
}
router.back();
};
const openAuthor = () => {
window.open(setData.value.authorUrl, '_blank');
};
</script>
@@ -67,7 +118,7 @@ const handleSave = () => {
@apply flex flex-col justify-center items-center pt-8;
}
.set-item {
@apply w-3/5 flex justify-between items-center mb-4;
@apply w-3/5 flex justify-between items-center mb-2 px-4 py-2 rounded-lg;
.set-item-title {
@apply text-gray-200 text-base;
}
@@ -75,4 +126,7 @@ const handleSave = () => {
@apply text-gray-400 text-sm;
}
}
.set-action {
@apply flex gap-3 mt-4;
}
</style>