Angular 输入框实现自定义验证功能


Posted in Javascript onFebruary 19, 2017

此插件使用angular.js、JQuery实现。(jQuery的引入需在angular 之前)

用户可以 在输入框输入数据后验证 必填项、整数型、浮点型验证。

如果在form 里面的输入框验证,可以点击 提交按钮后,实现 必填项验证。

效果图如下:

Angular 输入框实现自定义验证功能

(1)验证未通过时,背景标红等样式为

input.ng-invalid, select.ng-invalid {
   background-color: #ee82ee !important;
   border: 1px solid #CCC;
  }
  .qtip {
   position: absolute;
   max-width: 260px;
   display: none;
   min-width: 50px;
   font-size: 10.5px;
   line-height: 12px;
   direction: ltr;
  }
  .qtip-content {
   position: relative;
   padding: 5px 9px;
   overflow: hidden;
   text-align: left;
   word-wrap: break-word;
  }
  .qtip-rounded, .qtip-tipsy {
   -moz-border-radius: 5px;
   -webkit-border-radius: 5px;
   border-radius: 5px;
  }
  .qtipmodal-ie6fix {
   position: absolute !important;
  }
  .box-shadow-tips {
   background-color: #F63;
   border-color: #F5A88F;
   color: white;
   -moz-box-shadow: 2px 2px 2px #969696;
   -webkit-box-shaow: 2px 2px 2px #969696;
   box-shadow: 2px 2px 2px #969696;
  }

因为angular.js 内置验证未通过时,会自动为 标签 增加 .ng-invalid 样式,因为这里重写此样式

 input.ng-invalid, select.ng-invalid {
 background-color: #ee82ee !important;
 
border: 1px solid #CCC;

} 

  (2)HTML 代码如下

<body ng-app="myApp">
<form name="baseInfoForm">
 <div ng-controller="testCtrl">
  <input type="text" ng-model="age" my-valid="r"><br>
  <input type="text" ng-model="name" my-valid="int fn:certCheck"><br>
  <input type="button" value="提交" ng-click="submit()">
 </div>
</form>
</body>

(3)此插件使用 directive myValid 实现

app.directive('myValid', ['$parse', 'uiTipsFactory', 'uiValidFactory', function ($parse, tips, valid) {
  var uiValidAttrIdName = 'ui-valid-id';
  return {
   restrict: 'A',
   require: 'ngModel',
   link: function (scope, el, attrs, ctrl) {
    var validId = el.attr(uiValidAttrIdName);
    if (!validId) {
     validId = Math.guid();
     el.attr(uiValidAttrIdName, validId);
    }
    var getRules = function () {
     return attrs.myValid;
    };
    var lastOldRules;
    var validFn = function (value, oldRules) {
     var sp = '_';
     var rules = getRules();
     var r = valid.check(value, rules, scope, attrs.uiValidTips);
     if (lastOldRules && !oldRules) {
      oldRules = lastOldRules;
     }
     if (r.flag && oldRules) {
      rules = rules ? rules + ' ' + oldRules : oldRules;
     }
     if (rules) {
      var arrInner = rules.split(' ');
      var i = 0;
      for (; i < arrInner.length; i++) {
       var oneRule = arrInner[i];
       if (!oneRule.trim()) {
        continue;
       }
       ctrl.$setValidity(attrs.ngModel + sp + oneRule, r.flag ? true : oneRule != r.rule);
      }
     }
     if (!r.flag) {
      tips.on(el, r.msg);
     } else {
      tips.off(el);
     }
     return r.flag;
    };
    var init = function () {
     var rules = getRules();
     if (!rules) {
      return;
     }
     var parsers = ctrl.$parsers;
     if (parsers && parsers.length > 0) {
      parsers.clean();
     }
     parsers.unshift(function (value) {
      return validFn(value) ? value : undefined;
     });
    };
    scope.$watch(attrs.ngModel, function (newVal, oldVal) {
     if (newVal === oldVal) {
      return;
     }
     if (ctrl.$modelValue != undefined && (ctrl.$invalid || el.hasClass('ng-invalid'))) {
      validFn(ctrl.$modelValue);
     }
    });
    scope.$watch(getRules, function (newRules, oldRules) {
     init();
     lastOldRules = oldRules;
     if (ctrl.$modelValue === undefined || ctrl.$modelValue === null) {
      var needValid = false;
      el.hasClass('ng-invalid');
      var isValNaN = ctrl.$viewValue !== ctrl.$viewValue;
      if (ctrl.$invalid || (ctrl.$viewValue !== undefined && !isValNaN)) {
       needValid = true;
      }
      if (needValid) {
       ctrl.$setViewValue(ctrl.$viewValue);
      }
     } else {
      if (!ctrl.$dirty && attrs.dirtyCheck) {
       console.log('----');
      } else {
       validFn(ctrl.$modelValue, oldRules);
      }
     }
    });
   }
  }
 }]);

通过 监听 attrs.ngModel,验证规则 rules ,ctrl.$parser 来实现 输入框内容改变的响应。

一旦使用此directive,则动态为当前输入框添加ID,以便在 验证通过后,改变输入框的验证背景信息。 

(4)验证逻辑处理 uiValidFactory

app.factory('uiValidFactory', ['$parse', 'uiTipsFactory', function ($parse, tips) {
  return {
   check: function (val, rules, $scope, defaultTips, extendParam) {
    if (!rules) {
     return {
      flag: true
     };
    }
    var rulesArr = rules.split(' '),
      isBlank = val === null || val === undefined || val === '' || ('' + val === '');
    //如果不是必填项 且没有输入值 则清除提示框
    if ($.inArray('r', rulesArr) === -1 && isBlank) {
     return {
      flag: true
     }
    }
    var i = 0, len = rulesArr.length;
    for (; i < len; i++) {
     var rule = rulesArr[i];
     if (!rule) {
      continue;
     }
     var flag = true;
     if ('r' === rule) {
      //如果是必填项,有值 返回true
      flag = !isBlank;
     } else if (rule.contains(':')) {
      //如果校验规则是 fn:ctrl.certCheck
      flag = this.checkRule(val, rule.split(/:/), $scope, extendParam);
     } else {
      //校验 规则是 int 用正则匹配 数字 邮箱 长度
      var pat = this.pats[rule];
      if (pat instanceof RegExp) {
       if (angular.isString(val)) {
        flag = this.mat(val, pat);
       }
      } else if (angular.isFunction(pat)) {
       flag = pat(val);
      } else {
       flag = false;
      }
     }
     //这是干什么的呢
     if (angular.isString(flag)) {
      return {
       flag: false,
       msg: flag,
       rule: rule
      }
     }
     if (flag === false) {
      var msg = this.getMsg(rule, defaultTips) || this.getMsg('tips.valid');
      console.log(msg);
      return {
       flag: false,
       msg: msg,
       rule: rule
      }
     }
    }
    return {
     flag: true
    }
   },
   checkRule: function (val, ruleArr, $scope, extendParam) {
    //ruleArr fn:certCheck
    var rule = ruleArr[0];
    if (rule === 'fn') {
     fnName = ruleArr[1];//指定被调函数的名字 certCheck
     var fn = $parse(fnName)($scope);
     if (!fn) {
      return true;
     }
     return fn.call($scope, val, extendParam);
    } else {
     return true;
    }
   },
   checkValidForm: function (formName) {
    //只检查必填项
    //使用属性筛选器 获得里面所有的元素
    var formContext = $('form[name="{0}"],[ng-form="{0}"],[data-ng-form="{0}"]'.format(formName)),
      validList = formContext.find('[my-valid]');//validList 不是数组,是伪数组
    if (!validList.length) {
     return;
    }
    var that = this,
      validFlags = [];
    validList.each(function () {
       var ele = $(this),
         val = ele.val(),
         ruleStr = ele.attr('my-valid');
       if (!ruleStr) {
        return true;
       }
       if (angular.isString(val)) {
        val = val.trim();
       }
       var validRules = ruleStr.split(' ');
       if ($.inArray('r', validRules) != -1 && !val) {
        var modelValue = ele.attr('ng-model') || ele.attr('data-ng-model');
        validFlags.push(modelValue);
        tips.on(ele, that.getMsg('r'));
       }
      }
    );
    return validFlags;
   },
   mat: function (val, pat) {
    if (!pat) {
     return;
    }
    return pat.test(val);
   }
   ,
   getMsg: function (rule, tips) {
    tips = tips || '';
    //可以在界面上直接写 tips
    if (tips && tips.contains(':')) {
     return tips;
    }
    var msg = this.msgs[rule];
    if (msg) {
     var params0 = tips.contains(':') ? tips.split(/:/)[0] : '';
     var params1 = '';
     if (rule.startsWith('min') || rule.startsWith('max')) {
      var ruleArr = rule.split(/:/);
      params1 = ruleArr[ruleArr.length - 1];
     }
     return msg.format(params0, params1);
    } else {
    }
   }
   ,
   regPat: function (code, pat, msg) {
    if (this.pat[code]) {
     return;
    }
    this.pats[code] = pat;
    this.msgs[code] = msg;
   }
   ,
   msgs: {
    'r': '必填',
    'int': '{0}必须为整数'
   }
   ,
   pats: {
    'int': /^[\-\+]?([0-9]+)$/
   }
  }
 }
 ])
 ;

       通过获取输入框 ele.myValid  验证规则,

1、如果是必填,则返回 标红此输入框,鼠标移上,则显示 验证信息 “必填””。

2、如果是整数、浮点型等验证,则通过 正则表达式进行验证。

      3、如果是最大(max)、最小(min),则自定义逻辑。

4、如果是 fn 验证,则根据 对应controller中函数进行验证。

5、用户点击提交按钮,则 判断是否必填项,验证不通过,对应元素背景标红。

(5) 验证不通过,提示Factory---uiTipsFactory

app.factory('uiTipsFactory', function () {
  return {
   filterClass: function (ele, invalid) {
    if (invalid) {
     //如果验证不通过
     ele.removeClass('ng-valid').removeClass('ng-pristine').addClass('ng-invalid').addClass('ng-dirty');
    } else {
     ele.removeClass('ng-invalid').addClass('ng-valid');
    }
   },
   on: function (ele, msg) {
    var lastTip = ele.data('last-tip');
    if (lastTip && lastTip === msg) {
     return;
    }
    ele.data('last-tip', msg);
    this.filterClass(ele, true);
    var offset = ele.offset();
    if (!offset.top && !offset.left && ele.is('hidden')) {
     offset = ele.show().offset();
    }
    var id = ele.attr('ui-valid-id');
    if (!id) {
     id = Math.guid();
     ele.attr('ui-valid-id', id);
    }
    if (id.contains('.')) {
     id = id.replace(/\./g, '_');
    }
    var top = offset.top,
      left = offset.left;
    var getTips = function () {
     var _tip = $('#vtip_' + id);
     if (_tip.length) {
      _tip.html(msg).css({
       'display': 'none',
       'top': top + 'px',
       'left': left + ele.width() + 10 + 'px'
      });
     } else {
      var html = '<div id="vtip_' + id + '" class="vtip qtip qtip-rounded box-shadow-tips">' +
        '<div class="qtip-content">' + msg + '</div>';
      $(html).css({
       'display': 'none',
       'position': 'absolute',
       'top': top + 'px',
       'left': left + ele.width() + 10 + 'px'
      }).appendTo($('body'));
     }
    };
    var bindTipsShow = function () {
     getTips();
     ele.unbind('mouseenter mouseleave').bind('mouseenter', function () {
      var _tip = $('#vtip_' + id);
      if (_tip.is(':hidden')) {
       _tip.show();
      }
     }).bind('mouseleave', function () {
      $('#vtip_' + id).hide();
     });
    };
    bindTipsShow();
   },
   off: function (ele) {
    ele.data('last-tip', '');
    this.filterClass(ele);
    var id = ele.attr('ui-valid-id');
    if (!id) {
     return;
    }
    if (id.contains('.')) {
     id = id.replace(/\./g, '_');
    }
    $('#vtip_' + id).remove();
    ele.unbind('mouseenter mouseleave');
   }
  }
 });

1、验证不通过,增加背景色,元素css处理如下

ele.removeClass('ng-valid').removeClass('ng-pristine').addClass('ng-invalid').addClass('ng-dirty');

验证通过,CSS处理如下

 ele.removeClass('ng-invalid').addClass('ng-valid');

 

2、背景提示语,则是在body上增加一个div层。

(6)其他相关代码

var app = angular.module('myApp', []);
 app.controller('testCtrl', ['$scope', 'uiValidFactory', function ($scope, uiValidFactory) {
    $scope.certCheck = function (val) {
     if (val > 32) {
      return "数字太大了";
     }
     return true;
    };
    $scope.submit = function () {
     if (!uiValidFactory.checkValidForm($scope.baseInfoForm.$name)) {
     }
    };
   }]
 );
 Math.guid = function () {
  var a = "", b = 1;
  for (; b <= 32; b++) {
   var c = Math.floor(Math.random() * 16).toString(16);
   a += c;
   if (b === 8 || b === 12 || b === 16 || b === 20) {
    a += '-';
   }
  }
  return a;
 };
 String.prototype.contains = String.prototype.contains || function (a) {
  return this.indexOf(a) != -1;
 };
 String.prototype.format = String.prototype.format || function () {
  var a = Array.prototype.slice.call(arguments);
  return this.replace(/\{(\d+)}/g, function (c, b) {
   return a[b];
  })
 };

 整个代码如下:

<!DOCTYPE html>
<html>
<head lang="en">
 <meta charset="UTF-8">
 <title></title>
 <script src="jquery-1.11.1.js"></script>
 <script src="angular.js"></script>
 <style type="text/css">
  input.ng-invalid, select.ng-invalid {
   background-color: #ee82ee !important;
   border: 1px solid #CCC;
  }
  .qtip {
   position: absolute;
   max-width: 260px;
   display: none;
   min-width: 50px;
   font-size: 10.5px;
   line-height: 12px;
   direction: ltr;
  }
  .qtip-content {
   position: relative;
   padding: 5px 9px;
   overflow: hidden;
   text-align: left;
   word-wrap: break-word;
  }
  .qtip-rounded, .qtip-tipsy {
   -moz-border-radius: 5px;
   -webkit-border-radius: 5px;
   border-radius: 5px;
  }
  .qtipmodal-ie6fix {
   position: absolute !important;
  }
  .box-shadow-tips {
   background-color: #F63;
   border-color: #F5A88F;
   color: white;
   -moz-box-shadow: 2px 2px 2px #969696;
   -webkit-box-shaow: 2px 2px 2px #969696;
   box-shadow: 2px 2px 2px #969696;
  }
 </style>
</head>
<body ng-app="myApp">
<form name="baseInfoForm">
 <div ng-controller="testCtrl">
  <input type="text" ng-model="age" my-valid="r"><br>
  <input type="text" ng-model="name" my-valid="int fn:certCheck"><br>
  <input type="button" value="提交" ng-click="submit()">
 </div>
</form>
</body>
<script type="text/javascript">
 var app = angular.module('myApp', []);
 app.controller('testCtrl', ['$scope', 'uiValidFactory', function ($scope, uiValidFactory) {
    $scope.certCheck = function (val) {
     if (val > 32) {
      return "数字太大了";
     }
     return true;
    };
    $scope.submit = function () {
     if (!uiValidFactory.checkValidForm($scope.baseInfoForm.$name)) {
     }
    };
   }]
 );
 Math.guid = function () {
  var a = "", b = 1;
  for (; b <= 32; b++) {
   var c = Math.floor(Math.random() * 16).toString(16);
   a += c;
   if (b === 8 || b === 12 || b === 16 || b === 20) {
    a += '-';
   }
  }
  return a;
 };
 String.prototype.contains = String.prototype.contains || function (a) {
  return this.indexOf(a) != -1;
 };
 String.prototype.format = String.prototype.format || function () {
  var a = Array.prototype.slice.call(arguments);
  return this.replace(/\{(\d+)}/g, function (c, b) {
   return a[b];
  })
 };
 app.factory('uiTipsFactory', function () {
  return {
   filterClass: function (ele, invalid) {
    if (invalid) {
     //如果验证不通过
     ele.removeClass('ng-valid').removeClass('ng-pristine').addClass('ng-invalid').addClass('ng-dirty');
    } else {
     ele.removeClass('ng-invalid').addClass('ng-valid');
    }
   },
   on: function (ele, msg) {
    var lastTip = ele.data('last-tip');
    if (lastTip && lastTip === msg) {
     return;
    }
    ele.data('last-tip', msg);
    this.filterClass(ele, true);
    var offset = ele.offset();
    if (!offset.top && !offset.left && ele.is('hidden')) {
     offset = ele.show().offset();
    }
    var id = ele.attr('ui-valid-id');
    if (!id) {
     id = Math.guid();
     ele.attr('ui-valid-id', id);
    }
    if (id.contains('.')) {
     id = id.replace(/\./g, '_');
    }
    var top = offset.top,
      left = offset.left;
    var getTips = function () {
     var _tip = $('#vtip_' + id);
     if (_tip.length) {
      _tip.html(msg).css({
       'display': 'none',
       'top': top + 'px',
       'left': left + ele.width() + 10 + 'px'
      });
     } else {
      var html = '<div id="vtip_' + id + '" class="vtip qtip qtip-rounded box-shadow-tips">' +
        '<div class="qtip-content">' + msg + '</div>';
      $(html).css({
       'display': 'none',
       'position': 'absolute',
       'top': top + 'px',
       'left': left + ele.width() + 10 + 'px'
      }).appendTo($('body'));
     }
    };
    var bindTipsShow = function () {
     getTips();
     ele.unbind('mouseenter mouseleave').bind('mouseenter', function () {
      var _tip = $('#vtip_' + id);
      if (_tip.is(':hidden')) {
       _tip.show();
      }
     }).bind('mouseleave', function () {
      $('#vtip_' + id).hide();
     });
    };
    bindTipsShow();
   },
   off: function (ele) {
    ele.data('last-tip', '');
    this.filterClass(ele);
    var id = ele.attr('ui-valid-id');
    if (!id) {
     return;
    }
    if (id.contains('.')) {
     id = id.replace(/\./g, '_');
    }
    $('#vtip_' + id).remove();
    ele.unbind('mouseenter mouseleave');
   }
  }
 });
 app.factory('uiValidFactory', ['$parse', 'uiTipsFactory', function ($parse, tips) {
  return {
   check: function (val, rules, $scope, defaultTips, extendParam) {
    if (!rules) {
     return {
      flag: true
     };
    }
    var rulesArr = rules.split(' '),
      isBlank = val === null || val === undefined || val === '' || ('' + val === '');
    //如果不是必填项 且没有输入值 则清除提示框
    if ($.inArray('r', rulesArr) === -1 && isBlank) {
     return {
      flag: true
     }
    }
    var i = 0, len = rulesArr.length;
    for (; i < len; i++) {
     var rule = rulesArr[i];
     if (!rule) {
      continue;
     }
     var flag = true;
     if ('r' === rule) {
      //如果是必填项,有值 返回true
      flag = !isBlank;
     } else if (rule.contains(':')) {
      //如果校验规则是 fn:ctrl.certCheck
      flag = this.checkRule(val, rule.split(/:/), $scope, extendParam);
     } else {
      //校验 规则是 int 用正则匹配 数字 邮箱 长度
      var pat = this.pats[rule];
      if (pat instanceof RegExp) {
       if (angular.isString(val)) {
        flag = this.mat(val, pat);
       }
      } else if (angular.isFunction(pat)) {
       flag = pat(val);
      } else {
       flag = false;
      }
     }
     //这是干什么的呢
     if (angular.isString(flag)) {
      return {
       flag: false,
       msg: flag,
       rule: rule
      }
     }
     if (flag === false) {
      var msg = this.getMsg(rule, defaultTips) || this.getMsg('tips.valid');
      console.log(msg);
      return {
       flag: false,
       msg: msg,
       rule: rule
      }
     }
    }
    return {
     flag: true
    }
   },
   checkRule: function (val, ruleArr, $scope, extendParam) {
    //ruleArr fn:certCheck
    var rule = ruleArr[0];
    if (rule === 'fn') {
     fnName = ruleArr[1];//指定被调函数的名字 certCheck
     var fn = $parse(fnName)($scope);
     if (!fn) {
      return true;
     }
     return fn.call($scope, val, extendParam);
    } else {
     return true;
    }
   },
   checkValidForm: function (formName) {
    //只检查必填项
    //使用属性筛选器 获得里面所有的元素
    var formContext = $('form[name="{0}"],[ng-form="{0}"],[data-ng-form="{0}"]'.format(formName)),
      validList = formContext.find('[my-valid]');//validList 不是数组,是伪数组
    if (!validList.length) {
     return;
    }
    var that = this,
      validFlags = [];
    validList.each(function () {
       var ele = $(this),
         val = ele.val(),
         ruleStr = ele.attr('my-valid');
       if (!ruleStr) {
        return true;
       }
       if (angular.isString(val)) {
        val = val.trim();
       }
       var validRules = ruleStr.split(' ');
       if ($.inArray('r', validRules) != -1 && !val) {
        var modelValue = ele.attr('ng-model') || ele.attr('data-ng-model');
        validFlags.push(modelValue);
        tips.on(ele, that.getMsg('r'));
       }
      }
    );
    return validFlags;
   },
   mat: function (val, pat) {
    if (!pat) {
     return;
    }
    return pat.test(val);
   }
   ,
   getMsg: function (rule, tips) {
    tips = tips || '';
    //可以在界面上直接写 tips
    if (tips && tips.contains(':')) {
     return tips;
    }
    var msg = this.msgs[rule];
    if (msg) {
     var params0 = tips.contains(':') ? tips.split(/:/)[0] : '';
     var params1 = '';
     if (rule.startsWith('min') || rule.startsWith('max')) {
      var ruleArr = rule.split(/:/);
      params1 = ruleArr[ruleArr.length - 1];
     }
     return msg.format(params0, params1);
    } else {
    }
   }
   ,
   regPat: function (code, pat, msg) {
    if (this.pat[code]) {
     return;
    }
    this.pats[code] = pat;
    this.msgs[code] = msg;
   }
   ,
   msgs: {
    'r': '必填',
    'int': '{0}必须为整数'
   }
   ,
   pats: {
    'int': /^[\-\+]?([0-9]+)$/
   }
  }
 }
 ])
 ;
 app.directive('myValid', ['$parse', 'uiTipsFactory', 'uiValidFactory', function ($parse, tips, valid) {
  var uiValidAttrIdName = 'ui-valid-id';
  return {
   restrict: 'A',
   require: 'ngModel',
   link: function (scope, el, attrs, ctrl) {
    var validId = el.attr(uiValidAttrIdName);
    if (!validId) {
     validId = Math.guid();
     el.attr(uiValidAttrIdName, validId);
    }
    var getRules = function () {
     return attrs.myValid;
    };
    var lastOldRules;
    var validFn = function (value, oldRules) {
     var sp = '_';
     var rules = getRules();
     var r = valid.check(value, rules, scope, attrs.uiValidTips);
     if (lastOldRules && !oldRules) {
      oldRules = lastOldRules;
     }
     if (r.flag && oldRules) {
      rules = rules ? rules + ' ' + oldRules : oldRules;
     }
     if (rules) {
      var arrInner = rules.split(' ');
      var i = 0;
      for (; i < arrInner.length; i++) {
       var oneRule = arrInner[i];
       if (!oneRule.trim()) {
        continue;
       }
       ctrl.$setValidity(attrs.ngModel + sp + oneRule, r.flag ? true : oneRule != r.rule);
      }
     }
     if (!r.flag) {
      tips.on(el, r.msg);
     } else {
      tips.off(el);
     }
     return r.flag;
    };
    var init = function () {
     var rules = getRules();
     if (!rules) {
      return;
     }
     var parsers = ctrl.$parsers;
     if (parsers && parsers.length > 0) {
      parsers.clean();
     }
     parsers.unshift(function (value) {
      return validFn(value) ? value : undefined;
     });
    };
    scope.$watch(attrs.ngModel, function (newVal, oldVal) {
     if (newVal === oldVal) {
      return;
     }
     if (ctrl.$modelValue != undefined && (ctrl.$invalid || el.hasClass('ng-invalid'))) {
      validFn(ctrl.$modelValue);
     }
    });
    scope.$watch(getRules, function (newRules, oldRules) {
     init();
     lastOldRules = oldRules;
     if (ctrl.$modelValue === undefined || ctrl.$modelValue === null) {
      var needValid = false;
      el.hasClass('ng-invalid');
      var isValNaN = ctrl.$viewValue !== ctrl.$viewValue;
      if (ctrl.$invalid || (ctrl.$viewValue !== undefined && !isValNaN)) {
       needValid = true;
      }
      if (needValid) {
       ctrl.$setViewValue(ctrl.$viewValue);
      }
     } else {
      if (!ctrl.$dirty && attrs.dirtyCheck) {
       console.log('----');
      } else {
       validFn(ctrl.$modelValue, oldRules);
      }
     }
    });
   }
  }
 }]);
</script>
</html>
Javascript 相关文章推荐
js 自定义的联动下拉框
Feb 07 Javascript
IE中createElement需要注意的一个问题
Jul 13 Javascript
ASP.NET jQuery 实例16 通过控件CustomValidator验证RadioButtonList
Feb 03 Javascript
js如何判断不同系统的浏览器类型
Oct 28 Javascript
jquery 淡入淡出效果的简单实现
Feb 07 Javascript
JavaScript中创建对象和继承示例解读
Feb 12 Javascript
jQuery插件HighCharts实现的2D回归直线散点效果示例【附demo源码下载】
Mar 09 Javascript
浅谈webpack性能榨汁机(打包速度优化)
Jan 09 Javascript
Vue 理解之白话 getter/setter详解
Apr 16 Javascript
html-webpack-plugin修改页面的title的方法
Jun 18 Javascript
vue+elementUI中表格高亮或字体颜色改变操作
Nov 02 Javascript
JavaScript实现网页跨年倒计时
Dec 02 Javascript
js实现九宫格的随机颜色跳转
Feb 19 #Javascript
原生JS实现垂直手风琴效果
Feb 19 #Javascript
js鼠标移动时禁止选中文字
Feb 19 #Javascript
canvas雪花效果核心代码分享
Feb 19 #Javascript
Ajax和Comet技术总结
Feb 19 #Javascript
thinkphp标签实现bootsrtap轮播carousel实例代码
Feb 19 #Javascript
Angularjs中的ui-bootstrap的使用教程
Feb 19 #Javascript
You might like
怎样辨别一杯好咖啡
2021/03/03 新手入门
PHP简单操作MongoDB的方法(安装及增删改查)
2016/05/26 PHP
Laravel框架之解决前端显示图片问题
2019/10/24 PHP
读jQuery之二(两种扩展)
2011/06/11 Javascript
javascript中如何处理引号编码&amp;#034;
2013/08/15 Javascript
jquery更换文章内容与改变字体大小代码
2013/09/30 Javascript
Javascript基础 函数“重载” 详细介绍
2013/10/25 Javascript
Javascript基础教程之比较操作符
2015/01/18 Javascript
JavaScript中setTimeout和setInterval函数的传参及调用
2016/03/11 Javascript
总结JavaScript三种数据存储方式之间的区别
2016/05/03 Javascript
jQuery简单实现仿京东分类导航层效果
2016/06/07 Javascript
angular十大常见问题
2017/03/07 Javascript
React 子组件向父组件传值的方法
2017/07/24 Javascript
js通过Date对象实现倒计时动画效果
2017/10/27 Javascript
移动web开发之touch事件实例详解
2018/01/17 Javascript
使用javascript函数编写简单银行取钱存钱流程
2018/05/26 Javascript
基于jQuery使用Ajax动态执行模糊查询功能
2018/07/05 jQuery
详解微信小程序实现仿微信聊天界面(各种细节处理)
2019/02/17 Javascript
vue v-for直接循环数字实例
2019/11/07 Javascript
[02:40]DOTA2英雄基础教程 巨牙海民
2013/12/23 DOTA
[01:38]DOTA2第二届亚洲邀请赛中国区预选赛出线战队晋级之路
2017/01/17 DOTA
[01:00:12]2018DOTA2亚洲邀请赛 4.7 淘汰赛 VP vs LGD 第一场
2018/04/09 DOTA
利用Python批量压缩png方法实例(支持过滤个别文件与文件夹)
2017/07/30 Python
Python处理命令行参数模块optpars用法实例分析
2018/05/31 Python
tensorflow ckpt模型和pb模型获取节点名称,及ckpt转pb模型实例
2020/01/21 Python
django-csrf使用和禁用方式
2020/03/13 Python
Python+Dlib+Opencv实现人脸采集并表情判别功能的代码
2020/07/01 Python
CSS3中:nth-child和:nth-of-type的区别深入理解
2014/03/10 HTML / CSS
什么是JNDI的上下文?如何初始化JNDI上下文
2012/03/10 面试题
Unix如何在一行中运行多个命令
2015/05/29 面试题
授权委托书(法人单位用)
2014/09/29 职场文书
2014年房地产工作总结范文
2014/11/19 职场文书
2014年图书管理员工作总结
2014/12/01 职场文书
一波干货,会议主持词开场白范文
2019/05/06 职场文书
Mysql实现主从配置和多主多从配置
2021/06/02 MySQL
Java 泛型详解(超详细的java泛型方法解析)
2021/07/02 Java/Android