zoukankan      html  css  js  c++  java
  • 手写一个移动端带惯性的轮播图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',
                         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>

    总结:

    1. 相比于其他组件库的组件可能用起来不够简单
    2. 但是也有自己的优点即灵活度比较高,可以根据自己的想法扩展成自己的组件
    3. 可以随意的填写自己的样式,做成自己想要的样子
  • 相关阅读:
    子矩阵
    [Ahoi2008]Meet 紧急集合
    立体图
    CF933B A Determined Cleanup
    CF746G New Roads
    树的重量
    CF519E A and B and Lecture Rooms
    矩阵
    深入浅出乘法逆元
    20180519模拟赛T2——pretty
  • 原文地址:https://www.cnblogs.com/tipsydr/p/13784787.html
Copyright © 2011-2022 走看看