如何写一个li滑动组件

205 阅读1分钟
<template>
    <div class="drag-list">
        <ul class="drag-list-ul">
            <li v-for="(item, index) in list"
                :key="index"
                @touchstart.prevent="onTouchStart($event,item)"
                @touchmove.prevent="onTouchMove"
                @touchend="onTouchEnd"
                :class="{'drag': tarIndex === index, 'transition': tarIndex != -1}"
                :style="{'transform': 'translate3d(0, ' + item.translateY + 'px, 0)'}"
            >
                <div class="left-icon-wrapper" :class="'pay_type_' + item.value">
                    <i class="icon left-icon" v-html="item.icon"></i>
                </div>
                <div class="drag-list-ul-li-cont">{{item.text}} <i class="icon" v-if="list.length > 1">&#xe315;</i></div>
            </li>
        </ul>
    </div> 
</template>

<script>
export default {
    name: 'DragList',
    props: {
        list: {
            type: Array,
            default: []
        }
        // listItem: {
        //     text: '',
        //     value: 'E',
        //     translateY: 0,
        //     icon: '&#xe442;'
        // }
    },
    data(){
        return {
            delta: 0,
            startY: 0,
            tarIndex: -1,
            moveIndex: 0,
            direction: '',
            tarH: 0
        }
    },
    methods: {
        onTouchStart(e, item) {
            if(this.list.length <= 1) return;
            const target = e.currentTarget;
            this.delta = 0;
            this.startY = e.pageY || e.touches[0].pageY;
            this.tarH = target.clientHeight;
            this.tarIndex = this.list.indexOf(item);
        },
        onTouchMove(e) {
            if(this.list.length <= 1) return;
            const target = e.currentTarget;
            const nowY = e.pageY || e.touches[0].pageY;
            this.delta = nowY - this.startY;
            this.direction = this.delta < 0 ? 'up' : 'down';
            target.style.transform = 'translate3d(0,' + this.delta + 'px, 0)';
            this.moveIndex = this.getMoveIndex();
            this.jostleOtherNode();
        },
        onTouchEnd() {
            if(this.list.length <= 1) return;
            this.updateList();
            this.reset();
        },
        reset() {
            this.delta = 0;
            this.startY = 0;
            this.tarIndex = -1;
            this.moveIndex = 0;
        },
        getMoveIndex() {
            // 计算向上或者向下移动的几个位置 moveIndex < 0 向上  > 0 向下
            let moveIndex = Math.round( this.delta / this.tarH );
            // 边界判断
            const toIndex = this.tarIndex + moveIndex;
            if(toIndex < 0) { // 向上越界
                moveIndex = - this.tarIndex;
            }else if(toIndex > this.list.length - 1) {    // 向下越界
                moveIndex = this.list.length - 1 - this.tarIndex;
            }
            return moveIndex;
        },
        jostleOtherNode() {
            const index = this.tarIndex + this.moveIndex;
            let start, end;
            if(this.direction === 'up') {
                this.list[index].translateY = (index === this.tarIndex) ? this.delta : this.tarH;
                start = 0;
                end = index;
            }else {
                this.list[index].translateY = (index === this.tarIndex) ? this.delta : -this.tarH;
                start = index + 1;
                end = this.list.length;
            }
            // 重置其他节点
            for(let i = start; i < end; i++) {
                if(this.list[i].translateY !== 0) {
                    this.list[i].translateY = 0;
                }
            }
        },
        updateList() {
            const addIndex = this.direction === 'up' ?
                this.tarIndex + this.moveIndex :
                this.tarIndex + this.moveIndex + 1;
            const deleteIndex = this.direction === 'up' ? this.tarIndex + 1 : this.tarIndex;
            const value = this.list[this.tarIndex];
         
            this.$emit('updateList',{addIndex,deleteIndex,value}); //通知父组件重新渲染

        }
    }
}
</script>