前言
纯粹是因为无聊吧,然后就是突发奇想。
我以前开发过web端的收银系统。之前更早的时候也是做过零售软件方面的实施,通常在门店的时候收银员为了更为快速的去收银,是很少会去用鼠标的。都是键盘解决。但是web操作系统页面有一个问题。就是你的通过tab等方式其实不是很方便。然后我们还有商品列表也需要通过键盘方式选中返回。如果通过鼠标,在一些门店每天都是几万的销售额中,是非常累人,且效率低下的。这次开发的这个插件也是为了解决这方面的问题。
目前做到了基本的上下左右,属于初步的完成。未经业务实战。但是我想还是比较OK的。
原理:
首先,我们想要键盘上面操作选中dom元素。有本身的tap,上下左右等等,也可以使用tabindex,方式。但是这些都无法说使得操作统一方便。规则较为混乱,并且我们都知道div是么有焦点这个状态的。
那么我们想要实现的情况下,那么就需要自己造轮子了。我们自己来定义并且实现这一套规则。
1、监听键盘的上下左右
2、随着元素的上下左右进行数据移动。
吐槽一下,如果是jquery时代,怕是要麻烦很多。
实现左右移动
左右移动其实很简单,我们只要操作元素的数组的index对应的增加减就可以了。所以代码简单的不行。
同理,我们要操作元素的上下也可以这样实现。但是我的目的是要普适性的实现。那么左右我们是根据既定规则来实现的。
定义插入的数组的元素结构
// 设置绑定的初始数据this.dhtSetList({ bindData: value, // 绑定数据 self: this, // 本身 select: false, // 是否被选中})复制代码
这里其实比较简单能看出来,第一个是绑定的数据。第二个是vue当前实例本身。第三个就是状态,可以不管。
插入的顺序决定了左右移动的顺序
上下移动
上下移动最麻烦的是我们不能按数组的index进行移动。要根据元素本身的上下位置进行移动。
代码原理讲解:
1、过滤同级别元素
2、上过滤掉比自己低的,下过滤比自己高的
3、对元素的高低进行排序,上最小,下最小的元素。
4、如果上下存在一样的Y轴数据,那么比较X大小,得到最小X进行返回,X如果还有多个,那么默认返回第一个
// 上下移动topOrbottomMove(type) { let currentIndex = this.lastTimeLi() // 上一次的index,也是当前的index const list = this.list // 当前 const currentLi = list[currentIndex] const currentLiDom = currentLi.self.$el.getBoundingClientRect() const currentY = currentLiDom.y const currentX = currentLiDom.x const relativeList = [] list.forEach((item, index) => { const { y, x } = item.self.$el.getBoundingClientRect() relativeList.push({ li: item, y: currentY - y, x: Math.abs(currentX - x), index, }) }) // 过滤通等级元素 const eliminate = relativeList.filter(item => item.y !== 0) if (type === 'top') { // 往上过滤比自己低的 const topEliminate = eliminate.filter(item => item.y > 0) if (topEliminate.length === 0) { // 最终发送确认值 this.sendEmit({ item: list[currentIndex], index: currentIndex }) } else { topEliminate.sort((a, b) => a.y - b.y) const xArr = topEliminate.filter(item => item.y === topEliminate[0].y) if (xArr.length > 1) { xArr.sort((a, b) => a.x - b.x) this.sendEmit({ item: xArr[0], index: xArr[0].index }) } else { this.sendEmit({ item: xArr[0], index: xArr[0].index }) } } } if (type === 'bottom') { // 往下过滤比自己高的 const bottomEliminate = eliminate.filter(item => item.y < 0) if (bottomEliminate.length === 0) { // 最终发送确认值 this.sendEmit({ item: list[currentIndex], index: currentIndex }) } else { bottomEliminate.sort((a, b) => b.y - a.y) const xArr = bottomEliminate.filter(item => item.y === bottomEliminate[0].y) if (xArr.length > 1) { xArr.sort((a, b) => a.x - b.x) this.sendEmit({ item: xArr[0], index: xArr[0].index }) } else { this.sendEmit({ item: xArr[0], index: xArr[0].index }) } } }},复制代码
总结
基本原理其实挺简单的。
注意我这里为了保证每个子组件用了provide、inject方式进行数据分发。示例中是单独定义了一个子的组件,但是只要根据规则传递数据,那么也就没有什么问题了。
最后,咱给小编:
1. 点赞+评论
2. 点头像关注,转发给有需要的朋友。
谢谢!!