常见的API扩展形式
prototype
比如我现在有一个需求,给定一个字符串,给方法传递一个参数为数字类型来确定当前字符串重复次数,例如:
'abc'.repeatStringNumTimes(3) // abcabcabc
如果按照一般的思维就是我们把这个方法绑定到String的原型上,如下代码:
String.prototype.repeatStringNumTimes = String.prototype.repeatStringNumTimes || function(times) { var str = ''; for(var i = 0; i < times; i++) { str += this; } return str; }
jQuery
根据《jQuery高级编程》的描述,jQuery插件开发方式主要有三种:
通常我们使用第二种方法来进行简单插件开发,说简单是相对于第三种方式。第三种方式是用来开发更高级jQuery部件的,该模式开发出来的部件带有很多jQuery内建的特性,比如插件的状态信息自动保存,各种关于插件的常用方法等,非常贴心,这里不细说。
而第一种方式又太简单,仅仅是在jQuery命名空间或者理解成jQuery身上添加了一个静态方法而以。所以我们调用通过.extend()添加的函数时直接通过.extend()添加的函数时直接通过符号调用($.myfunction())而不需要选中DOM元素($('#example').myfunction())。请看下面的例子。
$.extend({ sayHello: (name) { console.log('Hello,' + (name ? name : 'Dude') + '!'); } }) $.sayHello(); 调用 $.sayHello('Wayou'); 带参调用
定义Beautifier的构造函数 var Beautifier = (ele,opt) { this.$element = ele,this.defaults = { 'color': 'red','fontSize': '12px' },1)">this.options = $.extend({},.defaults,opt) } 定义Beautifier的方法 Beautifier.prototype = { beautify: () { return .$element.css({ 'color': .options.color,'fontSize': .options.fontSize,'textDecoration': .options.textDecoration }); } } 在插件中使用Beautifier对象 $.fn.myPlugin = (options) { 创建Beautifier的实体 var beautifier = new Beautifier(调用其方法 beautifier.beautify(); }
调用方式:
$(() { $('a').myPlugin({ 'color': '#2C9929' }); })
感兴趣的可以详细查看文章:《jQuery插件开发进阶》
vue
插件通常会为 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 = (Vue,options) { 1. 添加全局方法或属性 Vue.myGlobalMethod = () { 逻辑... } 2. 添加全局资源 Vue.directive('my-directive' } ... }) 3. 注入组件 Vue.mixin({ created: () { 4. 添加实例方法 Vue.prototype.$myMethod = (methodOptions) { } } export default MyPlugin
封装的插件怎样使用?通过全局方法 Vue.use()
使用插件:
调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)
也可以传入一个选项对象:
Vue.use(MyPlugin,{ someOption: true })
实现一个表单验证
设计表单验证的规则就是开放-封闭验证,使用策略模式封装。
一般方案
<form action="" id="registerForm" method="post" onsubmit="return submitValidate()"> p> label>请输入用户名:</input type="text" name="userName" /> >请输入密码:="password" >请输入手机号码:="phoneNumber" divbutton ="submit">提交buttonform>
在form上绑定的submit,想实现的submitValidate方法代码如下:
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,message: '密码不能为空'},{rule:'minLength:6',message: '密码的长度不能小于6位'}] } ] var resultMsg = validate.check(rulesArr); if(resultMsg) { alert(resultMsg); falsetrue; }
var validate = (() { 校验规则的各种算法 var rules = { 判断非空 isNonEmpty: (value,errorMsg) { if(!value) { errorMsg; } },1)"> 判断最小长度 minLength: if(value.toString().length < length) { 判断最大长度 maxLength: if(value.toString().length > 判断手机号 isMobile: if (!/(^1[0-9]{10}$)/.test(value)) { 判断座机电话 isTel: if(!/^\d{3}-d{8}|d{4}-d{7}|d{11}$/ errorMsg; } } } /** 校验方法 * @param {Array} arr * @return {*} * */ check: (arr) { var ruleMsg; checkRule; _rule; var i = 0,len = arr.length; i < len; i++) { 没有当前校验字段 if(arr[i].el === undefined) { return '没有当前字段' } 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(ruleMsg) { ruleMsg; } } } } } })();
以上代码就是常规实现的表单验证,看似也够用了,但是如果一个系统中有多个表单提交验证,并且有部分验证方式不是那么通用,我们不可能再去修改代码中的rules,那样这个rules校验的算法越来越多,并且很多不是很通用的,那么我们怎样来解决呢?
ruleMsg; } } } },1)"> 添加规则 addRule: (ruleName,fn) { rules[ruleName] = fn; } } })();
比如用户名只能是字母跟数字的组合,那么我们就添加一个规则,代码如下:
validate.addRule('isAlphaNum',errorMsg) { if (/[^a-zA-Z0-9]/.test(value)) { errorMsg; } })
); validate.addRule('isAlphaNum',errorMsg) { .test(value)) { errorMsg; } }) [{ el: registerForm.userName.value,rules: [{ rule: 'isNonEmpty'用户名不能为空' },{ rule: 'minLength:3'用户名长度不能小于3位''用户名只能是数字跟字母的组合' }] },message: '密码不能为空''密码的长度不能小于6位''isMobile' }] } ] (resultMsg) { alert(resultMsg); ; }
运行效果如图所示:
升级方案
如果我们想实现如图这样的验证结果:
那么我们就需要保存所有元素的错误信息,那么我们新添加一个checkAll的方法,代码如下:
if (!if (value.toString().length <if (value.toString().length >if (!/^\d{3}-d{8}|d{4}-d{7}|d{11}$/ errorMsg; } } } for (if (arr[i].el === (ruleMsg) { ruleMsg; } } } },1)"> 校验所有接口 checkAll: var reusltMsg = []; (ruleMsg) { reusltMsg.push({ el: arr[i].el,rules: _rule,message: ruleMsg,alias: arr[i].alias 绑定一个别名用处:绑定到具体的一个DOM元素上显示错误信息 }) break; 跳出当前循环,不用把当前一个元素上多个验证不通过结果都存储起来 } } } return reusltMsg.length > 0 ? reusltMsg : ; },1)"> fn; } } })();
我们调整下HTML代码:
> /> span class="error"></span>
css样式:
style> .error { color: red; } >
'password' validate.checkAll(rulesArr);
(resultMsg) {
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;
}
;
}
这样得到的结果就是我们刚才截图的结果了。
兼容失去焦点的方案
如果想兼容失去焦点也触发后面的错误信息提示,暂写了一个草稿代码如下:
* 校验方法 * @param {Object} vertifyObj 验证结构如:{userName:[{rule: 'isNonEmpty',{rule: 'minLength:3',message: '用户名长度不能小于3位'}} * @param {Array} arr * @return {*} * (vertifyObj,arr) { vertifyObj[arr[i].alias][j]; checkRule = ruleObj.rule.split(':'); 用户触发验证事件 trigger: (params) { var self = ; var key in params.rules) { (params.rules.hasOwnProperty(key)) { var requireEl = document.querySelector(params.el + ' [name="'+key+'"]'); params.rules[key]; var resultRules = rulesArr.filter((rule) { if(!rule.trigger || rule.trigger === '') ; (Array.isArray(rule.trigger)) { return rule.trigger.indexOf('blur') > -1 } else { return rule.trigger === 'blur'; } }).map(function(rule){ JSON.parse(JSON.stringify(rule))}); ((dom,curDomRules){ dom.addEventListener('blur',1)">(event){ var val = dom.value; var ruleMsg = ''; ) { 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( (ruleMsg) { var errorDom = dom.nextElementSibling; errorDom.innerHTML = ruleObj.message; } } ruleMsg) { dom.nextElementSibling; errorDom.innerHTML = ''; } },1)">); })(requireEl,resultRules); } } },1)"> fn; } } })(); 添加-自定义校验算法 validate.addRule('isAlphaNum',1)"> errorMsg; } }) { userName: [ {rule: 'isNonEmpty',message: '用户名不能为空',trigger: 'blur'},{rule: 'minLength:3',message: '用户名长度不能小于3位',{rule: 'isAlphaNum',message: '用户名只能是数字跟字母的组合',1)">} ],password: [ {rule: 'isNonEmpty',message: '密码不能为空',{rule: 'minLength:6',message: '密码的长度不能小于6位',phoneNumber: [ {rule: 'isNonEmpty',message: '手机号不能为空',{rule: 'isMobile',message: '手机号码格式不正确',1)">} ] } validate.trigger({ el: '#registerForm' },1)"> } ] validate.checkAll(rules,rulesArr); curResult.message; } ; }
>
CSS代码:
>