绩效考核手机版
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

270 lines
8.5 KiB

3 years ago
<template>
<view class="s-swiper" :class="c_class" :style="custom_style">
<swiper
:indicator-dots="false"
:current="current"
:autoplay="autoplay"
:interval="interval"
:duration="duration"
:circular="circular"
:vertical="vertical"
:previous-margin="previous_margin"
:next-margin="next_margin"
:display-multiple-items="displayMultipleItems"
:style="swiper_style"
@change="onChange"
>
<swiper-item v-for="(item, index) of list" :key="index">
<view class="s-swiper-item" :class="{ 's-swiper-item--active': isActive(index) }" :style="item_style">
<view class="s-swiper-item__wrap" :style="wrap_style" @click="onItemClick(index)">
<slot :scopeParams="scopeParams" :item="item" :index="index" :active="isActive(index)">
<s-image
:src="getSrc(item)"
custom-class="s-swiper-item__image"
:mode="imgMode"
:show-loading="imgLoading"
:fade-show="imgFade"
/>
</slot>
</view>
</view>
</swiper-item>
</swiper>
<slot v-if="indicator" name="indicator">
<view class="s-swiper-indicators" :class="indicators_class" :style="indicators_style">
<view
v-for="(item, index) of list"
:key="index"
class="s-swiper-indicator"
:class="indicatorClassList[index]"
:style="indicatorStyleList[index]"
@click="onItemClick(index)"
></view>
</view>
</slot>
</view>
</template>
<script>
import componentMixin from '../../mixins/componentMixin';
/**
* s-swiper 轮播
* @description 该组件一般用于banner轮播
* @property {Array} list 轮播图数据
* @property {String|Number} height swiper 高度
* @property {String} name list中对象数据读取图片url的属性名
* @property {Boolean} autoplay 是否自动切换
* @property {Number} current 当前所在滑块的 index
* @property {String} type = [3d|chain] 轮播类型
* @property {String} background 图片容器背景
* @property {String|Number} margin 左右inset距离
* @property {String|Number} chainMargin type为chain时左右边距
* @property {String|Number} gutter 轮播之间间距
* @property {String|Number} padding 轮播内边距不能和gutter同时使用
* @property {Number} interval 自动切换时间间隔
* @property {Number} duration 滑动动画时长
* @property {Boolean} circular 是否采用衔接滑动即播放到末尾后重新回到开头
* @property {Boolean} vertical 滑动方向是否为纵向
* @property {Number} displayMultipleItems 同时显示的滑块数量
* @property {String|Number} radius 圆角
* @property {String} imgMode = [scaleToFill|aspectFill|widthFix] 图片裁剪缩放的模式
* @property {Boolean} imgLoading 图片是否显示加载状态
* @property {Boolean} imgFade 图片加载显示时fade效果
* @property {Boolean} indicator 是否显示指示点
* @property {String} indicatorType = [default|round|rect] 指示点类型
* @property {String|Object} indicatorWrapClass 指示点容器class
* @property {String|Object} indicatorWrapStyle 指示点容器样式
* @property {String|Number} indicatorGutter 指示点之间间距
* @property {String} indicatorColor 指示点颜色
* @property {String} indicatorActiveColor 当前选中的指示点颜色
* @property {String|Object} indicatorStyle 指示点样式
* @property {String|Object} indicatorActiveStyle 当前选中指示点样式
* @event {Function} click (current) 点击轮播图时触发
* @event {Function} change (current, source) 轮播图切换时触发(自动或者手动切换)
* @example <s-swiper :list="[]"/>
*/
export default {
name: 'SSwiper',
mixins: [componentMixin],
props: {
list: {
type: Array,
default: () => [],
},
height: {
type: [String, Number],
default: 300,
},
type: String,
background: String,
name: {
type: String,
default: 'url',
},
margin: [Number, String],
chainMargin: [Number, String],
gutter: [Number, String],
padding: [Number, String],
autoplay: Boolean,
current: {
type: Number,
default: 0,
},
interval: {
type: Number,
default: 5000,
},
duration: {
type: Number,
default: 500,
},
circular: Boolean,
vertical: Boolean,
displayMultipleItems: {
type: Number,
default: 1,
},
radius: [Number, String],
imgMode: {
type: String,
default: 'aspectFill',
},
imgLoading: Boolean,
imgFade: Boolean,
indicator: Boolean,
indicatorType: {
type: String,
default: 'default',
},
indicatorWrapClass: [String, Object],
indicatorWrapStyle: [String, Object],
indicatorGutter: [Number, String],
indicatorColor: String,
indicatorActiveColor: String,
indicatorStyle: [String, Object],
indicatorActiveStyle: [String, Object],
},
data: () => ({
activeIndex: 0,
}),
computed: {
c_class() {
return this.$mergeClass('s-swiper--' + (this.vertical ? 'vertical' : 'horizontal'), {
[`s-swiper--${this.type}`]: this.type,
}, this.custom_class);
},
swiper_style() {
return this.$mergeStyle({
height: this.$addUnit(this.height),
});
},
gutterNum() {
return Math.round(this.$toPx(this.gutter) / 2);
},
marginNum() {
return this.$toPx(this.margin) - this.gutterNum;
},
chainMarginNum() {
return this.$toPx(this.chainMargin) - this.gutterNum;
},
previous_margin() {
if (this.type === 'chain') {
switch (this.activeIndex) {
case 0:
return this.chainMarginNum + 'px';
case this.list.length - 1:
return this.marginNum + 'px';
default:
return parseInt((this.marginNum + this.chainMarginNum) / 2) + 'px';
}
}
return this.marginNum + 'px';
},
next_margin() {
if (this.type === 'chain') {
switch (this.activeIndex) {
case 0:
return this.marginNum + 'px';
case this.list.length - 1:
return this.chainMarginNum + 'px';
default:
return parseInt((this.marginNum + this.chainMarginNum) / 2) + 'px';
}
}
return this.marginNum + 'px';
},
indicators_class() {
return this.$mergeClass('s-swiper-indicators--' + (this.vertical ? 'vertical' : 'horizontal'), {
[`s-swiper-indicators--${this.indicatorType}`]: this.indicatorType !== 'none',
}, this.indicatorWrapClass);
},
indicators_style() {
return this.$mergeStyle(this.indicatorWrapStyle);
},
item_style() {
const style = {};
const { padding, vertical, gutterNum } = this;
if (padding) {
style.padding = this.$addUnit(padding);
} else if (gutterNum) {
style[vertical ? 'paddingTop' : 'paddingLeft'] = gutterNum + 'px';
style[vertical ? 'paddingBottom' : 'paddingRight'] = gutterNum + 'px';
}
return this.$mergeStyle(style);
},
wrap_style() {
return this.$mergeStyle({
background: this.background,
borderRadius: this.$addUnit(this.radius),
});
},
indicatorClassList() {
return this.list.map((item, index) => this.$mergeClass({
's-swiper-indicator--active': this.isActive(index),
}));
},
indicatorStyleList() {
return this.list.map((item, index) => {
const isActive = this.isActive(index);
const style = {
background: isActive ? this.indicatorActiveColor : this.indicatorColor,
};
if (index > 0) {
style[this.vertical ? 'marginTop' : 'marginLeft'] = this.$addUnit(this.indicatorGutter);
}
return this.$mergeStyle(style, this.indicatorStyle, isActive ? this.indicatorActiveStyle : '');
});
},
},
watch: {
current: {
immediate: true,
handler() {
this.activeIndex = this.current;
},
},
},
methods: {
getSrc(item) {
return item && typeof item === 'object' ? item[this.name] : item;
},
isActive(index) {
return this.activeIndex === index;
},
onItemClick(index) {
this.$emit('click', index);
},
onChange(e) {
const { current, source } = e.detail;
this.activeIndex = current;
this.$emit('update:current', current);
this.$emit('change', current, source);
},
},
};
</script>
<style lang="scss" src="./index.scss"></style>