策略模式(下)

上面一篇文章,我们已经学会了基本的策略模式的书写,好,现在我们就来用些例子来巩固下

动画现在是页面上一个不可或缺的部分,它会为我们的网页增色不少,下面我们就用策略模式来实现缓动动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<link rel="stylesheet" href="">
<style type="text/css" media="screen">
div{
position:absolute;
width:100px;
height:100px;
background:lime;
text-align:center;
line-height:100px;
}

</style>

</head>
<body>
<div id='div'>我要运动</div>
<script type="text/javascript" src='js/part3.js'></script>
</body>
</html>

html部分so easy,然后我们来看看js部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//缓动算法:
var tween = {
linear : function(t,b,c,d){
return c*t/d + b;
},
easeIn : function(t,b,c,d){
return c*(t/=d)*t+b
},
strongEaseIn : function(t,b,c,d){
return c*(t/=d)*t*t*t*t + b;
},
strongEaseOut : function(t,b,c,d){
return c*((t=t/d-1)*t*t*t*t+1)+b;
},
sineaseIn : function(t,c,b,d){
return c*(t/=d)*t*t+b
},
sineaseOut : function(t,c,b,d){
return c*((t=t/d-1)*t*t+1)+b
}
};

//定义Animate类,接受一个参数:将运动起来的dom节点

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]; //dom节点的初始位置
this.propertyName = propertyName; //dom需要改变的CSS属性名
this.endPos = endPos; //dom节点的目标位置
this.duration = duration; //动画持续时间
this.easing = tween[easing]; //缓动算法

var self = this;
var timeId = setInterval(function(){ //启动定时器,开始动画
if( self.step() === false ){ //如果动画已结束,则清除定时器
clearInterval(timeId)
}

},100);


}

Animate.prototype.step = function(){
var t = new Date(); //获取当前时间
console.log(t)
console.log(typeof this.startTime)
if( t >= this.startTime + this.duration ){

this.update( this.endPos ); //更新小球的CSS属性值
return false;
}

var pos = this.easing( t-this.startTime,this.startPos,this.endPos - this.startPos,this.duration);
this.update( pos ); //更新小球的CSS属性值

}

Animate.prototype.update = function( pos ){
this.dom.style[this.propertyName] = pos + 'px'
}

var oDiv = document.getElementById('div');

var animate = new Animate(oDiv);

animate.start('left',500,1000,'linear')

上面我们先定义了一个缓动算法tween这个我们也许并不陌生,最初来自flash,它包含四个参数: 动画已消耗的时间小球的原始位置小球的目标位置( 就是起始点与终点之间的距离)整个运动要消耗的时间

然后,我们定义一个动画类Animate,有一个方法start,用来设置传进来的参数以及判断运动是否已经结束,step用来设置每一步要做的事,最后一个update函数用来实时更新dom的状态

特别要注意的一个问题是
36行的this.startTime = +new Date;这里前面必须不能遗漏这个+,,他是将一个对象转换为Number类型,从而以便于与第58行里面的this.startTime + this.duration这样子,他们相加后的结果还是number,不然如果是一个对象,那么这个判断永远是false,dom不会停下,,有的人会说55行不也有个new Date吗,也要前面加上+?这里倒是不需要,具体可以自己试试,总结一句话: +new Date就是被对象转换为 Number

懂了上面的例子后,我们最后来看下我们常见的表单验证是如何与策略模式结合的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Eg</title>
<link rel="stylesheet" href="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/css/bootstrap.css">
</head>
<body class='container'>
<form id='registerForm' method='post'>

<fieldset class="form-group">
<label for="userName">请输入你的名字</label>
<input type="text" class="form-control" name='userName' id="userName" />
</fieldset>

<fieldset class="form-group">
<label for="oPassword">请输入密码</label>
<input type="password" class="form-control" name='password' id="oPassword" />
</fieldset>

<fieldset class="form-group">
<label for="tel">请输入联系方式</label>
<input type="text" class="form-control" name='phone' id="tel" />
</fieldset>

<button type="submit" class="btn btn-primary">提交</button>

</form>
<script type="text/javascript" src='js/part5.js'></script>
</body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
var strategies = {
isNoEmpty : function(value,errorMsg){
if(value === ''){
return errorMsg;
}
},
minLength : function(value,length,errorMsg){
if(value.length<length){
return errorMsg
}
},
isMobile : function(value,errorMsg){
if( !/^1[3|5|8][0-9]{9}$/.test(value)){
return errorMsg;
}
}
};

var validataFunc = function(){
var validator = new Validator();

// 添加校验规则
validator.add(registerForm.userName,'isNoEmpty','用户名不能为空');
validator.add(registerForm.password,'minLength:6','密码不能少于六位');
validator.add(registerForm.phone,'isMobile','手机号格式不正确');

// 获得校验结果
var errorMsg = validator.start();

return errorMsg;
}

var registerForm = document.getElementById('registerForm');
registerForm.onsubmit = function(){
var errorMsg = validataFunc();

if(errorMsg){
alert(errorMsg);
return false;
}

}


//校验类
var Validator = function(){
this.cache = []; //保存校验规则
};

Validator.prototype.add = function(dom,rule,errorMsg){
var ary = rule.split(':');
this.cache.push(function(){
var strategy = ary.shift();
ary.unshift( dom.value );
ary.push( errorMsg );
return strategies[strategy].apply( dom,ary );
})
};

Validator.prototype.start = function(){
for( var i=0,validataFunc;validataFunc = this.cache[i++]; ){
var msg = validataFunc(); //开始校验,并取得验证后的返回信息
if( msg ){ //如果有确切的返回值,说明验证并没有通过
return msg
}
}
}

具体的你们自己去细细品味吧~~

好了,策略模式,我们就交流到这,如其中有错误的,欢迎指出^_^
最后祝大家新年快乐,万事如意~~

学习自曾探的《Javascript设计模式与开发实战》

文章目录