// nvue操作dom的库,用于获取dom的尺寸信息 
 | 
const dom = uni.requireNativePlugin('dom'); 
 | 
const bindingX = uni.requireNativePlugin('bindingx'); 
 | 
const animation = uni.requireNativePlugin('animation'); 
 | 
  
 | 
export default { 
 | 
    data() { 
 | 
        return { 
 | 
            // 所有按钮的总宽度 
 | 
            buttonsWidth: 0, 
 | 
            // 是否正在移动中 
 | 
            moving: false 
 | 
        } 
 | 
    }, 
 | 
    computed: { 
 | 
        // 获取过渡时间 
 | 
        getDuratin() { 
 | 
            let duration = String(this.duration) 
 | 
            // 如果ms为单位,返回ms的数值部分 
 | 
            if (duration.indexOf('ms') >= 0) return parseInt(duration) 
 | 
            // 如果s为单位,为了得到ms的数值,需要乘以1000 
 | 
            if (duration.indexOf('s') >= 0) return parseInt(duration) * 1000 
 | 
            // 如果值传了数值,且小于30,认为是s单位 
 | 
            duration = Number(duration) 
 | 
            return duration < 30 ? duration * 1000 : duration 
 | 
        } 
 | 
    }, 
 | 
    watch: { 
 | 
        show(n) { 
 | 
            if(n) { 
 | 
                this.moveCellByAnimation('open')  
 | 
            } else { 
 | 
                this.moveCellByAnimation('close')  
 | 
            } 
 | 
        } 
 | 
    }, 
 | 
    mounted() { 
 | 
        this.initialize() 
 | 
    }, 
 | 
    methods: { 
 | 
        initialize() { 
 | 
            this.queryRect()  
 | 
        }, 
 | 
        // 关闭单元格,用于打开一个,自动关闭其他单元格的场景 
 | 
        closeHandler() { 
 | 
            if(this.status === 'open') { 
 | 
                // 如果在打开状态下,进行点击的话,直接关闭单元格 
 | 
                return this.moveCellByAnimation('close') && this.unbindBindingX() 
 | 
            } 
 | 
        }, 
 | 
        // 点击单元格 
 | 
        clickHandler() { 
 | 
            // 如果在移动中被点击,进行忽略 
 | 
            if(this.moving) return 
 | 
            // 尝试关闭其他打开的单元格 
 | 
            this.parent && this.parent.closeOther(this) 
 | 
            if(this.status === 'open') { 
 | 
                // 如果在打开状态下,进行点击的话,直接关闭单元格 
 | 
                return this.moveCellByAnimation('close') && this.unbindBindingX() 
 | 
            } 
 | 
        }, 
 | 
        // 滑动单元格 
 | 
        onTouchstart(e) { 
 | 
            // 如果当前正在移动中,或者disabled状态,则返回 
 | 
            if(this.moving || this.disabled) {  
 | 
                return this.unbindBindingX()    
 | 
            } 
 | 
            if(this.status === 'open') { 
 | 
                // 如果在打开状态下,进行点击的话,直接关闭单元格 
 | 
                return this.moveCellByAnimation('close') && this.unbindBindingX() 
 | 
            } 
 | 
            // 特殊情况下,e可能不为一个对象 
 | 
            e?.stopPropagation && e.stopPropagation()  
 | 
            e?.preventDefault && e.preventDefault() 
 | 
            this.moving = true 
 | 
            // 获取元素ref 
 | 
            const content = this.getContentRef() 
 | 
            let expression = `min(max(${-this.buttonsWidth}, x), 0)` 
 | 
            // 尝试关闭其他打开的单元格 
 | 
            this.parent && this.parent.closeOther(this) 
 | 
             
 | 
            // 阿里为了KPI而开源的BindingX 
 | 
            this.panEvent = bindingX.bind({ 
 | 
                anchor: content, 
 | 
                eventType: 'pan', 
 | 
                props: [{ 
 | 
                    element: content, 
 | 
                    // 绑定width属性,设置其宽度值 
 | 
                    property: 'transform.translateX', 
 | 
                    expression 
 | 
                }] 
 | 
            }, (res) => { 
 | 
                this.moving = false 
 | 
                if (res.state === 'end' || res.state === 'exit') { 
 | 
                    const deltaX = res.deltaX 
 | 
                    if(deltaX <= -this.buttonsWidth || deltaX >= 0) { 
 | 
                        // 如果触摸滑动的过程中,大于单元格的总宽度,或者大于0,意味着已经动过滑动达到了打开或者关闭的状态 
 | 
                        // 这里直接进行状态的标记 
 | 
                        this.$nextTick(() => { 
 | 
                            this.status = deltaX <= -this.buttonsWidth ? 'open' : 'close' 
 | 
                        }) 
 | 
                    } else if(Math.abs(deltaX) > uni.$u.getPx(this.threshold)) { 
 | 
                        // 在移动大于阈值、并且小于总按钮宽度时,进行自动打开或者关闭 
 | 
                        // 移动距离大于0时,意味着需要关闭状态 
 | 
                        if(Math.abs(deltaX) < this.buttonsWidth) { 
 | 
                            this.moveCellByAnimation(deltaX > 0 ? 'close' : 'open') 
 | 
                        } 
 | 
                    } else { 
 | 
                        // 在小于阈值时,进行关闭操作(如果在打开状态下,将不会执行bindingX) 
 | 
                        this.moveCellByAnimation('close') 
 | 
                    } 
 | 
                } 
 | 
            }) 
 | 
        }, 
 | 
        // 释放bindingX 
 | 
        unbindBindingX() { 
 | 
            // 释放上一次的资源 
 | 
            if (this?.panEvent?.token != 0) { 
 | 
                bindingX.unbind({ 
 | 
                    token: this.panEvent?.token, 
 | 
                    // pan为手势事件 
 | 
                    eventType: 'pan' 
 | 
                }) 
 | 
            } 
 | 
        }, 
 | 
        // 查询按钮节点信息 
 | 
        queryRect() { 
 | 
            // 历遍所有按钮数组,通过getRectByDom返回一个promise 
 | 
            const promiseAll = this.options.map((item, index) => { 
 | 
                return this.getRectByDom(this.$refs[`u-swipe-action-item__right__button-${index}`][0]) 
 | 
            }) 
 | 
            // 通过promise.all方法,让所有按钮的查询结果返回一个数组的形式 
 | 
            Promise.all(promiseAll).then(sizes => { 
 | 
                this.buttons = sizes 
 | 
                // 计算所有按钮总宽度 
 | 
                this.buttonsWidth = sizes.reduce((sum, cur) => sum + cur.width, 0) 
 | 
            }) 
 | 
        }, 
 | 
        // 通过nvue的dom模块,查询节点信息 
 | 
        getRectByDom(ref) { 
 | 
            return new Promise(resolve => { 
 | 
                dom.getComponentRect(ref, res => { 
 | 
                    resolve(res.size) 
 | 
                }) 
 | 
            })  
 | 
        }, 
 | 
        // 移动单元格到左边或者右边尽头 
 | 
        moveCellByAnimation(status = 'open') { 
 | 
            if(this.moving) return 
 | 
            // 标识当前状态 
 | 
            this.moveing = true 
 | 
            const content = this.getContentRef() 
 | 
            const x = status === 'open' ? -this.buttonsWidth : 0  
 | 
            animation.transition(content, { 
 | 
                styles: { 
 | 
                    transform: `translateX(${x}px)`, 
 | 
                }, 
 | 
                duration: uni.$u.getDuration(this.duration, false), 
 | 
                timingFunction: 'ease-in-out' 
 | 
            }, () => { 
 | 
                this.moving = false 
 | 
                this.status = status 
 | 
                this.unbindBindingX() 
 | 
            }) 
 | 
        }, 
 | 
        // 获取元素ref 
 | 
        getContentRef() { 
 | 
            return this.$refs['u-swipe-action-item__content'].ref 
 | 
        }, 
 | 
        beforeDestroy() { 
 | 
            this.unbindBindingX() 
 | 
        } 
 | 
    } 
 | 
} 
 |