上周上线了一个小的 webapp 项目,技术栈主要是 vue2 + echarts + vant2 + vue-easytable,这里重点总结一个 vue-easytable滑动tab 碰撞一起产生的问题。为了方便描述,下文会将 vue-easytable 简称为 table。

首先展示下效果:

移动端滑动tab和table同时存在,会引发什么问题?

注意看,第一下是触摸到表格上的,所以表格正常滑动,第二下是触摸到表格下方的,所以tab标签页滑动了。

下面来分析下:

在移动端想要实现滑动 tab ,vant2 的 tab 标签页组件就自带一个滑动属性 swipeable ,只要加到 van-tabs 组件标签上即可实现了。

但是有的 tab 标签页是存在表格的,那么就要用到 table 组件。所以就出现了如题的问题,这里停顿几秒思考下,怎么保证滑动表格和滑动 tab 互不影响?

碰到这个问题,我的第一反应就是如果触摸到表格上就禁止滑动 tab ,否则就允许滑动 tab 。

核心步骤如下:

  1. 监听 bodytouchstart 事件
  2. 事件回调函数中拿到一个触摸节点的唯一标识
  3. 根据这个唯一标识是否包含于 table 组件中,来动态更改 swipeable 的值

详细代码如下:

// commonMixin.js
export default {
    data() {
        return {
            mixinSwipeable: true
        }
    },
    methods: {
        mixinSwipeableHandler(){
            const myBody = document.getElementsByTagName('body')[0]
            myBody.addEventListener('touchstart', (e) => {
                console.log('isTouchTable', isTouchTable(e));
                this.mixinSwipeable = !isTouchTable(e)
            }, false)
            // 判断触摸的节点是否在表格内
            function isTouchTable(e) {
                const touchDomClassName = e.target.className
                console.log('touchDomClassName', touchDomClassName);
		// 根据log信息得出,触摸到表格节点元素的主要情况有三种,
		// 分别是表头,表格行,列头,它们的节点类名都是以ve-table开头的
		// 这里或许有更合适的判断方法,只是目前没有发现bug哈哈
                return touchDomClassName.includes('ve-table')
            }
        }
    },
}

因为有好几个标签页都有表格,所以为了方便维护,将核心代码写在一个mixin文件里面,然后每个标签页引入并执行,这样就不用每个标签页都定义一个 swipeable 变量了。

然后就是在 van-tabs 组件标签上加上 :swipeable=“mixinSwipeable” ,并引入这个 commonMixin.js 文件,最后在 mounted 里面执行 mixinSwiperableHandler 方法就可以了。

这里补充几点:

  1. mixin文件里的变量和函数前面加上 mixin前缀,是为了一眼就能看出这个变量和方法是 mixin 里的,当然也就需要多敲几个字母,难免显得多余,或许有更好的方式能解决这个问题。不过话说回来,如果不这样命名,组件里全局搜索不到的变量和方法,就要看下是否引入了 mixin 文件了。最后,切记 mixin 是一把双刃剑,不建议滥用。
  2. 其实这个滑动tab的需求不是产品要求的,是测试私下提出来的,而且也没有强制要求一定要做,对整个项目而言算是锦上添花。从他提出需求到实现需求花了将近一个小时,虽说代码只有短短几行,但是思路才是最重要的。

最后

这几天还有一点思考,当触摸到的表格没有滚动条或者已经滑到左右两端时,修改 mixinSwipeable 变量为 true ,这样就可以直接滑动到下一个tab标签页了。欢迎在评论区留言。

文笔有限,如果有没有表述清楚的,还请多多包涵,有错误的地方,万望告知,有什么疑问和建议,可以多多交流。