houzhongjian
2024-08-08 820397e43a0b64d35c6d31d2a55475061438593b
提交 | 用户 | 时间
820397 1 <template>
H 2   <el-carousel
3     :height="`${carouselHeight}px`"
4     :autoplay="false"
5     arrow="hover"
6     indicator-position="outside"
7   >
8     <el-carousel-item v-for="(page, pageIndex) in pages" :key="pageIndex">
9       <div class="flex flex-row flex-wrap">
10         <div
11           v-for="(item, index) in page"
12           :key="index"
13           class="relative flex flex-col items-center justify-center"
14           :style="{ width: columnWidth, height: `${rowHeight}px` }"
15         >
16           <!-- 图标 + 角标 -->
17           <div class="relative" :class="`h-${ICON_SIZE}px w-${ICON_SIZE}px`">
18             <!-- 右上角角标 -->
19             <span
20               v-if="item.badge?.show"
21               class="absolute right--10px top--10px z-1 h-20px rounded-10px p-x-6px text-center text-12px leading-20px"
22               :style="{ color: item.badge.textColor, backgroundColor: item.badge.bgColor }"
23             >
24               {{ item.badge.text }}
25             </span>
26             <el-image v-if="item.iconUrl" :src="item.iconUrl" class="h-full w-full" />
27           </div>
28           <!-- 标题 -->
29           <span
30             v-if="property.layout === 'iconText'"
31             class="text-12px"
32             :style="{
33               color: item.titleColor,
34               height: `${TITLE_HEIGHT}px`,
35               lineHeight: `${TITLE_HEIGHT}px`
36             }"
37           >
38             {{ item.title }}
39           </span>
40         </div>
41       </div>
42     </el-carousel-item>
43   </el-carousel>
44 </template>
45
46 <script setup lang="ts">
47 import { MenuSwiperProperty, MenuSwiperItemProperty } from './config'
48 /** 菜单导航 */
49 defineOptions({ name: 'MenuSwiper' })
50 const props = defineProps<{ property: MenuSwiperProperty }>()
51 // 标题的高度
52 const TITLE_HEIGHT = 20
53 // 图标的高度
54 const ICON_SIZE = 42
55 // 垂直间距:一行上下的间距
56 const SPACE_Y = 16
57
58 // 分页
59 const pages = ref<MenuSwiperItemProperty[][]>([])
60 // 轮播图高度
61 const carouselHeight = ref(0)
62 // 行高
63 const rowHeight = ref(0)
64 // 列宽
65 const columnWidth = ref('')
66 watch(
67   () => props.property,
68   () => {
69     // 计算列宽:每一列的百分比
70     columnWidth.value = `${100 * (1 / props.property.column)}%`
71     // 计算行高:图标 + 文字(仅显示图片时为0) + 垂直间距 * 2
72     rowHeight.value =
73       (props.property.layout === 'iconText' ? ICON_SIZE + TITLE_HEIGHT : ICON_SIZE) + SPACE_Y * 2
74     // 计算轮播的高度:行数 * 行高
75     carouselHeight.value = props.property.row * rowHeight.value
76
77     // 每页数量:行数 * 列数
78     const pageSize = props.property.row * props.property.column
79     // 清空分页
80     pages.value = []
81     // 每一页的菜单
82     let pageItems: MenuSwiperItemProperty[] = []
83     for (const item of props.property.list) {
84       // 本页满员,新建下一页
85       if (pageItems.length === pageSize) {
86         pageItems = []
87       }
88       // 增加一页
89       if (pageItems.length === 0) {
90         pages.value.push(pageItems)
91       }
92       // 本页增加一个
93       pageItems.push(item)
94     }
95   },
96   { immediate: true, deep: true }
97 )
98 </script>
99
100 <style lang="scss">
101 // 重写指示器样式,与 APP 保持一致
102 :root {
103   .el-carousel__indicator {
104     padding-top: 0;
105     padding-bottom: 0;
106     .el-carousel__button {
107       --el-carousel-indicator-height: 6px;
108       --el-carousel-indicator-width: 6px;
109       --el-carousel-indicator-out-color: #ff6000;
110       border-radius: 6px;
111     }
112   }
113   .el-carousel__indicator.is-active {
114     .el-carousel__button {
115       --el-carousel-indicator-width: 12px;
116     }
117   }
118 }
119 </style>