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