1.目标及知識點:
- css3 transition 使用
- css3 animation 使用
- css3 transform 使用
- 利用CSS3 transition 實作動畫
- transition 文法詳解
- transition-delay
- transition-duration
- transition-property
- transition-timing-function
- 貝塞爾曲線運動 https://cubic-bezier.com/
- transition 針對為渲染元素的問題
- transitionend 事件
- 利用CSS3 animation 動畫
- keyframes
- animation-name
- animation-duration
- animation-timing-function,
- animation-delay
- animation-iteration-count
- animation-direction
- animation-fill-mode
- animation 相關事件
- animationstart
- animationiteration
- animationend
- CSS3 transform 詳解
- transform 2D
- 旋轉: rotate()
- 縮放: scale()、scaleX()、scaleY()
- 傾斜: skew()、skewX()、skewY()
- 平移:translate()、translateX()、translateY()
- transform 多函數書寫時的執行順序
- transform-origin 源點設定
- translate 和 源點關系
- transform 3D
- 3D旋轉: rotateX()、rotateY()、rotateZ()
- 3D位移:translateZ()
- transform-style
- perspective
- perspective-origin
- 搭建立方體
- CSS3 transform 詳解
- transform 2D
- 旋轉: rotate()
- 縮放: scale()、scaleX()、scaleY()
- 傾斜: skew()、skewX()、skewY()
- 位移:translate()、translateX()、translateY()
- transform 多函數書寫時的執行順序
- transform-origin 源點設定
- translate 和 源點關系
- 執行個體:無縫滾動
- 執行個體:水滴按鈕
- 執行個體:時鐘實作
- 擴充:JS 擷取 transform 的問題
- matrix(a,b,c,d,e,f) 矩陣函數
- matrix(1,0,0,1,0,0);
- 通過矩陣實作縮放
- x軸縮放 a=x*a c=x*c e=x*e;
- y軸縮放 b=y*b d=y*d f=y*f;
- 通過矩陣實作位移
- x軸位移: e=e+x
- y軸位移: f=f+y
- 通過矩陣實作傾斜
- x軸傾斜: c=Math.tan(xDeg/180*Math.PI)
- y軸傾斜: b=Math.tan(yDeg/180*Math.PI)
- 通過矩陣實作旋轉
- a=Math.cos(deg/180*Math.PI);
- b=Math.sin(deg/180*Math.PI);
- c=-Math.sin(deg/180*Math.PI);
- d=Math.cos(deg/180*Math.PI);
- transform 3D
- 3D旋轉: rotateX()、rotateY()、rotateZ()
- 3D位移:translateZ()
- transform-style
- perspective
- perspective-origin
- 搭建立方體
2.transition
2.1 transition作用及樣式:
transition作用:
transition 在元素的樣式發生改變時,給元素添加一個過渡動畫。不是所有樣式都有效果,必須是寬高,背景色,距離,位置等數值類樣式才有效果。通過css和JS改變都會有動畫效果。
transition樣式:
- transition-delay:延遲時間,動畫延遲多長時間執行(s|ms),預設為0。可選
- transition-duration:動畫時長,動畫用多長時間完成(s|ms),預設為0,必填
- transition-property:要動畫的樣式。預設all。隻給某些加樣式如,transition:1s width;隻給寬加過渡動畫
- transition-timing-function:動畫形式
transition-timing-function動畫形式:
- linear 勻速
- ease 緩沖(預設值)
- ease-in 加速
- ease-out 減速
- ease-in-out 先加速再減速
- cubic-bezier()貝塞爾曲線
各個樣式之間不加逗号。除非給寬高分别加樣式:如,transition:1s width,.5s height;
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background: red;
}
.hover {
width: 400px;
height: 200px;
background: blue;
/* transition: .5s;transition-delay動畫延遲多長時間執行 */
/* transition: .5s 1s; transition-duration動畫用多長時間完成 */
/* transition: .5s 1s width; transition-property:要動畫的樣式,預設all是給所有樣式加過渡效果*/
/* transition: 1s .5s width ease-in-out; */
/*
transition-timing-function:動畫形式:
linear 勻速
ease 緩沖(預設值)
ease-in 加速
ease-out 減速
ease-in-out 先加速再減速
cubic-bezier()貝塞爾曲線 https://cubic-bezier.com/
*/
transition: 1s .5s width cubic-bezier(0,1.42,.83,.67);
}
</style>
</head>
<body>
<div></div>
<script>
//設定滑鼠移入移出事件,然後加上transition效果
var div = document.querySelector("div");
div.onmouseover = function(){
this.classList.add("hover");
};
div.onmouseout = function(){
this.classList.remove("hover");
};
</script>
</body>
</html>
2.2 transition使用時注意點:
預設隐藏的元素,設定點選後再顯示時,過渡動畫會失效。
解決:定時器延時過渡動畫執行
需求:預設div隐藏,點選按鈕後再顯示并設定過渡後效果
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#box {
width: 100px;
height: 100px;
background: red;
display: none;
transition: .5s;
}
</style>
</head>
<body>
<div id="box"></div>
<button>顯示</button>
<script>
//元素本身是隐藏的,點選時設定block,并改變其寬度,設定動畫過渡效果
//延時最好不低于20:因為螢幕有渲染幀頻問題,1s渲染60次,16.7ms渲染一次。如果寫0可能卡在上一屏,動畫過渡效果就可能出不來
var box = document.querySelector("#box");
var btn = document.querySelector("button");
btn.onclick = function(){
box.style["display"] = "block";
box.style["width"] = "400px";
box.style["background"] = "blue";
// setTimeout(function(){
// box.style["width"] = "400px";
// box.style["background"] = "blue";
// },20);
};
</script>
</body>
</html>
問題:發現此時并沒有動畫過渡效果。
原因:元素本身設定display為none是不會渲染這個元素的,當display設定為block時,才開始渲染這個元素。而元素在頁面渲染完(display設定為block)之前,transition是不起效果的。即螢幕繪制(display設定為block)需要時間,當display設定為block時,這個元素渲染需要時間,而代碼之間執行的速度很快,是以會直接執行下面設定的寬高等樣式,而不會通過transition動畫去執行,是以,動畫效果沒有執行,螢幕已經渲染完了。
解決:需要在事件裡,給元素的改變加上定時器延時。時間至少20ms
setTimeout(function(){
box.style["width"] = "400px";
box.style["background"] = "blue";
},20);
2.3 監聽transition執行結束的事件:
- transitionend事件:監聽元素的transition動畫是否執行完畢
- WebKitTransitionEnd:低版本WebKit核心需要寫成WebKitTransitionEnd
直接使用監聽事件ontransitionend會監聽不到transition執行結束:
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#box {
width: 100px;
height: 100px;
background: red;
display: none;
transition: .5s;
}
</style>
</head>
<body>
<div id="box"></div>
<button>顯示</button>
<script>
var box = document.querySelector("#box");
var btn = document.querySelector("button");
//如果元素事先隐藏,會監聽到兩次
btn.onclick = function(){
box.style["display"] = "block";
setTimeout(function(){
box.style["width"] = "400px";
box.style["background"] = "blue";
},20);
};
//監聽事件ontransitionend方法沒有效果
btn.ontransitionend = function(){
console.log("ontransitionend執行完成");//不會進行列印(沒有監聽到)
};
//監聽transition執行結束事件transitionend
box.addEventListener('transitionend',function(){
console.log("addEventListener transitionend執行完成");
});
</script>
</body>
</html>
結果:ontransitionend沒有監聽并列印結果,通過事件監聽正确監聽到結果
注意:每個樣式都是獨立的過渡效果,而不是整體進行一次性進行過渡,是以設定了多個過渡效果,事件監聽也就會監聽到多少次,是以這裡列印了兩次。
2.4 取消監聽事件:
注意:
- 如果要取消監聽事件,則添加監聽事件時不能使用匿名函數,而需要寫成有名函數
- 取消監聽事件必須寫在有名函數函數體内
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#box {
width: 100px;
height: 100px;
background: red;
transition: .5s;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
var box = document.querySelector("#box");
//給box添加click監聽事件,并給box width+200,然後監聽結束後,取消監聽
box.addEventListener('click',fn);
boxWidth = parseInt(getComputedStyle(box)["width"]);
function fn(){
boxWidth += boxWidth;
box.style["width"] = boxWidth + 'px';
//監聽事件結束後,取消監聽事件(注意必須寫在監聽的函數中)
box.removeEventListener('click',fn);
}
</script>
</body>
</html>
2.4 使用監聽事件好處
通過onXXX寫事件時,多個onXXX事件前一個事件處理會被覆寫。但是通過添加事件監聽方式,可以添加多個事件處理。
var box = document.querySelector("#box");
//給box添加click監聽事件,并給box width+200,然後監聽結束後,取消監聽
box.addEventListener('click',fn);
box.addEventListener('click',function(){
console.log("click事件2");
});
boxWidth = parseInt(getComputedStyle(box)["width"]);
function fn(){
boxWidth += boxWidth;
box.style["width"] = boxWidth + 'px';
//監聽事件結束後,取消監聽事件(注意必須寫在監聽的函數中)
box.removeEventListener('click',fn);
}
2.animation
2.1 transition作用及樣式
transition作用及樣式:
transition隻能做一些簡單的動畫,如果要做一些複雜的動畫就得使用animation。而且如果希望元素一開始就有動畫,就要使用animation。animation使用時必須聲明關鍵幀@keyframes 名字
- animation-name:動畫幀名稱 使用@keyframes 名字 進行定義 必選
- animation-duration :動畫持續時間 必選
- animation-timing-function : 動畫形式(參考transition)
- animation-delay : 動畫開始前的延遲時間
- animation-iteration-count 動畫執行次數 number | infinite(無限次)
- animation-direction : 偶數次動畫執行過程 alternate(倒序執行) | normal (順序執行)
- animation-fill-mode : backwards動畫開始前元素的樣式(保留在動畫幀0%);forwards動畫結束後,元素樣式保留在動畫幀0的100%的位置;both 動畫開始前和結束後樣式保留在動畫幀0%和100%的位置,即backwards+forwards
-
animation-play-state : 滑鼠移入後hover,動畫暫停(paused)| 繼續播放(running)
#box:hover {
animation-play-state:paused;
}
animation使用注意點:
- animation是基于關鍵幀@keyframes 名字實作;
- 如果0%不寫就預設使用計算後樣式,可以對其進行重新定義;
- 如果中間xx%不寫就沒有對應的過渡效果;
- 如果100%不寫就預設使用計算後樣式,可以對其進行重新定義;
- 動畫執行完後,又會回到計算後樣式;
- 加animation-fill-mode就能改變動畫執行完前/後保留的樣式。而不是預設0%/100%
- 如果使用from{} to{} to{}會自動計算百分比進行渲染;
- 關鍵幀聲明好後,需要進行調用animation: move 1s;
- 相容老版本Chrome,必須加字首-webkit-animation
- animation-play-state必須用在滑鼠移入事件中,否則會導緻整個動畫暫停
簡單示例:
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
/* animation是基于動畫幀實作 */
@keyframes move{
/* 如果0%不寫就預設使用計算後樣式,可以對其進行重新定義 */
0%{
width: 0;
height: 0;
}
25%{
width: 100px;
height: 150px;
}
50%{
width: 150px;
height: 300px;
}
75%{
width: 300px;
height: 100px;
}
/* 如果100%不寫就預設使用計算後樣式,可以對其進行重新定義,但是動畫執行完後,又會回到計算後樣式 */
100%{
width: 0;
height: 0;
}
/* 如果使用from{} to{} to{}會自動計算百分比進行渲染 */
}
#box {
width: 100px;
height: 100px;
background: red;
/* 動畫幀的調用 */
/* animation: move 1s infinite; 執行無限次*/
/* animation: move 1s 4; 執行指定次數 */
/* animation: move 1s infinite alternate; 倒序執行(必須多次執行才有效) */
/* animation: move 1s infinite normal; 順序執行 */
animation: move 1s linear;
animation-fill-mode: both;/* 動畫開始和結束後,元素樣式保留在動畫幀的0%和100% */
}
#box:hover {
animation-play-state:paused;
}
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
from{} to{} to{} 實作動畫效果:
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
@keyframes move{
from {
width: 100px;
height: 100px;
}
to {
width: 100px;
height: 100px;
}
to {
width: 200px;
height: 100px;
}
to {
width: 300px;
height: 100px;
}
to {
width: 400px;
height: 100px;
}
}
#box {
width: 100px;
height: 100px;
background: red;
animation: move 2s 4;
animation-fill-mode: both;
}
#box:hover {
animation-play-state:paused;
}
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
2.2 animation三個事件監聽:
- animationstart(動畫開始:第一次執行時監聽到)
- animationend(動畫結束)
- animationiteration(動畫多次執行時使用,監聽動畫再次執行)
必須使用事件監聽加這三個事件,而不能直接使用onXXX;
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
/* animation是基于動畫幀實作 */
@keyframes move{
0%{
width: 0;
height: 0;
}
25%{
width: 150px;
height: 100px;
}
50%{
width: 300px;
height: 100px;
}
75%{
width: 150px;
height: 100px;
}
100%{
width: 0;
height: 0;
}
}
#box {
width: 100px;
height: 100px;
background: red;
animation: move 2s linear 6;
animation-fill-mode: both;
}
#box:hover {
animation-play-state:paused;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
var box = document.querySelector("#box");
box.addEventListener("animationstart",function(){
console.log("動畫開始了");
});
box.addEventListener("animationend",function(){
console.log("動畫結束了");
});
box.addEventListener("animationstart",function(){
console.log("動畫又開始了");
});
</script>
</body>
</html>
結果:
3.transform 2D
transform需要和transition或者animation一起使用才有過渡效果。
transform本身不脫離文檔流,進行任何改變對其他元素都沒有任何影響。
transform變換:
- 旋轉:rotate() 機關:deg(角度,可為正負)。也有弧度,旋轉幾圈等機關,但用得比較少。
- 斜切:三個方法skew(x,y) skewX() skewY() 機關:deg(角度)
- 縮放:三個方法scale(x,y) scaleX() scaleY() 本身沒有機關,隻有倍數
- 位移:三個方法translate(x,y) translateX() translateY(),機關像素或其他
transform為了友善我們使用,将其所有的功能已經封裝成對應的方法。
3.1 transform旋轉rotate(deg):
transition實作transform的旋轉:
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#wrap {
width: 600px;
height: 600px;
border: 1px solid black;
margin: 0 auto;
}
#box {
width: 200px;
height: 200px;
background: red;
margin: 200px auto;
font: 140px/200px "宋體";
text-align: center;
color: white;
transition: 3s;
}
#wrap:hover #box{
/* 旋轉totate */
transform: rotate(-360deg);
}
</style>
</head>
<body>
<div id="wrap">
<div id="box">上</div>
</div>
</body>
</html>
animation實作旋轉:
如果要設定一直旋轉或其他操作就使用animation。把rotate()方法寫在關鍵幀中。
animation實作旋轉需要把transform旋轉寫在關鍵幀,再在對應元素樣式中調用animation。
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
/* animation實作旋轉就不能寫在hover樣式裡,就需要把transform旋轉寫在關鍵幀,在關鍵幀中寫旋轉方法,再在對應樣式中調用animation */
@keyframes rotate{
from {
transform: rotate(180deg);
}
to {
transform: rotate(360deg);
}
}
#wrap {
width: 600px;
height: 600px;
border: 1px solid black;
margin: 0 auto;
}
#box {
width: 200px;
height: 200px;
background: red;
margin: 200px auto;
font: 140px/200px "宋體";
text-align: center;
color: white;
animation: 3s rotate infinite;
}
</style>
</head>
<body>
<div id="wrap">
<div id="box">上</div>
</div>
</body>
</html>
3.2 transform斜切:
transform斜切有三個方法:
- skew(x,y) : X軸和Y軸都進行拉伸
- skewX() : 沿着X軸方向拉,使其與Y軸形成對應夾角。
- skewY() : 沿着Y軸方向拉,使其與X軸形成對應夾角。
shewX(): 角度為正數,沿着X軸方向拉兩個對角(左上角和右下角),使其與Y軸形成對應角度的夾角;如果角度為負值,拉伸對角相反,沿着X軸方向拉兩個對角(右上角和左下角),使其與Y軸形成對應角度的夾角;
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#wrap {
width: 600px;
height: 600px;
border: 1px solid black;
margin: 0 auto;
}
#box {
width: 200px;
height: 200px;
background: red;
margin: 200px auto;
font: 140px/200px "宋體";
text-align: center;
color: white;
transition: 3s;
}
#wrap:hover #box{
/* 斜切skewX() */
transform: skewX(30deg);
}
</style>
</head>
<body>
<div id="wrap">
<div id="box">上</div>
</div>
</body>
</html>
shewY(): 角度為正數,沿着Y軸方向拉兩個對角(左上角和右下角),使其與X軸形成對應角度的夾角;如果角度為負值,拉伸對角相反,沿着Y軸方向拉兩個對角(右上角和左下角),使其與X軸形成對應角度的夾角;
/* 斜切skewY() */
transform: skewY(30deg);
skew(x,y) :X軸和Y軸都進行拉伸
/* 斜切skew() */
transform: skew(-40deg,-30deg);
注意:skew(0)和skew(180)位置不一樣。 skew(0)不會變化,skew(180)斜切180度。
3.3 transform 縮放:
transform縮放三個方法:transform縮放本身沒有機關,隻有倍數
- scale(x,y) : X,Y 軸都縮放
- scaleX() :X軸縮放
- scaleY() :Y軸縮放
scale(x,y) :
/* scale(x,y)縮放X 和 Y軸 */
transform: scale(.5);
scaleX():
/* scaleX()縮放X軸 */
transform: scaleX(.5);
scaleY():
/* scaleY()縮放Y軸 */
transform: scaleY(.5);
3.4 transform 位移:
translate位移三個方法,機關像素或其他
- translate(x,y):沿x和y軸定位方向位移
- translateX() :沿X軸方向位移
- translateY() :沿Y軸方向位移
translate(x,y):
/* translate(x,y)向X 和 Y軸坐标方向位移 */
transform: translate(100px,200px);
translateX():
/* translateX()X軸方向位移 */
transform: translateX(200px);
translateY():
/* translateY()縮放Y軸方向位移 */
transform: translateY(200px);
3.4 transform多函數書寫時的執行順序問題
transform中寫多個函數(縮放,斜切,位移,旋轉同時寫)時,後寫先計算。
原因:CSS本身的解讀順序有關,CSS本身解讀順序就是從右向左進行解讀。
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#wrap {
width: 600px;
height: 600px;
border: 1px solid black;
margin: 0 auto;
}
#box1 {
width: 200px;
height: 200px;
background: red;
margin: 50px auto;
font: 140px/200px "宋體";
text-align: center;
color: white;
transition: 1s;
}
#box2 {
width: 200px;
height: 200px;
background: blue;
margin: 0 auto;
font: 140px/200px "宋體";
text-align: center;
color: white;
transition: 1s;
}
#wrap:hover #box1{
transform: translateX(200px) scale(0.5);
/* transform: translateY(200px) scale(0.5); */
}
#wrap:hover #box2{
transform: scale(0.5) translateX(200px);
/* transform: scale(0.5) translateY(200px); */
}
</style>
</head>
<body>
<div id="wrap">
<div id="box1">上</div>
<div id="box2">下</div>
</div>
</body>
</html>
解析: 都是進行transform: scale(0.5) translateX(200px);縮放和X軸位移,但是發現box2的X軸位置和box1不一樣,因為box1會先縮放0.5倍,再位移200px,而box2會先位移200px,再縮放0.5倍,是以整體box2比box1X軸方向少100px。
3.5 transform源點(錨點)transform-origin
transform源點:預設旋轉、縮放、斜切都是圍繞着元素的中心點進行變換。這是由于transform-origin變換基點的預設值決定。
transform-origin變換基點(旋轉、縮放、斜切 圍繞的哪個點進行操作):
- transform-origin預設值center center,即元素的正中心;
- 0,0點在元素的左上角;
- 其他自定義設定的點,在元素的具體對應位置。如transform-origin: 400px 400px;
位移本身圍繞自己設定的軸進行位移是以沒有源點的概念。
注意transform-origin: 400px 400px;設定在需要進行對應操作的元素上。
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#wrap {
width: 600px;
height: 600px;
border: 1px solid black;
margin: 0 auto;
}
#box {
width: 200px;
height: 200px;
background: red;
margin: 200px auto;
font: 140px/200px "宋體";
text-align: center;
color: white;
transition: 1s;
transform-origin: 400px 400px;
}
#wrap:hover #box{
transform: scale(.5) rotate(360deg);
}
</style>
</head>
<body>
<div id="wrap">
<div id="box">上</div>
</div>
</body>
</html>
3.6 transform應用一(時鐘表盤)
純CSS實作,使用圖檔,使用canvas位圖三種實作方式,canvas位圖方式相對性能最高。
思路:這裡使用css實作
- 通過CSS畫出表盤的刻度樣式:li的源點為表盤的中心,沒隔5個樣式不一樣li:nth-of-type(5n+1);
- 通過JS生成60個li;
- 設定時分秒指針,并進行定位,設定變換基點圍繞底部進行旋轉,設定中心點(為美觀);
- 擷取時分秒的時間,一秒鐘秒鐘指針走一個li(6度),一分鐘分鐘指針也走一個li(6度),一小時小時指針走5個li即30度;
- 通過定時器,控制各個指針走動;
- 需要給時針和分針擷取到小數位的小時或分鐘,否則一小時會跳一整格;
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>時鐘表盤</title>
<style>
ul,ul li {
margin: 0;
padding: 0;
list-style: none;
}
#time {
width: 200px;
height: 200px;
margin: 100px auto;
border: 4px solid rgb(196, 13, 13);
position: relative;
border-radius: 50%;
}
#time li {
width: 4px;
height: 10px;
background: rgba(255, 0, 0, 0.637);
position: absolute;
left: 98px;
top: 0px;
/* 源點:是以本元素為基點進行旋轉 */
transform-origin: 2px 100px;
}
/* 指定了父級元素下是 5 的倍數的第一個 li 背景色 */
#time li:nth-of-type(5n+1){
background: rgba(160, 20, 20, 0.863);
height: 12px;
}
/* 給li設定的旋轉樣式 */
.time_rotate {
transform: rotate(0deg);
}
/* 2.設定時分秒針樣式 */
.hour {
width: 6px;
height: 50px;
background: #000000;
position: absolute;
top: 50px;
left: 97px;
/* 設定上面兩個角圓角時針 */
border-radius:10px 10px 0 0 /50px;
/* 設定所有角圓角 */
/* border-radius:10/50px;
border-top-left-radius:10px/50px;
border-top-right-radius:10px/50px; */
transform-origin: 3px 50px;
}
.minute {
width: 4px;
height: 60px;
background: #d15f2a;
position: absolute;
top: 40px;
left: 98px;
border-radius:10px 10px 0 0 /50px;
transform-origin: 2px 60px;
}
.second {
width: 2px;
height: 70px;
background: #e0d20c;
position: absolute;
top: 30px;
left: 99px;
border-radius:10px 10px 0 0 /50px;
transform-origin: 1px 70px;
}
.circle {
width: 10px;
height: 10px;
background: #000000;
position: absolute;
top: 95px;
left: 95px;
border-radius: 50%;
}
</style>
</head>
<body>
<div id="time">
<ul>
<!-- <li style="transform: rotate(0deg);"></li>
<li style="transform: rotate(6deg);"></li>
<li style="transform: rotate(12deg);"></li>
<li style="transform: rotate(18deg);"></li>
<li style="transform: rotate(24deg);"></li> -->
</ul>
<div class="hour"></div>
<div class="minute"></div>
<div class="second"></div>
<div class="circle"></div>
</div>
<script>
//1.使用JS生成表盤刻度 總共有360度,和60和刻度,是以每個刻度代表6度
var time = document.querySelector("#time");
var ul = time.querySelector("ul");
var hour = time.querySelector(".hour");
var minute = time.querySelector(".minute");
var second = time.querySelector(".second");
var len = 360/6;
var lis = '';
var timer = null;
for (var i = 0; i < len; i++) {
lis +='<li style="transform: rotate('+ i*6 +'deg);"></li>';
}
ul.innerHTML = lis;
//3.通過定時器,讓時分秒中動起來
setTime();
//每次開啟定時器之前先關閉
clearInterval(timer);
timer = setInterval(setTime,1000);
function setTime(){
var date = new Date();
var seconds = date.getSeconds();
var minutes = date.getMinutes() + seconds/60;
var hours = date.getHours() + minutes/60;
//4.時針和分針不能一次跳一大格,需要有小數點
second.style.transform = 'rotate('+ seconds*6 +'deg)';
minute.style.transform = 'rotate('+ minutes*6 +'deg)';
//一個小時30度
hour.style.transform = 'rotate('+ hours*30 +'deg)';
}
</script>
</body>
</html>
3.7 transform應用二(水滴按鈕)
需求:滑鼠移入時,有動畫效果。
問題:使用hover實作時,發現滑鼠離開後,動畫就會停止了。
div:hover {
animation: .5s move linear;
}
解決: 要實作複雜的動畫就需要結合JS實作,且通過animationend監聽事件結束後,清除已有樣式,才會在滑鼠再次移入時有動畫效果
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>水滴按鈕</title>
<style>
@keyframes move {
0% {
transform: scaleX(1) scaleY(.75);
}
10% {
transform: scaleY(.8) scaleX(.95);
}
20% {
transform: scaleX(.9) scaleY(.85);
}
30% {
transform: scaleY(.9) scaleX(.85);
}
40% {
transform: scaleX(.8) scaleY(.95);
}
50% {
transform: scaleY(1) scaleX(.75);
}
60% {
transform: scaleX(.8) scaleY(.95);
}
70% {
transform: scaleY(.85) scaleX(.9);
}
80% {
transform: scaleX(.85) scaleY(.9);
}
90% {
transform: scaleY(.8) scaleX(.95);
}
100% {
transform: scaleX(1) scaleY(.75);
}
}
div {
width: 50px;
height: 50px;
margin: 100px auto;
background: rgb(138, 137, 137);
border-radius: 50%;
font: 18px/50px "宋體";
font-weight: bold;
color: #ffffff;
text-align: center;
}
/* div:hover {
animation: .5s move linear;
} */
.btn_hover {
animation: .4s move linear 2;
}
</style>
</head>
<body>
<div class="btn">More</div>
<script>
var btn = document.querySelector(".btn");
var water = document.querySelector(".water");
btn.addEventListener('mouseover',function(){
btn.classList.add("btn_hover");
});
btn.addEventListener('animationend',function(){
btn.classList.remove("btn_hover");
});
</script>
</body>
</html>
3.8 JS擷取transform (matrix)
transform可供操作的隻有一個值matrix,即矩陣。transform 2D 矩陣共有9位,預設三位不能操作,可供操作的隻有6位。transform 3D 矩陣共有16位,預設四位不能操作,可供操作的隻有12位。
而transform的旋轉,斜切,位移,縮放都是CSS封裝的操作matrix的各種方法。
matrix是不可逆的,即通過matrix是不能推出元素之前做過旋轉,斜切,位移,縮放哪些操作。是以transform的操作不能擷取。
- matrix(a,b,c,d,e,f) 矩陣函數 :預設值 matrix(1,0,0,1,0,0);
- 通過矩陣實作縮放
- x軸縮放 a=x*a c=x*c e=x*e;
- y軸縮放 b=y*b d=y*d f=y*f;
- 通過矩陣實作位移
- x軸位移: e=e+x
- y軸位移: f=f+y
- 通過矩陣實作傾斜
- x軸傾斜: c=Math.tan(xDeg/180*Math.PI)
- y軸傾斜: b=Math.tan(yDeg/180*Math.PI)
- 通過矩陣實作旋轉
- a=Math.cos(deg/180*Math.PI);
- b=Math.sin(deg/180*Math.PI);
- c=-Math.sin(deg/180*Math.PI);
- d=Math.cos(deg/180*Math.PI);
弧度轉角度:deg*180/Math.PI
角度轉弧度:deg/180*Math.PI
三角函數:
- tan正切:直角三角形中,對邊與鄰邊的比值
- sin正弦:直角三角形中,對邊與斜邊的比值
- cos餘弦:直角三角形中,鄰邊與斜邊的比值
需求:每次點選時,讓box在現有基礎上,繼續旋轉15度。
是以一開始需要擷取到box的旋轉角度,但是transform是擷取不到的,隻能操作其上面的matrix矩陣。
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#box {
width: 100px;
height: 100px;
background: red;
margin: 100px auto;
font: 80px/100px "宋體";
text-align: center;
}
</style>
</head>
<body>
<div id="box">上</div>
<script>
(function(){
// matrix(1,0,0,1,0,0);
var a = 1;
var b = 0;
var c = 0;
var d = 1;
var e = 0;
var f = 0;
//matrix(a,b,c,d,e,f)
var box = document.querySelector("#box");
// 位移 x軸位移: e=e+x
function translateX(x){
e += x;
box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';//matrix(a,b,c,d,e,f)
}
// 位移 y軸位移: f=f+y
function translateY(y){
f += y;
box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
}
//縮放 x軸縮放 a=x*a c=x*c e=x*e;
function scaleX(x){
a=x*a;
c=x*c;
e=x*e;
box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
}
//縮放 y軸縮放 b=y*b d=y*d f=y*f;
function scaleY(y){
b=y*b;
d=y*d;
f=y*f;
box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
}
// 通過矩陣實作傾斜
// x軸傾斜 c=Math.tan(xDeg/180*Math.PI)
function skewX(xDeg){
c=Math.tan(xDeg/180*Math.PI);
box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
}
// y軸傾斜: b=Math.tan(yDeg/180*Math.PI)
function skewY(yDeg){
b=Math.tan(yDeg/180*Math.PI);
box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
}
//通過矩陣實作旋轉
function rotate(deg){
a=Math.cos(deg/180*Math.PI);
b=Math.sin(deg/180*Math.PI);
c=Math.sin(deg/180*Math.PI);
d=Math.cos(deg/180*Math.PI);
box.style.transform = 'matrix('+a+','+b+','+c+','+d+','+e+','+f+')';
}
box.onclick = function(){
//x軸位移
// translateX(10);
//y軸位移
// translateY(20);
//x軸縮放
// scaleX(.5);
//y軸縮放
// scaleY(.5);
//x軸傾斜
// skewX(40);
//y軸傾斜
// skewY(60);
rotate(60);
};
})();
</script>
</body>
</html>
4.transform 3D
4.1 transform 3D方法
- 3D旋轉:
- rotateX() 圍繞X軸旋轉(上下翻轉)
- rotateY() 圍繞Y軸旋轉(左右翻轉)
- rotateZ() 圍繞Z軸旋轉
- 3D位移:
- translateZ() Z軸位移,近大遠小。機關像素
- transform-style :3D空間。父級進行3D變換時,是否保留子元素的3D變換。預設值flat平面不保留子級3D變換;preserve-3d保留。
- perspective :景深,在3D變換中,模拟我們的視角,去看元素在Z軸的距離。一般在父級添加。
- perspective-origin:景深基點,在3D變換中,我們的視角點。一般在父級添加。
- backface-visibility: hidden;隐藏背面:加給 3d 每一個面 。背面:和父級角度相對面
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#wrap {
width: 600px;
height: 600px;
border: 1px solid black;
margin: 0 auto;
/*
景深:在3D變換中,模拟我們的視角去看元素與Z軸的距離
*/
perspective: 200px;
}
#box {
width: 200px;
height: 200px;
background: red;
margin: 200px auto;
font: 140px/200px "宋體";
text-align: center;
color: white;
transition: 3s;
/* 3D空間,父級元素變換時,是否保留子元素的3D變換 preserve-3d保留,flat不保留*/
transform-style: preserve-3d;
}
#wrap:hover span {
display: block;
width: 200px;
height: 200px;
background: yellow;
transform: rotateX(45deg);
}
#wrap:hover #box{
/* 3D變換,圍繞X軸旋轉 */
transform: rotateY(360deg);
/* 3D變換,圍繞Y軸旋轉 */
/* transform: rotateY(180deg); */
/* 3D變換,圍繞Y軸旋轉 */
/* transform: rotateZ(180deg); */
/* 3D變換,Z軸位移 */
/* transform: translateZ(60px); */
}
</style>
</head>
<body>
<div id="wrap">
<div id="box">
<span></span>
</div>
</div>
</body>
</html>
4.2 搭建立方體
思路:先寫好立方體的6個面,在旋轉每個面。
景深大小;各個面的絕對定位;各個面的旋轉基點transform-origin
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#wrap {
width: 600px;
height: 600px;
border: 1px solid black;
margin: 0 auto;
perspective: 1000px;
/* 景深基點 */
perspective-origin: center center;
}
#box {
width: 200px;
height: 200px;
position: relative;
transform-style: preserve-3d;
transition: 3s;
}
#wrap #box div{
width: 200px;
height: 200px;
font: 140px/200px "宋體";
text-align: center;
position: absolute;
opacity: .5;
}
#box div:nth-child(1) {
background: rgb(255, 0, 0);
top: 0;
left: 200px;
/* 隻圍繞底部,可隻寫bottom */
transform-origin: bottom;
transform: rotateX(90deg);
}
#box div:nth-child(2) {
background: rgb(200, 255, 0);
top: 200px;
left: 0;
transform-origin: right;
transform: rotateY(-90deg);
}
#box div:nth-child(3) {
background: rgb(0, 255, 115);
top: 200px;
left: 200px;
/* transform-origin: 200px bottom;
transform: rotateX(90deg); */
}
#box div:nth-child(4) {
background: rgb(0, 153, 255);
top: 200px;
left: 400px;
transform-origin: left;
transform: rotateY(90deg);
}
#box div:nth-child(5) {
background: rgb(132, 0, 255);
top: 400px;
left: 200px;
transform-origin: top;
transform: rotateX(-90deg);
}
#box div:nth-child(6) {
background: rgb(255, 0, 200);
top: 200px;
left: 200px;
/* 第6面是在Z軸方向 */
transform: translateZ(-200px) rotateY(180deg);
}
#wrap:hover #box{
transform-origin: 300px 300px;
transform: rotateY(180deg);
}
</style>
</head>
<body>
<div id="wrap">
<div id="box">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
</div>
</body>
</html>
5.requestAnimationFarme動畫幀
人眼每秒可識别24幀,超過24幀在人眼中,就會形成連續動畫的錯覺。是以使用JS制作動畫,不斷修改元素的值,就可以實作動畫效果。
能使用CSS實作的效果,盡量使用CSS實作,而不是使用JS實作。CSS本身性能會比JS好。另外,一般做動畫,能操作transform改變的,不要使用修改left,top等值實作,因為這些屬性在解析完成後,會導緻回流。
requestAnimationFarme動畫幀不是CSS中的動畫幀,而是JS中本身存在的,window下的方法。
requestAnimationFarme動畫幀與定時器相關差別:動畫流暢度和性能都比定時器好。使用定時器做動畫有可能丢幀(畫面忽然卡一下)。
- 計算機顯示器重新整理頻率一般是60Hz,相當于每秒重繪60次
- 螢幕每次渲染時就會調用目前次requestAnimationFarme(注意并不是重複調用),看目前次requestAnimationFarme有沒有執行新的東西
- 動畫幀采用的是系統時間間隔,它與計算機螢幕重繪頻率保持一緻(高性能,視覺佳)
- 定時器執行時間間隔(16.6666循環)不精确
- 相容性 IE9 以下不相容
- 與setTimeOut類似,隻會執行一次,如果希望執行動畫效果,連續執行,就需要使用遞歸進行重複調用
- 注意遞歸調用多次都需要存儲requestAnimationFrame動畫幀編号,便于取消requestAnimationFrame
- 開啟動畫幀:index requestAnimationFrame(fn):參數為函數(隻有一個參數),傳回值為動畫幀對應編号
- 關閉動畫幀:cancelAnimationFrame()
需求:使用JS實作跑停動畫
使用定時器實作:
使用間隔定時器,不斷改變div的transform的值
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#box {
width: 100px;
height: 100px;
background: red;
margin-bottom: 50px;
}
</style>
</head>
<body>
<div id="box"></div>
<button>跑</button>
<button>停</button>
<script>
var box = document.querySelector("#box");
var l = 0;
var btns = document.querySelectorAll("button");
var timer = null;
btns[0].onclick = function(){
clearInterval(timer);
timer = setInterval(function(){
l +=10;
box.style.transform = 'translateX('+ l +'px)';
},50);
};
btns[1].onclick = function(){
clearInterval(timer);
};
</script>
</body>
</html>
問題:發現使用定時器實作的動畫,并不流暢。
解決:使用requestAnimationFrame實作
注意遞歸調用多次都需要存儲requestAnimationFrame動畫幀編号,便于取消requestAnimationFrame
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#box {
width: 100px;
height: 100px;
background: red;
margin-bottom: 50px;
}
</style>
</head>
<body>
<div id="box"></div>
<button>跑</button>
<button>停</button>
<script>
var box = document.querySelector("#box");
var l = 0;
var btns = document.querySelectorAll("button");
var runner = 0;
btns[0].onclick = function(){
cancelAnimationFrame(runner);
runner = requestAnimationFrame(setTranslateX);
function setTranslateX(){
l +=1;
box.style.transform = 'translateX('+ l +'px)';
runner = requestAnimationFrame(setTranslateX);
}
};
btns[1].onclick = function(){
cancelAnimationFrame(runner);
};
</script>
</body>
</html>
6.Tween 動畫公式
- Tween 參數解析
- - t: current time(目前時間-目前運動次數),動畫執行到第幾次(動畫已經消耗的時間)
- - b: beginning value(動畫開始前的初始值)
- - c: change in value(變化量:動畫初始值和目标點之間的內插補點)
- - d: duration(持續時間-運動總次數:動畫執行總次數)
Tween動畫算法:
/*
Tween 動畫算法
*/
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;
},
easeOut: function(t, b, c, d){ //減速曲線
return -c *(t/=d)*(t-2) + b;
},
easeBoth: function(t, b, c, d){ //加速減速曲線
if ((t/=d/2) < 1) {
return c/2*t*t + b;
}
return -c/2 * ((--t)*(t-2) - 1) + b;
},
easeInStrong: function(t, b, c, d){ //加加速曲線
return c*(t/=d)*t*t*t + b;
},
easeOutStrong: function(t, b, c, d){ //減減速曲線
return -c * ((t=t/d-1)*t*t*t - 1) + b;
},
easeBothStrong: function(t, b, c, d){ //加加速減減速曲線
if ((t/=d/2) < 1) {
return c/2*t*t*t*t + b;
}
return -c/2 * ((t-=2)*t*t*t - 2) + b;
},
elasticIn: function(t, b, c, d, a, p){ //正弦衰減曲線(彈動漸入)
if (t === 0) {
return b;
}
if ( (t /= d) == 1 ) {
return b+c;
}
if (!p) {
p=d*0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p/4;
} else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
},
elasticOut: function(t, b, c, d, a, p){ //*正弦增強曲線(彈動漸出)
if (t === 0) {
return b;
}
if ( (t /= d) == 1 ) {
return b+c;
}
if (!p) {
p=d*0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p / 4;
} else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
},
elasticBoth: function(t, b, c, d, a, p){
if (t === 0) {
return b;
}
if ( (t /= d/2) == 2 ) {
return b+c;
}
if (!p) {
p = d*(0.3*1.5);
}
if ( !a || a < Math.abs(c) ) {
a = c;
var s = p/4;
}
else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
if (t < 1) {
return - 0.5*(a*Math.pow(2,10*(t-=1)) *
Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
}
return a*Math.pow(2,-10*(t-=1)) *
Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
},
backIn: function(t, b, c, d, s){ //回退加速(回退漸入)
if (typeof s == 'undefined') {
s = 1.70158;
}
return c*(t/=d)*t*((s+1)*t - s) + b;
},
backOut: function(t, b, c, d, s){
if (typeof s == 'undefined') {
s = 1.70158; //回縮的距離
}
return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
},
backBoth: function(t, b, c, d, s){
if (typeof s == 'undefined') {
s = 1.70158;
}
if ((t /= d/2 ) < 1) {
return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
}
return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
},
bounceIn: function(t, b, c, d){ //彈球減振(彈球漸出)
return c - Tween['bounceOut'](d-t, 0, c, d) + b;
},
bounceOut: function(t, b, c, d){//*
if ((t/=d) < (1/2.75)) {
return c*(7.5625*t*t) + b;
} else if (t < (2/2.75)) {
return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
} else if (t < (2.5/2.75)) {
return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
}
return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
},
bounceBoth: function(t, b, c, d){
if (t < d/2) {
return Tween['bounceIn'](t*2, 0, c, d) * 0.5 + b;
}
return Tween['bounceOut'](t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
}
};
Tween的使用:
(function(){
var box = document.querySelector("#box");
//easeOut: function(t, b, c, d) //減速曲線
var t = 0;//動畫執行到第幾次(動畫已經消耗的時間)
var b = 0;//動畫開始前的初始值
var c = 500;//動畫初始值和目标點的內插補點
var d = 10;//動畫執行總次數
var s = 100;//回退的距離
var btns = document.querySelectorAll("button");
btns[0].onclick = function(){
t++;
var val = Tween["easeOut"](t, b, c, d);
box.style.transform = 'translateX('+ val +'px)';
};
})();
動畫幀中使用Tween:
(function(){
var box = document.querySelector("#box");
//bounceIn: function(t, b, c, d) //彈球減振(彈球漸出)
var t = 0;//動畫執行到第幾次(動畫已經消耗的時間)
var b = 0;//動畫開始前的初始值(如初始寬度等)
var c = 500;//動畫初始值和目标點的內插補點(如希望動畫走600,初始值為100,則內插補點應設定為500)
var d = 20;//動畫執行總次數
var s = 100;//回退的距離
var btns = document.querySelectorAll("button");
var timer = 0;
btns[0].onclick = function(){
cancelAnimationFrame(timer);
timer = requestAnimationFrame(move);
function move(){
t++;
var val = Tween["bounceIn"](t, b, c, d);
box.style.transform = 'translateX('+ val +'px)';
console.log(t);
//判斷當執行次數到達設定的次數時,不再繼續執行
if(t<d){
timer = requestAnimationFrame(move);
}
}
};
btns[1].onclick = function(){
cancelAnimationFrame(timer);
};
})();
7.動畫架構mTween的使用
- css(el,attr[,value]) css 函數 設定或擷取樣式
- 注意: 非數值類樣式的處理
- 注意: transform 相關樣式的處理問題
- mTween(option) 動畫函數
- option:{
el: element要動畫的元素,
attr: {
要動畫的樣式: '目标值',
要動畫的樣式2: '目标值'
},
duration: nub||op, 動畫時間
- op: {
multiple: 根據距離計算動畫時間比例
max: 動畫最大時間
min: 動畫最小時間
}
fx:'動畫形式',
moveing: function(){}, 動畫執行中回調
cb:function(){} 動畫執行之後回調
}
- mTween.stop(el) 停止某個元素的動畫
css(el,attr[,value]) css 函數 設定或擷取樣式,兩個參數時是擷取,三個參數時是設定樣式。因為css方法主要是配合動畫使用的,是以機關進行了處理。
- - 注意: 非數值類樣式的處理:非數值類樣式隻能擷取,不能設定,更不能用于動畫;
- - 注意: transform 相關樣式的處理問題:transform 不能擷取計算後樣式,是以必須通過css()方法進行操作,且必須先設定(給定初始化值),再擷取即可
隻有以下樣式可以用于動畫:
"background"
"opacity"
"rotate",
"rotateX",
"rotateY",
"rotateZ",
"translateX",
"translateY",
"translateZ",
"scale",
"scaleX",
"scaleY",
"skewX",
"skewY"
"width",
"height",
"left",
"top",
"right",
"bottom",
"marginBottom",
"marginleft",
"marginRight",
"marginTop",
"paddingLeft",
"paddingRight",
"paddingTop",
"paddingBottom"
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#box {
position: absolute;
left: 0;
top: 100px;
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="box"></div>
<script src="mTween.js"></script>
<script>
(function(){
var box = document.querySelector("#box");
//擷取樣式
console.log(css(box,"width"));//100注意沒有機關,mTween架構已經對機關進行了處理
//設定樣式
css(box,"height",400);
//非數值類樣式隻能擷取,不能設定,但是顔色可以設定
css(box,"background","blue");
console.log(css(box,"background"));//rgb(0, 0, 255) none repeat scroll 0% 0% / auto padding-box border-box
css(box,"float","left");
console.log(css(box,"float"));//none
})();
</script>
</body>
</html>
transform 相關樣式的處理問題:
//transform不能擷取計算後樣式,是以所有操作必須通過css()方法進行。且需要先設定再擷取
console.log(css(box,"translateX"));//undefined
css(box,"translateX",20);
console.log(css(box,"translateX"));//20
mTween同時設定多個值:需要傳一個對象進去
//同時設定多個樣式,需要傳入一個對象
css(box,{
"width":200,
"height":200,
"background":"blue",
"translateX":200
});
動畫架構的使用:
設定屬性值:
mTween({
el:box,
attr:{
width:200,
height:200,
// translateX:20
rotate:360
});
設定動畫持續時間:
//動畫持續時間(機關秒),預設時間400毫秒
// duration:1000
//動畫持續時間第二種用法,比例設定:
duration:{
multiple: 1,//根據距離計算動畫時間比例:擷取到attr樣式中最大內插補點,計算時間,此處360,然後360*1 就為360毫秒
min: 200,//動畫最大時間:如果 multiple*最大內插補點的時間小于min,則使用min的時間,非min和max,則使用multiple*最大內插補點的時間
max: 1000//動畫最小時間:如果 multiple*最大內插補點的時間大于max,則使用max的時間,非min和max,則使用multiple*最大內插補點的時間
},
設定動畫執行樣式:
//動畫執行樣式(參照transition)
fx:"linear",
設定回調函數:動畫執行中和動畫執行結束 回調
//回調:動畫執行中和動畫執行結束
cb:function(){
console.log("動畫執行完成");
//控制動畫過程:想在動畫執行完成後,再執行其他的動畫,直接在cb函數值再進行調用
mTween({
el:box,
attr:{
translateX:40
}
});
},
//動畫執行過程中:計算機每秒執行60次,在duration給定時間内,會列印duration/60次。即一次列印用時1000/60 = 16.6666666次。總共有16.666666*3次約等于50次
moveing:function(){
console.log("動畫執行過程中");//列印66次
}
動畫執行過程中結束動畫:
//想在動畫執行過程中結束動畫,mTween.stop(動畫執行的元素)
mTween.stop(box);
完整示例:
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#box {
width: 100px;
height: 100px;
background: red;
margin-bottom: 50px;
}
</style>
</head>
<body>
<div id="box"></div>
<button>執行</button>
<button>停</button>
<script src="mTween.js"></script>
<script>
var box = document.querySelector("#box");
var btns = document.querySelectorAll("button");
btns[0].onclick = function(){
//如果要設定transform,一定要先通過css()方法進行設定
css(box,"translateX",0);
css(box,"rotate",0);
//動畫架構的使用
mTween({
el:box,
attr:{
width:200,
height:200,
// translateX:20
rotate:360
},
//動畫持續時間(機關秒),預設時間400毫秒
// duration:1000
//動畫持續時間第二種用法,比例設定:
duration:{
multiple: 1,//根據距離計算動畫時間比例:擷取到attr樣式中最大內插補點,計算時間,此處360,然後360*1 就為360毫秒
min: 200,//動畫最大時間:如果 multiple*最大內插補點的時間小于min,則使用min的時間,非min和max,則使用multiple*最大內插補點的時間
max: 1000//動畫最小時間:如果 multiple*最大內插補點的時間大于max,則使用max的時間,非min和max,則使用multiple*最大內插補點的時間
},
//動畫執行樣式(參照transition)
fx:"linear",
//回調:動畫執行中和動畫執行結束
cb:function(){
console.log("動畫執行完成");
//控制動畫過程:想在動畫執行完成後,再執行其他的動畫,直接在cb函數值再進行調用
mTween({
el:box,
attr:{
translateX:40
}
});
},
//動畫執行過程中:計算機每秒執行60次,在duration給定時間内,會列印duration/60次。即一次列印用時1000/60 = 16.6666666次。總共有16.666666*3次約等于50次
moveing:function(){
console.log("動畫執行過程中");//列印66次
}
});
btns[1].onclick = function(){
//想在動畫執行過程中結束動畫,mTween.stop(動畫執行的元素)
mTween.stop(box);
};
};
</script>
</body>
</html>