| New file | 
 |  |  | 
 |  |  | // 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() | 
 |  |  |       } | 
 |  |  |    } | 
 |  |  | } |