上篇文章分享了一款史上最沒用的中文版的CSS漸變色庫,今天再來分享一篇它的兄弟庫chinese-layout。
chinese-layout是一款利用CSS自定義屬性來制作的中文布局CSS庫,由于grid布局十分強大,強大到甚至只需要兩行CSS代碼就可以完成一個基本的布局。不過grid屬性較多較為復雜,并且不支持IE瀏覽器等特點導致了許多人并不很了解它。
不過近些年來隨著IE瀏覽器的逐步退出市場,兼容性已經不再是特別需要糾結的一件事情了:
可以看到各大瀏覽器的支持情況已經較為樂觀了,為了讓大家快速體驗grid布局的強大之處,chinese-layout就此誕生!
該庫的尺寸十分輕量級,只有不到1KB的大小(653字節),并且使用起來也是十分的方便。
假設現在有一個ul元素,我們想要它變為一個九宮格的布局,首先需要在ul元素上寫:
ul {
/* 這個是固定寫法,必須先指定display為grid */
display: grid;
/* grid屬性需要指定哪種布局 */
grid: var(--九宮格);
/* 加入一點間距,讓九個元素相互之間有一定的距離 */
gap: 10px;
}
然后在父元素里面添加九個元素:
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
這就完事啦:
當然這里其實是省略了一些父元素上的寬高以及子元素的顏色等細節。
這些細節就交給你們來決定,在此案例中chinese-layout只負責將父元素分割成九等分。
本文采用了chinese-gradient來作為背景色
要記得先引入這個庫才能夠去正常的使用。如果你的項目是一個工程化的項目,那么:
npm i chinese-layout
記得要在主文件中引入:
import 'chinese-layout'
同時也支持sass、less等,如:
import 'chinese-layout/chinese-layout.scss'
如果你只是想在<link>標簽里引入的話,那么:
<link rel="stylesheet" href="https://unpkg.zhimg.com/chinese-layout">
首先一定要記得聲明 display: grid;
因為chinese-layout底層依賴的就是grid布局。
grid: var(--居中)
DOM結構:
<parent>
<child/>
</parent>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
這種布局需要先在父元素上寫這么兩行代碼:
parent {
display: grid;
grid: var(--居中);
}
然后再在子元素上寫上:
child {
grid-area: 中;
}
但是看起來除了灰蒙蒙一片的背景好像啥也沒有是吧,那是因為我們沒給子元素加上寬高,而且子元素里也沒有任何的內容,導致子元素寬高為0不可見,那么現在我們來給子元素一個寬高再來看看:
child {
width: 20px;
height: 20px;
grid-area: 中;
}
子元素便會在父元素里水平垂直居中:
grid: var(--雙列)
DOM結構:
parent {
display: grid;
grid: var(--雙列);
}
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
來看看語法:
parent {
display: grid;
grid: var(--雙列);
}
可以看到現在兩列緊緊的貼合在一起了,不過有時候這兩列我們并不想它們緊貼在一起,這時我們可以使用 gap 屬性來控制列與列之間的間距:
parent {
display: grid;
grid: var(--雙列);
gap: 10px;
}
運行結果:
可以看到列與列直接距離變成我們設置的10px了,但 gap 屬性只會改變列與列之間的距離,并不會改變與父元素之間的距離,所以之前緊貼著父元素的現在還是緊貼著父元素,如果想與父元素有間距的話可以給父元素加padding:
雙列布局是不需要指定子元素的 grid-area 屬性的,不過你要是非要想指定一下的話也不是不可以:
child1 {
grid-area: 左;
}
child2 {
grid-area: 右;
}
運行結果:
(可以通過指定grid-area來顛倒DOM位置,沒事可以去試試)
grid: var(--三列)
咦?這不是雙列嗎?說好的三列呢?
其實是這樣,三列中的最中間一列被做成了自適應了,如果不給寬度并且也沒有任何帶寬度的子元素的話寬度就會為0,所以就看不到最中間那列啦!
那咱們給中間的DOM元素一個寬度吧:
<parent>
<child1/>
<child2/>
<child3/>
</parent>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
parent {
display: grid;
grid: var(--三列);
}
child2 {
width: 800px;
}
運行結果:
也可以不給寬度,直接用內容去撐開:
<parent>
<child1/>
<child2>child2</child2>
<child3/>
</parent>
運行結果:
也同樣可以用gap屬性來控制間距:
parent {
display: grid;
grid: var(--三列);
gap: 10px;
}
child2 {
width: 800px;
}
運行結果:
三列布局是不需要指定子元素的 grid-area 屬性的,不過你要是非要想指定一下的話也不是不可以:
child1 {
grid-area: 左;
}
child2 {
grid-area: 中;
}
child2 {
grid-area: 右;
}
運行結果:
(可以通過指定子元素的 grid-area 屬性來顛倒DOM位置,沒事可以去試試)
grid: var(--呂形)
可是這看起來也不像呂形啊,呂不是應該上面一個口下面一個口嗎?
其實還是那個原理:上面的盒子如果不給高度的話默認為0。
那咱們給個高度再看看:
<parent>
<child1/>
<child2/>
</parent>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
parent {
display: grid;
grid: var(--呂形);
}
child1 {
height: 100px;
}
child2 {
overflow-y: auto;
}
運行結果:
還可以通過 gap 屬性來控制間距:
parent {
display: grid;
grid: var(--呂形);
gap: 10px;
}
child1 {
height: 100px;
}
運行結果:
也可以通過指定子元素的 grid-area 屬性來顛倒DOM位置:
parent {
display: grid;
grid: var(--呂形);
gap: 10px;
}
child1 {
grid-area: 下;
overflow-y: auto;
}
child2 {
height: 100px;
grid-area: 上;
}
運行結果:
grid: var(--上下欄)
看過前面幾種布局的朋友應該猜到了,是因為上盒子和下盒子沒給高度導致現在只能看見中間那欄,咱們給個高度再來看看:
<parent>
<child1/>
<child2/>
<child3/>
</parent>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
parent {
display: grid;
grid: var(--上下欄);
}
child1 {
height: 80px;
}
child2 {
overflow-y: auto;
}
child3 {
height: 100px;
}
運行結果:
還可以通過 gap 屬性來控制間距:
parent {
display: grid;
grid: var(--上下欄);
gap: 10px;
}
child1 {
height: 80px;
}
child2 {
overflow-y: auto;
}
child3 {
height: 100px;
}
運行結果:
也可以通過指定子元素的 grid-area 屬性來顛倒DOM位置:
parent {
display: grid;
grid: var(--上下欄);
gap: 10px;
}
child1 {
grid-area: 中;
overflow-y: auto;
}
child2 {
height: 80px;
grid-area: 上;
}
child3 {
height: 100px;
grid-area: 下;
}
運行結果:
grid: var(--四宮格)
DOM結構:
<parent>
<child1/>
<child2/>
<child3/>
<child4/>
<parent/>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
parent {
display: grid;
grid: var(--四宮格);
}
如果不想各個宮格緊貼在一起,可以用 gap 屬性來控制間距:
parent {
display: grid;
grid: var(--四宮格);
gap: 10px;
}
運行結果:
gap 屬性是控制行和列之間間距的,但如果你想要行間距和列間距不一樣的話,就要用到下面兩個屬性了:
也可以通過 grid-area 屬性來重新分配DOM元素的位置:
child1 { grid-area: 左上; }
child2 { grid-area: 右上; }
child3 { grid-area: 左下; }
child4 { grid-area: 右下; }
運行結果:
grid: var(--六宮格)
DOM結構:
<parent>
<child1/>
<child2/>
<child3/>
<child4/>
<child5/>
<child6/>
<parent/>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
parent {
display: grid;
grid: var(--六宮格);
}
如果不想各個宮格緊貼在一起,可以用 gap 屬性來控制間距:
parent {
display: grid;
grid: var(--六宮格);
gap: 10px;
}
運行結果:
gap 屬性是控制行和列之間間距的,但如果你想要行間距和列間距不一樣的話,就要用到下面兩個屬性了:
也可以通過 grid-area 屬性來重新分配DOM元素的位置:
child1 { grid-area: 左上; }
child2 { grid-area: 右上; }
child3 { grid-area: 左下; }
child4 { grid-area: 右下; }
運行結果:
grid: var(--九宮格)
DOM結構:
<parent>
<child1/>
<child2/>
<child3/>
<child4/>
<child5/>
<child6/>
<child7/>
<child8/>
<child9/>
<parent/>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
parent {
display: grid;
grid: var(--九宮格);
}
如果不想各個宮格緊貼在一起,可以用 gap 屬性來控制間距:
parent {
display: grid;
grid: var(--九宮格);
gap: 10px;
}
運行結果:
gap 屬性是控制行和列之間間距的,但如果你想要行間距和列間距不一樣的話,就要用到下面兩個屬性了:
也可以通過 grid-area 屬性來重新分配DOM元素的位置:
child1 { grid-area: 左上; }
child2 { grid-area: 中上; }
child3 { grid-area: 右上; }
child4 { grid-area: 左中; }
child5 { grid-area: 中中; }
child6 { grid-area: 右中; }
child7 { grid-area: 左下; }
child8 { grid-area: 中下; }
child9 { grid-area: 右下; }
運行結果:
grid: var(--鋪滿)
看起來貌似啥也沒有,那是因為顧名思義,鋪滿就是子元素和父元素的大小一樣大嘛,來看看DOM結構:
<parent>
<child/>
</parent>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
parent {
display: grid;
gird: var(--鋪滿);
}
grid: var(--圣杯)
DOM結構:
<parent>
<child1/>
<child2/>
<child3/>
<child4/>
<child5/>
</parent>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
圣杯布局的子元素必須指定位置:
parent {
display: grid;
grid: var(--圣杯);
}
child1 { grid-area: 上; }
child2 { grid-area: 左; }
child3 { grid-area: 中; }
child4 { grid-area: 右; }
child5 { grid-area: 下; }
但是看起來并沒有看到圣杯布局的影子,灰蒙蒙的一片,還是那個原因,把上下左右的寬高控制權都留給用戶,如果子元素里沒有任何內容并且沒有指定寬高的話就不會顯示在屏幕上,我們來給個合適的寬高再看看:
parent {
display: grid;
grid: var(--圣杯);
}
child1 {
height: 80px;
grid-area: 上;
}
child2 {
width: 100px;
grid-area: 左;
}
child3 { grid-area: 中; }
child4 {
width: 100px;
grid-area: 右;
}
child5 {
height: 80px;
grid-area: 下;
}
運行結果:
再給個間距看看效果:
parent {
display: grid;
grid: var(--圣杯);
gap: 10px;
}
運行結果:
不給寬高只靠子元素的內容撐起來也可以,而且可以缺少某一個DOM元素,比如我們不想要"右"了:
<parent>
<child1/>
<child2/>
<child3/>
<child4/>
</parent>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
parent {
display: grid;
grid: var(--圣杯);
gap: 10px;
}
child1 {
height: 80px;
grid-area: 上;
}
child2 {
width: 100px;
grid-area: 左;
}
child3 { grid-area: 中; }
child4 {
height: 80px;
grid-area: 下;
}
運行結果:
雖然看起來"中"的右側受 gap 屬性的影響導致有一定的間距,但我們可以不加 gap,靠 margin 來控制間距:
parent > child {
margin: 10px;
}
運行結果:
即使不給"中"設置寬高,"中"也會根據父元素的寬高來自動調整自己的寬高大小。
也可以靠 row-gap 和 column-gap 屬性來單獨控制橫、縱間距:
grid: var(--雙飛翼)
DOM結構:
<parent>
<child1/>
<child2/>
<child3/>
<child4/>
<child5/>
</parent>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
雙飛翼布局的子元素必須指定位置:
parent {
display: grid;
grid: var(--雙飛翼);
}
child1 { grid-area: 上; }
child2 { grid-area: 左; }
child3 { grid-area: 中; }
child4 { grid-area: 右; }
child5 { grid-area: 下; }
但是看起來并沒有看到雙飛翼布局的影子,灰蒙蒙的一片,還是那個原因,把上下左右的寬高控制權都留給用戶,如果子元素里沒有任何內容并且沒有指定寬高的話就不會顯示在屏幕上,我們來給個合適的寬高再看看:
parent {
display: grid;
grid: var(--雙飛翼);
}
child1 {
height: 80px;
grid-area: 上;
}
child2 {
width: 100px;
grid-area: 左;
}
child3 { grid-area: 中; }
child4 {
width: 100px;
grid-area: 右;
}
child5 {
height: 80px;
grid-area: 下;
}
運行結果:
再給個間距看看效果:
parent {
display: grid;
grid: var(--雙飛翼);
gap: 10px;
}
運行結果:
不給寬高只靠子元素的內容撐起來也可以,而且可以缺少某一個DOM元素,比如我們不想要"右"了:
<parent>
<child1/>
<child2/>
<child3/>
<child4/>
</parent>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
parent {
display: grid;
grid: var(--雙飛翼);
gap: 10px;
}
child1 {
height: 80px;
grid-area: 上;
}
child2 {
width: 100px;
grid-area: 左;
}
child3 { grid-area: 中; }
child4 {
height: 80px;
grid-area: 下;
}
運行結果:
雖然看起來"中"的右側受 gap 屬性的影響導致有一定的間距,但我們可以不加 gap ,靠 margin 來控制間距:
parent > child {
margin: 10px;
}
運行結果:
即使不給"中"設置寬高,"中"也會根據父元素的寬高來自動調整自己的寬高大小。
也可以靠 row-gap 和 column-gap 屬性來單獨控制橫、縱間距:
grid: var(--響應式)
響應式布局會根據父元素的大小以及子元素的數量來自行決定如何排版
DOM結構:
<parent>
<child1/>
<child2/>
......
<child-N/>
</parent>
DOM結構只是示意,真實布局時要把parent和child換成你想要的元素,如:<ul> <li></li> </ul>
parent {
display: grid;
grid: var(--響應式);
}
不過每列的最小寬度默認是100px,如果想改變這一大小的話需要在 :root 選擇器上定義一個 --寬 變量,比如想要寬變成30px:
:root {
--寬: 30px;
}
如果每個子元素之間的距離太近了的話別忘記用 gap 屬性來控制間距哦:
parent {
display: grid;
grid: var(--響應式);
gap: 10px;
}
整體來說這款插件還是不錯的,使用簡單方便,中文命名雖然符合中國人的習慣,但命名太多比較依賴文檔。
還在為布局頭疼的朋友可以快速入手哦!
擊右上方紅色按鈕關注“web秀”,讓你真正秀起來
以前說頁面是動態,基本都是說數據是從數據庫查詢的,不是寫死在html代碼里面的。現在的說頁面動態,一般會問:你是說數據,還是效果動態?
CSS3 Grid布局實現Loading動畫效果
好的前端動畫效果,能給用戶帶來非常舒適的體驗效果,更甚者,有用戶覺的你這個動畫效果非常nice,反復操作,就為看你這個動畫。停留時間,預覽量上了,帶來的收益也不是一丁點吧。
當然也不用為了動畫,而額外的來制作動畫效果。比如一個彈框,可以直接漸變出現的,你還加了飛了一圈出現,那就是不必要的動畫了。
所以恰大好處的動畫效果,能帶來非常不錯的效果。
下面我們來學習如果只做一些簡單的動畫效果:
CSS3 Grid布局實現Loading動畫效果
CSS3 Grid布局實現Loading動畫效果
上圖的動畫,就是一個簡單的loading加載效果,而且是一個3x3的九宮格。是因為旋轉才變成一個菱形的樣子。我們先來畫出3x3的九宮格:
html
<div class="loading"> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> </div>
這里用9個span來做每個格子元素。
css
body { margin: 0; height: 100vh; /*=100%*/ display: flex; /*flex布局*/ align-items: center; /*flex布局:垂直居中*/ justify-content: center; /*flex布局:水平居中*/ background-color: black; } .loading { width: 10em; height: 10em; display: grid; /*grid布局*/ grid-template-columns: repeat(3, 1fr); grid-gap: 0.5em; /*grid 每個item之間的間距*/ } /** * --name 是css中定義變量的方式 * 可以直接用 var(--name) 使用 */ .loading span { background-color: var(--color); /*背景顏色*/ } .loading span:nth-child(2n+2) { /*n=0: 2*/ /*n=1: 4*/ /*n=2: 6*/ /*n=3: 8*/ /*n=4: 10(不存在)*/ --color: #f13f84; } .loading span:nth-child(4n+3) { /*n=0: 3*/ /*n=1: 7*/ /*n=2: 11(不存在)*/ --color: #46b0ff; } .loading span:nth-child(4n+1) { /*n=0: 1*/ /*n=1: 5*/ /*n=2: 9*/ /*n=3: 13(不存在)*/ --color: #44bb44; }
CSS3 Grid布局實現Loading動畫效果
grid-template-columns: 該屬性是基于 網格列. 的維度,去定義網格線的名稱和網格軌道的尺寸大小。
repeat: 表示網格軌道的重復部分,以一種更簡潔的方式去表示大量而且重復列的表達式。
有了九宮格布局后,我們直接旋轉這個loading元素,制作動畫。
.loading { ... transform: rotate(45deg); /*旋轉45°*/ } .loading span { background-color: var(--color); /** * 動畫名字是blinking * 動畫整個時間是2s * 每個元素的執行延時時間 var(--delay) * 動畫的速度曲線 由慢到快 ease-in-out * 永久執行 infinite */ animation: blinking 2s var(--delay) ease-in-out infinite; animation-fill-mode: backwards; } /** * 每個元素執行動畫延時時間變量 */ .loading span:nth-child(7) { --delay: 0s; } .loading span:nth-child(4n+4) { --delay: 0.2s; } .loading span:nth-child(4n+1) { --delay: 0.4s; } .loading span:nth-child(4n+2) { --delay: 0.6s; } .loading span:nth-child(3) { --delay: 0.8s; } /** * 動畫效果 */ @keyframes blinking { 0%, 20% { transform: rotate(0deg) scale(0); } 40%, 80% { /* * 旋轉一圈rotate(1turn)[轉、圈(Turns)。一個圓共1圈] * 縮放 scale 如果大于1就代表放大;如果小于1就代表縮小 */ transform: rotate(1turn) scale(1); } 100% { transform: rotate(2turn) scale(0); } }
animation語法
animation: name duration timing-function delay iteration-count direction;
1、animation-name 規定需要綁定到選擇器的 keyframe 名稱。
2、animation-duration 規定完成動畫所花費的時間,以秒或毫秒計。
3、animation-timing-function 規定動畫的速度曲線。
4、animation-delay 規定在動畫開始之前的延遲。
5、animation-iteration-count 規定動畫應該播放的次數。
6、animation-direction 規定是否應該輪流反向播放動畫。
CSS3 Grid布局實現Loading動畫效果
動畫的速度曲線
1、linear 規定以相同速度開始至結束的過渡效果(等于 cubic-bezier(0,0,1,1))。(勻速)
2、ease 規定慢速開始,然后變快,然后慢速結束的過渡效果(cubic-bezier(0.25,0.1,0.25,1))(相對于勻速,中間快,兩頭慢)。
3、ease-in 規定以慢速開始的過渡效果(等于 cubic-bezier(0.42,0,1,1))(相對于勻速,開始的時候慢,之后快)。
4、ease-out 規定以慢速結束的過渡效果(等于 cubic-bezier(0,0,0.58,1))(相對于勻速,開始時快,結束時候間慢,)。
5、ease-in-out 規定以慢速開始和結束的過渡效果(等于 cubic-bezier(0.42,0,0.58,1))(相對于勻速,(開始和結束都慢)兩頭慢)。
6、cubic-bezier(n,n,n,n) 在 cubic-bezier 函數中定義自己的值。可能的值是 0 至 1 之間的數值。
CSS3 Grid布局實現Loading動畫效果
CSS3動畫基礎知識可以看看 《如何快速上手基礎的CSS3動畫》 這篇文章,里面用更小的示例,講述了CSS3動畫的每個屬性。CSS3動畫,無外乎就是animation、transform、transition等屬性的使用,記住他們每個的作用特效就可以了。
喜歡小編或者覺得小編文章對你有幫助的,可以點擊一波關注哦!
我們就來學點有意思的,用幾十行代碼來實現一個高性能的抽獎小游戲.也基于此,來鞏固我們的javascript基礎,以及前端一些基本算法的應用.
由于目前已有很多方案可以實現九宮格抽獎動畫,比如使用動態active實現邊框動畫,用隨機算法和定時器設置在何處停止等等. 為了進一步提高性能,本文介紹的方法,將使用坐標法,將操作dom的成本降低,完全由js實現滑塊的路徑的計算,滑塊元素采用絕對定位,讓其脫離文檔流,避免其他元素的重繪等等,最后點擊按鈕我們會使用防抖函數來避免頻繁執行函數,造成不必要的性能損失.
為了讓大家更加熟悉dom結構,這里我就不用js動態生成了.如下html結構:
<div class="wrap">
<div class="title">圣誕抽抽樂</div>
<div class="box">
<div class="item">我愛你</div>
<div class="item">你愛我</div>
<div class="item">我不愛你</div>
<div class="item">你愛我</div>
<div class="item start">開始</div>
<div class="item">你愛我</div>
<div class="item">再見</div>
<div class="item">謝謝惠顧</div>
<div class="item">你愛我</div>
<div class="spin"></div>
</div>
</div>
復制代碼
九宮格布局我們使用flex來實現,核心代碼如下:
.box {
display: flex;
flex-wrap: wrap;
width: 300px;
height: 300px;
position: relative;
.item {
box-sizing: border-box;
width: 100px;
}
// 滑塊
.spin {
box-sizing: border-box;
position: absolute;
left: 0;
top: 0;
display: inline-block;
width: 100px;
height: 100px;
background-color: rgba(0,0,0,.2);
}
}
復制代碼
由上可知容器box采用flex布局,要想讓flex子元素換行,我們這里要設置flex-wrap: wrap;此時九宮格布局就實現了. 滑塊采用絕對定位,至于具體如何去沿著環形軌道運動,請繼續看下文介紹.
由上圖我們可以知道,一個九宮格的4條邊,可以用以上8個坐標收尾連接起來,那么我們可以基于這個規律.來生成環形坐標集合.代碼如下:
/**
* 生成n維環形坐標
* @param {number} n 維度
* @param {number} cell 單位坐標長度
*/
function generateCirclePath(n, cell) {
let arr = []
for(let i=0; i< n; i++) {
arr.push([i*cell, 0])
}
for(let i=0; i< n-1; i++) {
arr.push([(n-1)*cell, (i+1)*cell])
}
for(let i=0; i< n-1; i++) {
arr.push([(n-i-2)*cell, (n-1)*cell])
}
for(let i=0; i< n-2; i++) {
arr.push([0, (n-i-2)*cell])
}
return arr
}
復制代碼
如果是單位坐標,那么cell為1,cell設計的目的就位為了和現實的元素相結合,我們可以手動設置單元格的寬度來實現不同大小的n維環形坐標集.
由抽獎動畫分析可知,我們滑塊運動的軌跡,其實就是環形坐標集合,所以我們只要讓滑塊的頂點(默認左上角)沿著環形坐標集合一步步變化就好了.
function run(el, path, n = 1, i = 0, len = path.length) {
setTimeout(() => {
if(n > 0) {
if(len <= i) {
i = n === 1 ? len : 0
n--
}
el.css('transform', `translate(${path[i][0]}px, ${path[i][1]}px)`)
run(el, path, n, ++i, len)
}
}, 300)
}
復制代碼
這樣就能實現我們的滑塊按照九宮格邊框運動的動畫了,當然以上函數只是基本的動畫, 還沒有實現在隨機位置停止, 以及滑塊的加速度運動,這塊需要一定的技巧和js基礎知識比如閉包.
加速度運動其實很簡單,比如每轉過一圈將setTimeout的延遲時間改變即可.代碼如下:
function run(el, path, n = 1, speed = 60, i = 0, len = path.length) {
setTimeout(() => {
if(n > 0) {
if(len <= i) {
i = n === 1 ? len : 0
n--
speed += (300 - speed) / n
}
el.css('transform', `translate(${path[i][0]}px, ${path[i][1]}px)`)
run(el, path, n, speed, ++i, len)
}
}, speed)
}
復制代碼
隨機停止這塊主要是用了Math.random這個API, 我們在最后一圈的時候, 根據隨機返回的數值來決定何時停止,這里我們在函數內部實現隨機數值,完整代碼如下:
/**
* 環形隨機軌道運動函數
* @param {element} el 運動的dom元素
* @param {array} path 運動的環形坐標集合
* @param {number} speed 運動的初始速度
* @param {number} i 運動的初始位置
* @param {number} len 路徑的長度
* @param {number} random 中獎坐標
*/
function run(el, path, n = 1, speed = 60, i = 0, len = path.length, random = Math.floor(Math.random() * len)) {
setTimeout(() => {
if(n > 0) {
// 如果n為1,則設置中獎數值
if(n === 1) {
len = random
}
if(len <= i) {
i = n === 1 ? len : 0
n--
speed += (300 - speed) / n
}
el.css('transform', `translate(${path[i][0]}px, ${path[i][1]}px)`)
run(el, path, n, speed, ++i, len, random)
}
}, speed)
}
復制代碼
防抖函數實現:
// 防抖函數,避免頻繁點擊執行多次函數
function debounce(fn, interval = 300) {
let timeout = null
return function () {
clearTimeout(timeout)
timeout = setTimeout(() => {
fn.apply(this, arguments)
}, interval)
}
}
復制代碼
那么我們點擊時,代碼應該長這樣:
// 點擊開始按鈕,開始抽獎
$('.start').on('click',debounce(() => { run($('.spin'), generateCirclePath(3, 100), 3) }))
復制代碼
在文章發布之后,有熱心的小伙伴們提出了幾個建議,綜合如下:
綜合以上問題,我在之前基礎上做了進一步擴展,來解決以上提到的問題.
/**
* 環形隨機軌道運動函數
* @param {element} el 運動的dom元素
* @param {array} path 運動的環形坐標集合
* @param {func} cb 動畫結束時回調
* @param {number} speed 運動的初始速度
* @param {number} i 運動的初始位置
* @param {number} len 路徑的長度
* @param {number} random 中獎坐標
*/
function run(el, path, n = 1, cb, speed = 60, i = 0, len = path.length, random = Math.floor(Math.random() * len)) {
setTimeout(() => {
if(n > 0) {
// 如果n為1,則設置中獎數值
if(n === 1) {
len = random
}
if(len <= i) {
i = n === 1 ? len : 0
n--
speed += (300 - speed) / n
}
el.css('transform', `translate(${path[i][0]}px, ${path[i][1]}px)`)
run(el, path, n, cb, speed, ++i, len, random)
}else {
cb && cb()
}
}, speed)
}
復制代碼
// 1. 點擊開始按鈕,開始抽獎
$('.start').on('click',debounce(() => {
// 點擊開始后禁用點擊
$('.start').css('pointer-events', 'none')
run($('.spin'), generateCirclePath(3, 100), 3, () => {
// 動畫結束后開啟按鈕點擊
$('.start').css('pointer-events', 'auto')
alert('抽獎結束')
})
}))
復制代碼
謝謝各位認真的建議,繼續優化吧.
該實現方式的好處是支持n維環形坐標的抽獎,基于坐標法的應用還有很多,尤其是游戲和圖形領域,在實現過程中一定要考慮性能和可擴展性,這樣我們就可以在不同場景使用同一套方法論,豈不樂哉?本文完整源碼我會放在github上,歡迎交流學習~
github地址:https://github.com/MrXujiang?tab=repositories
歡迎在公眾號《趣談前端》加入我們一起學習討論,共同探索前端的邊界。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。