导航组单行时支持轮播

v1.1.0
于肖磊 2024-11-19 13:35:39 +08:00
parent bade4b326f
commit f06963d5ac
4 changed files with 85 additions and 70 deletions

View File

@ -23,6 +23,7 @@ interface nav_group_styles {
radius_bottom_right: number;
is_show: string;
is_roll: string;
rolling_fashion: string;
interval_time: number;
indicator_style: string;
indicator_location: string;

View File

@ -1,8 +1,8 @@
<template>
<div :style="style_container">
<div class="re" :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">
<swiper :key="carouselKey" class="w flex" direction="horizontal" :loop="true" :autoplay="autoplay" :slides-per-view="slides_per_view" :slides-per-group="1" :allow-touch-move="false" :pause-on-mouse-enter="true" :modules="modules" @slide-change="slideChange">
<swiper-slide 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">
@ -11,13 +11,12 @@
<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>
</swiper-slide>
</swiper>
<div v-if="form.display_style == 'slide' && new_style.is_show == '1'" :class="['left', 'right'].includes(new_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="indicator_location_style">
<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>
<span class="num-active">{{ actived_index + 1 }}</span><span>/{{ nav_content_list.length }}</span>
</div>
</template>
<template v-else>
@ -30,6 +29,10 @@
<script setup lang="ts">
import { common_styles_computer, radius_computer, get_math, common_img_computer } from '@/utils';
import { isEmpty, cloneDeep, throttle } from 'lodash';
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Autoplay } from 'swiper/modules';
import 'swiper/css';
const modules = [Autoplay];
const props = defineProps({
value: {
@ -117,17 +120,8 @@ const nav_title_space = computed(() => 'row-gap:' + (new_style.value?.title_spac
const bannerImg = ref();
//
const newHeight = ref('100px');
//
const interval_time = ref(2000);
//
const is_roll = ref(false);
// key
const carouselKey = ref('0');
//
const interval_list = ref({
time: 2000,
is_roll: '0',
});
//
onMounted(() => {
@ -142,8 +136,6 @@ onMounted(() => {
});
//
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');
@ -153,56 +145,70 @@ const nav_content_list = computed(() => {
//
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) });
let nav_list: any[] = [];
//
if (form.value.row == 1 && new_style.value.rolling_fashion == 'translation') {
//
list.forEach((item: any) => {
nav_list.push({
split_list: [item],
});
});
return nav_list;
} else {
//
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;
}
return nav_list;
} else {
//
return [{ split_list: list }];
}
});
const autoplay = ref<boolean | object>(false);
const slides_per_view = ref(1);
//
const group_width = ref('100%');
//
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();
watch(() => props.value, (val) => {
const display_is_roll = form.value.display_style == 'slide' ? new_style.value.is_roll : '0';
//
if (display_is_roll == '1') {
autoplay.value = {
delay: (new_style.value.interval_time || 2) * 1000,
pauseOnMouseEnter: true,
};
} else {
autoplay.value = false;
}
//
if (form.value?.display_style == 'slide') {
if (form.value.row == 1 && new_style.value.rolling_fashion == 'translation') {
slides_per_view.value = form.value.single_line || 4;
group_width.value = '100%';
} else {
slides_per_view.value = 1;
group_width.value = `${100 / (form.value.single_line || 4)}%`;
}
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;
} else {
group_width.value = `${100 / (form.value.single_line || 4)}%`;
}
// key
carouselKey.value = get_math();
nextTick(() => {
if (!isEmpty(bannerImg.value)) {
newHeight.value = (bannerImg.value[0]?.clientHeight || 100) + 'px';
}
});
}, {immediate: true, deep: true});
const slideChange = (swiper: { realIndex: number }) => {
actived_index.value = swiper.realIndex;
};
</script>
<style lang="scss" scoped>
@ -231,9 +237,7 @@ const carousel_change = (index: number) => {
}
}
:deep(.el-carousel) {
.el-carousel__container {
height: v-bind(newHeight);
}
:deep(.swiper) {
height: v-bind(newHeight);
}
</style>

View File

@ -27,9 +27,17 @@
<el-form-item label="自动轮播">
<el-switch v-model="form.is_roll" active-value="1" inactive-value="0" />
</el-form-item>
<el-form-item v-if="form.is_roll == '1'" label="间隔时间">
<slider v-model="form.interval_time" :min="1" :max="100"></slider>
</el-form-item>
<template v-if="form.is_roll == '1'">
<el-form-item label="间隔时间">
<slider v-model="form.interval_time" :min="1" :max="100"></slider>
</el-form-item>
<el-form-item v-if="data_content.row === 1" label="滚动方式">
<el-radio-group v-model="form.rolling_fashion">
<el-radio value="translation">平移</el-radio>
<el-radio value="cut-screen">切屏</el-radio>
</el-radio-group>
</el-form-item>
</template>
</card-container>
<div class="divider-line"></div>
<card-container>
@ -68,6 +76,7 @@ const props = withDefaults(defineProps<Props>(), {
radius_bottom_right: 0,
is_show: '1',
is_roll: '1',
rolling_fashion: 'translation',
interval_time: 3,
indicator_style: 'dot',
indicator_location: 'center',
@ -90,10 +99,10 @@ const props = withDefaults(defineProps<Props>(), {
const state = reactive({
form: props.value,
content: props.content,
data_content: props.content,
});
// 使toRefs
const { form } = toRefs(state);
const { form, data_content } = toRefs(state);
//
const radius_change = (radius: nav_group_styles) => {
@ -106,9 +115,8 @@ const common_styles_update = (val: Object) => {
//
const display_style_show = computed(() => {
const { content } = toRefs(state);
if (!isEmpty(content.value)) {
return content.value.display_style == 'slide';
if (!isEmpty(data_content.value)) {
return data_content.value.display_style == 'slide';
} else {
return false;
}

View File

@ -24,6 +24,7 @@ interface defaultSearch {
radius_bottom_right: number;
is_show: string;
is_roll: string;
rolling_fashion: string;
interval_time: number;
indicator_style: string;
indicator_bottom: number;
@ -94,6 +95,7 @@ const defaultSearch: defaultSearch = {
interval_time: 3,
// 指示器处理逻辑
is_show: '1',
rolling_fashion: 'translation',
indicator_style: 'dot',
indicator_new_location: 'bottom',
indicator_location: 'center',