添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

比如我现在有一个需求,给定一个字符串,给方法传递一个参数为数字类型来确定当前字符串重复次数,例如:

'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插件开发方式主要有三种:

通过$.extend()来扩展jQuery

通过$.fn 向jQuery添加新的方法

通过$.widget()应用jQuery UI的部件工厂方式创建

通常我们使用第二种方法来进行简单插件开发,说简单是相对于第三种方式。第三种方式是用来开发更高级jQuery部件的,该模式开发出来的部件带有很多jQuery内建的特性,比如插件的状态信息自动保存,各种关于插件的常用方法等,非常贴心,这里不细说。

而第一种方式又太简单,仅仅是在jQuery命名空间或者理解成jQuery身上添加了一个静态方法而以。所以我们调用通过.extend().extend()添加的函数时直接通过符号调用($.myfunction())而不需要选中DOM元素($('#example').myfunction())。请看下面的例子。

$.extend({
    sayHello: function(name) {
        console.log('Hello,' + (name ? name : 'Dude') + '!');
$.sayHello(); //调用
$.sayHello('Wayou'); //带参调用

看一个jquery封装的面向对象的插件开发代码:

//定义Beautifier的构造函数
var Beautifier = function(ele, opt) {
    this.$element = ele,
    this.defaults = {
        'color': 'red',
        'fontSize': '12px',
        'textDecoration':'none'
    this.options = $.extend({}, this.defaults, opt)
//定义Beautifier的方法
Beautifier.prototype = {
    beautify: function() {
        return this.$element.css({
            'color': this.options.color,
            'fontSize': this.options.fontSize,
            'textDecoration': this.options.textDecoration
//在插件中使用Beautifier对象
$.fn.myPlugin = function(options) {
    //创建Beautifier的实体
    var beautifier = new Beautifier(this, options);
    //调用其方法
    return beautifier.beautify();

调用方式:

$(function() {
    $('a').myPlugin({
        'color': '#2C9929',
        'fontSize': '20px'

 感兴趣的可以详细查看文章:《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
  •