209 lines
4.3 KiB
Vue
209 lines
4.3 KiB
Vue
<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>
|