automated_uniapp/uni_modules/cool-fixtures/components/fix-menus/fix-menus.vue

209 lines
4.3 KiB
Vue
Raw Normal View History

2025-01-09 16:40:44 +08:00
<template>
<fix-base-style
:styleSpacing="styleSpacing"
:styleColor="styleColor"
:position="position"
:index="index"
>
<view class="fix-menus">
<swiper
class="inner"
:style="{
height: height,
}"
:circular="false"
:indicator-dots="false"
@change="changeCurrent"
>
<swiper-item v-for="(item, index) in tabs" :key="index">
<view
class="row"
:class="[`is-${style.rowNum}`]"
v-for="(row, r) in item"
:key="r"
>
<view
class="item"
v-for="(col, c) in row"
:key="c"
@click="toPath(col.link)"
>
<view
:class="[`is-${style.shape}`, `is-${col.mode}`]"
:style="{ backgroundColor: col.backgroundColor }"
class="icon-box"
>
<cl-image :src="col.icon" mode="aspectFill" class="icon">
</cl-image>
</view>
<span
v-if="col.mode == 'mode-1'"
class="text"
:style="{ color: col.color }"
>{{ col.text }}</span
>
</view>
</view>
</swiper-item>
</swiper>
<!-- 自定义指示器 -->
<view class="custom-indicator">
<view
v-for="(item, index) in tabs"
:key="index"
class="custom-indicator-dot"
:class="{ active: current === index }"
></view>
</view>
</view>
</fix-base-style>
</template>
<script lang="ts" setup name="fix-menus">
import { computed, ref, type PropType } from "vue";
import type { Form } from "../../types/form";
import { baseProps } from "../../hooks";
const emits = defineEmits(["jump"]);
const props = defineProps({
style: {
type: Object,
default: () => {
return {
shape: "round",
pageNum: 1,
rowNum: 3,
};
},
},
list: {
type: Array as PropType<Form.Menu[]>,
default: () => [],
},
index: {
type: Number,
default: 0,
},
...baseProps,
});
const current = ref(0);
function changeCurrent(event: any) {
current.value = event.detail.current;
}
const height = computed(() => {
return 180 * props.style.pageNum + "rpx";
});
const tabs = computed(() => {
return paginateArray(props.list, props.style.pageNum, props.style.rowNum);
});
// 解决 每页1行 每行3个 的问题
function paginateArray(data: Form.Menu[], pageNum: number, rowNum: number) {
const result: any[] = [];
const totalItems = data.length;
let pageIndex = 0;
while (pageIndex < totalItems) {
const page: any[] = [];
for (let i = 0; i < pageNum && pageIndex < totalItems; i++) {
const row: any[] = [];
for (let j = 0; j < rowNum && pageIndex < totalItems; j++) {
row.push(data[pageIndex]);
pageIndex++;
}
page.push(row);
}
result.push(page);
}
return result;
}
function toPath(link: Form.Link) {
emits("jump", link);
}
</script>
<style lang="scss" scoped>
.fix-menus {
width: 100%;
padding-bottom: 20rpx;
.inner {
height: 100%;
padding: 10rpx;
box-sizing: border-box;
.row {
margin-bottom: 20rpx;
.item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 160rpx;
box-sizing: border-box;
.is-round {
border-radius: 40rpx;
}
.is-mode-2 {
width: 120rpx !important;
height: 120rpx !important;
}
.icon-box {
width: 80rpx;
height: 80rpx;
overflow: hidden;
.icon {
width: 100%;
height: 100%;
}
}
.text {
font-size: 26rpx;
margin-top: 12rpx;
}
}
}
.row:last-child {
margin-bottom: 0;
}
.is-3 {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 每行3列每列宽度相等 */
gap: 20rpx; /* 间距 */
}
.is-4 {
display: grid;
grid-template-columns: repeat(4, 1fr); /* 每行3列每列宽度相等 */
gap: 20rpx; /* 间距 */
}
.is-5 {
display: grid;
grid-template-columns: repeat(5, 1fr); /* 每行3列每列宽度相等 */
gap: 20rpx; /* 间距 */
}
}
}
.custom-indicator {
display: flex;
justify-content: center;
}
.custom-indicator-dot {
width: 12rpx;
height: 12rpx;
background-color: #686580;
border-radius: 50%; /* 默认圆形 */
margin: 0 10rpx;
transition: all 0.3s ease; /* 过渡效果 */
}
.custom-indicator-dot.active {
width: 40rpx; /* 激活状态变成长方形 */
height: 12rpx;
background: var(--btn-color) !important;
border-radius: 20rpx; /* 调整边角的圆度 */
transition: all 0.5s ease; /* 激活状态有更慢的动画过渡 */
}
</style>