感兴趣的可以详细查看文章:《jQuery插件开发进阶》
插件通常会为 Vue 添加全局功能。插件的范围没有限制——一般有下面几种:
1.添加全局方法或者属性,如: vue-custom-element
2.添加全局资源:指令/过滤器/过渡等,如 vue-touch
3.通过全局 mixin 方法添加一些组件选项,如: vue-router
4.添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
5.一个库,提供自己的 API,同时提供上面提到的一个或多个功能,如 vue-router
Vue.js 的插件应当有一个公开方法 install
。这个方法的第一个参数是 Vue
构造器,第二个参数是一个可选的选项对象:
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或属性
Vue.myGlobalMethod = function () {
// 逻辑...
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
// 3. 注入组件
Vue.mixin({
created: function () {
// 逻辑...
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
export default MyPlugin
封装的插件怎样使用?通过全局方法 Vue.use()
使用插件:
// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)
也可以传入一个选项对象:
Vue.use(MyPlugin, { someOption: true })
实现一个表单验证
设计表单验证的规则就是开放-封闭验证,使用策略模式封装。
我们先写一个html代码片段好验证代码:
<form action="" id="registerForm" method="post" onsubmit="return submitValidate()">
<label>请输入用户名:</label>
<input type="text" name="userName" />
<label>请输入密码:</label>
<input type="text" name="password" />
<label>请输入手机号码:</label>
<input type="text" name="phoneNumber" />
<button type="submit">提交</button>
</div>
</form>
在form上绑定的submit,想实现的submitValidate方法代码如下:
function submitValidate() {
var registerForm = document.getElementById("registerForm");
var rulesArr = [
el: registerForm.userName.value,
rules: [{rule: 'isNonEmpty',message: '用户名不能为空'},{rule:'minLength:3',message: '用户名长度不能小于3位'}]
el: registerForm.password.value,
rules: [{rule: 'isNonEmpty',message: '密码不能为空'},{rule:'minLength:6',message: '密码的长度不能小于6位'}]
el: registerForm.phoneNumber.value,
rules: [{rule: 'isNonEmpty',message: '手机号不能为空'},{rule:'isMobile',message: '手机号码格式不正确'}]
var resultMsg = validate.check(rulesArr);
if(resultMsg) {
alert(resultMsg);
return false;
return true;
下面我们编写validate验证方法,代码如下:
var validate = (function() {
// 校验规则的各种算法
var rules = {
// 判断非空
isNonEmpty: function(value,errorMsg) {
if(!value) {
return errorMsg;
// 判断最小长度
minLength: function(value,length,errorMsg) {
if(value.toString().length < length) {
return errorMsg;
// 判断最大长度
maxLength: function(value,length,errorMsg) {
if(value.toString().length > length) {
return errorMsg;
// 判断手机号
isMobile: function(value,errorMsg) {
if (!/(^1[0-9]{10}$)/.test(value)) {
return errorMsg;
// 判断座机电话
isTel: function(value,errorMsg) {
if(!/^\d{3}-d{8}|d{4}-d{7}|d{11}$/.test(value)) {
return errorMsg;
return {
/** 校验方法
* @param {Array} arr
* @return {*}
check: function(arr) {
var ruleMsg;
var checkRule;
var _rule;
for(var i = 0, len = arr.length; i < len; i++) {
// 没有当前校验字段
if(arr[i].el === undefined) {
return '没有当前字段'
for(var j = 0, ruleLen = arr[i].rules.length; j < ruleLen; j++) {
var ruleObj = arr[i].rules[j];
checkRule = ruleObj.rule.split(':'); // rule规则存在minLenth:6这样的校验
_rule = checkRule.shift(); // 获取校验算法名称
checkRule.unshift(arr[i].el); // checkRule首位存入校验的value值
checkRule.push(ruleObj.message); // checkRule末尾加入校验的message
ruleMsg = rules[_rule].apply(null,checkRule);
if(ruleMsg) {
return ruleMsg;
})();
以上代码就是常规实现的表单验证,看似也够用了,但是如果一个系统中有多个表单提交验证,并且有部分验证方式不是那么通用,我们不可能再去修改代码中的rules,那样这个rules校验的算法越来越多,并且很多不是很通用的,那么我们怎样来解决呢?
在验证函数中增加一个添加规则算法的方法,代码如下:
var validate = (function() {
// 校验规则的各种算法
var rules = {
// 判断非空
isNonEmpty: function(value,errorMsg) {
if(!value) {
return errorMsg;
// 判断最小长度
minLength: function(value,length,errorMsg) {
if(value.toString().length < length) {
return errorMsg;
// 判断最大长度
maxLength: function(value,length,errorMsg) {
if(value.toString().length > length) {
return errorMsg;
// 判断手机号
isMobile: function(value,errorMsg) {
if (!/(^1[0-9]{10}$)/.test(value)) {
return errorMsg;
// 判断座机电话
isTel: function(value,errorMsg) {
if(!/^\d{3}-d{8}|d{4}-d{7}|d{11}$/.test(value)) {
return errorMsg;
return {
/** 校验方法
* @param {Array} arr
* @return {*}
check: function(arr) {
var ruleMsg;
var checkRule;
var _rule;
for(var i = 0, len = arr.length; i < len; i++) {
// 没有当前校验字段
if(arr[i].el === undefined) {
return '没有当前字段'
for(var j = 0, ruleLen = arr[i].rules.length; j < ruleLen; j++) {
var ruleObj = arr[i].rules[j];
checkRule = ruleObj.rule.split(':'); // rule规则存在minLenth:6这样的校验
_rule = checkRule.shift(); // 获取校验算法名称
checkRule.unshift(arr[i].el); // checkRule首位存入校验的value值
checkRule.push(ruleObj.message); // checkRule末尾加入校验的message
ruleMsg = rules[_rule].apply(null,checkRule);
if(ruleMsg) {
return ruleMsg;
// 添加规则
addRule: function(ruleName,fn) {
rules[ruleName] = fn;
})();
比如用户名只能是字母跟数字的组合,那么我们就添加一个规则,代码如下:
validate.addRule('isAlphaNum', function(value, errorMsg) {
if (/[^a-zA-Z0-9]/.test(value)) {
return errorMsg;
submitValidate方法的代码修改为如下:
function submitValidate() {
var registerForm = document.getElementById("registerForm");
validate.addRule('isAlphaNum', function(value, errorMsg) {
if (/[^a-zA-Z0-9]/.test(value)) {
return errorMsg;
var rulesArr = [{
el: registerForm.userName.value,
rules: [{
rule: 'isNonEmpty',
message: '用户名不能为空'
rule: 'minLength:3',
message: '用户名长度不能小于3位'
rule: 'isAlphaNum',
message: '用户名只能是数字跟字母的组合'
el: registerForm.password.value,
rules: [{
rule: 'isNonEmpty',
message: '密码不能为空'
rule: 'minLength:6',
message: '密码的长度不能小于6位'
el: registerForm.phoneNumber.value,
rules: [{
rule: 'isNonEmpty',
message: '手机号不能为空'
rule: 'isMobile',
message: '手机号码格式不正确'
var resultMsg = validate.check(rulesArr);
if (resultMsg) {
alert(resultMsg);
return false;
return true;
运行效果如图所示:
如果我们想实现如图这样的验证结果:
那么我们就需要保存所有元素的错误信息,那么我们新添加一个checkAll的方法,代码如下:
var validate = (function() {
// 校验规则的各种算法
var rules = {
// 判断非空
isNonEmpty: function(value, errorMsg) {
if (!value) {
return errorMsg;
// 判断最小长度
minLength: function(value, length, errorMsg) {
if (value.toString().length < length) {
return errorMsg;
// 判断最大长度
maxLength: function(value, length, errorMsg) {
if (value.toString().length > length) {
return errorMsg;
// 判断手机号
isMobile: function(value, errorMsg) {
if (!/(^1[0-9]{10}$)/.test(value)) {
return errorMsg;
// 判断座机电话
isTel: function(value, errorMsg) {
if (!/^\d{3}-d{8}|d{4}-d{7}|d{11}$/.test(value)) {
return errorMsg;
return {
/** 校验方法
* @param {Array} arr
* @return {*}
check: function(arr) {
var ruleMsg;
var checkRule;
var _rule;
for (var i = 0, len = arr.length; i < len; i++) {
// 没有当前校验字段
if (arr[i].el === undefined) {
return '没有当前字段'
for (var j = 0, ruleLen = arr[i].rules.length; j < ruleLen; j++) {
var ruleObj = arr[i].rules[j];
checkRule = ruleObj.rule.split(':'); // rule规则存在minLenth:6这样的校验
_rule = checkRule.shift(); // 获取校验算法名称
checkRule.unshift(arr[i].el); // checkRule首位存入校验的value值
checkRule.push(ruleObj.message); // checkRule末尾加入校验的message
ruleMsg = rules[_rule].apply(null, checkRule);
if (ruleMsg) {
return ruleMsg;
// 校验所有接口
checkAll: function(arr) {
var ruleMsg;
var checkRule;
var _rule;
var reusltMsg = [];
for (var i = 0, len = arr.length; i < len; i++) {
// 没有当前校验字段
if (arr[i].el === undefined) {
return '没有当前字段'
for (var j = 0, ruleLen = arr[i].rules.length; j < ruleLen; j++) {
var ruleObj = arr[i].rules[j];
checkRule = ruleObj.rule.split(':'); // rule规则存在minLenth:6这样的校验
_rule = checkRule.shift(); // 获取校验算法名称
checkRule.unshift(arr[i].el); // checkRule首位存入校验的value值
checkRule.push(ruleObj.message); // checkRule末尾加入校验的message
ruleMsg = rules[_rule].apply(null, checkRule);
if (ruleMsg) {
reusltMsg.push({
el: arr[i].el,
rules: _rule,
message: ruleMsg,
alias: arr[i].alias // 绑定一个别名用处:绑定到具体的一个DOM元素上显示错误信息
break; // 跳出当前循环,不用把当前一个元素上多个验证不通过结果都存储起来
return reusltMsg.length > 0 ? reusltMsg : false;
// 添加规则
addRule: function(ruleName, fn) {
rules[ruleName] = fn;
})();
我们调整下html代码:
<form action="" id="registerForm" method="post" onsubmit="return submitValidate()">
<label>请输入用户名:</label>
<input type="text" name="userName" />
<span class="error"></span>
<label>请输入密码:</label>
<input type="text" name="password" />
<span class="error"></span>
<label>请输入手机号码:</label>
<input type="text" name="phoneNumber" />
<span class="error"></span>
<button type="submit">提交</button>
</div>
</form>
css样式:
<style>
.error {
color: red;
</style>
submitValidate方法的代码调整为:
function submitValidate() {
var registerForm = document.getElementById("registerForm");
validate.addRule('isAlphaNum', function(value, errorMsg) {
if (/[^a-zA-Z0-9]/.test(value)) {
return errorMsg;
var rulesArr = [{
el: registerForm.userName.value,
alias: 'userName',
rules: [{
rule: 'isNonEmpty',
message: '用户名不能为空'
rule: 'minLength:3',
message: '用户名长度不能小于3位'
rule: 'isAlphaNum',
message: '用户名只能是数字跟字母的组合'
el: registerForm.password.value,
alias: 'password',
rules: [{
rule: 'isNonEmpty',
message: '密码不能为空'
rule: 'minLength:6',
message: '密码的长度不能小于6位'
el: registerForm.phoneNumber.value,
alias: 'phoneNumber',
rules: [{
rule: 'isNonEmpty',
message: '手机号不能为空'
rule: 'isMobile',
message: '手机号码格式不正确'
var resultMsg = validate.checkAll(rulesArr);
if (resultMsg) {
for(var re = 0, len = resultMsg.length; re < len; re++) {
var curResult = resultMsg[re];
var errorDom = document.querySelector('#registerForm p [name="'+curResult.alias+'"]').nextElementSibling;
errorDom.innerHTML = curResult.message;
return false;
return true;
这样得到的结果就是我们刚才截图的结果了。
兼容失去焦点的方案
如果想兼容失去焦点也触发后面的错误信息提示,暂写了一个草稿代码如下:
var validate = (function() {
// 校验规则的各种算法
var rules = {
// 判断非空
isNonEmpty: function(value, errorMsg) {
if (!value) {
return errorMsg;
// 判断最小长度
minLength: function(value, length, errorMsg) {
if (value.toString().length < length) {
return errorMsg;
// 判断最大长度
maxLength: function(value, length, errorMsg) {
if (value.toString().length > length) {
return errorMsg;
// 判断手机号
isMobile: function(value, errorMsg) {
if (!/(^1[0-9]{10}$)/.test(value)) {
return errorMsg;
// 判断座机电话
isTel: function(value, errorMsg) {
if (!/^\d{3}-d{8}|d{4}-d{7}|d{11}$/.test(value)) {
return errorMsg;
return {
/** 校验方法
* @param {Object} vertifyObj 验证结构如:{userName:[{rule: 'isNonEmpty',message: '用户名不能为空'},{rule: 'minLength:3',message: '用户名长度不能小于3位'}}
* @param {Array} arr
* @return {*}
check: function(vertifyObj,arr) {
var ruleMsg;
var checkRule;
var _rule;
for (var i = 0, len = arr.length; i < len; i++) {
// 没有当前校验字段
if (arr[i].el === undefined) {
return '没有当前字段'
for (var j = 0, ruleLen = vertifyObj[arr[i].alias].length; j < ruleLen; j++) {
var ruleObj = vertifyObj[arr[i].alias][j];
checkRule = ruleObj.rule.split(':'); // rule规则存在minLenth:6这样的校验
_rule = checkRule.shift(); // 获取校验算法名称
checkRule.unshift(arr[i].el); // checkRule首位存入校验的value值
checkRule.push(ruleObj.message); // checkRule末尾加入校验的message
ruleMsg = rules[_rule].apply(null, checkRule);
if (ruleMsg) {
return ruleMsg;
// 校验所有接口
checkAll: function(vertifyObj,arr) {
var ruleMsg;
var checkRule;
var _rule;
var reusltMsg = [];
for (var i = 0, len = arr.length; i < len; i++) {
// 没有当前校验字段
if (arr[i].el === undefined) {
return '没有当前字段'
for (var j = 0, ruleLen = vertifyObj[arr[i].alias].length; j < ruleLen; j++) {
var ruleObj = vertifyObj[arr[i].alias][j];
checkRule = ruleObj.rule.split(':'); // rule规则存在minLenth:6这样的校验
_rule = checkRule.shift(); // 获取校验算法名称
checkRule.unshift(arr[i].el); // checkRule首位存入校验的value值
checkRule.push(ruleObj.message); // checkRule末尾加入校验的message
ruleMsg = rules[_rule].apply(null, checkRule);
if (ruleMsg) {
reusltMsg.push({
el: arr[i].el,
rules: _rule,
message: ruleMsg,
alias: arr[i].alias // 绑定一个别名用处:绑定到具体的一个DOM元素上显示错误信息
break; // 跳出当前循环,不用把当前一个元素上多个验证不通过结果都存储起来
return reusltMsg.length > 0 ? reusltMsg : false;
// 用户触发验证事件
trigger: function(params) {
var self = this;
for(var key in params.rules) {
if(params.rules.hasOwnProperty(key)) {
var requireEl = document.querySelector(params.el + ' [name="'+key+'"]');
var rulesArr = params.rules[key];
var resultRules = rulesArr.filter(function(rule) {
if(!rule.trigger || rule.trigger === '') return true;
if(Array.isArray(rule.trigger)) {
return rule.trigger.indexOf('blur') > -1
} else {
return rule.trigger === 'blur';
}).map(function(rule){return JSON.parse(JSON.stringify(rule))});
(function(dom,curDomRules){
dom.addEventListener('blur',function(event){
var val = dom.value;
var ruleMsg = '';
for (var j = 0, ruleLen = curDomRules.length; j < ruleLen; j++) {
var ruleObj = curDomRules[j];
var checkRule = ruleObj.rule.split(':'); // rule规则存在minLenth:6这样的校验
var _rule = checkRule.shift(); // 获取校验算法名称
checkRule.unshift(val); // checkRule首位存入校验的value值
checkRule.push(ruleObj.message); // checkRule末尾加入校验的message
ruleMsg = rules[_rule].apply(null, checkRule);
if (ruleMsg) {
var errorDom = dom.nextElementSibling;
errorDom.innerHTML = ruleObj.message;
break; // 跳出当前循环,不用把当前一个元素上多个验证不通过结果都存储起来
if(!ruleMsg) {
var errorDom = dom.nextElementSibling;
errorDom.innerHTML = '';
},false);
})(requireEl,resultRules);
// 添加规则
addRule: function(ruleName, fn) {
rules[ruleName] = fn;
})();
// 添加-自定义校验算法
validate.addRule('isAlphaNum', function(value, errorMsg) {
if (/[^a-zA-Z0-9]/.test(value)) {
return errorMsg;
var rules = {
userName: [
{rule: 'isNonEmpty',message: '用户名不能为空', trigger: 'blur'},
{rule: 'minLength:3',message: '用户名长度不能小于3位', trigger: 'blur'},
{rule: 'isAlphaNum',message: '用户名只能是数字跟字母的组合', trigger: 'blur'}
password: [
{rule: 'isNonEmpty',message: '密码不能为空', trigger: 'blur'},
{rule: 'minLength:6',message: '密码的长度不能小于6位', trigger: 'blur'}
phoneNumber: [
{rule: 'isNonEmpty',message: '手机号不能为空', trigger: 'blur'},
{rule: 'isMobile',message: '手机号码格式不正确', trigger: 'blur'}
validate.trigger({
el: '#registerForm',
rules: rules
function submitValidate() {
var registerForm = document.getElementById("registerForm");
var rulesArr = [{
el: registerForm.userName.value,
alias: 'userName'
el: registerForm.password.value,
alias: 'password'
el: registerForm.phoneNumber.value,
alias: 'phoneNumber'
var resultMsg = validate.checkAll(rules,rulesArr);
if (resultMsg) {
for(var re = 0, len = resultMsg.length; re < len; re++) {
var curResult = resultMsg[re];
var errorDom = document.querySelector('#registerForm p [name="'+curResult.alias+'"]').nextElementSibling;
errorDom.innerHTML = curResult.message;
return false;
return true;
html代码:
<form action="" id="registerForm" method="post" onsubmit="return submitValidate()">
<label>请输入用户名:</label>
<input type="text" name="userName" />
<span class="error"></span>
<label>请输入密码:</label>
<input type="text" name="password" />
<span class="error"></span>
<label>请输入手机号码:</label>
<input type="text" name="phoneNumber" />
<span class="error"></span>
<button type="submit">提交</button>
</div>
</form>
CSS代码:
<style>
.error {
color: red;
</style>
JS策略模式参考-《[JS设计模式]:策略模式及应用-计算奖金、表单验证的实现(5)》
重构 - 设计API的扩展机制
【笔记】原生JS实现验证框架 checkFun