利用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>
总结:
- 相比于其他组件库的组件可能用起来不够简单
- 但是也有自己的优点即灵活度比较高,可以根据自己的想法扩展成自己的组件
- 可以随意的填写自己的样式,做成自己想要的样子