利用vue的插槽(solt)的方法实现
- 带有惯性
- 可以适应手机端屏幕
- 可以灵活的修改样式
- 可以手动的拖拽
- 拉力
调用方式:
- 引入组件
export default defineComponent({ components: { slide },
- 在template模板插入代码
<slide ref="slide" :count="swiperData.length" :springrange=".2" > <slot slot="swiper-item" v-for="(item, index) in swiperData"> <div class="emoji-item"> </div> </slot> </slide>
- 在style编swiper-item的样式。
组件代码:
<template>
<div class="swiper-container">
<div
class="swiper-touch"
ref="touch"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd">
<div
class="swiper-wrapper"
:style="{
transform: 'translate3d(' + slideEffect + 'px, 0px, 0px)',
transitionDuration: tdurationTime + 'ms',
count + '00%'
}"
>
<slot name="swiper-item"></slot>
</div>
</div>
<ul class="swiper-dots">
<li
v-for="num in count"
:key="num"
:class="currantIndex === num?'swiper-dots-active':''"
@click="handleChangeCurrantIndex(num)">
</li>
</ul>
</div>
</template>
<script lang="ts">
import {
VueCompositionApiLib as VC,
toRefs,
defineComponent,
reactive,
onMounted
} from 'common';
interface Props {
count: number;
springrange: number;
tduration: number;
isShowIndexBtn: boolean;
}
export default defineComponent({
props: {
count: {
type: Number,
default: 0
},
isShowIndexBtn: {
type: Boolean,
default: true
},
springrange: {
type: Number,
default: 0.2
},
tduration: {
type: Number,
default: 300
}
},
setup(props: Props, context: VC.SetupContext) {
const state = reactive({
startX: 0, // 开始触摸的位置
moveX: 0, // 滑动时的位置
endX: 0, // 结束触摸的位置
disX: 0, // 移动距离
springWidth: 0, // 回弹的范围屏幕的百分比0.2即左右五分之一
slideEffect: 0, // 当前位移像素
btnWidth: 0, // 页面宽度
currantIndex: 1, // 当前slide
tdurationTime: 300, // 过渡时间
lastEndSpead: 0, // 上次的位置
status: 'a' // c不可以切换上一张,a可以上下切换,b不能切换下一张
});
onMounted(() => {
state.btnWidth = context.refs.touch.offsetWidth;
state.springWidth = props.springrange * state.btnWidth;
state.tdurationTime = props.tduration;
});
const touchStart = (e: any) => {
e = e || event;
if (e.touches.length === 1) {
state.startX = e.touches[0].clientX; // 记录开始位置
}
};
const touchMove = (e: any) => {
e = e || event;
state.tdurationTime = 0;
state.moveX = e.touches[0].clientX;
state.disX = state.moveX - state.startX;
// 在边界的时候做一些拉力的判断
if(state.disX > 0 && state.currantIndex === 1){
state.slideEffect = state.disX / 3 + state.lastEndSpead;
}
else if(state.disX < 0 && state.currantIndex === props.count)
state.slideEffect = state.disX / 3 + state.lastEndSpead;
else {
state.slideEffect = state.disX + state.lastEndSpead;
}
// disX不考虑回弹时小于0下一张大于0上一张
};
const next = () => {
state.slideEffect = -state.btnWidth + state.lastEndSpead;
state.currantIndex += 1;
};
const last = () => {
state.slideEffect = state.btnWidth + state.lastEndSpead;
state.currantIndex -= 1;
};
const forbidChange = () => {
state.slideEffect = state.lastEndSpead;
};
const actions: any = {
'a': next,
'b': last,
'c': forbidChange
};
const touchEnd = (e: any) => {
e = e || event;
state.tdurationTime = props.tduration;
state.endX = e.changedTouches[0].clientX;
if (Math.abs(state.disX) < state.springWidth && state.currantIndex) {
state.status = 'c';
}
else if (state.disX < 0 && state.currantIndex === props.count) {
state.status = 'c';
}
else if (state.disX > 0 && state.currantIndex === 1) {
state.status = 'c';
}
else if (state.disX > 0) {
state.status = 'b';
}
else if (state.disX < 0) {
state.status = 'a';
}
state.disX = 0;
actions[state.status]();
state.lastEndSpead = state.slideEffect;
};
const handleChangeCurrantIndex = (num: number) => {
state.currantIndex = num;
state.slideEffect = -state.btnWidth * (num - 1);
state.lastEndSpead = state.slideEffect;
};
return {
...toRefs(state),
touchStart,
touchMove,
touchEnd,
handleChangeCurrantIndex
};
}
});
</script>
<style lang="less" scoped>
.swiper-container {
overflow: hidden;
z-index: 1;
100%;
background: #F5F5F5;
.swiper-dots {
display: block;
position: absolute;
right: 0;
100%;
bottom: .25rem;
height: .06rem;
list-style: none;
text-align: center;
& > li {
.07rem;
height: .07rem;
margin: 0 .04rem;
background: #ccc;
display: inline-block;
vertical-align: top;
border-radius: 50%;
opacity: .45;
}
.swiper-dots-active {
opacity: 1;
}
}
}
.swiper-touch {
100%;
position: relative;
.swiper-wrapper {
display: flex;
position: relative;
transition-property: transform, height, -webkit-transform, -moz-transform, -o-transform;
}
}
</style>
总结:
- 相比于其他组件库的组件可能用起来不够简单
- 但是也有自己的优点即灵活度比较高,可以根据自己的想法扩展成自己的组件
- 可以随意的填写自己的样式,做成自己想要的样子