五十音小游戲中的前端知識(shí)小結(jié)
背景
在日語(yǔ)學(xué)習(xí)初期階段,我發(fā)現(xiàn)日語(yǔ)五十音的記憶并不是很容易的,片假名的記憶尤其令人費(fèi)神。這時(shí)我想如果有一個(gè)應(yīng)用可以充分利用碎片時(shí)間,在午休或地鐵上隨時(shí)可以練習(xí)五十音該多好。于是搜索 App Store
,確實(shí)有很多五十音學(xué)習(xí)的小軟件,但是商店的軟件不是含有內(nèi)購(gòu)、夾帶廣告、就是動(dòng)輒 40M
以上,沒(méi)找到一個(gè)自己滿意的應(yīng)用。于是打算自己寫一個(gè),主要介紹自己在開發(fā)設(shè)計(jì)該應(yīng)用過(guò)程中的一些收獲。
實(shí)現(xiàn)
在線體驗(yàn)地址 https://dragonir.github.io/kanaApp/
實(shí)現(xiàn)效果如下,該應(yīng)用主要分為三個(gè)頁(yè)面:
- 首頁(yè):包括菜單選項(xiàng)(平假名練習(xí)、片假名練習(xí)、混合練習(xí))、深色模式切換按鈕。
- 答題頁(yè):包括剩余機(jī)會(huì)和分?jǐn)?shù)顯示區(qū)、中間出題區(qū)、底部答題按鈕。
- 結(jié)果頁(yè):結(jié)果分?jǐn)?shù)顯示和返回首頁(yè)按鈕。
答題邏輯規(guī)則是從給出的 4
個(gè)答案按鈕中選出題目展示區(qū)的那個(gè)單詞對(duì)應(yīng)正確的那個(gè)選項(xiàng),應(yīng)用根據(jù)點(diǎn)擊給出錯(cuò)對(duì)反饋并進(jìn)行記分,錯(cuò)誤 10
次后游戲結(jié)束,加載結(jié)果頁(yè)。游戲邏輯實(shí)現(xiàn)不是本文的主要內(nèi)容,因此后面不再贅述。本文后續(xù)主要內(nèi)容是此次小游戲開發(fā)流程涉及到的前端知識(shí)的介紹。
深色模式 ⚪⚫
隨著 Windows 10
、 MacOs
、 Android
等系統(tǒng)陸續(xù)推出深色模式,瀏覽器也開始支持檢測(cè)系統(tǒng)主題色配置,越來(lái)越多的網(wǎng)頁(yè)應(yīng)用都配置了深色模式切換功能。為了優(yōu)化 50音小游戲
的視覺體驗(yàn),我也配置了深色樣式,實(shí)現(xiàn)效果如下:
CSS
媒體查詢判斷深色模式
prefers-color-scheme
媒體特性用于檢測(cè)用戶是否有將系統(tǒng)的主題色設(shè)置為亮色或者暗色。使用語(yǔ)法如下所示:
@media (prefers-color-scheme: value) {}
其中 value
有以下 3
種值,其中:
light
:表示用戶系統(tǒng)支持深色模式,并且已設(shè)置為淺色主題(默認(rèn)值)。dark
:表示用戶系統(tǒng)支持深色模式,并且已設(shè)置為深色主題。no-preference
:表示用戶系統(tǒng)不支持深色模式或無(wú)法得知是否設(shè)置為深色模式(已廢棄)。
若結(jié)果為 no-preference
,無(wú)法通過(guò)此媒體特性獲知宿主系統(tǒng)是否支持設(shè)置主題色,或者用戶是否主動(dòng)將其設(shè)置為無(wú)偏好。出于隱私保護(hù)等方面的考慮,用戶或用戶代理也可能在一些情況下在瀏覽器內(nèi)部將其設(shè)置為 no-preference
。
下面例子中,當(dāng)系統(tǒng)主題色為深色時(shí) .demo
元素的背景色為 #FFFFFF
;當(dāng)系統(tǒng)主題色為淺色時(shí),.demo
元素的背景色為 #000000
。
@media (prefers-color-scheme: dark) { .demo { background: #FFFFFF; } } @media (prefers-color-scheme: light) { .demo { background: #000000; } }
JavaScript
判斷深色模式
window.matchMedia()
方法返回一個(gè)新的 MediaQueryList
對(duì)象,表示指定的媒體查詢 (en-US)字符串
解析后的結(jié)果。返回的 MediaQueryList
可被用于判定 Document
是否匹配媒體查詢,或者監(jiān)控一個(gè) document
來(lái)判定它匹配了或者停止匹配了此媒體查詢。其中 MediaQueryList
對(duì)象具有屬性 matches
和 media
,方法 addListener
和 removeListener
。
使用 matchMedia
作為判斷媒介,也可以識(shí)別系統(tǒng)是否支持主題色:
if (window.matchMedia('(prefers-color-scheme)').media === 'not all') { // 瀏覽器不支持主題色設(shè)置 } if (window.matchMedia('(prefers-color-scheme: dark)').matches){ // 深色模式 } else { // 淺色模式 }
另外還可以動(dòng)態(tài)監(jiān)聽系統(tǒng)深色模式的狀態(tài),根據(jù)系統(tǒng)深色模式的切換做出實(shí)時(shí)響應(yīng):
window.matchMedia('(prefers-color-scheme: dark)').addListener(e => { if (e.matches) { // 開啟深色模式 } else { // 關(guān)閉深色模式 } });
或者單獨(dú)檢測(cè)深色或淺色模式:
const listeners = { dark: (mediaQueryList) => { if (mediaQueryList.matches) { // 開啟深色模式 } }, light: (mediaQueryList) => { if (mediaQueryList.matches) { // 開啟淺色模式 } } }; window.matchMedia('(prefers-color-scheme: dark)').addListener(listeners.dark); window.matchMedia('(prefers-color-scheme: light)').addListener(listeners.light);
在50音小游戲中,就是使用 JavaScript
檢測(cè)系統(tǒng)是否開啟深色模式,動(dòng)態(tài)添加 css
類名來(lái)自動(dòng)加載深色模式,同時(shí)也提供深淺色切換按鈕,可以手動(dòng)切換主題。
HTML
元素中判斷深色模式
頁(yè)面使用圖片元素時(shí),可以直接在 HTML
中判斷系統(tǒng)是否開啟深色模式。如:
<picture> <source srcset="dark.jpg" media="(prefers-color-scheme: dark)"> <img src="light.jpg"> </picture>
picture
元素允許我們?cè)诓煌脑O(shè)備上顯示不同的圖片,一般用于響應(yīng)式。HTML5
引入了 <picture>
元素,該元素可以讓圖片資源的調(diào)整更加靈活。<picture>
元素零或多個(gè) <source>
元素和一個(gè) <img>
元素,每個(gè) <source>
元素匹配不同的設(shè)備并引用不同的圖像源,如果沒(méi)有匹配的,就選擇 <img>
元素的 src
屬性中的 url
。
注意: <img>
元素是放在最后一個(gè) <picture>
元素之后,如果瀏覽器不支持該屬性則顯示 <img>
元素的的圖片。
離線緩存
為了能夠像原生應(yīng)用一樣可以在桌面生成快捷方式快速訪問(wèn),隨時(shí)隨地離線使用,50音小游戲
使用了離線緩存技術(shù),它是一個(gè) PWA應(yīng)用
。下面內(nèi)容是 PWA離線應(yīng)用
實(shí)現(xiàn)技術(shù)的簡(jiǎn)要描述。
PWA (progressing web app)
,漸進(jìn)式網(wǎng)頁(yè)應(yīng)用程序,是 下一代WEB應(yīng)用模型
。一個(gè) PWA
應(yīng)用首先是一個(gè)網(wǎng)頁(yè), 并借助于 App Manifest
和 Service Worker
來(lái)實(shí)現(xiàn)安裝和離線等功能。
特點(diǎn):
- 漸進(jìn)式:適用于選用任何瀏覽器的所有用戶,因?yàn)樗且詽u進(jìn)式增強(qiáng)作為核心宗旨來(lái)開發(fā)的。
- 自適應(yīng):適合任何機(jī)型:桌面設(shè)備、移動(dòng)設(shè)備、平板電腦或任何未來(lái)設(shè)備。
- 連接無(wú)關(guān)性:能夠借助于服務(wù)工作線程在離線或低質(zhì)量網(wǎng)絡(luò)狀況下工作。
- 離線推送:使用推送消息通知,能夠讓我們的應(yīng)用像
Native App
一樣,提升用戶體驗(yàn)。及時(shí)更新:在服務(wù)工作線程更新進(jìn)程的作用下時(shí)刻保持最新狀態(tài)。 - 安全性:通過(guò)
HTTPS
提供,以防止窺探和確保內(nèi)容不被篡改。
配置頁(yè)面參數(shù)
在項(xiàng)目根目錄添加文件 manifest.webmanifest
或 manifest.json
文件,并在文件內(nèi)寫入如下配置信息,本例中 50音小游戲
的頁(yè)面參數(shù)信息配置如下:
// manifest.webmainifest { "name": "かなゲーム", "short_name": "かなゲーム", "start_url": "index.html", "display": "standalone", "background_color": "#fff", "description": "かなゲーム", "icons": [ { "src": "assets/images/icon-64x64.jpg", "sizes": "64x64", "type": "image/jpg" }, { "src": "assets/images/icon-256x256.jpg", "sizes": "256x256", "type": "image/jpg" } ] }
參數(shù)說(shuō)明:
name
:Web App
的名稱,也是保存到桌面上時(shí)應(yīng)用圖標(biāo)的名稱。short_name
:name
過(guò)長(zhǎng)時(shí),將會(huì)使用short_name
代替name
顯示,是Web App
的簡(jiǎn)稱。start_url
:指定了用戶打開該Web App
時(shí)加載URL
。URL
會(huì)相對(duì)于manifest
文件所在路徑。display
:指定了應(yīng)用的顯示模式,它有四個(gè)值可以選擇:
fullscreen
:全屏顯示,會(huì)盡可能將所有的顯示區(qū)域都占滿。
standalone
:瀏覽器相關(guān) UI
(如導(dǎo)航欄、工具欄等)將被隱藏,看起來(lái)更像一個(gè) Native App
。
minimal-ui
:顯示形式與 standalone
類似,瀏覽器相關(guān) UI
會(huì)最小化為一個(gè)按鈕,不同瀏覽器在實(shí)現(xiàn)上略有不同。browser
:一般來(lái)說(shuō),會(huì)和正常使用瀏覽器打開樣式一致。
需要說(shuō)明的是,當(dāng)一些系統(tǒng)的瀏覽器不支持 fullscreen
時(shí)將會(huì)顯示成 standalone
效果,當(dāng)不支持 standalone
時(shí),將會(huì)顯示成 minimal-ui
的效果,以此類推。
description
:應(yīng)用描述。
icons
:指定了應(yīng)用的桌面圖標(biāo)和啟動(dòng)頁(yè)圖像,用數(shù)組表示:
- sizes:圖標(biāo)大小。通過(guò)指定大小,系統(tǒng)會(huì)選取最合適的圖標(biāo)展示在相應(yīng)位置上。
- src:圖標(biāo)路徑。相對(duì)路徑是相對(duì)于
manifest
文件,也可以使用絕對(duì)路徑。 - type:圖標(biāo)圖片類型。 瀏覽器會(huì)從
icons
中選擇最接近128dp(px = dp * (dpi / 160))
的圖片作為啟動(dòng)畫面圖像。
background_color
:指定啟動(dòng)畫面的背景顏色,采用相同顏色可以實(shí)現(xiàn)從啟動(dòng)畫面到首頁(yè)的平穩(wěn)過(guò)渡,也可以用來(lái)改善頁(yè)面資源正在加載時(shí)的用戶體驗(yàn)。
theme_color
:指定了Web App
的主題顏色??梢酝ㄟ^(guò)該屬性來(lái)控制瀏覽器 UI
的顏色。比如狀態(tài)欄、內(nèi)容頁(yè)中狀態(tài)欄、地址欄的顏色。
配置信息自動(dòng)生成工具:https://tomitm.github.io/appmanifest/
配置 HTML
文件
在 index.html
中引入 manifest
配置文件,并在 head
中添加以下配置信息以兼容 iOS系統(tǒng)
<meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover"> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-title" content="かなゲーム"> <link rel="stylesheet" type="text/css" href="./assets/css/main.css" rel="external nofollow" > <link rel="stylesheet" type="text/css" href="./assets/css/dark.css" rel="external nofollow" > <link rel="stylesheet" type="text/css" href="./assets/css/petals.css" rel="external nofollow" > <link rel="shortcut icon" href="./assets/images/icon-256x256.jpg" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <link rel="apple-touch-icon" href="./assets/images/icon-256x256.jpg" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> <link rel="apple-touch-icon-precomposed" href="./assets/images/icon-256x256.jpg" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <link rel="Bookmark" href="./assets/images/icon-256x256.jpg" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> <link rel="manifest" href="./manifest.webmanifest" rel="external nofollow" > <title>かなゲーム</title>
apple-touch-icon
: 指定應(yīng)用圖標(biāo),類似與manifest.json
文件的icons
配置,也是支持sizes
屬性,來(lái)供不同場(chǎng)景的選擇。apple-mobile-web-app-capable
:類似于manifest.json
中的display
的功能,通過(guò)設(shè)置為yes
可以進(jìn)入standalone
模式。apple-mobile-web-app-title
:指定應(yīng)用的名稱。apple-mobile-web-app-status-bar-style
:指定iOS移動(dòng)設(shè)備的狀態(tài)欄status bar
的樣式,有Default
,Black
,Black-translucent
可以設(shè)置。
注冊(cè)使用 Service Worker
在 index.html
中添加如下代碼進(jìn)行server-worker注冊(cè):
window.addEventListener('load', () => { registerSW(); }); async function registerSW() { if ('serviceWorker' in navigator) { try { await navigator.serviceWorker.register('./sw.js'); } catch (e) { console.log(`SW registration failed`); } } }
使用 serviceWorkerContainer.register()
進(jìn)行 Service worker
注冊(cè),同時(shí)添加 try...catch...
容錯(cuò)判斷,以保證在不支持 Service worker
的情況下正常運(yùn)行。另外需要注意的是只有在 https
下,navigator
里才會(huì)有 serviceWorker
對(duì)象。
Service workers
本質(zhì)上充當(dāng) Web
應(yīng)用程序、瀏覽器與網(wǎng)絡(luò)(可用時(shí))之間的代理服務(wù)器。旨在創(chuàng)建有效的離線體驗(yàn),它會(huì)攔截網(wǎng)絡(luò)請(qǐng)求并根據(jù)網(wǎng)絡(luò)是否可用采取來(lái)適當(dāng)?shù)膭?dòng)作、更新來(lái)自服務(wù)器的的資源。它還提供入口以推送通知和訪問(wèn)后臺(tái)同步 API
。了解更多 Service workder
知識(shí)可以訪問(wèn)文章末尾鏈接 🔗
。
在根目錄添加 sw.js
,定義緩存信息和方法
// 定義緩存的key值 const cacheName = 'kana-v1'; // 定義需要緩存的文件 const staticAssets = [ './', './index.html', './assets/css/main.css', './assets/js/main.js', './assets/images/bg.jpg' // ... ]; // 監(jiān)聽install事件,安裝完成后,進(jìn)行文件緩存 self.addEventListener('install', async e => { // 找到key對(duì)應(yīng)的緩存并且獲得可以操作的cache對(duì)象 const cache = await caches.open(cacheName); // 將需要緩存的文件加進(jìn)來(lái) await cache.addAll(staticAssets); return self.skipWaiting(); }); // 監(jiān)聽activate事件來(lái)更新緩存數(shù)據(jù) self.addEventListener('activate', e => { // 保證第一次加載fetch觸發(fā) self.clients.claim(); }); // 監(jiān)聽fetch事件來(lái)使用緩存數(shù)據(jù): self.addEventListener('fetch', async e => { const req = e.request; const url = new URL(req.url); if (url.origin === location.origin) { e.respondWith(cacheFirst(req)); } else { e.respondWith(networkAndCache(req)); } }); async function cacheFirst(req) { // 判斷當(dāng)前請(qǐng)求是否需要緩存 const cache = await caches.open(cacheName); const cached = await cache.match(req); // 有緩存就用緩存,沒(méi)有就從新發(fā)請(qǐng)求獲取 return cached || fetch(req); } async function networkAndCache(req) { const cache = await caches.open(cacheName); try { // 緩存報(bào)錯(cuò)還直接從新發(fā)請(qǐng)求獲取 const fresh = await fetch(req); await cache.put(req, fresh.clone()); return fresh; } catch (e) { const cached = await cache.match(req); return cached; } }
在 sw.js
中采用的標(biāo)準(zhǔn)的 web worker
的編程方式,由于運(yùn)行在另一個(gè)全局上下文中 (self)
,這個(gè)全局上下文不同于 window
,所以采用 self.addEventListener()
。
Cache API
是 Service Worker
提供用來(lái)操作緩存的的接口,這些接口基于 Promise
實(shí)現(xiàn),包括 Cache
和 Cache Storage
,Cache
直接和請(qǐng)求打交道,為緩存的 Request / Response
對(duì)象對(duì)提供存儲(chǔ)機(jī)制,CacheStorage
表示 Cache
對(duì)象的存儲(chǔ)實(shí)例,我們可以直接使用全局的 caches
屬性訪問(wèn) Cache API
。
** Cache
相關(guān) API
說(shuō)明:
Cache.match(request, options)
:返回一個(gè)Promise
對(duì)象,resolve
的結(jié)果是跟Cache
對(duì)象匹配的第一個(gè)已經(jīng)緩存的請(qǐng)求。Cache.matchAll(request, options)
:返回一個(gè)Promise
對(duì)象,resolve
的結(jié)果是跟Cache
對(duì)象匹配的所有請(qǐng)求組成的數(shù)組。Cache.addAll(requests)
:接收一個(gè)URL
數(shù)組,檢索并把返回的response
對(duì)象添加到給定的Cache
對(duì)象。Cache.delete(request, options)
:搜索key
值為request
的Cache
條目。如果找到,則刪除該Cache
條目,并且返回一個(gè)resolve
為true
的Promise
對(duì)象;如果未找到,則返回一個(gè)resolve
為false
的Promise
對(duì)象Cache.keys(request, options)
:返回一個(gè)Promise
對(duì)象,resolve
的結(jié)果是Cache
對(duì)象key
值組成的數(shù)組。
注:使用 request.clone()
和 response.clone()
是因?yàn)?request
和 response
是一個(gè)流,只能消耗一次。緩存時(shí)已經(jīng)消耗一次,再發(fā)起 HTTP
請(qǐng)求還要消耗一次,此時(shí)使用 clone
方法克隆請(qǐng)求。
至此,當(dāng)已安裝的 Service Worker
頁(yè)面被打開時(shí),便會(huì)觸發(fā) Service Worker
腳本更新。當(dāng)上次腳本更新寫入 Service Worker
數(shù)據(jù)庫(kù)的時(shí)間戳與本次更新超過(guò) 24小時(shí)
,便會(huì)觸發(fā) Service Worker
腳本更新。當(dāng) sw.js
文件改變時(shí),便會(huì)觸發(fā) Service Worker
腳本更新。更新流程與安裝類似,只是在更新安裝成功后不會(huì)立即進(jìn)入 active
狀態(tài),更新后的 Service Worker
會(huì)和原始的 Service Worker
共同存在,并運(yùn)行它的 install
,一旦新 Service Worker
安裝成功,它會(huì)進(jìn)入 wait
狀態(tài),需要等待舊版本的 Service Worker
進(jìn)/線程終止。
更多 Server Worker
進(jìn)階知識(shí)可以查看文章末尾鏈接 🔗
實(shí)現(xiàn)效果:
PC端 🖥️:Windows
上,在瀏覽器中初次打開應(yīng)用后會(huì)有安裝提示,點(diǎn)擊安裝圖標(biāo)之后進(jìn)行安裝,桌面和開始菜單中會(huì)生成應(yīng)用快捷方式,點(diǎn)擊快捷方式就可以打開應(yīng)用。
Mac 💻
: 上面 chromiumn內(nèi)核
的瀏覽器(chrome
、opera
、新版edge
)也是類似的。安裝之后會(huì)在 launchpad
中生成快捷方式。
移動(dòng)端 📱:iPhone
。瀏覽器中選擇保存到桌面,就可生成桌面圖標(biāo),點(diǎn)擊圖標(biāo)打開離線應(yīng)用。
櫻花飄落動(dòng)畫 🌸
為增強(qiáng)視覺效果和趣味性,于是在頁(yè)面增加了櫻花 🌸
飄落的效果。飄落效果動(dòng)畫主要使用到 Element.animate()
方法。
Element
的 animate()
方法是一個(gè)創(chuàng)建新 Animation
的便捷方法,將它應(yīng)用于元素,然后運(yùn)行動(dòng)畫。它將返回一個(gè)新建的 Animation
對(duì)象實(shí)例。一個(gè)元素上可以應(yīng)用多個(gè)動(dòng)畫效果。你可以通過(guò)調(diào)用此函數(shù)獲得這些動(dòng)畫效果的一個(gè)列表: Element.getAnimations()
。
基本語(yǔ)法:
var animation = element.animate(keyframes, options);
參數(shù):
keyframes
:關(guān)鍵幀。一個(gè)對(duì)象,代表關(guān)鍵幀的一個(gè)集合。options
:可選項(xiàng)代表動(dòng)畫持續(xù)時(shí)間的整形數(shù)字 (以毫秒為單位), 或者一個(gè)包含一個(gè)或多個(gè)時(shí)間屬性的對(duì)象:
id
: 可選,在 animate()
里可作為唯一標(biāo)識(shí)的屬性: 一個(gè)用來(lái)引用動(dòng)畫的字符串( DOMString
)delay
:可選,開始時(shí)間的延遲毫秒數(shù),默認(rèn)值為 0
。
direction
:可選,動(dòng)畫的運(yùn)動(dòng)方向。向前運(yùn)行 normal
、向后運(yùn)行 reverse
、每次迭代后切換方向 alternate
,向后運(yùn)行并在每次迭代后切換方向 alternate-reverse
。默認(rèn)為 normal
。
duration
:可選,動(dòng)畫完成每次迭代的毫秒數(shù),默認(rèn)值為 0
。easing
:可選,動(dòng)畫隨時(shí)間變化的頻率。接受預(yù)設(shè)的值包括 linear
、ease
、 ease-in
、ease-out
、ease-in-out
及一個(gè)自定義值 cubic-bezier
, 如 cubic-bezier(0.42, 0, 0.58, 1)
。默認(rèn)值為 linear
。
endDelay
:可選,一個(gè)動(dòng)畫結(jié)束后的延遲,默認(rèn)值為 0
。
fill
:可選,定義動(dòng)畫效果對(duì)元素的影響時(shí)機(jī),backwards
動(dòng)畫開始前影響到元素上、 forwards
動(dòng)畫完成后影響到元素上、both
兩者兼具。默認(rèn)值為 none
。
iterationStart
:可選,描述動(dòng)畫應(yīng)該在迭代中的哪個(gè)點(diǎn)開始。例如,0.5
表示在第一次迭代中途開始,并且設(shè)置此值后,具有 2
次迭代的動(dòng)畫將在第三次迭代中途結(jié)束。默認(rèn)為 0.0
。
iterations
:可選,動(dòng)畫應(yīng)該重復(fù)的次數(shù)。默認(rèn)為 1
,也可以取 infinity
的值,使其在元素存在時(shí)重復(fù)。
以下代碼為本例中的具體實(shí)現(xiàn),HTML
中有若干個(gè) .petal
元素,然后 JavaScript
中獲取到所有 .petal
元素添加隨機(jī)動(dòng)畫,css中添加兩種旋轉(zhuǎn)和變形兩種動(dòng)畫,實(shí)現(xiàn)櫻花花瓣飄落的效果。
<div id="petals_container"> <div class="petal"></div> <!-- ... --> <div class="petal"></div> </div>
var petalPlayers = []; function animatePetals() { var petals = document.querySelectorAll('.petal'); if (!petals[0].animate) { var petalsContainer = document.getElementById('petals_container'); return false; } for (var i = 0, len = petals.length; i < len; ++i) { var petal = petals[i]; petal.innerHTML = '<div class="rotate"><img src="petal.jpg" class="askew"></div>'; var scale = Math.random() * .6 + .2; var player = petal.animate([{ transform: 'translate3d(' + (i / len * 100) + 'vw,0,0) scale(' + scale + ')', opacity: scale }, { transform: 'translate3d(' + (i / len * 100 + 10) + 'vw,150vh,0) scale(' + scale + ')', opacity: 1 } ], { duration: Math.random() * 90000 + 8000, iterations: Infinity, delay: -(Math.random() * 5000) }); petalPlayers.push(player); } } animatePetals();
.petal .rotate { animation: driftyRotate 1s infinite both ease-in-out; perspective: 1000; } .petal .askew { transform: skewY(10deg); display: block; animation: drifty 1s infinite alternate both ease-in-out; perspective: 1000; } .petal:nth-of-type(7n) .askew { animation-delay: -.6s; animation-duration: 2.25s; } .petal:nth-of-type(7n + 1) .askew { animation-delay: -.879s; animation-duration: 3.5s; } /* ... */ .petal:nth-of-type(9n) .rotate { animation-duration: 2s; } .petal:nth-of-type(9n + 1) .rotate { animation-duration: 2.3s; } /* ... */ @keyframes drifty { 0% { transform: skewY(10deg) translate3d(-250%, 0, 0); display: block; } 100% { transform: skewY(-12deg) translate3d(250%, 0, 0); display: block; } } @keyframes driftyRotate { 0% { transform: rotateX(0); display: block; } 100% { transform: rotateX(359deg); display: block; } }
完整代碼可查看文后鏈接 🔗
。
CSS
判斷手機(jī)橫屏
本例 50音小游戲
應(yīng)用是針對(duì)移動(dòng)端開發(fā),未作pc端的樣式適配,所以可以添加一個(gè)橫屏引導(dǎo)頁(yè)面提示用戶使用豎屏。在 CSS
中判斷移動(dòng)設(shè)備是否處于橫屏狀態(tài),需要用到 aspect-ratio
進(jìn)行媒體查詢,通過(guò)測(cè)試 viewport
的寬高比來(lái)進(jìn)行判斷。
aspect-ratio
寬高比屬性被指定為 <ratio>
值來(lái)代表 viewport
的寬高比。其為一個(gè)范圍,可以使用 min-aspect-ratio
和 max-aspect-ratio
分別查詢最小和最大值?;菊Z(yǔ)法如下:
/* 最小寬高比 */ @media (min-aspect-ratio: 8/5) { // ... } /* 最大寬高比 */ @media (max-aspect-ratio: 3/2) { // ... } /* 明確的寬高比, 放在最下部防止同時(shí)滿足條件時(shí)的覆蓋 */ @media (aspect-ratio: 1/1) { // ... }
在應(yīng)用中的具體實(shí)現(xiàn)方式是添加一個(gè) .mod_orient_layer
引導(dǎo)層并隱藏,當(dāng)達(dá)到最小寬高比時(shí)將其顯示:
<div class="mod_orient_layer"></div>
.mod_orient_layer { display: none; position: fixed; height: 100%; width: 100%; left: 0; top: 0; right: 0; bottom: 0; z-index: 999; background: #FFFFFF url('landscape.jpg') no-repeat center; background-size: auto 100%; } @media screen and (min-aspect-ratio: 13/8) { .mod_orient_layer { display: block; } }
實(shí)現(xiàn)效果:
兼容性
下面是本文中涉及的幾個(gè)屬性的兼容性視圖,在實(shí)際生產(chǎn)項(xiàng)目中需要注意兼容性適配。
Photoshop 技能
logo設(shè)計(jì)
logo
主要由兩個(gè)元素構(gòu)成由一個(gè) ⛩️
圖標(biāo)和日語(yǔ)平假名 あ
構(gòu)成,都是經(jīng)典的日系元素,同時(shí)對(duì) あ
進(jìn)行拉伸漸變,形成類似 ⛩️
的陰影,使字母和圖形巧妙連接在一起,使畫面和諧。logo背景色使用應(yīng)用主題背景色,與頁(yè)面在無(wú)形之中建立聯(lián)系,形成 全鏈路
統(tǒng)一風(fēng)格標(biāo)準(zhǔn)。(編不下去了。。。😂
⛩
鳥居原始模型來(lái)源于 dribbble
: https://dribbble.com
外部鏈接及參考資料
櫻花散落動(dòng)畫完整版 https://codepen.io/dragonir/full/WNjEPwW
Dark Mode Support in WebKit https://webkit.org/blog/8840/dark-mode-support-in-webkit
PWA技術(shù)理論+實(shí)戰(zhàn)全解析 https://www.cnblogs.com/yangyangxxb/p/9964959.html
H5 PWA技術(shù) https://zhuanlan.zhihu.com/p/144512343
aspect-ratio https://developer.mozilla.org/zh-CN/docs/Web/CSS/@media/aspect-ratio
Service Worker https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API
Element.animate() https://developer.mozilla.org/zh-CN/docs/Web/API/Element/animate
作者:dragonir 博客地址:https://www.cnblogs.com/dragonir/p/15041977.html
到此這篇關(guān)于五十音小游戲中的前端知識(shí)的文章就介紹到這了,更多相關(guān)前端知識(shí)小游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript的for循環(huán)中嵌套一個(gè)點(diǎn)擊事件的問(wèn)題解決
本文主要介紹了JavaScript的for循環(huán)中嵌套一個(gè)點(diǎn)擊事件點(diǎn)擊一次彈出多個(gè)相同的值的解決方法,具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-03-03JavaScript使用prototype屬性實(shí)現(xiàn)繼承操作示例
這篇文章主要介紹了JavaScript使用prototype屬性實(shí)現(xiàn)繼承操作,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript使用prototype屬性實(shí)現(xiàn)繼承的相關(guān)原理、實(shí)現(xiàn)方法與操作注意事項(xiàng),需要的朋友可以參考下2020-05-05javascript實(shí)現(xiàn)tabs選項(xiàng)卡切換效果(自寫原生js)
常用的頁(yè)面效果有彈出層效果,無(wú)縫滾動(dòng)效果,選項(xiàng)卡切換效果,接下來(lái)與大家分享一款自己用原生javascript寫的選項(xiàng)卡切換效果,感興趣的朋友可以參考下哈2013-03-03js AppendChild與insertBefore用法詳細(xì)對(duì)比
本篇文章主要是對(duì)js中AppendChild與insertBefore的用法進(jìn)行了詳細(xì)的對(duì)比。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-12-12ES6解構(gòu)賦值(數(shù)組,對(duì)象,函數(shù))使用詳解
這篇文章主要介紹了ES6解構(gòu)賦值(數(shù)組,對(duì)象,函數(shù))使用詳解,JavaScript 中最常用的兩種數(shù)據(jù)結(jié)構(gòu)是 Object 和 Array,解構(gòu)操作對(duì)那些具有很多參數(shù)和默認(rèn)值等的函數(shù)也很奏效,本文通過(guò)實(shí)例代碼詳細(xì)講解需要的朋友可以參考下2022-11-11JavaScript實(shí)現(xiàn)表單驗(yàn)證案例
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)表單驗(yàn)證案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08