2017年2月19日

為 MAC 的 Terminal 上色 - 透過 iTerm 2 和 Oh My Zsh 高亮你的終端機

img
奇怪,為什麼你的終端機畫面可以長的這麼好看阿?我的換來換去卻還是長的像我是個 Hacker ...
img
今天,就來讓我們看一下可以怎麼做把 MAC 的終端機畫面用的更有人性吧。
讓 MAC 終端機高亮的過程雖然看起來很複雜又冗長,但是如果你是常會使用終端機的使用者,又希望有一個比較好看的視覺介面,只要按照下面一步步跟著做就可以完成了。
在下面的終端機的指令中,$ 只是表示是終端機指令的開頭,不需要複製輸入到終端機中。

安裝 Homebrew

Homebrew 是 Mac OSX 上的的套件管理工具,是方便安裝管理 OSX 裡需要用到但預設沒安裝的套件。Homebrew 的安裝只需要打開終端機,輸入:
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
就可以了。接著可以輸入以下指令確認是否有安裝成功:
$ brew --version

安裝 iTerm2

iTerm2 是一個可以用來取代 MAC 原生終端機的工具,擁有許多更方便的功能和特色,只需到官網下載安裝就可以了。
或者也可以在 terminal 中輸入下述的指令,直接透過 homebrew 安裝:
$ brew install --cask iterm2

iTerm2 配色主題下載

iTerm2 提供非常多的配色主題可以下載,可以到 iterm2 color schemes 的網站選擇喜歡的配色,右上角有下載的標示可以整包下載下來,下面則會顯示各種配色。
解壓縮後在 schemes 中有許多副檔名為 .itermcolors 的配色檔可以載入,這裡我們選擇 Solarized Dark Theme Patched Version(下載)
Imgur

iTerm2 套用配色

選好喜歡的配色後,打開 iTerm2 後按快捷鍵 cmd + i ,選擇上方名為 color 的頁籤,在右下方的 Color Presets 中透過 import 匯入配色後再點選一次 Color Preset 就可以選取:
Imgur
你也可以在 Iterm2-color-schemes 中下載選擇其他的配色主題,像我個人也蠻喜歡用 Blazer 這個主題配色:
Screen Shot 2020-12-26 at 11.29.20 PM

安裝 ZSH

接著我們要安裝 ZSH ,這是用來取代 BASH 的一種工具,打開 Terminal 輸入:
$ brew install zsh zsh-completions
確認安裝成功
$ zsh --version
接著要將預設終端機窗口改為 ZSH,一樣在終端機輸入:
$ sudo sh -c "echo $(which zsh) >> /etc/shells"
$ chsh -s $(which zsh)
然後重新開啟你的 Terminal ,輸入:
$ echo $SHELL
如果有成功變更 SHELL 為 ZSH 的話應該會看到 /usr/local/bin/zsh

安裝 Oh My ZSH

Oh My Zsh 是一個用來管理 ZSH 設定檔(configuration)的框架,提供了很多的外掛(plugin)和主題(theme)可以選擇。
安裝的方式一樣是透過 Terminal ,輸入:
$ sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
接下來我們要套用主題,輸入:
$ open ~/.zshrc
接著會打開 zsh 的設定檔,找到 ZSH_THEME=”…”,將這段的內容改成下面這段後,在透過 cmd + s 存檔:
ZSH_THEME="agnoster"

字體修改

在安裝的過程中,如果你發現出現一些看不懂的文字或亂碼時,很可能是因為沒有相對應的字體,因此我們要下載字體。
下載字體檔:Meslo(截圖中所使用的)或者也可以到 Powerline fonts @ github 中找到其他你要的字體後,在 「view raw」上點右鍵選擇「另存連結」將字體檔下載後並安裝。
在 iTerm2 中套用字體(Meslo):iTerm --> Preferences --> Profiles --> Text --> Change Font

補充:透過 homebrew-cask-fonts 下載字體

另一種下載字體的方式是直接透過 homebrew-cask-fonts 下載。例如:
$ brew tap homebrew/cask-fonts
$ brew install font-meslo-for-powerline

其他外掛或建議

其他外掛或建議

Auto Suggestions (for Oh My ZSH)

Auto Suggestions 會根據你過去所輸入的指令來提示要輸入的內容。
在終端機輸入:
$ git clone git://github.com/zsh-users/zsh-autosuggestions $ZSH_CUSTOM/plugins/zsh-autosuggestions
接著打開 ZSH 設定檔,找到 plugins = “” 的地方,在 plugins 的欄位中加入 zsh-autosuggestion 後存檔(若有多個 plugin 則以空白分開:
plugins=(zsh-autosuggestions)
有時候你的背景色和提是的文字會太過接近,以致於你看不到 autosuggestions 的文字,這時候需要去設定顯示的文字。一樣先在終端機輸入以下文字,以開啟設定檔:
open $ZSH_CUSTOM/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
打開設定檔後,在文件中找到這行(預設會是 fg=8),這就是給終端機所使用的256色碼,你可以改成自己喜歡的顏色,這裡我用 fg=240 感覺比較合適。
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=240'
接著,只要你輸入過相關的文字,下次再次打入同樣的文字的時候,就會產生自動建議的文字,按下→後就會自動帶入,像是這樣的效果:
img

程式碼高亮(Syntax Highlighting)

在終端機輸入下面這段,下載 Syntax Highlighting:
$ brew install zsh-syntax-highlighting
接著一樣打開 ZSH 設定檔:
$ open ~/.zshrc
在設定檔的最下面加上這段
# For zsh syntax-highlighting
source /usr/local/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

客制化 Prompt

在終端機中預設的 prompt 會是”user@hostname”,非常長一串,我們可以透過以下的方式讓那一長串不要顯示出來。
打開 ZSH 設定檔:
$ open ~/.zshrc
找個地方加入下面這段,DEFAULT_USER 中 “yourname” 要填的是你使用者的名稱:
# .zshrc

# optionally set DEFAULT_USER in ~/.zshrc to your regular username to hide the “user@hostname” info when you’re logged in as yourself on your local machine.
DEFAULT_USER=yourname
如果不知道使用者的名稱的話,可以在終端機輸入 whoami

git-open with oh-my-zsh

如果常使用 git 的話,一般當我們 commit 並 push 完之後,蠻常會到該 repository 的 github 或 gitlab 去發 Pull Request,這時候可以使用 git-open 這個工具,未來只需要在 Terminal 中輸入 $ git open 即可到該 git repository 對應的網站。

參考

2017年1月25日

[筆記] JavaScript ES6 中的模版字符串(template literals)和標籤模版(tagged template)


在 ES6 中,我們多了一個非常好用的模版字符串(template literal),如果你會在 JS 中「放入 HTML 的內容」、或者有「很長的字串包含換行」、又或者會有「字串連結變數」這樣的需求,模版字符串會是非常方便的作法。

另外,在 ES6 中可以將模版字符串和函式結合使用,形成一個標籤模版(tagged template),可以以此過濾 HTML 字串,避免使用者輸入惡意內容。

模版字符串(template literal)的基本應用


模版字符串的使用非常簡單,就是使用反引號" ` "(鍵盤左上角的~),舉例來說,如果我們會在 JS 的字串中放入 HTML 內容,在過去我們可能需要這樣寫:


let component_es5 = '<header>\n'+
'<div class="banner">\n'+
'<img src="img1.jpg"\n'+
'</div>\n'+
'</header>'


這麼寫相當麻煩,而且不易閱讀。而在 ES6 中我們可以用反引號快速的解決這樣的狀況:


let component_es6 = `
<header>
    <div class='banner'>
        <img src="img1.jpg>
    </div>
</header>
`


這樣的作法,會直接輸出如下的結果:


也就是說,透過反引號包住的內容,會保留所有的換行和空行

在模版字符串中嵌入變數


另外,在模版字符串中,我們還可以透過 ${...} 這樣的方式,嵌入變量或任何的表達式:


let myName = "PJCHENder",
    numA = 4,
    numB = 7;

let content = `Hello, my name is ${myName}, my lucky number is ${2*(numA + numB)}`;

console.log(content);  // "Hello, my name is PJCHENder, my lucky number is 22"


我們可以看到透過 ${...},裡面我們不只可以放入變數,還可以放入表達式(例如${3+4})。

最後,如果在模版字符串中我們又會使用到反引號的話,這時候我們必須使用跳脫字元 \ 來處理,像是這樣:


var greeting = `\`Hello\` World!`;

console.log(greeting); // "`Hello` World!"


進階:標籤模版(tagged template)


接著我們可以來看一下模版字符串的進階用法,這樣的用法非常適合用在前端用來過濾使用者所輸入的訊息。讓我們先來看一下基本的用法。

標籤模版的使用就是直接在函式後面加上模版字符串,如果模版字符串中沒有使用 ${...} 代入任何的變數的話,那麼它其實就和一般將參數代入函式中差不多:


console.log `Hello EveryOne`;    //  Array  ["Hello EveryOne"]
console.log('Hello EveryOne');   //  String "Hello EveryOne"


但是如果在模版字符串中有 ${...} 的話,意義就相當不同:


let myName = "PJCHENder";
let myCountry = "Taiwan";

tag `<p> My name is ${myName} and my coutry is ${myCountry}</p>`;  //  使用標籤模版
tag(["<p> My name is ", " and my coutry is ", "</p>"], "PJCHENder", "Taiwan")  // 等同於上面這段


很大的差別在於若我們使用標籤模版(tagged template),也就是在函式後面直接代入模版字符串(`...`),它等於會先將模版字符串的內容切成多個參數,在放入函式中,切法就是把所有沒有被放在 ${...} 中的內容都組成一個陣列(就像上例中["<p> My name is ", " and my coutry is ", "</p>"]),當作這個函式的第一個參數;接著將 ${...}  裡面的內容,依次當做後面的第二個、第三個、...參數(看你使用了幾次${...} )。

因此,如果我們將 tag 這個 function 寫成這樣:

let myName = "PJCHENder";
let myCountry = "Taiwan";

tag `<p> My name is ${myName} and my coutry is ${myCountry}</p>`;
// tag(["<p> My name is ", " and my coutry is ", "</p>"], "PJCHENder", "Taiwan")  // 等同於上面這一段

function tag(template){
  console.log(template);
  console.log(arguments);
}


這個 function 做的事情很簡單,就是把 template 呼叫出來,還有把 arguments 呼叫出來(arguments 是 JS 中內建的關鍵字,若不清楚可參考:[筆記] 談談JavaScript中函式的參數(parameter),arguments和展開運算子(spread))。輸出的結果如下,其中上面是 template,下面是 arguments:


在下圖中下面的部分,我們可以看到它實際代入了三個參數,第一個參數是一個陣列,裡面包含所有除了${...} 內的內容,後面的兩個參數,則分別放入 ${...} 的內容作為參數。

結合其餘運算子(rest operator)做使用:因為 ${...}  的數量可能是不固定的,因此我們可以搭配其餘運算子(...),將這些參數組成陣列來使用(若不清楚其餘運算子,可參考:[筆記] JavaScript ES6 中的展開運算子(spread operator)和其餘運算子(rest operator)),像是這樣:


let myName = "PJCHENder";
let myCountry = "Taiwan";

tag `<p> My name is ${myName} and my coutry is ${myCountry}</p>`;
// tag(["<p> My name is ", " and my coutry is ", "</p>"], "PJCHENder", "Taiwan")  // 等同於上面這一段

function tag(template, ...values){
  console.log(template);  //  ["<p> My name is ", " and my coutry is ", "</p>"]
  console.log(values);  //  ["PJCHENder", "Taiwan"]
}


等於把不在${...}內的,和在${...},拆成兩個陣列來做使用。

這樣的標籤模版有一個好處,就是我們可以把使用者輸入的內容${...},和我們網頁原本的內容分開做處理,以達到過濾 HTML 字符串,防止用戶輸入惡意內容的效果:

截圖自:阮一峰-ECMAScript 6 入門

2017年1月24日

[筆記] JavaScript ES6 中的 for ... of(處理陣列的好幫手)


過去我們可以使用 for, while, do while, for...in 等內在的函式來處理資料,而在 ES6 中我們多了 for...of 這個簡易的用法來處理這些疊代型的資料(iterable objects),包含陣列、字串、map、set、等等...。

陣列中 for...of 的基本用法


for...of 的使用非常簡單,以陣列為例:


let arr = [10, 20, 30]

for(let value of arr){
  console.log(value);  // 10, 20, 30
}


只要用這樣的方式,就可以把陣列的值一個個取出,不用像過去寫一大串像是 for(let i = 0; i < arr.length; i++){...} 是不是方便許多呢

for...of 的其它用法


for...of 除了用在陣列之外,也可以用在其他的資料型態,像是字串、map、set 等等...,舉字串為例:


let string = "ES6";

for(let value of string){
  console.log(value);  // "E", "S", "6"
}


是不是非常方便呢?


2017年1月21日

[筆記] JS30系列:監聽按鍵事件及撥放音效(Day1)


此課程內容來自 Wes Bos ,文章內容為整理課程內容學習之筆記,如果直接看筆記的話可能會覺得有點跳,不適合直接當成單篇文章閱讀,因此建議可以先看過該堂課程內容後,需要複習的時候在回來看筆記。關於此課程的上課說明可參考 JavaScript30 課程說明

第一堂課完成的頁面會像這個網站所顯示的樣子,當按下畫面上的所對應的按鍵時會有對應的動畫效果和音效。

思考分析


1. 瀏覽器能夠辨認使用者在鍵盤上所按下的按鍵
2. 當鍵盤按下指定的按鍵後能夠觸發音效
3. 當鍵盤按下指定的按鍵後能夠觸發網頁上的元件產生相對應的變化
4. 網頁上元件的變化要能夠回覆成原本的狀態
5. 播放的音效要能夠停止

辨認使用者在鍵盤上所按下的按鍵


KeyCode:每一個按鍵其實都有對應的鍵碼(keycode),而我們可以透過使用者所按下的鍵碼來得知使用者是按了鍵盤上的哪一個按鈕。在 keycode.info 這個網站中,你就可以得到每一個按鍵所對應到的鍵碼。

keycode @ keycode.info

addEventListener:在 JS 中,我們要監聽事件的話通常會用到 addEventListener,在這裡也不例外,為了要監聽使用者按了那個按鍵,我們會寫這樣子:


// 監聽鍵盤按鍵事件,並回傳所按的按鍵為何
  window.addEventListener('keydown', function(e){
    console.log(e);
  });


這裡我們用的是 keydown 事件,後面可以帶函式 function(e){...}),函式的參數中會預設回傳一個屬於該事件引發後的物件,在這裡我們用 console.log 來看看它會回傳什麼事件。

假設我在網頁上點選 "A",這時候它會回傳一個物件長這樣,其中包含了像是我們按了哪個按鍵的屬性(key),也包含這個按鍵的鍵碼(keyCode)等等:


在這裡 keyCode 會是很重要的屬性,有了它我們就知道使用者按了鍵盤上的哪個鍵,然後我們針對是個按鍵提供網頁上相對應要產生的效果。

鍵盤按下指定按鈕後能夠觸發音效


在來你會看到課程的 HTML 文件中,不論是 button 或 audio 標籤都加入了 data-* attribute,這裡它用的是 data-key 像是這樣:


data-* attribute:簡單說明一下什麼是 data-* attribute,有時我們會需要使用到某些自定義的屬性,但是為了要避免大家在 HTML 中隨意的添加屬性,於是在 HTML5 中就多了 data-* attribte 這個屬性,其中的 * 就是一個可以自定義的名稱,例如:data-key='83' 或者是 data-item='1',關於 data-* attribute 屬性如果想要有更多的瞭解,可以參考([教學] 什麼是 HTML 5 中的資料屬性)。

有了 data attribute 我們就可以選擇到和按鍵所對應的音效,並使他播放。但我們要做的是要先選到和按鍵所對應的音效元素,這時候我們會需要用到 JavaScript 中的 querySelector

querySelector:這是 JS 中原生的 CSS 選擇器,裡面可以像 jQuery 一樣去選擇想要選擇到的元素,有一些要注意的地方像是,若找不到相對性的元素會回傳 null,否則會回傳第一個符合的元素,因此,若你是多個屬性具有相同的 class 名稱時,它只會選到第一個符合的元素。如果你是想要選擇多個具有相同 class 名稱的屬性時,就要用 querySelectorAll
瞭解更多關於 querySelectorquerySelectorAll

下面這段程式碼的意思,就是當我按了鍵盤上的按鍵後,幫我選擇相對應的 keyCode 元素,否則的話就會回傳 null 。


//  選擇鍵盤按鍵所對應到的網頁元素
window.addEventListener('keydown',function(e){
    const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
    console.log(audio);
})


在下面這段程式碼中還有一個可以留意的是在 querySelector( ) 裡面,使用了 ES6 中的模版語言,它是使用 ` 符號(鍵盤左上角的~)來將,在模版字串中如果有需要引入變數,則可以是用${ },來代入變數(若不清楚模版字符串的使用,可參考[筆記] JavaScript ES6 中的模版字符串和標籤模版)。

當我們按鍵按到了相對應 keyCode 時就可以選到該元素,否則就會回傳null


當我們能夠找到指定的元素時,我們就可以透過 JS 叫它播放,要讓它播放的方式很簡單,只要在找到的這個元素後面寫 .play() 就可以了。

另外,為了避免當我們沒有按到頁面上所指定的按鍵時,會回傳錯誤結果,我們多一行 if(!audio) return,意思是如果沒有按到指定的按鍵,則透過 return 來停止這個函式,像是這樣:


//  播放元素音效檔
window.addEventListener('keydown',function(e){
    const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
    if(!audio) return;  //  如果沒有按到對應的按鍵,則停止此函式
    audio.play();       //  播放元素的音效
})


做到這裡當你下所對應的按鍵時,就會發出音效了。但我們會碰到另一個問題,就是當我們快速連續點擊同一個按鍵時,原本我們預期音效應該會快速重複,但實際上卻沒有這樣的效果。

之所以會有這個問題,是因為一個音效檔的時間長度可能是 3 秒,當我們使用 .play( ) 來觸發音效時,在音效檔還沒撥到結束的時候,它不會再重複執行一次。

解決這個問題的方法,就是讓函式每次執行的時候,當讓音效檔的時間點回到一開始,這樣它才會重新播放,寫法是利用到 currentTime 這個屬性,它可以使用在 HTML 中 audio 或是 video 標籤(參考:W3Schools),寫法像是下面這樣:


window.addEventListener('keydown',function(e){
    const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
    if(!audio) return;      //  如果沒有按到對應的按鍵,則停止此函式
    audio.currentTime = 0;  //  讓每次回到音效檔的起始點
    audio.play();           //  播放元素的音效
})


到這裡如果沒問題的話,你按下對應的鍵應該就會發出對應的音效了。

鍵盤按下指定按鈕後能夠網頁動畫效果


接下來我們要做的,就是讓鍵盤按下指定的按鈕後,能夠讓網頁產生動畫效果,而這個動畫效果之所以會產生,是因為在指定的元素上,加了特定的 class 之後再移除所造成的。

所以和剛剛一樣,我們要先監聽使用者鍵盤按下的按鍵,接著取的他所按下按鍵所對應到的網頁元素:


//  監聽使用者按鍵事件,並取得對應的元素
window.addEventListener('keydown', function(e){
    const key = document.querySelector(`.key[data-key="${e.keyCode}"]`);
})


我們可以看到,在作者的 CSS 程式碼中,原本按鍵只套用 .key ,當我們按下指定的按鍵時,則會多套用 .playing 這個 class 來達到動態的效果。

另外,這裡也有用到 CSS 中的 transition 屬性,除了讓動畫的改變更滑順外,我們後面也會利用它的功能,來自動的拿掉 .playing 這個屬性。



classList 物件:接下來我們要做的就是讓按下按鍵之後,能夠在該元素上添加指定的 class 以產生動態的效果,可以利用 JS 中內建的 element.classList.add( ) 這個方法:


window.addEventListener('keydown', function(e){
    const key = document.querySelector(`.key[data-key="${e.keyCode}"]`);    //  取得按鍵對應的元素
    key.classList.add('playing');       ///為該元素增加 class
})


現在當我們按下按鍵後,他就會自動加上 .playing 這個 class,進一步的問題是,要怎麼讓它自動移除這個 class ,否則這個動畫產生的效果不會消失。

transitionend event:這個 transitionend 事件主要是對應到 CSS 中 transition 的動畫效果,當這個 transition 效果執行結束的時候會引發事件。

所以我們能做的就是監控每一個按鍵的 transitionend event ,一旦我們偵測到這個動畫效果(transition)已經結束,那麼我們就可以把原本添加的 .playing 這個 class 拿掉。

querySelectorAll:為了監聽每一個按鍵的事件,這裡我們就會用到 querySelectorAll 這個方法,它會選出所有具有該 class 的元素,並回傳為一 NodeList

forEach( ):接著為了要重複的讀出這個 NodeList 的內容,我們會用到 forEach( ) 這個方法,forEach( ) 這個方法裡面可以放入 callback function,預設的參數包含該 NodeList 的屬性值和屬性名稱。因此我們可以寫出如下的語法:


const keys = document.querySelectorAll('.key'); //  選出所有具有 .key 的元素,回傳成陣列
keys.forEach((key) => {key.addEventListener('transitionend', removeTransition)});   //  利用 forEach 方法讀取 NodeList 並為每一個元素加上 transitionend 事件,事件執行時會促發 removeTransition 


接著我們就要來撰寫 removeTransition 的函式,這個 removeTransition 就是 addEventListener( ) 當中的函式,所以它一樣可以回傳一個屬於該事件的物件,這裡我們把它稱做 e:


let removeTransition = function(e){
    console.log(e);
}


我們來看一下當我們按下按鍵後,會回傳什麼內容:


這落落長的到底是什麼東西呢?我們可以在圖片中看到 propertyName 的地方分別有 border-*-color, border-*-width, 另外還有一個 transform,這些東西是當 transition 效果結束之後會回傳的內容,在這裡我們就拿 propertyName = transform 這個來當指標,當transform 出來(也就是 transition 結束,transitionend 被觸發時),把 .playing 這個 class 移除。


let removeTransition = function(e){
    if(e.propertyName !== 'transform') return; //    省略掉其他 propertyName 不是 transform 的物件
    this.classList.remove('playing');   //  把 playing 這個 class 移除
}


如果你不清楚 this 是什麼可以參考這篇:[筆記] 談談JavaScript中的"this"和它的bug,或者直接透過 console.log(this) 把它呼叫出來看看就會更明白了。

到這裡我們就把所有需要用到的效果都寫完拉!

看一下我們學到了什麼


  • 監聽事件(addEventListener(event, function))--- 在 function 中代入參數會回傳和該事件有關的物件
  • 按鍵事件(keydown
  • 透過 CSS 選擇元素(querySelector, querySelectorAll)
  • 音效相關(element.play( ), element.currentTime)
  • 資料屬性(data-* attribute
  • CSS相關(element.classList.add( ), element.classList.remove( )
  • 動畫結束事件 --- transitionEnd
  • forEach( )
  • 若不符合則退出函式:function( ){if(...) return}

如果想要看一下簡單的 DEMO 的話,可以到 CodePen 看看喔!



資料來源:

2017年1月20日

[技術分享] 什麼是 HTML 5 中的資料屬性(data-* attribute)

img
在接觸 HTML5 一段時間,認識大部分的屬性名稱像是 src, img, type, ... 後,一定會看到像是 data-item, data-key, data-...這類的屬性名稱,但是如果你直接去 google "data-item" 或 "data-key" 你可能又查不到這個屬性,到底這是哪種屬性呢?又可以如何應用呢?

HTML5 中的 data-* attribute 屬性

之所以會有 data-* attribute 的出現,是因為在製作網頁的過程中,我們常常會添加一些自己需要用到的屬性名稱,以方便自己容易理解,但總不能每個人在自己的網頁裡面都定義自己的屬性名稱,於是為了要避免大家在 HTML 結構中隨意的添加屬性,在 HTML5 中就多了 data-* attribte 這個屬性,其中的 * 就是一個可以自定義的名稱,例如:data-key='83' 或者是 data-item='1',這也就是為什麼如果你去 google "data-key" 或 "data-item" 會找不到東西的原因了!因為那是網頁工程師自己定義出來的字詞。
在使用 data-* attribute 時,* 字號的地方不能包含大寫字母,也就是屬性名稱不能包含大寫字母,而屬性值則可以是任何的字串。例如說我們可以這樣用:
<div id="slider" data-type="slideShow">
  <img class='photo' data-item="1" data-size="xs" src="http://fakeimg.pl/350x200/?text=Hello" />
  <img class='photo' data-item="2" data-size="lg" src="http://fakeimg.pl/550x200/?text=Welcome" />
</div>

使用 JS 取得 data-* attribute 的屬性值

當我們要取得 data-* attribute 的屬性值時,我們可以簡單利用 JavaScript 中的 dataset 物件,就可以取得了,以上面的 HTML 為例,可以寫成這樣:
let slider = document.getElementById('slider');
console.log(slider.dataset.type);   //  "slideShow

let photo = document.querySelectorAll('.photo');
console.log(photo[0].dataset.item);   //  "1"
console.log(photo[0].dataset.size);   //  "xs"
如果你習慣使用的是 jQuery ,也可以用內建的 .data( ) 這個方法來獲取屬性值:
console.log($('#slider').data('type')); //  "slideShow"

透過 CSS 取得或選取 data-*attribute

在 CSS 當中,我們一樣可以取得這個 data-* attribute 的內容,例如:
<article data-content="Hello Everyone">
</article>
如果我希望在 article 這個空的區塊中顯示 data-content 內容,只需要輸入在 CSS 的地方寫入:
article::before{
  content: attr(data-content);
}
如果我是希望選取具有某個屬性和屬性值的元素,我們也可以搭配使用 CSS 中的屬性選取器
#slider img[data-size="xs"] {
  width: 400px;
}
#slider img[data-size="lg"] {
  width: 800px;
}

程式範例

程式範例 @ CodePen
只要善用 HTML5 中的 data-* attribute 可以幫助我們在網頁開發的時候更有效率或做出更多不同的效果。

參考

2017年1月19日

[筆記] JS30 系列 Day0 - 課程說明



你可能已經有了一些 JavaScript 的基礎,做過了 Codecademy, FreeCodecamp 當中有關 JS 的練習,甚至在 Code SchoolTree House 上付費學習 ,然而卻總是不知道實際上可以怎麼應用,那麼由 Wes Bos 所開設的這堂 JavaScript30 相信會非常適合你!

這堂課程是完全免費搭配英文字幕,在課程中由 Wes Bos 帶你製作 30 個精緻的東西,就讓我們一起來學習吧!

個人的課程筆記會另外放在這個目錄底下:[學習筆記目錄] JS30 系列文章

註冊方式


註冊方式很簡單,只要到 JavaScript30 的網站填入 Email,接著就會收到一封通知信,告知你可以開始課程了:


課程檔案下載


這門課程檔案全部都放在 github 上可以自行下載,進入的方法是點選他回信給你的連結,會帶你到課程導覽頁,裡面有個 "Starter Files" 可以點選,點下去之後就會連到作者的 github 了。

如果你還是找不到這顆按扭,那也可以直接透過這個連結進入。


進入 github 之後,如果你之前就有使用 git 的經驗,可以直接把整個資料夾 clone 下來,如果沒有的話也不用擔心,網頁的右手邊有一個 "clone or download",點下去之後在按下 Download ZIP 就可以把整個課程用的檔案下載下來了!


我聽到 JavaScript 就怕,這門課適合我嗎?

以下是我個人的意見,這門課雖然主要在講的是網頁前端三劍客中的 JavaScript,但如果你完全沒有 HTML 和 CSS 的基礎,上起來的確會顯得比較吃力。

因此,我認為如果你已經有基本的 HTML、CSS 和 JS 能力 (例如,已經把 codecademy 上的基本練習都做過或掌握了),然後覺得學了這些語言後卻又好像不知道該怎麼應用的話,那麼我認為這麼課會非常適合你,你將會更熟悉 JavaScript 這個語言。

但因為課程中有許多部分老師是直接實際操作而沒有做太多觀念上的講解,因此有些部分不理解是正常的,對於不理解的部分你可以:

(1)先跳過,先抓住自己理解的部分,把成品做出來,因為如果你一直卡在不懂的地方,你可能會沒辦法享受這門課程。這就好像在讀英文文章的時候,如果你碰到每一個不懂的單字就停下來查字典,那麼你可能很難享受這篇文章(有許是文章太難了,也許可以先試著讀懂文章的大意就好)。
(2)google 你覺得不清楚的部分。
(3)問人,Facebook 上有許多關於前端網頁的社群,試著自己先理解看看,如果還是不懂的話,問人會是很有效率的方式,當然也可以發訊息到PJCHENder網頁前端資源站

準備好了嗎?一起開始來學習 JavaScript30 吧!PJ 將整理每堂課中的重點,幫助大家(自己)學習整理。

如果課程中有任何問題,也歡迎到 PJCHENder網頁前端資源站,一起來學習討論吧!

課程筆記

個人的課程筆記會另外放在這個目錄底下:[學習筆記目錄] JS30 系列文章

資料來源

資料來源:

[筆記] JavaScript ES6 中的展開運算子(spread operator)和其餘運算子(rest operator)


在 ES6 中,新增了一個 "..." 的關鍵字,這個關鍵字在不同時間點有不同的效果,有些時候它會被當作展開運算子(spread operator)使用,有些時候則是被當作其餘運算子(rest operator)使用。

其餘運算子(rest operator)


假設現在我想要寫一個函式,它可以把所有陣列的值相加後取平均,在過去如果我們要在函式中放入陣列的資料,一般我們會這樣寫:


let arr = [1,2,3,4,5];

let avg = function(arr){
  let sum = 0;
  for(let i = 0; i < arr.length; i++){
    sum += arr[i];
  }
  return sum / arr.length;
}

console.log(avg(arr));  //  3


但是在使用函式的時候,有些時候我們並不清楚我們會放入多少參數數目,假設我們把輸入的參數改成許多數值的話,最後會回傳 NaN 這樣的結果:


let avg = function(arr){
  let sum = 0;
  for(let i = 0; i < arr.length; i++){
    sum += arr[i];
  }
  return sum / arr.length;
}

console.log(avg(1,3,5,7,9));  // NaN


這時候就可以用到其餘運算字的概念(...),其餘運算字會幫助我們把輸入函式中的參數值變成陣列的形式,這時候我們就可以像這樣子撰寫程式:


let avg = function(...arr){
  console.log(arr)  // [1,3,5,7,9]
  let sum = 0;
  for(let i = 0; i < arr.length; i++){
    sum += arr[i];
  }
  return sum / arr.length;
}

console.log(avg(1,3,5,7,9));  // 5


我們可以看到在上面程式碼第二行的地方,從原本的 function(arr) 改成 function(...arr),透過在參數的前面加上 "..." 便可以把所輸入多個參數轉成陣列(我們可以從上面程式碼中把參數 arr 呼叫出來看)。

展開運算子(spread operator)


展開運算子和其餘運算子一樣都是 "..." ,但是在應用的效果上是完全相反的,其餘運算子是把許多的參數轉換成一個陣列,而展開運算子則是可以把陣列中的元素取出

假設我們想用 Math.max( ) 這個函式來找出最大值,但是我們輸入的參數卻是陣列:


let number = [1,2,3,4,5];

console.log(Math.max(number));  //  NaN


這時候因為帶入的參數是陣列的關係,所以我們會得到 NaN 的結果。但如果我們能夠適時的應用展開運算子,我們就可以把這個陣列展開成許多數值:


let number = [1,2,3,4,5];

console.log(Math.max(...number));  //  5

console.log(...number);  // 1,2,3,4,5


這時候我們在陣列的前面加上 "..." ,它就會把陣列從 [1,2,3,4,5] 轉換成 1,2,3,4,5,如此就可以正確的取得最大值。