期望结果
期望输入
handleParams({messgage:“用户名不能为空”},“code”)
期望输出
[
{
required: true,
message: “用户名不能为空”,
trigger: “blur”,
},
{
// validate:根据参数实现的自定义校验
validator: validate(isCode, “请输入数字或字母”),
trigger: “blur”,
}
]
实现
- 第一步就是对参数的初始化,在这一步中,我们需要对参数进行简略的处理,并且定义一个默认参数,大致如下代码;
// 将参数转成数组,方便处理
const args = [].slice.call(arguments);
// 默认配置
const DEFAULT_MESSAGE = {
required: true,
message: “该输入项为必填项”,
trigger: “blur”,
};
- 处理参数,根据具体的参数的转成对应的合法参数并返回,这里需要对输入做一个合法性进行判断;
// 处理参数
const params = handleParams(args);
/**
-
处理参数
-
@param {Array} array 参数
-
@returns 合法值
*/
const handleParams = (array) => {
const result = {
type: “”,
require: null,
};
if (array.length === 0) {
result.require = DEFAULT_MESSAGE;
} else {
for (let item = 0; item < 2; item++) {
if (utils.isString(array[item])) {
result.type = array[item];
} else if (utils.isObj(array[item])) {
result.require = array[item];
// 判断用户是否手写了require,默认true
result.require.required = utils.hasProperty(
array[item],
“required”
)
-
? array[item].required
- true;
}
}
if (result.require === null) {
result.require = DEFAULT_MESSAGE;
}
}
return result;
};
- 生成对应类型的自定义校验规则;
if (params.type !== “”) {
switch (params.type) {
case “code”:
rules.push({
validator: validate(isCode, “请输入数字或字母”),
trigger: “blur,change”,
});
break;
case “mobile”:
rules.push({
validator: validate(isMobile, “请输入正确的手机号”),
trigger: “blur,change”,
});
break;
case “number”:
rules.push({
validator: validate(isNumber, “请输入数字”),
trigger: “blur,change”,
});
break;
case “letter”:
rules.push({
validator: validate(isLetter, “请输入字母”),
trigger: “blur,change”,
});
break;
default:
rules.push({});
break;
}
}
小结
简单的来说就是实现差不多就是这样,可能有不完善的地方,但大致方向没有问题,之后便是扩展了,扩展的话需要根据自身的需求进行进一步可扩展了;
回过头来想我们抽离的最终目的,最终我们的目的就是为了实现:
-
减少书写的代码量,过于频繁的书写校验规则和必输这些数组实在浪费时间;
-
统一管理校验代码,尤其是协同开发的时候,一个人在某个业务场景里写了一遍自定义校验了,如果另外一个在不知道的情况下也同样写了一遍,那是不是浪费时间;
-
减少BUG提升开发效率,不可否认的是在一个项目组中,尤其是规模不大的小项目组,并不是每个人都能书写公共方法,很多新人往往考虑不周导致了隐性BUG的存在,如果一开始就有人将工具函数写完整,那么开发效率和BUG可以避免很多
这种方式其实有点 另类 ,也是我们某个项目中用到的,不是特别正统,但是发展方向我觉得还是没有问题的,它最终实现的效果是, 让输入框只能输入我们期望的合法值,如果输入值不合法,直接会被删除无法输入;这也就导致了它并不能 有效的利用IView或者ElementUI的错误提示,这也就是我为什么说它有点另类的原因;
虽然它没有有效的利用formItem的错误提示,但在体验上影响却不大,必输这一块它依然使用的是async-validator,再加之用法简单,确实有些独到之处;
效果
大致效果如下,是不是相较于正常的错误提示,这种稍微有那么一点点另类…
用法
// 以IView的Input组件为例
大致用法就这么简单,当输入的内容不为数字时,直接将该字符串给delete掉,这样就达到了控制输入的目的;
流程图
实现
其实没有太多的技术难点,总结一下,主要的技术点在于以下几个:
-
获取DOM,因为绑定的DOM必须是input或者包含input,而不管是IView还是ElementUI的Input组件都不是单纯的Input,是div以及Input的组合,毕竟涉及到了样式问题,因此第一步需要对绑定DOM的获取与判定;
-
输入时中文输入的异常处理,当正在输入中文的时候,输入框内会存在重复触发的问题,但这个可以通过compositionstart和compositionend解决;
解决了这两个问题,大致代码如下:
获取DOM
getElement(el, type) {
// 容错判断,排除非DOM
if (!(el instanceof HTMLElement)) {
console.error(“类型错误,绑定对象必须是HTMLElement”);
return false;
}
const list = type === “input” ? INPUT : DISABLED_LIST;
const domTagName = el.tagName.toLowerCase();
// 是否在可操作列表中
if (list.indexOf(domTagName) > -1) {
return el.getAttribute(“type”) === null ||
el.getAttribute(“type”) === “text”
-
? el
- false;
}
// 子集是否存在可操作列表中的元素
else {
const domList = [].slice.call(el.querySelectorAll(list.join(“,”)));
if (domList.length === 0) return false;
// 遍历子集
for (let item = 0; item < domList.length; item++) {
if (
domList[item].getAttribute(“type”) === null ||
domList[item].getAttribute(“type”) === “text”
) {
return domList[item];
}
}
return false;
}
},
绑定事件
/**
-
为DOM添加事件
-
@param {HTMLElement} el 绑定事件的DOM
-
@param {Object} binding 集合
*/
function handleFilter(el, binding) {
switch (binding.arg) {
case “number”:
numberFilter(el);
break;
case “letter”:
letterFilter(el);
break;
break;
default:
codeFilter(el);
break;
}
}
/**
-
数字验证
-
@param {HTMLElement} el 待绑定元素
*/
const numberFilter = function(el) {
exAddListener(el, () => {
el.value = handleNumber(el.value);
});
};
const addListener = function(el, type, fn) {
el.removeEventListener(type, fn, false);
el.addEventListener(type, fn, false);
};
const exAddListener = function(el, fn) {
addListener(el, “compositionstart”, (e) => {
e.target.isNeedPrevent = true;
});
addListener(el, “compositionend”, (e) => {
e.target.isNeedPrevent = false;
});
addListener(el, “keydown”, (e) => {
e.target.keyEvent = true;
});
addListener(el, “keyup”, (e) => {
if (e.target.isNeedPrevent) return;
fn();
e.target.keyEvent = false;
});
};
/**
-
字母验证
-
@param {HTMLElement} el 待绑定元素
*/
const letterFilter = function(el) {
exAddListener(el, () => {
el.value = el.value.replace(/[^A-Za-z]+/g, “”);
});
};
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-HrrF8KIK-1715721656411)]
[外链图片转存中…(img-MMrLe2Cm-1715721656412)]
[外链图片转存中…(img-m9cOYT54-1715721656412)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!