上周上线了一个小的 webapp 项目,技术栈主要是 vue2 + echarts + vant2 + vue-easytable,这里重点总结一个 vue-easytable
和 滑动tab
碰撞一起产生的问题。为了方便描述,下文会将 vue-easytable 简称为 table。
首先展示下效果:
注意看,第一下是触摸到表格上的,所以表格正常滑动,第二下是触摸到表格下方的,所以tab标签页滑动了。
下面来分析下:
在移动端想要实现滑动 tab ,vant2 的 tab 标签页组件就自带一个滑动属性 swipeable
,只要加到 van-tabs 组件标签上即可实现了。
但是有的 tab 标签页是存在表格的,那么就要用到 table 组件。所以就出现了如题的问题,这里停顿几秒思考下,怎么保证滑动表格和滑动 tab 互不影响?
碰到这个问题,我的第一反应就是如果触摸到表格上就禁止滑动 tab ,否则就允许滑动 tab 。
核心步骤如下:
- 监听
body
的touchstart
事件 - 事件回调函数中拿到一个触摸节点的唯一标识
- 根据这个唯一标识是否包含于 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 方法就可以了。
这里补充几点:
- mixin文件里的变量和函数前面加上 mixin前缀,是为了一眼就能看出这个变量和方法是 mixin 里的,当然也就需要多敲几个字母,难免显得多余,或许有更好的方式能解决这个问题。不过话说回来,如果不这样命名,组件里全局搜索不到的变量和方法,就要看下是否引入了 mixin 文件了。最后,切记 mixin 是一把双刃剑,不建议滥用。
- 其实这个滑动tab的需求不是产品要求的,是测试私下提出来的,而且也没有强制要求一定要做,对整个项目而言算是锦上添花。从他提出需求到实现需求花了将近一个小时,虽说代码只有短短几行,但是思路才是最重要的。
最后
这几天还有一点思考,当触摸到的表格没有滚动条或者已经滑到左右两端时,修改 mixinSwipeable 变量为 true ,这样就可以直接滑动到下一个tab标签页了。欢迎在评论区留言。
文笔有限,如果有没有表述清楚的,还请多多包涵,有错误的地方,万望告知,有什么疑问和建议,可以多多交流。