vr-uniapp/src/components/model-nav-group/index.vue

209 lines
7.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div :style="style_container">
<div :style="style_img_container">
<el-carousel :key="carouselKey" indicator-position="none" :interval="interval_time" arrow="never" :autoplay="is_roll" @change="carousel_change">
<el-carousel-item v-for="(item, index) in nav_content_list" :key="index">
<div ref="bannerImg" class="flex flex-wrap" :style="nav_space">
<div v-for="(item1, index1) in item.split_list" :key="index1" class="item flex-col align-c" :style="nav_title_space">
<div v-if="['image_with_text', 'image'].includes(nav_style)" class="top-img flex align-c jc-c">
<image-empty v-model="item1.img[0]" :style="img_style"></image-empty>
</div>
<p v-if="['image_with_text', 'text'].includes(nav_style)" class="w size-12 ma-0 nowrap oh tc" :style="text_style">{{ item1.title }}</p>
</div>
</div>
</el-carousel-item>
</el-carousel>
<div v-if="form.display_style == 'slide' && new_style.is_show == '1'" :style="{ 'justify-content': new_style?.indicator_location || 'center' }" class="dot flex mt-10 mb-4">
<template v-if="new_style.indicator_style == 'num'">
<div :style="indicator_style" class="dot-item">
<span class="num-active">{{ actived_index + 1 }}</span
><span>/{{ nav_content_list.length }}</span>
</div>
</template>
<template v-else>
<div v-for="(item, index) in nav_content_list" :key="index" :style="indicator_style" :class="{ 'dot-item': true, active: actived_index == index }" />
</template>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { common_styles_computer, radius_computer, get_math, common_img_computer } from '@/utils';
import { isEmpty, cloneDeep, throttle } from 'lodash';
const props = defineProps({
value: {
type: Object,
default: () => {
return {};
},
},
});
// 用于页面判断显示
const state = reactive({
form: props.value.content,
new_style: props.value.style,
});
// 如果需要解构确保使用toRefs
const { form, new_style } = toRefs(state);
// 用于样式显示
const style_container = computed(() => common_styles_computer(new_style.value.common_style));
const style_img_container = computed(() => common_img_computer(new_style.value.common_style));
// 图片的设置
const img_style = computed(() => radius_computer(new_style.value));
// 标题的样式
const text_style = computed(() => `font-size: ${new_style.value.title_size || 12}px; color: ${new_style.value.title_color || '#000'};`);
// 指示器的样式
const indicator_style = computed(() => {
let indicator_styles = '';
if (!isEmpty(new_style.value.indicator_radius)) {
indicator_styles += radius_computer(new_style.value.indicator_radius);
}
const size = new_style.value?.indicator_size || 5;
if (new_style.value.indicator_style == 'num') {
indicator_styles += `color: ${new_style.value?.color || '#DDDDDD'};`;
indicator_styles += `font-size: ${size}px;`;
} else if (new_style.value.indicator_style == 'elliptic') {
indicator_styles += `background: ${new_style.value?.color || '#DDDDDD'};`;
indicator_styles += `width: ${size * 3}px; height: ${size}px;`;
} else {
indicator_styles += `background: ${new_style.value?.color || '#DDDDDD'};`;
indicator_styles += `width: ${size}px; height: ${size}px;`;
}
return indicator_styles;
});
// 导航间距
const nav_space = computed(() => 'row-gap:' + (new_style.value?.space || '0') + 'px');
// 导航标题间距
const nav_title_space = computed(() => 'row-gap:' + (new_style.value?.title_space || '0') + 'px');
// 获取轮播图片的节点
const bannerImg = ref();
// 轮播图自适应高度
const newHeight = ref('100px');
// 轮播图定时显示
const interval_time = ref(2000);
// 轮播图是否滚动
const is_roll = ref(false);
// 轮播图key值
const carouselKey = ref('0');
// 轮播图滚动位置
const actived_index = ref(0);
// 轮播图显示样式
const actived_color = computed(() => new_style.value?.actived_color || '#2A94FF');
// 记录当前显示的轮播图的数据
const interval_list = ref({
time: 2000,
is_roll: '0',
});
//监听屏幕缩放事件
onMounted(() => {
window.onresize = () => {
newHeight.value = bannerImg.value[0].clientHeight + 'px';
};
});
// 导航图片大小
const img_size = computed(() => (new_style.value?.img_size || '0') + 'px');
// 每个导航所占位置
const group_width = computed(() => `${100 / (form.value.single_line || 4)}%`);
// 是否显示标题和图片
const nav_style = computed(() => form.value?.nav_style || 'image_with_text');
const nav_content_list = computed(() => {
// 深拷贝一下,确保不会出现问题
const list = cloneDeep(form.value?.nav_content_list || Array(4));
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
if (list.length > 0 && form.value?.display_style == 'slide') {
// 存储数据显示
let nav_list = [];
// 每页显示的数量
const num = (form.value?.single_line || 4) * (form.value?.row || 1);
// 拆分的数量
const split_num = Math.ceil(list.length / num);
for (let i = 0; i < split_num; i++) {
nav_list.push({ split_list: list.slice(i * num, (i + 1) * num) });
}
return nav_list;
} else {
// 否则的话,就返回全部的信息
return [{ split_list: list }];
}
});
// 内容参数的集合
watch(
props.value,
(val) => {
const new_style = val.style;
const form = val.content;
//#region 轮播图设置
const time = (new_style.interval_time || 2) * 1000;
const display_is_roll = form.display_style == 'slide' ? new_style.is_roll || true : new_style.is_roll || false;
// 判断跟历史的是否相等,不相等更新组件时间
if (interval_list.value.time != time || interval_list.value.is_roll != display_is_roll) {
// 滚动时间
interval_time.value = time;
// 是否滚动
is_roll.value = display_is_roll == '1' ? true : false;
// 记录历史保存的时间
interval_list.value = {
time: time,
is_roll: display_is_roll,
};
// 更新轮播图的key确保更换时能重新更新轮播图
carouselKey.value = get_math();
}
nextTick(() => {
if (!isEmpty(bannerImg.value)) {
newHeight.value = (bannerImg.value[0]?.clientHeight || 100) + 'px';
}
});
//#endregion
},
{ immediate: true, deep: true }
);
const carousel_change = (index: number) => {
actived_index.value = index;
};
</script>
<style lang="scss" scoped>
.top-img {
height: v-bind(img_size);
width: v-bind(img_size);
border-radius: 4px;
:deep(.image-slot) {
height: v-bind(img_size);
width: v-bind(img_size);
img {
width: 3.5rem;
height: 3.5rem;
}
}
}
.flex-wrap .item {
width: v-bind(group_width);
}
.dot {
padding-right: 10px;
padding-left: 10px;
.dot-item {
margin: 0 0.3rem;
&.active {
background: v-bind(actived_color) !important;
}
.num-active {
color: v-bind(actived_color) !important;
}
}
}
:deep(.el-carousel) {
.el-carousel__container {
height: v-bind(newHeight);
}
}
</style>