javascript
/*
v-input-limit:price 金额
v-input-limit:phone 电话
v-input-limit:number 数字
v-input-limit:negativePrice 负数金额
v-input-limit:loginVerify 登录验证码
v-input-limit:verify 短信验证码
v-input-limit:idCard 身份证号
v-input-limit="RegExp" 自定义验证规则
*/
export default {
// 该指令会频发触发input事件,并且ctrl+z会失效,使用时请注意
inserted(el, binding, vnode) {
// 通过修饰符储备可用的正则
const regObj = {
price: /^(\d*|(\d+\.\d{0,2}))$/,
phone: /^\d{0,11}$/,
number: /^\d*$/,
negativePrice: /^\-?(\d*|(\d+\.\d{0,2}))$/, //负数金额
loginVerify: /^[0-9a-zA-Z]{0,4}$/,
verify: /^\d{0,6}$/,
idCard: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,//身份证号(15位、18位数字),最后一位是校验位,可能为数字或字符X
allphone: /^[0-9\+\-]{0,14}$/ //电话+手机
}
// 要应用的正则表达式 优先binding.value
let reg =
binding.value && binding.value instanceof RegExp
? binding.value
: binding.arg && regObj[binding.arg] ? regObj[binding.arg] : null
// input输入事件
el._inputHandle = function (e) {
// 判断是否是用户行为
if (
e.isTrusted &&
!(
!e.isComposing &&
e.inputType === 'insertCompositionText' && e.data
)
) {
// 判断正则匹配
let isFalse = reg && !reg.test(e.target.value)
// 如果匹配错误返回上次输入值
el._input = isFalse ? el._input : e.target.value
e.target.value = '' //重置中文输入法
e.target.value = el._input // 重新赋值
// 控制光标所在位置
if (isFalse) {
// 输入内容不匹配,光标不动
e.target.selectionStart = el._start
e.target.selectionEnd = el._end
} else {
// 判断inputType计算光标位置
// inputType类型 https://www.jc2182.com/javascript/javascript-html-dom-inputtype-event-attr.html
switch (e.inputType) {
case 'deleteContentForward': //delete
case 'deleteByDrag': //dropout
case 'deleteByCut': //cut
e.target.selectionStart = el._start
e.target.selectionEnd = el._start
break
case 'deleteContentBackward': //backspace
e.target.selectionStart =
el._start === el._end
? el._start - 1
: el._start
e.target.selectionEnd =
el._start === el._end
? el._start - 1
: el._start
break
case 'insertFromPaste': //粘贴
case 'insertFromDrop': //拖入
let dataTransfer =
e.dataTransfer ||
e.clipboardData ||
null
if (dataTransfer) {
let txt =
dataTransfer.getData('text') || ''
e.target.selectionStart =
el._start + txt.length
e.target.selectionEnd =
el._start + txt.length
}
break
case 'insertText': //insert
case 'insertCompositionText': //中文输入法输入
e.target.selectionStart = el._start + 1
e.target.selectionEnd = el._start + 1
break
default:
break
}
}
// 发送input事件同步字符串
let event = new InputEvent('input', {
isComposing: false,
})
e.target.dispatchEvent(event)
// 中文下触发el-input input事件
// if (e.isComposing) {
// // 中文时同步字符串--表示内容以输入完毕
// let event = new CompositionEvent('input', {
// isComposing: false,
// data: ''
// })
// e.target.dispatchEvent(event)
// console.log
// } else {
// // 同步字符串
// let event = new InputEvent('input')
// e.target.dispatchEvent(event)
// }
} else {
return
}
}
// input输入前事件
el._beforeinputHandle = function (e) {
el._input =
reg && !reg.test(e.target.value) ? '' : e.target.value
el._start = e.target.selectionStart
el._end = e.target.selectionEnd
}
// input以及el-input可使用本指令
if (
vnode.tag === 'input' ||
(vnode.componentOptions &&
vnode.componentOptions.tag === 'el-input')
) {
// 监听input事件
el.addEventListener('input', el._inputHandle)
// 监听inputbefore事件 给el._input赋值(未知的兼容性)
el.addEventListener('keydown', el._beforeinputHandle)
// 阻止事件传播(firefox)
el.addEventListener('drop', e => {
e.stopPropagation()
})
} else {
console.warn('该指令应应用于input或el-input')
}
},
unbind(el, binding) {
// 取消事件绑定
el._inputHandle &&
el.removeEventListener('input', el._inputHandle)
el._beforeinputHandle &&
el.removeEventListener('beforeinput', el._beforeinputHandle)
}
}
在main.js中全局注册
javascript
//引入自定义指令
import * as directives from "./directives";
//注册指令
Object.keys(directives).forEach((k) => Vue.directive(k, directives[k]));
组件中直接使用
javascript
<el-input
v-model.trim="item.giveHour"
placeholder="请输入"
clearable
v-inputLimit:number
>
</el-input>