vue3自定义指令验证输入
vue3自定义指令验证输入
当我简单写几个带输入验证的input时,比如必填和邮件格式等,又不想引入antd那种大型库,就想试一下用vue的自定义指令来验证,确实效果嘎嘎好。
自定义指令
先来看一下自定义指令的基本语法。
一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。
一个指令的定义对象可以提供几种钩子函数 (都是可选的):
const myDirective = {
// 在绑定元素的父组件
// 及他自己的所有子节点都挂载完成后调用
mounted(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件
// 及他自己的所有子节点都更新后调用
updated(el, binding, vnode, prevVnode) {},
}
主要会用到的参数是el和binding,el是指令绑定到的元素,可以直接操作DOM,bingding是一个对象,包含value属性,是传递给指令的值。
实现
最终效果是这样
模版
先简单写个模版,也不是那么简单,看input和hint就好了。
<div class="form_field">
<div class="field">
<div class="field_label">email:</div>
<input
id="email"
data-rules="required|email"
v-validate="displayErrors"
type="text"
/>
</div>
<div class="hint">{{ state.errors['email'] }}</div>
</div>
<div class="form_field">
<div class="field">
<div class="field_label">password:</div>
<input
id="password"
data-rules="required|minLength:8"
v-validate="displayErrors"
type="password"
/>
</div>
<div class="hint">{{ state.errors['password'] }}</div>
</div>
在data-rules中写上需要哪些验证,email是必填和邮箱格式,password是必填和长度至少为8。
自定义指令是v-validate,需要传递displayErrors函数过去,在这个函数里面可以拿到输入验证的结果,有error的话展现到页面上。hint就是展示错误的地方,需要拿到对应的error,这里的关键字要和input的id属性对应。
setup
setup部分比较简单,定义一个state,包含errors对象。displayErrors函数就是拿到验证结果,把错误放入erros中。
<script setup>
import { reactive } from 'vue';
const state = reactive({
errors: {},
});
function displayErrors(errors) {
if (errors) {
state.errors[errors.name] = errors.error;
}
}
</script>
自定义指令实现
接下来是重头戏了。在元素mounted了后,拿到rules。如果有rules,就监听元素的input事件,并验证每一条rule是不是符合,不符合的就给出error,并调用组件传过来displayErrors函数。
const validateDirective = {
mounted(el, binding, vnode, prevVnode) {
// 获取定义在dataset.rules的规则
const rules = el.dataset['rules'];
// 获取组件传递的displayErrors函数
const displayErrors = binding.value;
if (!rules) return;
// 解析rules
const specRules = getRules(rules);
el.addEventListener('input', (e) => {
// input的值
const value = e.target.value;
let error;
if ('email' in specRules) {
const emailRegex =
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
if (!emailRegex.test(value)) {
error = `字符串不符合邮件格式`;
}
}
if ('minLength' in specRules) {
if (value.length < specRules['minLength']) {
error = `字符串长度至少为${specRules['minLength']}`;
}
}
if ('required' in specRules) {
if (!value) {
error = '字符串不能为空';
}
}
displayErrors({
name: el.id,
error: error,
});
});
},
};
rules和getRules这里都是简单的实现。
function getRules(rules) {
// rules用|分隔
const validateRules = rules.split('|');
const rulesObj = {};
validateRules.forEach((rule) => {
// rule参数用:分隔
const specRule = rule.split(':');
if (specRule.length > 1) {
rulesObj[specRule[0]] = specRule[1];
} else {
// 没有参数的rule用true代表
rulesObj[specRule[0]] = true;
}
});
return rulesObj;
}
注册自定义指令
可以在main.js中全局注册自定义指令
import validateDirective from './directives/validate';
const app = createApp(App);
app.directive('validate', validateDirective);
app.mount('#app');
也可以通过directives选项注册
import validateDirective from './directives/validate';
export default {
directives: {
// 在模板中启用 v-validate
validate: validateDirective
}
}
总结
以上就是通过自定义指令验证输入的全部内容了。除了这个,自定义指令还有更多有趣又有用的功能,如v-copy
, v-lazy-img
,v-emoji
,v-longpress
等,可以参考这篇文章。当遇到需要通用的操作原生DOM的情况时,除了$refs
,试试看自定义指令吧!
转载自:https://juejin.cn/post/7250382724879122489