策略模式算法
特色 由一個上下文對象負責選擇策略,將策略的實現委託給策略類,節省if-else判斷分支app
實現思路 定義算法(即策略)族,將算法的使用與實現隔離dom
/* 策略模式 模板 */ var strategies = function () { "s1" : function ( arg ) { // body... }, "s2" :function ( arg ) { // body... } //,"s3"... } var context = function ( str, arg ) { return strategies[ str ]( arg ); }
實例 緩動動畫,表單驗證動畫
//策略模式 示例:緩動動畫 //緩動效果策略族 var tween = { linear: function ( t, b, c, d ) { return c*t /d +b; }, easyin: function ( t, b, c, d ) { return c* ( t /= d ) *t +b; } } //曲線策略族 var path = { //beze: } var Animate = function ( dom ) { this.dom = dom; this.startTime = 0; this.startPos = 0; this.endPos = 0; this.propertyName = null; this.easing = null; this.duration = null; }; Animate.prototype.start = function ( propertyName, endPos, duration, easing ) { this.startTime = +new Date; this.startPos = this.dom.getBoundingClientRect()[ propertyName ]; this.propertyName = propertyName; this.endPos = endPos; this.duration = duration; this.easing = tween[ easing ]; var self = this; var timeId = setInterval(function () { if ( self.step() == false ){ clearInterval(timeId); } },19); }; Animate.prototype.step = function ( propertyName, endPos, duration, easing ) { var t = +new Date; if( t >= this.startTime + this.duration ){ this.update( this.endPos ); return false; } var pos = this.easing( t-this.startTime, this.startPos, this.endPos - this.startPos, this.duration ); this.update( pos ); }; Animate.prototype.update = function ( pos ) { this.dom.style[ this.propertyName ] = pos + 'px'; }; var div = document.getElementById( 'xxx' ); var animate = new Animate( div ); animate.start('left', 500, 1000, 'easyin');
//策略模式 示例:表單校驗 /* @strategies 驗證規則族*/ var strategies = { isNotEmpty : function ( value, errMsg ) { if ( value === '' ){ return errMsg; } }, minLength: function ( value, length, errMsg ) { if( value.length < length ){ return errMsg; } }, maxLength: function ( value, length, errMsg ) { if( value.length > length ){ return errMsg; } }, isMobile: function ( value, errMsg ) { if( ! /(^1[3|5|8][0-9]{9}$)/ .test( value ) ){ return errMsg; } } }; var Validator = function () { this.cache = []; }; Validator.prototype.add = function ( dom, rules ) { var self = this; for ( var i =0, rule; rule = rules[ i++ ]; ){ (function ( rule ) { var ary = rule.strategy.split( ':' ); var errorMsg = rule.errorMsg; self.cache.push(function () { var strategy = ary.shift(); ary.unshift( dom.value ); ary.push( errorMsg ); return strategies[ strategy ].apply( dom, ary ); }); })( rule ); } }; Validator.prototype.start = function () { for( var i = 0, validataFunc; validataFunc = this.cache[ i++ ]; ){ var msg = validataFunc(); if( msg ){ return msg; } } }; //表單校驗使用場景 /* @validataFunc 驗證規則配置*/ var xxxForm = document.getElementById( 'xxxForm' ); var validataFunc = function () { var validator = new Validator(); //註冊validator的驗證規則 validator.add( xxxForm.userName, [ { strategy: 'isNotEmpty', errorMsg: '用戶名不能爲空' }, { strategy: 'minLength:6', errorMsg: '用戶名長度不能小於6位' }, { strategy: 'maxLength:20', errorMsg: '用戶名長度不能小於20位' } ] ); validator.add( xxxForm.password, [ { strategy: 'minLength:6', errorMsg: '密碼長度不能少於6位' } ]); validator.add( xxxForm.phoneNumber, [ { strategy: 'isMobile', errorMsg: '手機號碼格式不正確' } ]); var errMsg = validator.start(); return errMsg; }; function check ( ) { } xxxForm.onsubmit= function () { var errorMsg = validataFunc(); if( errorMsg ){ //errorMsg不爲空,表示驗證不經過,阻止提交表單 //阻止提交表單的代碼 alert( errorMsg ); return false; } };