公司自己用的平板上有一个飞梭部件,功能类似一个在pad上用的鼠标,左右滑动触发keydown事件,利用返回不同的keycode去选择不同的按钮
鉴于界面里的所有按钮是分布在不同的地方、有些在布局文件,有些在路由所在组件,有些在别的组件,那怎么样才能做到全局控制不同的button
考虑到不同的button会有不同的样式,当然这里的button不止是普通的一个按钮,它可能是一个圆,一个字体图标夹带文字的点击区域,等等的
我的想法是,可以建立一个全局的按钮配置文件,在模板上就可以直接根据不同的key去做不同的按钮渲染
配置文件:
'common': [{
key: 'tabBtn1',
className: (target) => { return ['icon', 'iconfont', target === 'tabBtn1' ? 'icon-timeout' : 'icon-play-circle'] },
textKey: 'tabBtn1',
that: null
}, {
key: 'tabBtn2',
className: () => { return ['icon', 'iconfont', 'icon-setting'] },
textKey: 'tabBtn2',
that: null
}, {
key: 'tabBtn3',
className: () => { return ['icon', 'iconfont', 'icon-setting'] },
textKey: 'tabBtn3',
that: null
}, {
key: 'tabBtn4',
className: () => { return ['icon', 'iconfont', 'icon-file-text'] },
textKey: 'tabBtn4',
that: null
}, {
key: 'otherBtn1',
that: null
}, {
key: 'otherBtn2',
that: null
}]
Key是对应要调用的方法名称。className是对应的class,考虑到样式可能要根据某些参数决定,所以这里要用经过方法决定返回的样式。textKey只是用于模板或者组件需要用到的参数,所以可以根据自己的需求作调整。
那按钮渲染配置有了,怎么控制飞梭滑动时按钮焦点的变化
我在vuex里定义了三个变量
- 按钮渲染配置 - allBtn
- 当前按钮的索引 - currentShuttle,用于控制焦点
- 当前可视区域的标记 - currentPage,决定焦点出现的界面
只要currentShuttle === index,当前按钮就会获得焦点样式,index可以是v-for后的index,也可以是固定的数字
因为有些按钮它并不是连续有规则地一路排列,可能是分开的,所以会有单独在另一个位置渲染的按钮
按钮渲染
<template v-for="(item, index) in allBtn['common']">
<div class="tab-item" @click="excute(item.key)" :key="index" v-if="index < 4">
<!-- 把对象绑定其中 -->
{{ _setThat($store.state.common.allBtn['common'][index], that) }}
<div class="tab-item-icon"
:style="
currentPage === 'common'
&& currentShuttle >= 0
&& currentShuttle === index ? 'background: orange;color: #fff' : ''">
<span>{{ item.key }}</span>
</div>
</div>
</template>
按钮渲染完,飞梭的滑动事件就要控制currentShuttle的变化了
在vuex中写了两个方法
[SET_SHUTTLE]: (state, direction) => {
const len = state.allBtn[state.currentPage].length
if (state.currentShuttle >= 0) {
if (direction) {
// 顺时针
if (state.currentShuttle === len - 1) state.currentShuttle = 0
else state.currentShuttle += 1
} else {
// 逆时针
if (state.currentShuttle === 0) state.currentShuttle = len - 1
else state.currentShuttle -= 1
}
} else state.currentShuttle = 0
console.log('state.currentShuttle', state.currentShuttle)
},
[CLEAR_SHUTTLE]: (state) => {
state.currentShuttle = -1
},
SET_SHUTTLE是利用传入的方向去自己判断焦点index加减或置0
CLEAR_SHUTTLE是currentPage改变后,页面中的按钮不应该还留有焦点,所以把焦点索引变为-1
接着currentPage改变的情况有以下两种:
- 整体的界面改变【路由跳转、全屏页面弹出】
- 带有按键的确认框【确认框、模态框】(总体原则是当页面有高层及覆盖时的组件)
只要符合这两种原则,currentPage就要改变为当前可操作的key,即allBtn里的key
最后一个重要环节是,怎么调用这个按钮的方法呢?当时在最初设计时还没有遇到按钮会分布在各个地方的这种情况,就单单是在对应的页面,设定一个excute方法
根据传入的key即可调用
但这个方法对于分布在不同位置的按钮来说不太可行,因为this指向不一样
所以考虑到this指向,我觉得在对应的allBtn里每一页的每一项加入一个属性that,用于描述当前button所属的this
那应该怎么把这个this记录到that中呢?
我在把一个_setThat方法挂载到全局,直接利用vue表达式调用这个对象写入方法
最后,我写了一个用鼠标模拟飞梭的demo,供大家参考一下