在网页的表单中,常常须要用程序来控制input和textarea的自动聚焦行为。例如我最近作的一个项目,有个装箱出库的流程,input框自动聚焦的流程以下:页面进入时自动聚焦到订单号输入框->订单号扫描完毕聚焦到商品条码输入框->扫描完一个商品条码后依然停留在条码输入框->全部条码扫描完毕聚焦到订单号输入框。为了应付这种需求,就作了这个指令,github地址:vue-auto-focus,欢迎star。javascript
<template>
<form v-auto-focus="focusCtrl" :data-current="currentIndex" :data-action="actionType">
<input @focus="setFocusIndex(0)" type="text" data-index="0">
<input @focus="setFocusIndex(1)" type="text" data-index="1">
<textarea @focus="setFocusIndex(2)" name="" id="" cols="30" rows="10" data-index="2"></textarea>
<input @focus="setFocusIndex(3)" type="text" data-index="3">
</form>
</template>
<style scoped>
</style>
<script type="text/babel">
export default {
data() {
return {
focusCtrl: 0, // 自动聚焦控制,变更时,执行自动聚焦指令
currentIndex: 0, // 当前聚焦元素的索引
actionType: 'next', // 自动聚焦的行为类型
}
},
methods: {
/**
* 控制自动聚焦指令执行
* @param actionType {string} 自动聚焦类型 it can be 'next'/'prev'/'first'/'last'/'jump'
* @param index {string} 当actionType为'jump'时,须要传入将要聚焦元素的索引
**/
setFocus(actionType,index) {
if (actionType === 'jump') {
this.currentIndex = index
}
this.focusCtrl++
this.actionType = actionType
},
/**
* 元素聚焦时,获取当前聚焦元素的索引
* @param index {number} 当前聚焦的索引
**/
setFocusIndex(index) {
this.currentIndex = index
},
}
}
</script>复制代码
/** * 聚焦行为控制 * next 聚焦到下一个元素 * prev 聚焦到上一个元素 * first 聚焦到第一个元素 * last 聚焦到最后一个元素 * jump 跳转到指定的元素 * @param el */
const focusCtrl = function (el) {
const action = el.dataset.action
const allFocusEls = getAllFocusEls(el)
const focusLen = allFocusEls.length
let current = getTargetIndex(el,allFocusEls)
switch (action) {
case 'next': // 若是action为next,则聚焦到下一个输入框
if (current >= focusLen - 1) {
current = focusLen - 1
} else {
current++
}
autoFocus(allFocusEls[current])
break
case 'prev': // 若是action为prev,则聚焦到上一个输入框
if (current <= 0) {
current = 0
} else {
current--
}
autoFocus(allFocusEls[current])
break
case 'first': // 若是为first,则聚焦到第一个输入框
current = 0
autoFocus(allFocusEls[current])
break;
case 'last': // 若是为last,则聚焦到最后一个输入框
current = focusLen - 1
autoFocus(allFocusEls[current])
break
case 'jump': // 若是为jump,则获取focusIndex,跳转到对应的输入框
if (current >= 0 && current < focusLen) {
autoFocus(allFocusEls[current])
}
break
}
}复制代码
必须在须要控制的元素上添加data-index属性,须要在父元素上添加data-action属性和data-current属性,data-action为指令行为的类型(值为next,prev等),data-current为当前聚焦元素的data-index值,getAllFocusEls
方法其实就是获取全部属性为data-index的元素,代码以下:vue
/** * 获取须要聚焦的全部元素 * @param el {Node} 指令挂载的元素 * @returns {NodeList} 须要聚焦的元素列表 */
const getAllFocusEls = function (el) {
return el.querySelectorAll('[data-index]')
}复制代码
getTargetIndex
方法用来获取当前聚焦元素的在集合中的索引值,代码以下:java
/** * 获取当前聚焦元素在集合中的位置 * @param el * @param collection * @returns {number} */
const getTargetIndex = function(el,collection) {
const target = document.querySelector(`[data-index="${el.dataset.current}"]`)
return Array.from(collection).indexOf(target)
}复制代码
指令挂载时,自动聚焦到指定的元素git
/** * 进入页面时,根据设置的data-index索引值,聚焦到对应的输入框 * @param el */
inserted: function (el) {
const allFocusEls = getAllFocusEls(el) // 获取须要聚焦的input元素组
let current = getTargetIndex(el,allFocusEls)
if (!current || current < 0 || current >= allFocusEls.length) { // 若是没有设置data-current,或者current的数值范围不符合要求,则默认聚焦到第一个输入框
current = 0
}
const currentEl = allFocusEls[current]
autoFocus(currentEl)
},复制代码
经过指令的value值控制指令的执行,若是值有变更,则执行指定的操做,聚焦到指定的元素github
/** * 更新时,若是focusCtrl有变更,则根据actionType来判断聚焦的行为,聚焦到对应的元素 * @param el * @param value * @param oldValue */
update: function (el,{value,oldValue}) {
if (value !== oldValue) {
focusCtrl(el)
}
},复制代码
最后,全部文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:segmentfault