|
|
// nvue操作dom的库,用于获取dom的尺寸信息
const dom = uni.requireNativePlugin('dom'); const bindingX = uni.requireNativePlugin('bindingx'); const animation = uni.requireNativePlugin('animation'); import { getPx, getDuration } from '../../libs/function/index'; 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) > 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: 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 }, // #ifdef VUE2
beforeDestroy() { // #endif
// #ifdef VUE3
beforeUnmount() { // #endif
this.unbindBindingX() } } }
|