您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)Angular如何使用輸入框?qū)崿F(xiàn)自定義驗(yàn)證功能,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
此插件使用angular.js、JQuery實(shí)現(xiàn)。(jQuery的引入需在angular 之前)
用戶可以 在輸入框輸入數(shù)據(jù)后驗(yàn)證 必填項(xiàng)、整數(shù)型、浮點(diǎn)型驗(yàn)證。
如果在form 里面的輸入框驗(yàn)證,可以點(diǎn)擊 提交按鈕后,實(shí)現(xiàn) 必填項(xiàng)驗(yàn)證。
效果圖如下:
(1)驗(yàn)證未通過(guò)時(shí),背景標(biāo)紅等樣式為
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; }
因?yàn)閍ngular.js 內(nèi)置驗(yàn)證未通過(guò)時(shí),會(huì)自動(dòng)為 標(biāo)簽 增加 .ng-invalid 樣式,因?yàn)檫@里重寫此樣式
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 實(shí)現(xiàn)
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); } } }); } } }]);
通過(guò) 監(jiān)聽 attrs.ngModel,驗(yàn)證規(guī)則 rules ,ctrl.$parser 來(lái)實(shí)現(xiàn) 輸入框內(nèi)容改變的響應(yīng)。
一旦使用此directive,則動(dòng)態(tài)為當(dāng)前輸入框添加ID,以便在 驗(yàn)證通過(guò)后,改變輸入框的驗(yàn)證背景信息。
(4)驗(yàn)證邏輯處理 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 === ''); //如果不是必填項(xiàng) 且沒(méi)有輸入值 則清除提示框 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) { //如果是必填項(xiàng),有值 返回true flag = !isBlank; } else if (rule.contains(':')) { //如果校驗(yàn)規(guī)則是 fn:ctrl.certCheck flag = this.checkRule(val, rule.split(/:/), $scope, extendParam); } else { //校驗(yàn) 規(guī)則是 int 用正則匹配 數(shù)字 郵箱 長(zhǎng)度 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];//指定被調(diào)函數(shù)的名字 certCheck var fn = $parse(fnName)($scope); if (!fn) { return true; } return fn.call($scope, val, extendParam); } else { return true; } }, checkValidForm: function (formName) { //只檢查必填項(xiàng) //使用屬性篩選器 獲得里面所有的元素 var formContext = $('form[name="{0}"],[ng-form="{0}"],[data-ng-form="{0}"]'.format(formName)), validList = formContext.find('[my-valid]');//validList 不是數(shù)組,是偽數(shù)組 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}必須為整數(shù)' } , pats: { 'int': /^[\-\+]?([0-9]+)$/ } } } ]) ;
通過(guò)獲取輸入框 ele.myValid 驗(yàn)證規(guī)則,
1、如果是必填,則返回 標(biāo)紅此輸入框,鼠標(biāo)移上,則顯示 驗(yàn)證信息 “必填””。
2、如果是整數(shù)、浮點(diǎn)型等驗(yàn)證,則通過(guò) 正則表達(dá)式進(jìn)行驗(yàn)證。
3、如果是最大(max)、最小(min),則自定義邏輯。
4、如果是 fn 驗(yàn)證,則根據(jù) 對(duì)應(yīng)controller中函數(shù)進(jìn)行驗(yàn)證。
5、用戶點(diǎn)擊提交按鈕,則 判斷是否必填項(xiàng),驗(yàn)證不通過(guò),對(duì)應(yīng)元素背景標(biāo)紅。
(5) 驗(yàn)證不通過(guò),提示Factory---uiTipsFactory
app.factory('uiTipsFactory', function () { return { filterClass: function (ele, invalid) { if (invalid) { //如果驗(yàn)證不通過(guò) 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、驗(yàn)證不通過(guò),增加背景色,元素css處理如下
ele.removeClass('ng-valid').removeClass('ng-pristine').addClass('ng-invalid').addClass('ng-dirty');
驗(yàn)證通過(guò),CSS處理如下
ele.removeClass('ng-invalid').addClass('ng-valid');
2、背景提示語(yǔ),則是在body上增加一個(gè)div層。
(6)其他相關(guān)代碼
var app = angular.module('myApp', []); app.controller('testCtrl', ['$scope', 'uiValidFactory', function ($scope, uiValidFactory) { $scope.certCheck = function (val) { if (val > 32) { return "數(shù)字太大了"; } 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]; }) };
整個(gè)代碼如下:
<!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 "數(shù)字太大了"; } 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) { //如果驗(yàn)證不通過(guò) 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 === ''); //如果不是必填項(xiàng) 且沒(méi)有輸入值 則清除提示框 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) { //如果是必填項(xiàng),有值 返回true flag = !isBlank; } else if (rule.contains(':')) { //如果校驗(yàn)規(guī)則是 fn:ctrl.certCheck flag = this.checkRule(val, rule.split(/:/), $scope, extendParam); } else { //校驗(yàn) 規(guī)則是 int 用正則匹配 數(shù)字 郵箱 長(zhǎng)度 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];//指定被調(diào)函數(shù)的名字 certCheck var fn = $parse(fnName)($scope); if (!fn) { return true; } return fn.call($scope, val, extendParam); } else { return true; } }, checkValidForm: function (formName) { //只檢查必填項(xiàng) //使用屬性篩選器 獲得里面所有的元素 var formContext = $('form[name="{0}"],[ng-form="{0}"],[data-ng-form="{0}"]'.format(formName)), validList = formContext.find('[my-valid]');//validList 不是數(shù)組,是偽數(shù)組 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}必須為整數(shù)' } , 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>
關(guān)于“Angular如何使用輸入框?qū)崿F(xiàn)自定義驗(yàn)證功能”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。