194 lines
5.2 KiB
Vue
194 lines
5.2 KiB
Vue
|
|
<template>
|
||
|
|
<view
|
||
|
|
:class="classPrefix + ' ' + tClass"
|
||
|
|
:style="tools._style([customStyle])"
|
||
|
|
>
|
||
|
|
<swiper
|
||
|
|
:class="classPrefix + '-host'"
|
||
|
|
:autoplay="autoplay"
|
||
|
|
:current="current"
|
||
|
|
:interval="interval"
|
||
|
|
:duration="duration"
|
||
|
|
:circular="loop"
|
||
|
|
:vertical="direction == 'vertical'"
|
||
|
|
:easing-function="easingFunction"
|
||
|
|
:previous-margin="tools.addUnit(previousMargin)"
|
||
|
|
:next-margin="tools.addUnit(nextMargin)"
|
||
|
|
:snap-to-edge="snapToEdge"
|
||
|
|
:display-multiple-items="displayMultipleItems"
|
||
|
|
:style="'height: ' + tools.addUnit(height)"
|
||
|
|
@change="onChange"
|
||
|
|
@animationfinish="onAnimationFinish"
|
||
|
|
>
|
||
|
|
<swiper-item
|
||
|
|
v-for="(item, index) in list"
|
||
|
|
:key="index"
|
||
|
|
:class="
|
||
|
|
tools.cls(classPrefix + '__item', [
|
||
|
|
['preview', isPrev(navCurrent, index, list)],
|
||
|
|
['next', isNext(navCurrent, index, list)]
|
||
|
|
])
|
||
|
|
"
|
||
|
|
:data-index="index"
|
||
|
|
:aria-hidden="navCurrent !== index"
|
||
|
|
aria-role="image"
|
||
|
|
:aria-label="tools.isObject(item) ? item.ariaLabel : ''"
|
||
|
|
@click="onTap($event, { index })"
|
||
|
|
>
|
||
|
|
<t-image
|
||
|
|
:t-class="getImageClass(prefix, navCurrent, index, list, tClassImage, tClassPrevImage, tClassNextImage)"
|
||
|
|
:custom-style="'height: ' + tools.addUnit(height) || ''"
|
||
|
|
:error="imageProps.error || 'default'"
|
||
|
|
:lazy="imageProps.lazy || false"
|
||
|
|
:loading="imageProps.loading || 'default'"
|
||
|
|
:shape="imageProps.shape || 'square'"
|
||
|
|
:src="tools.isObject(item) ? item.value : item"
|
||
|
|
:mode="imageProps.mode || 'aspectFill'"
|
||
|
|
:webp="imageProps.webp || false"
|
||
|
|
:show-menu-by-longpress="imageProps.showMenuByLongpress || false"
|
||
|
|
@load="onImageLoad($event, { custom: index || null })"
|
||
|
|
/>
|
||
|
|
</swiper-item>
|
||
|
|
</swiper>
|
||
|
|
<t-swiper-nav
|
||
|
|
v-if="navigation"
|
||
|
|
:t-class="tClassNav"
|
||
|
|
:type="navigation.type || 'dots'"
|
||
|
|
:current="navCurrent || 0"
|
||
|
|
:total="list.length || 0"
|
||
|
|
:direction="direction || 'horizontal'"
|
||
|
|
:pagination-position="paginationPosition || 'bottom'"
|
||
|
|
:min-show-num="navigation.minShowNum || 2"
|
||
|
|
:show-controls="navigation.showControls || false"
|
||
|
|
@nav-btn-change="onNavBtnChange"
|
||
|
|
/>
|
||
|
|
<slot name="navigation" />
|
||
|
|
<slot name="nav" />
|
||
|
|
</view>
|
||
|
|
</template>
|
||
|
|
<script>
|
||
|
|
import TSwiperNav from '../swiper-nav/swiper-nav';
|
||
|
|
import TImage from '../image/image';
|
||
|
|
import { uniComponent } from '../common/src/index';
|
||
|
|
import { prefix } from '../common/config';
|
||
|
|
import props from './props';
|
||
|
|
import tools from '../common/utils.wxs';
|
||
|
|
import { isPrev, isNext, getImageClass } from './computed.js';
|
||
|
|
import { ParentMixin, RELATION_MAP } from '../common/relation';
|
||
|
|
|
||
|
|
const name = `${prefix}-swiper`;
|
||
|
|
|
||
|
|
export default uniComponent({
|
||
|
|
name,
|
||
|
|
options: {
|
||
|
|
multipleSlots: true,
|
||
|
|
styleIsolation: 'shared',
|
||
|
|
},
|
||
|
|
externalClasses: [`${prefix}-class`, `${prefix}-class-nav`, `${prefix}-class-image`, `${prefix}-class-prev-image`, `${prefix}-class-next-image`],
|
||
|
|
mixins: [ParentMixin(RELATION_MAP.SwiperNav)],
|
||
|
|
components: {
|
||
|
|
TSwiperNav,
|
||
|
|
TImage,
|
||
|
|
},
|
||
|
|
props: {
|
||
|
|
...props,
|
||
|
|
},
|
||
|
|
emits: [
|
||
|
|
'click',
|
||
|
|
'change',
|
||
|
|
'animationfinish',
|
||
|
|
'image-load',
|
||
|
|
],
|
||
|
|
data() {
|
||
|
|
return {
|
||
|
|
prefix,
|
||
|
|
classPrefix: name,
|
||
|
|
tools,
|
||
|
|
navCurrent: 0,
|
||
|
|
};
|
||
|
|
},
|
||
|
|
watch: {
|
||
|
|
navCurrent(t) {
|
||
|
|
this.updateNav(t);
|
||
|
|
},
|
||
|
|
},
|
||
|
|
|
||
|
|
mounted() {
|
||
|
|
this.navCurrent = this.current;
|
||
|
|
},
|
||
|
|
|
||
|
|
methods: {
|
||
|
|
isPrev,
|
||
|
|
isNext,
|
||
|
|
getImageClass,
|
||
|
|
|
||
|
|
updateNav(currentValue) {
|
||
|
|
if (this.navigation) return;
|
||
|
|
const $nav = this.getRelationNodes('./swiper-nav')?.[0];
|
||
|
|
if (!$nav) return;
|
||
|
|
const { direction, paginationPosition, list } = this;
|
||
|
|
|
||
|
|
this.current = currentValue;
|
||
|
|
this.total = list.length;
|
||
|
|
this.direction = direction;
|
||
|
|
this.paginationPosition = paginationPosition;
|
||
|
|
},
|
||
|
|
|
||
|
|
onTap(e, dataset) {
|
||
|
|
const { index } = dataset;
|
||
|
|
this.$emit('click', { index });
|
||
|
|
},
|
||
|
|
|
||
|
|
onChange(e) {
|
||
|
|
const { current, source } = e.detail;
|
||
|
|
|
||
|
|
if (!source) return;
|
||
|
|
|
||
|
|
this.navCurrent = current;
|
||
|
|
this.triggerSource = source;
|
||
|
|
|
||
|
|
this.$emit('change', { current, source });
|
||
|
|
},
|
||
|
|
|
||
|
|
onAnimationFinish(e) {
|
||
|
|
const { current, source } = e.detail;
|
||
|
|
|
||
|
|
this.$emit('animationfinish', { current, source: source || this.triggerSource });
|
||
|
|
},
|
||
|
|
|
||
|
|
onNavBtnChange(e) {
|
||
|
|
const { dir, source } = e;
|
||
|
|
|
||
|
|
this.doNavBtnChange(dir, source);
|
||
|
|
},
|
||
|
|
|
||
|
|
doNavBtnChange(dir, source) {
|
||
|
|
const { current, list, loop, navCurrent } = this;
|
||
|
|
const count = list.length;
|
||
|
|
let nextPos = dir === 'next' ? current + 1 : current - 1;
|
||
|
|
|
||
|
|
if (loop) {
|
||
|
|
nextPos = dir === 'next' ? (current + 1) % count : (current - 1 + count) % count;
|
||
|
|
} else {
|
||
|
|
nextPos = nextPos < 0 || nextPos >= count ? current : nextPos;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nextPos === navCurrent) return;
|
||
|
|
|
||
|
|
this.navCurrent = nextPos;
|
||
|
|
this.triggerSource = source;
|
||
|
|
|
||
|
|
this.$emit('change', { current: nextPos, source });
|
||
|
|
},
|
||
|
|
|
||
|
|
onImageLoad(e, dataset) {
|
||
|
|
this.$emit('image-load', { index: dataset.custom });
|
||
|
|
},
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
</script>
|
||
|
|
<style scoped>
|
||
|
|
@import './swiper.css';
|
||
|
|
</style>
|