1. 程式人生 > 實用技巧 >手寫一個移動端帶慣性的輪播圖vue元件

手寫一個移動端帶慣性的輪播圖vue元件

利用vue的插槽(solt)的方法實現

  1. 帶有慣性
  2. 可以適應手機端螢幕
  3. 可以靈活的修改樣式
  4. 可以手動的拖拽
  5. 拉力
呼叫方式:
  1. 引入元件
    export default defineComponent({
        components: {
            slide
        },

  2. 在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>

  3. 在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', width: 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/vendor/vendor'; 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; width: 100%; background: #F5F5F5; .swiper-dots { display: block; position: absolute; right: 0; width: 100%; bottom: .25rem; height: .06rem; list-style: none; text-align: center; & > li { width: .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 { width: 100%; position: relative; .swiper-wrapper { display: flex; position: relative; transition-property: transform, height, -webkit-transform, -moz-transform, -o-transform; } } </style>

總結:

  1. 相比於其他元件庫的元件可能用起來不夠簡單
  2. 但是也有自己的有點即靈活度比較高,可以根據自己的想法擴充套件成自己的元件
  3. 可以隨意的填寫自己的樣式,做成自己想要的樣子