摘要:中文指南作者簡(jiǎn)介是推出的一個(gè)天挑戰(zhàn)。頁(yè)面基礎(chǔ)布局標(biāo)簽定義鍵盤文本說(shuō)到技術(shù)概念上的特殊樣式時(shí),就要提到標(biāo)簽。主要代碼主要屬性有以下幾個(gè)中有一個(gè)樣式為,在本案例中,就是,是以中的為參照物,就是。
Day01 - JavaScript Drum Kit 中文指南
簡(jiǎn)介作者:?liyuechun
簡(jiǎn)介:JavaScript30 是 Wes Bos 推出的一個(gè) 30 天挑戰(zhàn)。項(xiàng)目免費(fèi)提供了 30 個(gè)視頻教程、30 個(gè)挑戰(zhàn)的起始文檔和 30 個(gè)挑戰(zhàn)解決方案源代碼。目的是幫助人們用純 JavaScript 來(lái)寫東西,不借助框架和庫(kù),也不使用編譯器和引用?,F(xiàn)在你看到的是這系列指南的第 1 篇。完整指南在 從零到壹全棧部落。
第一天的練習(xí)是用JS制作一個(gè)爵士鼓的頁(yè)面,通過(guò)敲擊鍵盤上不同的字母,會(huì)發(fā)出不同的聲音,并且頁(yè)面上會(huì)伴隨著敲擊的動(dòng)畫。
效果如下:
想要實(shí)現(xiàn)以上效果,大致思路和解決方案如下:
檢測(cè)到鍵盤上什么鍵被按下--監(jiān)聽keydown事件
在按鍵被按下的時(shí)候,播放音效--audio.play()
在按鍵被按下的同時(shí),播放動(dòng)畫--Element.classList.add("playing")
在動(dòng)畫結(jié)束后,移除動(dòng)畫,不然之后再點(diǎn)擊不會(huì)有任何效果--Element.classList.remove("playing")
基礎(chǔ)語(yǔ)法 一些 ES6 語(yǔ)法const :聲明一個(gè)只讀的常量,標(biāo)識(shí)符的值只能賦值一次。
`字符串 ${ 變量、屬性名 } `:模板字面量(Template literals)中用于表示模板字符串的標(biāo)識(shí)。特點(diǎn)是字符串首尾用反引號(hào)(`),內(nèi)部的模板部分用 ${ } 括起來(lái)表示,具體請(qǐng)看MDN文檔。簡(jiǎn)單例子如下:
var a = 1; var b = 2; //不用模板的寫法 console.log("三是" + (a + b) + "不是" + (2 * a + b)); //"三是3不是4" //使用模板字符串的寫法 console.log(`三是${a + b}不是${2 * a + b}`); //"三是3不是4"forEach 與箭頭函數(shù)
使用 document.querySelector 獲取一組符合 CSS 選擇符的元素快照,類型為 NodeList(此對(duì)象是對(duì)于文檔的實(shí)時(shí)運(yùn)行的動(dòng)態(tài)查詢),對(duì)其進(jìn)行遍歷時(shí)可采用 forEach 方法。
// Code from http://es6-features.org/#StatementBodies // ES6 nums.forEach(v => { if (v % 5 === 0) fives.push(v); }) // ES5 nums.forEach(function (v) { if (v % 5 === 0) five.push(v); })頁(yè)面基礎(chǔ)布局
JS Drum Kit A clapS hihatD kickF openhatG boomH rideJ snareK tomL tink
標(biāo)簽定義鍵盤文本
說(shuō)到技術(shù)概念上的特殊樣式時(shí),就要提到 標(biāo)簽。正如你已經(jīng)猜到的,它用來(lái)表示文本是從鍵盤上鍵入的。
瀏覽器通常用等寬字體來(lái)顯示該標(biāo)簽中包含的文本。
標(biāo)簽經(jīng)常用在于計(jì)算機(jī)相關(guān)的文檔和手冊(cè)中。例如:
鍵入 quit 來(lái)退出程序,或者鍵入 menu 來(lái)返回主菜單。
使用 data-* 屬性來(lái)嵌入自定義數(shù)據(jù)
頁(yè)面里通過(guò)data-key將頁(yè)面展示的內(nèi)容和audio關(guān)聯(lián)起來(lái)。使用方法如下介紹:
① data-* 屬性用于存儲(chǔ)頁(yè)面或應(yīng)用程序的私有自定義數(shù)據(jù)。
② data-* 屬性賦予我們?cè)谒?HTML 元素上嵌入自定義 data 屬性的能力。
③ 屬性名不應(yīng)該包含任何大寫字母,并且在前綴 "data-" 之后必須有至少一個(gè)字符
④ 屬性值可以是任意字符串
語(yǔ)法:
屬性值:
值 | 描述 |
---|---|
somevalue | 規(guī)定屬性的值(以字符串)。 |
html { font-size: 10px; background: url(http://i.imgur.com/b9r5sEL.jpg) bottom center; background-size: cover; } body, html { margin: 0; padding: 0; font-family: sans-serif; } .keys { display: flex; flex: 1; min-height: 100vh; align-items: center; justify-content: center; } .key { border: .4rem solid black; border-radius: .5rem; margin: 1rem; font-size: 1.5rem; padding: 1rem .5rem; transition: all .07s ease; width: 10rem; text-align: center; color: white; background: rgba(0, 0, 0, 0.4); text-shadow: 0 0 .5rem black; } .playing { transform: scale(1.1); border-color: #ffc600; box-shadow: 0 0 1rem #ffc600; } kbd { display: block; font-size: 4rem; } .sound { font-size: 1.2rem; text-transform: uppercase; letter-spacing: .1rem; color: #ffc600; }
主要屬性有以下幾個(gè):
html中有一個(gè)樣式為font-size: 10px;,在本案例中,1rem就是10px,rem是以html中的font-size為參照物,1.2rem就是12px。
transform: scale(1.1);--該屬性在鍵盤被點(diǎn)擊時(shí)將該元素縮放至原來(lái)的1.1倍。
.key{border: .4rem solid black;} .playing{border-color: #ffc600;}--這兩條屬性在按鍵點(diǎn)擊的時(shí)候改變邊框顏色。
.key{text-shadow: 0 0 .5rem black;} .playing{box-shadow: 0 0 1rem #ffc600;}--這兩條屬性在按鍵點(diǎn)擊的時(shí)候改變陰影的效果
transition: all .07s ease;--定義以上動(dòng)畫在0.07秒內(nèi)完成。
我們注意到我們定義了.palying類,在按鍵按下的時(shí)侯為該元素添加playing類,在結(jié)束后移除playing類。
function playSound(e) { const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`); const key = document.querySelector(`div[data-key="${e.keyCode}"]`); if (!audio) return; key.classList.add("playing"); audio.currentTime = 0; audio.play(); } /** * 監(jiān)聽頁(yè)面的keydown事件,觸發(fā)playAudio函數(shù)。 */ window.addEventListener("keydown", playSound);
監(jiān)聽頁(yè)面的keydown事件,觸發(fā)playAudio函數(shù)。
通過(guò)KeyCode檢測(cè)我們按下的鍵盤按鈕是哪個(gè)按鈕。
A -> 65
B -> 66
C -> 67
D -> 68
E -> 69
F -> 70
G -> 71
H -> 72
I -> 73
J -> 74
K -> 75
L -> 76
M -> 77
N -> 78
O -> 79
P -> 80
Q -> 81
R -> 82
S -> 83
T -> 84
U -> 85
V -> 86
W -> 87
X -> 88
Y -> 89
Z -> 90
http://keycode.info打開這個(gè)網(wǎng)站,可以輕松查看鍵盤的按鈕對(duì)應(yīng)的code。
在這里我們用到了ES6的模板字符串,${e.keyCode},可以動(dòng)態(tài)的將按鍵的Keycode傳過(guò)去,以使audio動(dòng)態(tài)的獲取每一個(gè)按鍵綁定的audio。需要注意的是模板字符串一定要使用"`"(Esc下面那個(gè)鍵)包裹,而不是雙引號(hào)。
我們注意到audio.play();前面一行是audio.currentTime = 0;,這是因?yàn)?,如果沒(méi)有在播放音效前將該音樂(lè)重置,會(huì)發(fā)生以下情況,當(dāng)我連續(xù)點(diǎn)擊某一按鍵的時(shí)候,只有第一次點(diǎn)擊會(huì)響,第二次第三次連續(xù)的點(diǎn)擊可能沒(méi)聲音。所以在每一次點(diǎn)擊之前重置音效是很有必要的。
key.classList.add("playing");可以在按鍵點(diǎn)擊的同時(shí)為該元素添加playing類,展示小動(dòng)畫。
if(!audio) return; if(!key) return;因?yàn)椴⒉皇敲恳粋€(gè)按鍵都有音效,當(dāng)用戶點(diǎn)擊了非綁定音效按鍵,及時(shí)退出函數(shù)是很好的習(xí)慣。
動(dòng)畫結(jié)束后移除動(dòng)畫function stopTransition(e) { if (e.propertyName !== "transform") return; e.target.classList.remove("playing"); } const keys = Array.from(document.querySelectorAll(".key")); keys.forEach(key => key.addEventListener("transitionend",stopTransition));
監(jiān)聽每一個(gè)按鍵元素的transitionend事件,當(dāng)按鍵元素的動(dòng)畫結(jié)束后會(huì)觸發(fā)stopTransition函數(shù)。
首先在stopTransition函數(shù)中可以輸出事件e的內(nèi)容,會(huì)輸出該動(dòng)畫每一步具體的變化,發(fā)現(xiàn)其中會(huì)有propertyName屬性,可以通過(guò)判斷propertyName等于其中的一個(gè)值(例如"transform"),等于該值就移除playing類,也即移除動(dòng)畫。
在定位元素的時(shí)候,可以使用this也可以使用e.target,可以簡(jiǎn)單這么理解,this值的是誰(shuí)出發(fā)了這次事件,也就是key,就等同于事件的目標(biāo)(e.target).
解決難點(diǎn) 如何將鍵盤按鍵與頁(yè)面按鈕對(duì)應(yīng)起來(lái)?連接的幫手是 keydown 事件中的 keyCode 屬性,keyCode 屬性的值和 ASCII 編碼值相同(對(duì)應(yīng)小寫字母)。在這個(gè)網(wǎng)站可以用按鍵盤來(lái)查看對(duì)應(yīng)的鍵碼。
我們能獲取到的初始頁(yè)面中,按鈕 div 和音頻 audio 標(biāo)簽中都添加了一個(gè)屬性 data-key 用于存儲(chǔ)對(duì)應(yīng)的鍵碼,這樣做的目的是,添加鍵盤事件監(jiān)聽后,觸發(fā)鍵盤事件時(shí)即可獲取事件的 keyCode 屬性值,以此為線索,操作對(duì)應(yīng)的按鈕及音頻。
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`); const key = document.querySelector(`div[data-key="${e.keyCode}"]`);如何保證按鍵被按住不放時(shí),可以馬上響起連續(xù)鼓點(diǎn)聲?
每次播放音頻之前,設(shè)置播放時(shí)間戳為 0:
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`); audio.currentTime = 0; audio.play();如何使頁(yè)面按鈕恢復(fù)原狀?
利用一個(gè)叫 transitionened 的事件,它在 CSS transition 結(jié)束后會(huì)被觸發(fā)。我們就可以利用這個(gè)事件,在每次打鼓的效果(尺寸變大、顏色變化)完成之后,去除相應(yīng)樣式。
在這個(gè)頁(yè)面中,發(fā)生 transition 的樣式屬性不止一個(gè)(box-shadow, transform, border-color),所以需要添加一個(gè)判斷語(yǔ)句,使每發(fā)生一次按鍵事件時(shí),只去除一次樣式。
funciton remove(event) { if (event.propertyName !== "transform") return; this.classList.remove("playing"); // event.target.classList.remove("playing"); }完整源碼
Github Source Code
掃碼申請(qǐng)加入全棧部落 |
---|
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84066.html
摘要:中文指南二作者簡(jiǎn)介是推出的一個(gè)天挑戰(zhàn)。完整中文版指南及視頻教程在從零到壹全棧部落。第七天的練習(xí)是接著之前中文指南一的練習(xí),繼續(xù)熟練數(shù)組的方法,依舊沒(méi)有頁(yè)面顯示效果,所以請(qǐng)打開瀏覽器的面板進(jìn)行調(diào)試運(yùn)行。 Day07 - Array Cardio 中文指南二 作者:?liyuechun 簡(jiǎn)介:JavaScript30 是 Wes Bos 推出的一個(gè) 30 天挑戰(zhàn)。項(xiàng)目免費(fèi)提供了 30 個(gè)...
摘要:加入我們,一起挑戰(zhàn)吧掃碼申請(qǐng)加入全棧部落 JavaScript 30 - 一起做一次了不起的挑戰(zhàn) (Node+Vue+微信公眾號(hào)開發(fā))企業(yè)級(jí)產(chǎn)品全棧開發(fā)速成周末班首期班(10.28號(hào)正式開班,歡迎搶座) 在Github上看到了wesbos的一個(gè)Javascript30天挑戰(zhàn)的repo,旨在使用純JS來(lái)進(jìn)行練習(xí),不允許使用任何其他的庫(kù)和框架,該挑戰(zhàn)共30天,我會(huì)在這里復(fù)現(xiàn)這30天遇到的挑...
摘要:前端日?qǐng)?bào)精選騰訊前端團(tuán)隊(duì)社區(qū)源碼分析入門指南一些關(guān)于使用的心得基本類型與引用類型知多少掘金中文第期框架選型周刊第期入門系列模塊車棧重構(gòu)基于的網(wǎng)絡(luò)請(qǐng)求庫(kù)某熊的全棧之路的那些奇技淫巧的平凡之路模仿寫個(gè)數(shù)組監(jiān)聽掘 2017-07-01 前端日?qǐng)?bào) 精選 Why you shouldn`t use Preact, Fast-React, etc. to replace React today -...
摘要:上一步中執(zhí)行時(shí),明確的指出腳本由解釋器來(lái)執(zhí)行。為了表示更多的中文漢字有了,但是,中華文化博大精深,發(fā)現(xiàn)不夠用,因此有了對(duì)的擴(kuò)展即。但是,用編碼對(duì)于英文只占一個(gè)字節(jié),,一個(gè)中文漢字在卻占三個(gè)字節(jié)可能是中國(guó)人有錢啊,我大天朝。 簡(jiǎn)介: Python是一種解釋型語(yǔ)言,需要解釋器來(lái)執(zhí)行??梢酝ㄟ^(guò)在IDLE下執(zhí)行,也可以在文本文件里寫入代碼,然后將該文件命名為xx.py 然后在Windows下可...
閱讀 1229·2021-09-26 09:55
閱讀 3200·2019-08-30 15:55
閱讀 971·2019-08-30 15:53
閱讀 2297·2019-08-30 13:59
閱讀 2383·2019-08-29 13:08
閱讀 1111·2019-08-29 12:19
閱讀 3307·2019-08-26 13:41
閱讀 421·2019-08-26 13:24