动画效果对于前端来说,我觉得是比较重要的内容。特别是对于界面的体验等,这个是相当重要的。

动画主要可以从js或者css来实现,常用的JS动画引擎有velocity,CSS 动画库则有animate.css

jQuery方法有animate, animate, slideDown等。常用的css3属性有transition, animation, transform等。

以下就记录一下自己写过以及收集的一些动画效果的写作心得,还请各位看官拍砖:

要实现的效果是类似移动端购物网站的商品规格详情弹窗,这种效果非常常见。

这里给出两种写法:

遮罩层是body的直接子元素

代码如下:

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
78
79
80
81
82
83
84
85
86
87
88
89
90
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>animation</title>
<style>
.pop-modal.modal-in {
opacity: 1;
-webkit-transition-duration: 400ms;
transition-duration: 400ms;
-webkit-transform: translate3d(0, 0, 0) scale(1);
transform: translate3d(0, 0, 0) scale(1);
}
.pop-modal.modal-out {
opacity: 0;
z-index: 10009;
-webkit-transition-duration: 400ms;
transition-duration: 400ms;
-webkit-transform: translate3d(0, 0, 0) scale(0.815);
transform: translate3d(0, 0, 0) scale(0.815);
}
.pop-modal {
position: absolute;
left: 0;
right: 0;
height: 800px;
/*top: 0;*/
bottom: 0;
opacity: 0;
z-index: 10400;
background-color: #fff;
-webkit-transition: all 0.2s cubic-bezier(0, 0, 0.25, 1);
transition: all 0.2s cubic-bezier(0, 0, 0.25, 1);
-webkit-transform: translate3d(0, 100%, 0);
}
.popup-overlay {
z-index: 10000;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.4);
visibility: hidden;
opacity: 0;
-webkit-transition-duration: 400ms;
transition-duration: 400ms;
}
.popup-overlay_visible {
opacity: 1;
visibility: visible;
}
.tm {
font-size: 60px;
}
</style>
</head>
<body>
<button id="tm" class="tm">切换modal显示</button>
<buton id="J_close">关闭modal</buton>
<div class="popup-overlay" id="J_overlay"></div>
<div id="pop" class="pop-modal">
<div class="pop__content">
这是弹出内容
</div>
</div>
<script src="../jquery.js"></script>
<script src="../adapter.js"></script>
<script>
$('#J_close').on('click', function () {
$('#pop').removeClass('modal-in').transitionEnd(function () {
$('#J_overlay').removeClass('popup-overlay_visible')
})
})
$('#J_overlay').on('click', function () {
$('#pop').removeClass('modal-in').transitionEnd(function () {
$('#J_overlay').removeClass('popup-overlay_visible')
})
})
$('#tm').on('click', function () {
$('#pop').addClass('modal-in')
$('#J_overlay').addClass('popup-overlay_visible')
})
</script>
</body>
</html>

这里模仿的是淘宝的SUI里面的modal.js插件。大概的意思就是在点击按钮的时候给遮罩层和弹窗内容添加类,元素会应用因为属性的更改而触发元素自身定义的动画。

这里的adapter.js只是SUI里面的对于zepto.js的方法的补充源码里面有一个zepto-adapter.js里面包含了transitionEnd这个扩展方法,这个方法的意思是说监听动画完成的事件,当动画完成才去做某些动作比如当动画完成才去进行其它步骤。其实这个有点像是那个jQuery的animate的回调。

引用MDN上的说法:

The transitionend event is fired when a CSS transition has completed. In the case where a transition is removed before completion, such as if the transition-property is removed or display is set to “none”, then the event will not be generated.

意思是说当一个CSS的渐变效果完成而触发,但是这个渐变的属性被移除或者元素设置为none的时候这个事件不会触发。查看Quicks上的transimitionend这个事件是每个属性触发一次。与此相应的有animitionend事件。

遮罩层和弹出出层的内容是同一级

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>animation</title>
<style>
.pop-modal.modal-in {
opacity: 1;
-webkit-transition-duration: 400ms;
transition-duration: 400ms;
-webkit-transform: translate3d(0, 0, 0) scale(1);
transform: translate3d(0, 0, 0) scale(1);
}
.pop-modal.modal-out {
opacity: 0;
z-index: 10009;
-webkit-transition-duration: 400ms;
transition-duration: 400ms;
-webkit-transform: translate3d(0, 0, 0) scale(0.815);
transform: translate3d(0, 0, 0) scale(0.815);
}
/*.pop-modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9990;
background-color: rgba(0, 0, 0, 0.8);
webkit-transition: -webkit-transform .3s;
transition: -webkit-transform .3s;
transition: transform .3s;
transition: transform .3s, -webkit-transform .3s;
}*/
.pop__content.modal-in {
transform: translate3d(0px, 0px, 0px);
}
.pop__content {
position: absolute;
left: 0;
right: 0;
bottom: 0;
/*height: 700px;*/
/* top: 15%; */
background-color: #fff;
z-index: 5000;
/*-webkit-transition: all 0.2s cubic-bezier(0, 0, 0.25, 1);
transition: all 0.2s cubic-bezier(0, 0, 0.25, 1);
-webkit-transform: translate3d(0, 100%, 0);*/
-webkit-transition: -webkit-transform .3s;
transition: -webkit-transform .3s;
transition: transform .3s;
transition: transform .3s, -webkit-transform .3s;
-webkit-transform: translate3d(0, 100%, 0);
}
.popup-overlay {
display: none;
z-index: 100;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
/*visibility: hidden;*/
opacity: 0;
-webkit-transition-duration: 200ms;
transition-duration: 200ms;
background: rgba(0, 0, 0, 0.6);
/*width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.4);
visibility: hidden;
opacity: 0;
-webkit-transition-duration: 400ms;
transition-duration: 400ms;*/
}
.popup-overlay_visible {
opacity: 1;
visibility: visible;
}
.tm {
font-size: 60px;
}
.pop-dialog__title {
height: 500px;
}
</style>
</head>
<body>
<button id="tm" class="tm">切换modal显示</button>
<buton id="J_close">关闭modal</buton>
<div id="pop" class="pop-modal">
<div class="popup-overlay" id="J_overlay">
</div>
<div class="pop__content">
<div class="pop-dialog__title">
这是弹出内容
</div>
</div>
</div>
<script src="../jquery.js"></script>
<script src="../adapter.js"></script>
<script>
function getStyle(el, styleProp) {
var value, defaultView = (el.ownerDocument || document).defaultView;
// W3C standard way:
if (defaultView && defaultView.getComputedStyle) {
// sanitize property name to css notation
// (hypen separated words eg. font-Size)
styleProp = styleProp.replace(/([A-Z])/g, '-$1').toLowerCase();
return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
} else if (el.currentStyle) { // IE
// sanitize property name to camelCase
styleProp = styleProp.replace(/\-(\w)/g, (str, letter) => {
return letter.toUpperCase();
});
value = el.currentStyle[styleProp];
// convert other units to pixels on IE
if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
return ((value) => {
var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
el.runtimeStyle.left = el.currentStyle.left;
el.style.left = value || 0;
value = el.style.pixelLeft + 'px';
el.style.left = oldLeft;
el.runtimeStyle.left = oldRsLeft;
return value;
})(value);
}
return value;
}
}
$('#J_close').on('click', function () {
// addClass('modal-out')
$('.pop__content').removeClass('modal-in').transitionEnd(function () {
// $('#pop').hide()
$(this).hide()
$('#J_overlay').removeClass('popup-overlay_visible').hide()
})
})
$('#J_overlay').on('click', function () {
// addClass('modal-out')
$('#J_overlay').removeClass('popup-overlay_visible');
$('.pop__content').removeClass('modal-in').transitionEnd(function () {
$(this).hide()
$('#J_overlay').removeClass('popup-overlay_visible').hide()
})
})
$('#tm').on('click', function () {
$('.pop__content').show();
// 只有这样才可以触发动画效果
getStyle($('#pop')[0], 'transform');
$('#J_overlay').addClass('popup-overlay_visible').show();
$('.pop__content').addClass('modal-in');
})
</script>
</body>
</html>

这里的做法是模仿微信weui里面的actionSheet.js有一个方法$.getStyle($actionSheet[0], 'transform');这里我看的注释是说:

这里获取一下计算后的样式,强制触发渲染. fix IOS10下闪现的问题

可是我怎么这里就是为了要有动画效果的。这里的关键点就在这个函数上面,其它的和上一段代码是差不多的。

思考

其实,动画就是对于元素的某个属性的渐变的效果。那么这里其实会涉及到好多东西比如requestAnimationFrame还有多个动画效果的叠加问题,复杂的动画是需要有一定的数学算法基础的

TodoList:

  • 购物车的抛物线功能
  • Vue动画
  • Animation与Transimition的区别