此篇筆記為參加程式導師實驗計畫中,整理在 Lidemy [Git101] Git 超新手入門 的課程筆記。
Git 就是一種版本控制的系統。版本控制簡單來說就是進階版的檔案管理。我們平常管理資料夾與檔案的操作,包含最常見的複製、命名等。例如:HW1, HW2...; Work1-1, Work1-2...
版本控制不只是基本的新增、複製與刪除檔案,還能詳細紀錄檔案內容是誰以及什麼時候寫的,保留所有歷史紀錄。在不小心刪掉檔案後,還能找回來!不管是個人或團隊開發上使用 Git 進行版本控制,都相當方便!
可以使用 CLI (命令列介面) 或 GUI (圖形化介面),進行操作。著名的 GUI 例如:SourceTree, GitKraken 等。本篇筆記以 CLI 進行 Git 指令的介紹。
你有一個叫做菜哥的朋友,他有一個煩惱。因為他的笑話太多了,所以他目前都用文字檔記錄在電腦裡,可是變得越來越多之後很難紀錄,而且他的笑話是會演進的。會有版本一、版本二甚至到版本十,這樣他就要建立好多個不同的檔案,弄得他頭很痛。他希望你能教他用 Git 來做版本控制。
好心的你就要來教他 Git 的基本概念以及基礎的使用囉!
到官網下載 Git。
下載後,打開終端機,輸入 git --version
,若有出現下載版本資訊,就代表你安裝成功了。
$ git --version
git version 2.24.3 (Apple Git-128)
在開始使用 Git 前,先移動目前的位置到要進行版本控制的目標資料夾
$ pwd # 目前所在位置
/Users/tsai
$ ls # 列出目前所在位置底下的所有資料夾與檔案
Applications Documents Library Music Pictures Public hello-world
Desktop Downloads Movies
$ cd Documents/jokesAll # 移動到 jokesAll 這個資料夾
使用 git init
才能讓 Git 對這個資料夾進行版本控制。
$ git init
Initialized empty Git repository in /Users/tsai/Documents/jokesAll/.git/
這時你會發現在你的 jokesAll 這個資料夾內,多了一個 .git
的隱藏檔。有了這個隱藏檔,就表示你的 Git 初始化成功啦!
使用 git status
這個好用的指令,他可以呈現目前所有檔案的 Git 狀態。告訴你許多有用的資訊喔!
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
joke1
nothing added to commit but untracked files present (use "git add" to track)
使用 git add
可以把檔案從本地端移到 Git 的暫存區
$ git add joke1 #或是
$ git add .
git add 檔案名稱
: 一次移動一個檔案git add .
: 一次移動全部檔案使用 git commit
把檔案從暫存區移動到儲存庫,並留下這次提交的一些訊息內容,例如:"This is my first joke!"
唯有把檔案放到儲存庫中,才能在 Git 中留下紀錄!
$ git commit -m "訊息內容"
在這之後,若想到什麼新的點子想放進 joke1,或是想到另一個全新的笑話,寫在 joke2,都可以用 git add
, git commit
,把檔案提交給 Git。
使用 git log
指令就能查看你 commit 的所有歷史紀錄。包含:版本號碼、是誰以及什麼時間提交等資訊。
$ git log
commit fb6232b78f5db742e2da3a7e2e4a00d96fa65e43 (HEAD -> master)
Author: XX <xxxxxx@gmail.com>
Date: Sun Jun 21 00:57:23 2020 +0800
create joke2
commit 8794f2c6b534156f0672ffc319a3546ef764aa18
Author: XX <xxxxxx@gmail.com>
Date: Sun Jun 21 00:24:15 2020 +0800
first commit
(END)
git log --oneline --graph
: 獲得較簡短的歷史紀錄資訊有了 commit 留下的紀錄,我們就能用 git checkout
加上其獨特的識別碼,讓我們的工作區回復到某個特定的版本。
$ git checkout {版本號}
假設今天你覺得第二次 commit 的內容不喜歡,想回到第一個版本時,就可以利用 git checkout
加上第一次的版本號,就能回到過去了。
$ git branch {分支名稱}
如果今天你想找你的朋友 h0w 哥一起幫你想更好笑的笑話。那就可以另開分支,意思就是複製一份現在的工作區域內容。這樣你們可以分頭進行而不會相互影響了。
$ git merge {new-feature}
今天 h0w 哥想出了不錯的點子,記錄在他分支上。你想把他的檔案合併進來,就可以使用 git merge
加上他的分支名稱,就能讓你的工作區包含他寫的新內容了。
而目前這些版本控制都是放在電腦內,若你想要讓更多人看見你的笑話。就可以使用 GitHub。
GitHub 簡言之就是雲端的 Git repository。
$ git remote add origin {網址} # 建立遠端的連線
$ git push -u origin master
利用 git push
指令,就可以把電腦裡的檔案上傳到 GitHub
$ git pull origin master
假設今天跟你一起合作工作的 h0w 哥,修改了一份檔案並上傳到 GitHub,若你想要獲得這份新的更動資料,就可以使用 git pull
指令,把遠端 master 分支的檔案拉下來到你的電腦裡。
以上就是基本的 Git 操作,多練習就能得心應手,做好檔案的版本控制囉!
在 GitHub 上管理分支的方法
Create a branch -> Add commits -> Open a Pull Request -> Discuss and review your code -> Deploy -> Merge
詳細資訊請參考:Understanding the GitHub flow
$ git commit --amend -m "{訊息}"
1. $ git log --oneline
2. $ git rebase -i {要回去的版本號}
3. 把 pick 改成 reword
4. 修改訊息內容,存檔離開
git reset HEAD^ --hard, --soft
詳細資料請參考:Git reset 的三種模式( soft mixed hard )比較
git checkout -- <file>
git checkout .
git branch -m <new brach name>
git checkout <遠端branch名稱>
此篇筆記為參加程式導師實驗計畫中,整理在 Lidemy [Git101] Git 超新手入門 的課程筆記。
Git 就是一種版本控制的系統。版本控制簡單來說就是進階版的檔案管理。我們平常管理資料夾與檔案的操作,包含最常見的複製、命名等。例如:HW1, HW2...; Work1-1, Work1-2...
版本控制不只是基本的新增、複製與刪除檔案,還能詳細紀錄檔案內容是誰以及什麼時候寫的,保留所有歷史紀錄。在不小心刪掉檔案後,還能找回來!不管是個人或團隊開發上使用 Git 進行版本控制,都相當方便!
可以使用 CLI (命令列介面) 或 GUI (圖形化介面),進行操作。著名的 GUI 例如:SourceTree, GitKraken 等。本篇筆記以 CLI 進行 Git 指令的介紹。
你有一個叫做菜哥的朋友,他有一個煩惱。因為他的笑話太多了,所以他目前都用文字檔記錄在電腦裡,可是變得越來越多之後很難紀錄,而且他的笑話是會演進的。會有版本一、版本二甚至到版本十,這樣他就要建立好多個不同的檔案,弄得他頭很痛。他希望你能教他用 Git 來做版本控制。
好心的你就要來教他 Git 的基本概念以及基礎的使用囉!
到官網下載 Git。
下載後,打開終端機,輸入 git --version
,若有出現下載版本資訊,就代表你安裝成功了。
$ git --version
git version 2.24.3 (Apple Git-128)
在開始使用 Git 前,先移動目前的位置到要進行版本控制的目標資料夾
$ pwd # 目前所在位置
/Users/tsai
$ ls # 列出目前所在位置底下的所有資料夾與檔案
Applications Documents Library Music Pictures Public hello-world
Desktop Downloads Movies
$ cd Documents/jokesAll # 移動到 jokesAll 這個資料夾
使用 git init
才能讓 Git 對這個資料夾進行版本控制。
$ git init
Initialized empty Git repository in /Users/tsai/Documents/jokesAll/.git/
這時你會發現在你的 jokesAll 這個資料夾內,多了一個 .git
的隱藏檔。有了這個隱藏檔,就表示你的 Git 初始化成功啦!
使用 git status
這個好用的指令,他可以呈現目前所有檔案的 Git 狀態。告訴你許多有用的資訊喔!
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
joke1
nothing added to commit but untracked files present (use "git add" to track)
使用 git add
可以把檔案從本地端移到 Git 的暫存區
$ git add joke1 #或是
$ git add .
git add 檔案名稱
: 一次移動一個檔案git add .
: 一次移動全部檔案使用 git commit
把檔案從暫存區移動到儲存庫,並留下這次提交的一些訊息內容,例如:"This is my first joke!"
唯有把檔案放到儲存庫中,才能在 Git 中留下紀錄!
$ git commit -m "訊息內容"
在這之後,若想到什麼新的點子想放進 joke1,或是想到另一個全新的笑話,寫在 joke2,都可以用 git add
, git commit
,把檔案提交給 Git。
使用 git log
指令就能查看你 commit 的所有歷史紀錄。包含:版本號碼、是誰以及什麼時間提交等資訊。
$ git log
commit fb6232b78f5db742e2da3a7e2e4a00d96fa65e43 (HEAD -> master)
Author: XX <xxxxxx@gmail.com>
Date: Sun Jun 21 00:57:23 2020 +0800
create joke2
commit 8794f2c6b534156f0672ffc319a3546ef764aa18
Author: XX <xxxxxx@gmail.com>
Date: Sun Jun 21 00:24:15 2020 +0800
first commit
(END)
git log --oneline --graph
: 獲得較簡短的歷史紀錄資訊有了 commit 留下的紀錄,我們就能用 git checkout
加上其獨特的識別碼,讓我們的工作區回復到某個特定的版本。
$ git checkout {版本號}
假設今天你覺得第二次 commit 的內容不喜歡,想回到第一個版本時,就可以利用 git checkout
加上第一次的版本號,就能回到過去了。
$ git branch {分支名稱}
如果今天你想找你的朋友 h0w 哥一起幫你想更好笑的笑話。那就可以另開分支,意思就是複製一份現在的工作區域內容。這樣你們可以分頭進行而不會相互影響了。
$ git merge {new-feature}
今天 h0w 哥想出了不錯的點子,記錄在他分支上。你想把他的檔案合併進來,就可以使用 git merge
加上他的分支名稱,就能讓你的工作區包含他寫的新內容了。
而目前這些版本控制都是放在電腦內,若你想要讓更多人看見你的笑話。就可以使用 GitHub。
GitHub 簡言之就是雲端的 Git repository。
$ git remote add origin {網址} # 建立遠端的連線
$ git push -u origin master
利用 git push
指令,就可以把電腦裡的檔案上傳到 GitHub
$ git pull origin master
假設今天跟你一起合作工作的 h0w 哥,修改了一份檔案並上傳到 GitHub,若你想要獲得這份新的更動資料,就可以使用 git pull
指令,把遠端 master 分支的檔案拉下來到你的電腦裡。
以上就是基本的 Git 操作,多練習就能得心應手,做好檔案的版本控制囉!
在 GitHub 上管理分支的方法
Create a branch -> Add commits -> Open a Pull Request -> Discuss and review your code -> Deploy -> Merge
詳細資訊請參考:Understanding the GitHub flow
$ git commit --amend -m "{訊息}"
1. $ git log --oneline
2. $ git rebase -i {要回去的版本號}
3. 把 pick 改成 reword
4. 修改訊息內容,存檔離開
git reset HEAD^ --hard, --soft
詳細資料請參考:Git reset 的三種模式( soft mixed hard )比較
git checkout -- <file>
git checkout .
git branch -m <new brach name>
git checkout <遠端branch名稱>
此篇筆記為參加程式導師實驗計畫中,整理在 Lidemy [CMD101] Command Line 超新手入門 的課程筆記。
命令列介面(英語:Command-Line Interface,縮寫:CLI)是在圖形使用者介面得到普及之前使用最為廣泛的使用者介面,它通常不支援滑鼠,用戶通過鍵盤輸入指令,電腦接收到指令後,予以執行。也有人稱之為文字使用者介面(character user interface, CUI)。by Wiki-命令列介面
簡言之,就是以文字的方式跟電腦溝通。
而以下常見的名稱都是指 CLI,只是在不同作業系統下,有不同稱呼:
關於更多 CLI 的介紹,可以參考:
在 GUI 盛行的年代,為什麼要學 CLI 呢?
使用 CLI 有以下的好處:
舉簡單的例子來說,如果你只會 GUI,但今天要用別人的電腦工作,而對方沒有安裝相關的 GUI,或是他安裝的 GUI 跟你的不同,就得再去下載你熟悉的 GUI,或花時間去了解對方的 GUI 如何操作;又如果連線到只能用 terminal 工作的 server 時......,在這些情況下,還是會 CLI 會比較好。
而到底是 CLI 還是 GUI 比較好,其實兩者各有優點與缺點,端看使用情境。關於兩者的比較,可以參見以下文章:
以 Mac OS 為例。參考以下文章建置環境:
其中,安裝字體的部分,操作指令為:
# 第一次使用 homebrew 安裝字型
# 現在已經不使用 brew tap caskroom/fonts
brew tap homebrew/cask-fonts
# 安裝字體指令
brew cask install font-hack-nerd-font
先關閉 iTerm2,才能在 preference 中選擇該字體。
最後的結果
pwd
:Print Working Directory,印出從根目錄到現在的所在位置路徑ls
:LiSt,印出現在資料夾下的資料夾與檔案註:藍色的是資料夾,白色的是檔案
ls -l
: 顯示檔案與目錄的詳細資訊ls -a
: 顯示隱藏的檔案與目錄.
來表示ls -al
: 顯示隱藏檔案與目錄的詳細資訊ls -l
與 ls -a
的組合關於 ls
的詳細使用方法,可以參考:
可以使用相對路徑或絕對路徑
cd
:Change Directory,切換資料夾cd ./
: 在同一層當中移動cd ..
: 回到上一層cd ~
: 回到起始目錄cd /
: 回到根目錄註:起始目錄與根目錄並不相同
man
:MANual,列出使用指令的詳細資訊,包括可以帶什麼參數q
離開touch
:若檔案已存在則會更改檔案的修改時間,若檔案不存在則是新增該檔案rm
:RoMove,刪除檔案(非資料夾)rm -r
/ rmdir
:刪除資料夾rm -f
:強制刪除檔案(請慎用!)mkdir
:MaKe DIRectory,建立新資料夾mv
:MoVe,mv 檔案 資料夾
為移動檔案;mv 檔案 新檔案
為更改檔案名稱cp
:CoPy,複製檔案(非資料夾)cp -r
:複製資料夾vim
:編輯檔案文字內容i
為 insert modeesc
為 normal mode:q
為離開編輯器:wq
為儲存後離開編輯器:qa!
為不儲存就離開編輯器關於 Vim 如何操作,可以參考以下文章:
grep 字詞 檔案
:搜尋檔案內的特定字詞wget 檔案網址
:下載檔案若電腦內沒有 wget
指令的話,請先使用 homebrew
套件安裝
brew install wget
關於 wget
的詳細使用方法,可參考:
curl
:送出 request,可以用來測試 API取得 Response Header 以及網頁內容
關於 curl 的詳細使用方法,可參考:
Output > Input
:將前面指令的 Output 作為後面檔案的 Input將 ls -l
的資訊輸出到 result 這個檔案
Output >> Input
:將前面指令的 Output 新增(append) 到後面指令或檔案若原本只用 >
會覆蓋所有內容,使用 >>
可以把內容新增到後面
Output | Input
:將前面指令的 Output 作為後面指令的 Input印出 text 的內容後,再抓出 3 這個字
一開始使用 CLI 會很不習慣,但打久了,那些常用的指令就能記起來,對於電腦的 response 也比較能看懂。尤其在幫 iTerm2 安裝管理套件與主題後,畫面美觀許多,也更好上手。用起來心情變得不一樣。可謂工欲善其事必先利其器吧(笑)。
]]>此篇筆記為參加程式導師實驗計畫中,整理在 Lidemy [CMD101] Command Line 超新手入門 的課程筆記。
命令列介面(英語:Command-Line Interface,縮寫:CLI)是在圖形使用者介面得到普及之前使用最為廣泛的使用者介面,它通常不支援滑鼠,用戶通過鍵盤輸入指令,電腦接收到指令後,予以執行。也有人稱之為文字使用者介面(character user interface, CUI)。by Wiki-命令列介面
簡言之,就是以文字的方式跟電腦溝通。
而以下常見的名稱都是指 CLI,只是在不同作業系統下,有不同稱呼:
關於更多 CLI 的介紹,可以參考:
在 GUI 盛行的年代,為什麼要學 CLI 呢?
使用 CLI 有以下的好處:
舉簡單的例子來說,如果你只會 GUI,但今天要用別人的電腦工作,而對方沒有安裝相關的 GUI,或是他安裝的 GUI 跟你的不同,就得再去下載你熟悉的 GUI,或花時間去了解對方的 GUI 如何操作;又如果連線到只能用 terminal 工作的 server 時......,在這些情況下,還是會 CLI 會比較好。
而到底是 CLI 還是 GUI 比較好,其實兩者各有優點與缺點,端看使用情境。關於兩者的比較,可以參見以下文章:
以 Mac OS 為例。參考以下文章建置環境:
其中,安裝字體的部分,操作指令為:
# 第一次使用 homebrew 安裝字型
# 現在已經不使用 brew tap caskroom/fonts
brew tap homebrew/cask-fonts
# 安裝字體指令
brew cask install font-hack-nerd-font
先關閉 iTerm2,才能在 preference 中選擇該字體。
最後的結果
pwd
:Print Working Directory,印出從根目錄到現在的所在位置路徑ls
:LiSt,印出現在資料夾下的資料夾與檔案註:藍色的是資料夾,白色的是檔案
ls -l
: 顯示檔案與目錄的詳細資訊ls -a
: 顯示隱藏的檔案與目錄.
來表示ls -al
: 顯示隱藏檔案與目錄的詳細資訊ls -l
與 ls -a
的組合關於 ls
的詳細使用方法,可以參考:
可以使用相對路徑或絕對路徑
cd
:Change Directory,切換資料夾cd ./
: 在同一層當中移動cd ..
: 回到上一層cd ~
: 回到起始目錄cd /
: 回到根目錄註:起始目錄與根目錄並不相同
man
:MANual,列出使用指令的詳細資訊,包括可以帶什麼參數q
離開touch
:若檔案已存在則會更改檔案的修改時間,若檔案不存在則是新增該檔案rm
:RoMove,刪除檔案(非資料夾)rm -r
/ rmdir
:刪除資料夾rm -f
:強制刪除檔案(請慎用!)mkdir
:MaKe DIRectory,建立新資料夾mv
:MoVe,mv 檔案 資料夾
為移動檔案;mv 檔案 新檔案
為更改檔案名稱cp
:CoPy,複製檔案(非資料夾)cp -r
:複製資料夾vim
:編輯檔案文字內容i
為 insert modeesc
為 normal mode:q
為離開編輯器:wq
為儲存後離開編輯器:qa!
為不儲存就離開編輯器關於 Vim 如何操作,可以參考以下文章:
grep 字詞 檔案
:搜尋檔案內的特定字詞wget 檔案網址
:下載檔案若電腦內沒有 wget
指令的話,請先使用 homebrew
套件安裝
brew install wget
關於 wget
的詳細使用方法,可參考:
curl
:送出 request,可以用來測試 API取得 Response Header 以及網頁內容
關於 curl 的詳細使用方法,可參考:
Output > Input
:將前面指令的 Output 作為後面檔案的 Input將 ls -l
的資訊輸出到 result 這個檔案
Output >> Input
:將前面指令的 Output 新增(append) 到後面指令或檔案若原本只用 >
會覆蓋所有內容,使用 >>
可以把內容新增到後面
Output | Input
:將前面指令的 Output 作為後面指令的 Input印出 text 的內容後,再抓出 3 這個字
一開始使用 CLI 會很不習慣,但打久了,那些常用的指令就能記起來,對於電腦的 response 也比較能看懂。尤其在幫 iTerm2 安裝管理套件與主題後,畫面美觀許多,也更好上手。用起來心情變得不一樣。可謂工欲善其事必先利其器吧(笑)。
]]>使用 v-model
可以對表單元素 <input>
、<textarea>
及 <select>
進行資料的雙向綁定。
雙向綁定的意思是,data
驅動 view
,也能從 view
改變 data
。
v-model
其實是一種語法糖 (syntax sugar),結合 v-bind
(data binding) 與 v-on
(event handling)。
v-model
針對不同的表單元素使用不同的屬性 property 與事件:
text
和 textarea
元素使用 value
property 和 input
事件checkbox
和 radio
使用 checked
property 和 change
事件;select
元素將 value 作為 prop
並將 change
作為事件v-model
會忽略所有表單元素的 value
、checked
、selected
這些屬性 attribute 的初始值。因此必須在一開始建立 Vue 實體時的 data
內宣告,才能達到響應式互動。
中文、日文或是韓文的輸入法會需要將多個字組合後才會變為一個完整的字,例如中文的嗨就需要鍵入ㄏㄞˋ後按下 Enter 鍵才會輸入, v-model
並不會在拼音時就更新資料,而是會在按下 Enter 後才更新,因此如果想要讓資料在拼音時即時響應,可以直接使用 input
事件實作。
<div>
<button @click="msg=''">Clear</button>
<input placeholder="Use IME" :value="msg" @input="msg=$event.target.value">
{{msg}}
</div>
<input type="text">
text
綁定的是字串
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
<textarea>
textarea
綁定的是字串
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
<input type="checkbox">
單一 checkbox
綁定的是布林值,判斷這個選項是否有勾選
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
多個 checkbox
綁定的是陣列,當有勾選時,綁定的資料陣列會加上這個 input
標籤的 value
屬性值
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
new Vue({
el: '...',
data: {
checkedNames: []
}
})
<input type="radio">
radio
綁定的是字串
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
<select>
單選 select
綁定的是字串
<div id="example-5">
<select v-model="selected">
<option disabled value="">請選擇</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
new Vue({
el: '...',
data: {
selected: ''
}
})
如果初始值沒有符合任何的選項時, select
標籤會處於未選擇的狀態,也就是選項框中沒有任何值,在 IOS 下會有問題,因此最好的方法就是增加一個初始的選項,像是 <option disabled value="">Please select one</option>
來解決此問題。
複選 select
(加上 multiple
屬性) 綁定的是陣列
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br>
<span>Selected: {{ selected }}</span>
v-for
渲染動態選項<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
new Vue({
el: '...',
data: {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
})
把 value
動態綁定在 Vue 實體中的資料屬性上
<input type="checkbox">
checkbox
使用 true-value
及 false-value
分別綁定勾選及未勾選時的資料
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no"
>
// when checked:
vm.toggle === 'yes'
// when unchecked:
vm.toggle === 'no'
這裡的 true-value
和 false-value
attribute 並不會影響輸入控件的 value
attribute,因為瀏覽器在提交表單時不會包含未被選中的複選框。如果要確保表單中這兩個值中的一個能夠被提交,(即“yes”或“no”),請改用單選按鈕 radio
。
<input type="radio">
<input type="radio" v-model="pick" v-bind:value="a">
// when checked:
vm.pick === vm.a
<select>
<select v-model="selected">
<!-- inline object literal -->
<option v-bind:value="{ number: 123 }">123</option>
</select>
// when selected:
typeof vm.selected // => 'object'
vm.selected.number // => 123
.lazy
原本的 v-model
會在 input
事件觸發時更新資料,加上 .lazy
修飾符後,更新的時間點會被延到 change
事件時。因此如果加上 .lazy
,要在離開輸入框時才會更新資料
<!-- synced after "change" instead of "input" -->
<input v-model.lazy="msg">
.number
如果想讓輸入框的值其型別為數字,必須要使用 .number
修飾符
因為 HTML 的輸入框就算是
type="number"
,輸入值的型別也還是字串
<input v-model.number="age" type="number">
.trim
去除首尾空白
<input v-model.trim="msg">
使用 v-model
可以對表單元素 <input>
、<textarea>
及 <select>
進行資料的雙向綁定。
雙向綁定的意思是,data
驅動 view
,也能從 view
改變 data
。
v-model
其實是一種語法糖 (syntax sugar),結合 v-bind
(data binding) 與 v-on
(event handling)。
v-model
針對不同的表單元素使用不同的屬性 property 與事件:
text
和 textarea
元素使用 value
property 和 input
事件checkbox
和 radio
使用 checked
property 和 change
事件;select
元素將 value 作為 prop
並將 change
作為事件v-model
會忽略所有表單元素的 value
、checked
、selected
這些屬性 attribute 的初始值。因此必須在一開始建立 Vue 實體時的 data
內宣告,才能達到響應式互動。
中文、日文或是韓文的輸入法會需要將多個字組合後才會變為一個完整的字,例如中文的嗨就需要鍵入ㄏㄞˋ後按下 Enter 鍵才會輸入, v-model
並不會在拼音時就更新資料,而是會在按下 Enter 後才更新,因此如果想要讓資料在拼音時即時響應,可以直接使用 input
事件實作。
<div>
<button @click="msg=''">Clear</button>
<input placeholder="Use IME" :value="msg" @input="msg=$event.target.value">
{{msg}}
</div>
<input type="text">
text
綁定的是字串
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
<textarea>
textarea
綁定的是字串
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
<input type="checkbox">
單一 checkbox
綁定的是布林值,判斷這個選項是否有勾選
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
多個 checkbox
綁定的是陣列,當有勾選時,綁定的資料陣列會加上這個 input
標籤的 value
屬性值
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
new Vue({
el: '...',
data: {
checkedNames: []
}
})
<input type="radio">
radio
綁定的是字串
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
<select>
單選 select
綁定的是字串
<div id="example-5">
<select v-model="selected">
<option disabled value="">請選擇</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
new Vue({
el: '...',
data: {
selected: ''
}
})
如果初始值沒有符合任何的選項時, select
標籤會處於未選擇的狀態,也就是選項框中沒有任何值,在 IOS 下會有問題,因此最好的方法就是增加一個初始的選項,像是 <option disabled value="">Please select one</option>
來解決此問題。
複選 select
(加上 multiple
屬性) 綁定的是陣列
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br>
<span>Selected: {{ selected }}</span>
v-for
渲染動態選項<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
new Vue({
el: '...',
data: {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
})
把 value
動態綁定在 Vue 實體中的資料屬性上
<input type="checkbox">
checkbox
使用 true-value
及 false-value
分別綁定勾選及未勾選時的資料
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no"
>
// when checked:
vm.toggle === 'yes'
// when unchecked:
vm.toggle === 'no'
這裡的 true-value
和 false-value
attribute 並不會影響輸入控件的 value
attribute,因為瀏覽器在提交表單時不會包含未被選中的複選框。如果要確保表單中這兩個值中的一個能夠被提交,(即“yes”或“no”),請改用單選按鈕 radio
。
<input type="radio">
<input type="radio" v-model="pick" v-bind:value="a">
// when checked:
vm.pick === vm.a
<select>
<select v-model="selected">
<!-- inline object literal -->
<option v-bind:value="{ number: 123 }">123</option>
</select>
// when selected:
typeof vm.selected // => 'object'
vm.selected.number // => 123
.lazy
原本的 v-model
會在 input
事件觸發時更新資料,加上 .lazy
修飾符後,更新的時間點會被延到 change
事件時。因此如果加上 .lazy
,要在離開輸入框時才會更新資料
<!-- synced after "change" instead of "input" -->
<input v-model.lazy="msg">
.number
如果想讓輸入框的值其型別為數字,必須要使用 .number
修飾符
因為 HTML 的輸入框就算是
type="number"
,輸入值的型別也還是字串
<input v-model.number="age" type="number">
.trim
去除首尾空白
<input v-model.trim="msg">
v-for
使用 v-for
迭代陣列或物件中的每個元素。
<ul id="example-1">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
可以用 of
替代 in
作為分隔符。請參考 MDN-for...of
<div id="v-for-object" class="demo">
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
</div>
</div>
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
物件的巡覽是使用
Object.keys()
, 它不保證順序會跟原本的相同,例如 Object.keys({2: 'two', 0: 'zero', 1: 'one' }) 出來的結果會是 [ "0", "1", "2" ] ,因此 v-for 不能保證其順序。
<div>
<span v-for="n in 10">{{ n }}</span>
</div>
<template>
v-for
可以使用 <template>
一次渲染多個元素。
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
:key
屬性決定復用行為當 v-for
的陣列或是物件改變時, Vue 會去比對修改前及修改後的元素是否可以復用,以復用元素的方式減少建立及銷毀元素增加效能。
這時加上 key
屬性可以讓 Vue 有個依據來辨識每個節點,因此在使用 v-for
的時候最好為每個節點加上 key
屬性,並且每個節點的 key
值最好是唯一。
不要使用物件或陣列等非基本類型值作為
v-for
的key
。請用字串或數值類型的值。
v-for
迭代的資料可以為使用 computed
或 methods
處理後的結果。
<li v-for="n in evenNumbers">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
但如果資料是需要巢狀使用 v-for
的話,computed
就派不上用場了,因為 computed
只能設定實體中的資料屬性,這時可以使用 methods
來達成需求。
<ul v-for="set in sets">
<li v-for="n in even(set)">{{ n }}</li>
</ul>
data: {
sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
v-for
與 v-if
一起使用當它們處於同一節點,v-for
的優先級比 v-if
更高,這代表 v-if
將分別重複運行於每個 v-for
迴圈中。
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
不推薦在同一元素上使用
v-if
和v-for
。更多細節可參考風格指南。
v-for
使用 v-for
迭代陣列或物件中的每個元素。
<ul id="example-1">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
可以用 of
替代 in
作為分隔符。請參考 MDN-for...of
<div id="v-for-object" class="demo">
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
</div>
</div>
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
物件的巡覽是使用
Object.keys()
, 它不保證順序會跟原本的相同,例如 Object.keys({2: 'two', 0: 'zero', 1: 'one' }) 出來的結果會是 [ "0", "1", "2" ] ,因此 v-for 不能保證其順序。
<div>
<span v-for="n in 10">{{ n }}</span>
</div>
<template>
v-for
可以使用 <template>
一次渲染多個元素。
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
:key
屬性決定復用行為當 v-for
的陣列或是物件改變時, Vue 會去比對修改前及修改後的元素是否可以復用,以復用元素的方式減少建立及銷毀元素增加效能。
這時加上 key
屬性可以讓 Vue 有個依據來辨識每個節點,因此在使用 v-for
的時候最好為每個節點加上 key
屬性,並且每個節點的 key
值最好是唯一。
不要使用物件或陣列等非基本類型值作為
v-for
的key
。請用字串或數值類型的值。
v-for
迭代的資料可以為使用 computed
或 methods
處理後的結果。
<li v-for="n in evenNumbers">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
但如果資料是需要巢狀使用 v-for
的話,computed
就派不上用場了,因為 computed
只能設定實體中的資料屬性,這時可以使用 methods
來達成需求。
<ul v-for="set in sets">
<li v-for="n in even(set)">{{ n }}</li>
</ul>
data: {
sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
v-for
與 v-if
一起使用當它們處於同一節點,v-for
的優先級比 v-if
更高,這代表 v-if
將分別重複運行於每個 v-for
迴圈中。
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
不推薦在同一元素上使用
v-if
和v-for
。更多細節可參考風格指南。
設定 v-if
的元素只會在其 Value 為 Truthy 時被渲染。
<div id="app">
<span v-if="isA">A</span>
</div>
var vm = new Vue({
el: '#app',
data: {
isA: true
}
});
當 isA 為 true 時 <span>A</span>
會出現在畫面上,但當 isA 為 false 時,<span>A</span>
整個 DOM 會不存在於 HTML 內。
可以搭配 v-else-if
和 v-else
來做判斷運算。
<div id="app">
<div v-if="type === A">A</div>
<div v-else-if="type === B">B</div>
<div v-else>C</div>
</div>
var vm = new Vue({
el: '#app',
data: {
type: "B"
}
});
v-else
沒有 Value ,它是一個單純的 Directive。v-else-if
可以使用多次。v-else-if
跟 v-else
相同必須緊跟在 v-if
或是 v-else-if
設置元素之後,而且必須是同一層的元素。因為 v-if
只能使用在一個元素上,所以當需要多個元素做切換時,可以使用 <template>
這個標籤把多個元素包裹起來。
<template>
標籤只做包裹元素之用,實際被渲染出來時,並不存在,因此不影響原本網頁元素的配置。
<span v-if="isA">A1</span>
<span v-if="isA">A2</span>
<span v-if="isA">A3</span>
等同於下例
<template v-if="isA">
<span>A1</span>
<span>A2</span>
<span>A3</span>
</template>
Vue 會儘可能高效地渲染元素。如果是相同的結構則會繼續沿用原本的 DOM 元素,並不會重新渲染,用這個方法減少重新渲染所需的資源以提高效能。
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
切換 loginType 將不會清除使用者已經輸入的內容。因為兩個模板使用了相同的元素,<input>
不會被替換掉,只是替換了它的 placeholder
。
所以 Vue 提供了一種方式來表達“這兩個元素是完全獨立的,不要重複使用它們”。只需要添加一個具有唯一值的 key
attribute 即可:
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
v-show
跟 v-if
在頁面上的效果相同,都是決定元素是否顯示,但其渲染的方式不同。
v-if
: 真正的建立及銷毀元素。v-show
: 元素始終會被渲染並保留在 DOM 中,只是使用 display 的樣式屬性切換顯示效果。<span v-show="isA">A</span>
等同於下例:
<span style="display: none;">A</span>
v-show
不支持 <template>
元素,也不支持 v-else
。比較兩者在渲染時所需消耗的資源與效能:
v-show
> v-if
v-if
> v-show
設定 v-if
的元素只會在其 Value 為 Truthy 時被渲染。
<div id="app">
<span v-if="isA">A</span>
</div>
var vm = new Vue({
el: '#app',
data: {
isA: true
}
});
當 isA 為 true 時 <span>A</span>
會出現在畫面上,但當 isA 為 false 時,<span>A</span>
整個 DOM 會不存在於 HTML 內。
可以搭配 v-else-if
和 v-else
來做判斷運算。
<div id="app">
<div v-if="type === A">A</div>
<div v-else-if="type === B">B</div>
<div v-else>C</div>
</div>
var vm = new Vue({
el: '#app',
data: {
type: "B"
}
});
v-else
沒有 Value ,它是一個單純的 Directive。v-else-if
可以使用多次。v-else-if
跟 v-else
相同必須緊跟在 v-if
或是 v-else-if
設置元素之後,而且必須是同一層的元素。因為 v-if
只能使用在一個元素上,所以當需要多個元素做切換時,可以使用 <template>
這個標籤把多個元素包裹起來。
<template>
標籤只做包裹元素之用,實際被渲染出來時,並不存在,因此不影響原本網頁元素的配置。
<span v-if="isA">A1</span>
<span v-if="isA">A2</span>
<span v-if="isA">A3</span>
等同於下例
<template v-if="isA">
<span>A1</span>
<span>A2</span>
<span>A3</span>
</template>
Vue 會儘可能高效地渲染元素。如果是相同的結構則會繼續沿用原本的 DOM 元素,並不會重新渲染,用這個方法減少重新渲染所需的資源以提高效能。
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
切換 loginType 將不會清除使用者已經輸入的內容。因為兩個模板使用了相同的元素,<input>
不會被替換掉,只是替換了它的 placeholder
。
所以 Vue 提供了一種方式來表達“這兩個元素是完全獨立的,不要重複使用它們”。只需要添加一個具有唯一值的 key
attribute 即可:
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
v-show
跟 v-if
在頁面上的效果相同,都是決定元素是否顯示,但其渲染的方式不同。
v-if
: 真正的建立及銷毀元素。v-show
: 元素始終會被渲染並保留在 DOM 中,只是使用 display 的樣式屬性切換顯示效果。<span v-show="isA">A</span>
等同於下例:
<span style="display: none;">A</span>
v-show
不支持 <template>
元素,也不支持 v-else
。比較兩者在渲染時所需消耗的資源與效能:
v-show
> v-if
v-if
> v-show
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
})
computed 內的 reversedMessage function 就是一個 getter method,每當 message 的值有變化時,便重新計算把值存回 reversedMessage
computed 預設只有 getter 屬性,但也可以經由以下方法重設 setter 屬性。
<div id="app">
<p>fullName (computed):{{ fullName }}</p>
</div>
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
當再次運行 vm.fullName = 'John Doe' 時,setter 會被調用,vm.firstName 和 vm.lastName 也會相對應地被更新。
更多關於 getter 和 setter 的知識可以參考這篇文章:那些關於 Vue 的小細節 - Computed 中 getter 和 setter 觸發的時間點
使用 methods 改寫上例,也能得到相同的效果。
<p>Reversed message: "{{ reverseMessage() }}"</p>
methods: {
reverseMessage: function () {
return this.message.split('').reverse().join('')
}
}
不同的是,computed 是根據相依的資料改變時才做計算,而 method 是不管有無相依都會計算,只要每次重新渲染畫面就會執行一次。
<div id="app">
<p>message:{{ message }}</p>
<p>now (computed):{{ now }}</p>
<p>getNow (method):{{ getNow() }}</p>
</div>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello World!',
},
computed: {
now: function() {
return Date.now();
},
},
methods: {
getNow: function() {
return Date.now();
},
},
});
在一開始都會執行 computed 和 methods 的時候,沒有任何差異。
當改變 message 時,由於 now 這個計算屬性沒有用到任何相依的資料,因此不重新計算取值;但 getNow 是方法,無論是否有相依,只要有變動都會重新計算。
<div id="demo">{{ fullName }}</div>
使用 watch
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
使用 computed
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
使用 watch:多了一個 fullName 屬性,而且其相依的屬性有幾個,就得多幾個 watcher 監聽。
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
})
computed 內的 reversedMessage function 就是一個 getter method,每當 message 的值有變化時,便重新計算把值存回 reversedMessage
computed 預設只有 getter 屬性,但也可以經由以下方法重設 setter 屬性。
<div id="app">
<p>fullName (computed):{{ fullName }}</p>
</div>
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
當再次運行 vm.fullName = 'John Doe' 時,setter 會被調用,vm.firstName 和 vm.lastName 也會相對應地被更新。
更多關於 getter 和 setter 的知識可以參考這篇文章:那些關於 Vue 的小細節 - Computed 中 getter 和 setter 觸發的時間點
使用 methods 改寫上例,也能得到相同的效果。
<p>Reversed message: "{{ reverseMessage() }}"</p>
methods: {
reverseMessage: function () {
return this.message.split('').reverse().join('')
}
}
不同的是,computed 是根據相依的資料改變時才做計算,而 method 是不管有無相依都會計算,只要每次重新渲染畫面就會執行一次。
<div id="app">
<p>message:{{ message }}</p>
<p>now (computed):{{ now }}</p>
<p>getNow (method):{{ getNow() }}</p>
</div>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello World!',
},
computed: {
now: function() {
return Date.now();
},
},
methods: {
getNow: function() {
return Date.now();
},
},
});
在一開始都會執行 computed 和 methods 的時候,沒有任何差異。
當改變 message 時,由於 now 這個計算屬性沒有用到任何相依的資料,因此不重新計算取值;但 getNow 是方法,無論是否有相依,只要有變動都會重新計算。
<div id="demo">{{ fullName }}</div>
使用 watch
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
使用 computed
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
使用 watch:多了一個 fullName 屬性,而且其相依的屬性有幾個,就得多幾個 watcher 監聽。
修飾符依照功能可以分為下面兩類:
Vue 提供一些常用處理的修飾符,讓我們可以直接設定在屬性上,除了減少程式碼量外,最大的目的是讓方法盡量只是單純處理邏輯,而不用多去擔心相關的 DOM 處理。
.stop
: 呼叫 event.stopPropagation(),停止觸發上層 DOM 元素事件.prevent
: 呼叫 event.preventDefault(),避免瀏覽器預設行為.capture
: 不管觸發事件的目標是否是下層, 設定 capture
的事件一定會先觸發.self
: 僅觸發自己範圍的事件,不包含子層.stop
修飾符.stop
修飾符會叫用 event.stopPropagation()
,stopPropagation
方法會停止事件的冒泡。
在預設的情況下,觸發了下層 DOM 元素的事件後,會往上叫用其他 DOM 元素的事件,可是當加上 stopPropagation
後,就只會到目前的事件為止,不會往父層觸發。
Js 預設的事件傳遞方向為向上冒泡(event bubbling),也就是從內到外執行。
<div class="outer" @click="alert('outer, none-once, default')">
outer
<div class="middle" target="_blank" @click="alert('middle, none-capture, default')">
middle
<div class="inner" target="_blank" @click.stop="alert('inner, not trigger upper except capture')">
inner, stopPropagation(not trigger upper except capture)
</div>
</div>
</div>
當按下 inner 後, middle 跟 outer 的事件會因為 inner 的 click 加入了 .stop
修飾符而不被觸發。
.prevent
修飾符.prevent
修飾符會叫用 event.preventDefault()
,preventDefault
會停止瀏覽器的預設行為。例如: checkbox 的勾選/取消勾選行為、 form 的 submit 送出表單行為等,都會因為 preventDefault
而沒有觸發。
<a class="inner" href="https://developer.mozilla.org/" target="_blank"
@click.prevent="alert('inner2, none-passive, default, not open new page')">
inner2, none-passive & preventDefault(not open new page)
</a>
原本按下超連結後會直接開啟 href 設定的頁面,可是因為 click 事件有設定 .prevent
修飾符,所以不會開啟連結。
.capture
修飾符不管觸發事件的 DOM 元素是誰,使用 .capture
修飾符的事件會優先觸發。
<div class="middle" target="_blank" @click.capture="alert('middle, capture')" @click="alert('middle, none-capture, default')">
middle, capture & none-capture & self
<a class="inner1" href="https://www.mozilla.org" target="_blank" @click="alert('inner1, passive, open new page')">
inner1, passive & preventDefault(which is not allowed)
</a>
</div>
當按下 inner1 時,可以看到 alert('middle, capture') 先被觸發,再來是 alert('inner1, passive, open new page') ,最後才是 alert('middle, none-capture, default') ,由此現象可知 .capture
會打破由內而外的事件傳遞規則,先行觸發。
關於捕獲與冒泡事件,可參考以下文章:
.self
修飾符.self
修飾符只會觸發自己範圍內的事件,不包含子元素。
<div class="middle" target="_blank" @click.self="alert('middle, self')">
middle, self
<div class="inner4" target="_blank" @click="alert('inner4')">
inner4
</div>
</div>
.once
修飾符.once
修飾符使事件只會觸發一次。
<div class="outer" @click.once="alert('outer, once')" @click="alert('outer, none-once, default')">
outer
</div>
當點擊第一次的時候兩個事件都會被觸發,可是之後都只有沒有 .once
修飾符的事件會被觸發。
.passive
修飾符.passive
修飾符會無視 event.preventDefault()
的功能,只要加上此修飾符就一定會觸發瀏覽器的預設行為。
不要把 .passive
和 .prevent
一起使用,因為 .prevent
將會被忽略。
<a class="inner1" href="https://www.mozilla.org" target="_blank" @click.passive.prevent="alert('inner1, passive, open new page')">
inner1, passive & preventDefault(which is not allowed)
</a>
由於 .passive
會使 preventDefault
無效,所以就算在 .passive
後面加上 .prevent
還是會開啟連結頁面。
使用修飾符時,順序很重要;相應的程式碼會以同樣的順序產生。因此,用 v-on:click.prevent.self
會阻止所有的點擊,而 v-on:click.self.prevent
只會阻止對元素自身的點擊。
監聽鍵盤事件的特定鍵值。
注意:keyCode 的事件用法已經被廢棄了並可能不會被最新的瀏覽器支持。
只要是在 KeyboardEvent.key 上的按鍵名稱都可以用 kebab-case 的方式設定在修飾符上。
<input v-on:keyup.page-down="onPageDown">
Vue 會在函數中使用 $event.key === 'PageDown' 判斷式決定是否為目標按鈕
為了在必要的情況下支持舊瀏覽器,Vue 提供了絕大多數常用的按鍵碼的別名:
.enter
.tab
.delete
(Delete 跟 Backspace 按鍵都會觸發).esc
.space
.up
.down
.left
.right
在 Vue.config.KeyCodes
物件中設定自定義的別名:
<div id="app">
<input @keyup.f1="what='keyup.f1'" @keyup.up="what='keyup.up'" @keyup.insert-mode="what='keyup.insert-mode'" />
<span>You trigger event by <strong>{{what}}</strong></span>
</div>
Vue.config.keyCodes = {
f1: 112, // f1
up: [38, 87], // 數字鍵 8 跟 w
// insertMode: 73, // won't work
"insert-mode": 73 // i
};
僅在按下相應按鍵時才觸發滑鼠或鍵盤事件的監聽器
.ctrl
.alt
.shift
.meta
<!-- Alt + C -->
<input v-on:keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div v-on:click.ctrl="doSomething">Do something</div>
使用系統修飾鍵設定修飾符的 keyup
事件只有在該系統鍵按住的狀態下才會觸發事件,例如:
<div id="app">
<input"
@keyup.ctrl="what='keyup.ctrl'"
@keyup.17="what='keyup.17'"
/>
<span>You trigger event by <strong>{{what}}</strong></span>
</div>
@keyup.ctrl
: 要在按住 Ctrl 鍵的狀況下釋放其他按紐才會觸發。@keyup.17
: 只要釋放 Ctrl 按鈕就會觸發。.exact
修飾符設定 .exact
修飾符代表一定要完全符合系統修飾鍵的設定才會觸發事件
<!-- 即使 Alt 或 Shift 被一同按下時也會觸發 -->
<button v-on:click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的時候才觸發 -->
<button v-on:click.ctrl.exact="onCtrlClick">A</button>
<!-- 沒有任何系統修飾符被按下的時候才觸發 -->
<button v-on:click.exact="onClick">A</button>
Vue 提供左中右三個滑鼠按鍵的修飾符
.left
.right
.middle
修飾符依照功能可以分為下面兩類:
Vue 提供一些常用處理的修飾符,讓我們可以直接設定在屬性上,除了減少程式碼量外,最大的目的是讓方法盡量只是單純處理邏輯,而不用多去擔心相關的 DOM 處理。
.stop
: 呼叫 event.stopPropagation(),停止觸發上層 DOM 元素事件.prevent
: 呼叫 event.preventDefault(),避免瀏覽器預設行為.capture
: 不管觸發事件的目標是否是下層, 設定 capture
的事件一定會先觸發.self
: 僅觸發自己範圍的事件,不包含子層.stop
修飾符.stop
修飾符會叫用 event.stopPropagation()
,stopPropagation
方法會停止事件的冒泡。
在預設的情況下,觸發了下層 DOM 元素的事件後,會往上叫用其他 DOM 元素的事件,可是當加上 stopPropagation
後,就只會到目前的事件為止,不會往父層觸發。
Js 預設的事件傳遞方向為向上冒泡(event bubbling),也就是從內到外執行。
<div class="outer" @click="alert('outer, none-once, default')">
outer
<div class="middle" target="_blank" @click="alert('middle, none-capture, default')">
middle
<div class="inner" target="_blank" @click.stop="alert('inner, not trigger upper except capture')">
inner, stopPropagation(not trigger upper except capture)
</div>
</div>
</div>
當按下 inner 後, middle 跟 outer 的事件會因為 inner 的 click 加入了 .stop
修飾符而不被觸發。
.prevent
修飾符.prevent
修飾符會叫用 event.preventDefault()
,preventDefault
會停止瀏覽器的預設行為。例如: checkbox 的勾選/取消勾選行為、 form 的 submit 送出表單行為等,都會因為 preventDefault
而沒有觸發。
<a class="inner" href="https://developer.mozilla.org/" target="_blank"
@click.prevent="alert('inner2, none-passive, default, not open new page')">
inner2, none-passive & preventDefault(not open new page)
</a>
原本按下超連結後會直接開啟 href 設定的頁面,可是因為 click 事件有設定 .prevent
修飾符,所以不會開啟連結。
.capture
修飾符不管觸發事件的 DOM 元素是誰,使用 .capture
修飾符的事件會優先觸發。
<div class="middle" target="_blank" @click.capture="alert('middle, capture')" @click="alert('middle, none-capture, default')">
middle, capture & none-capture & self
<a class="inner1" href="https://www.mozilla.org" target="_blank" @click="alert('inner1, passive, open new page')">
inner1, passive & preventDefault(which is not allowed)
</a>
</div>
當按下 inner1 時,可以看到 alert('middle, capture') 先被觸發,再來是 alert('inner1, passive, open new page') ,最後才是 alert('middle, none-capture, default') ,由此現象可知 .capture
會打破由內而外的事件傳遞規則,先行觸發。
關於捕獲與冒泡事件,可參考以下文章:
.self
修飾符.self
修飾符只會觸發自己範圍內的事件,不包含子元素。
<div class="middle" target="_blank" @click.self="alert('middle, self')">
middle, self
<div class="inner4" target="_blank" @click="alert('inner4')">
inner4
</div>
</div>
.once
修飾符.once
修飾符使事件只會觸發一次。
<div class="outer" @click.once="alert('outer, once')" @click="alert('outer, none-once, default')">
outer
</div>
當點擊第一次的時候兩個事件都會被觸發,可是之後都只有沒有 .once
修飾符的事件會被觸發。
.passive
修飾符.passive
修飾符會無視 event.preventDefault()
的功能,只要加上此修飾符就一定會觸發瀏覽器的預設行為。
不要把 .passive
和 .prevent
一起使用,因為 .prevent
將會被忽略。
<a class="inner1" href="https://www.mozilla.org" target="_blank" @click.passive.prevent="alert('inner1, passive, open new page')">
inner1, passive & preventDefault(which is not allowed)
</a>
由於 .passive
會使 preventDefault
無效,所以就算在 .passive
後面加上 .prevent
還是會開啟連結頁面。
使用修飾符時,順序很重要;相應的程式碼會以同樣的順序產生。因此,用 v-on:click.prevent.self
會阻止所有的點擊,而 v-on:click.self.prevent
只會阻止對元素自身的點擊。
監聽鍵盤事件的特定鍵值。
注意:keyCode 的事件用法已經被廢棄了並可能不會被最新的瀏覽器支持。
只要是在 KeyboardEvent.key 上的按鍵名稱都可以用 kebab-case 的方式設定在修飾符上。
<input v-on:keyup.page-down="onPageDown">
Vue 會在函數中使用 $event.key === 'PageDown' 判斷式決定是否為目標按鈕
為了在必要的情況下支持舊瀏覽器,Vue 提供了絕大多數常用的按鍵碼的別名:
.enter
.tab
.delete
(Delete 跟 Backspace 按鍵都會觸發).esc
.space
.up
.down
.left
.right
在 Vue.config.KeyCodes
物件中設定自定義的別名:
<div id="app">
<input @keyup.f1="what='keyup.f1'" @keyup.up="what='keyup.up'" @keyup.insert-mode="what='keyup.insert-mode'" />
<span>You trigger event by <strong>{{what}}</strong></span>
</div>
Vue.config.keyCodes = {
f1: 112, // f1
up: [38, 87], // 數字鍵 8 跟 w
// insertMode: 73, // won't work
"insert-mode": 73 // i
};
僅在按下相應按鍵時才觸發滑鼠或鍵盤事件的監聽器
.ctrl
.alt
.shift
.meta
<!-- Alt + C -->
<input v-on:keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div v-on:click.ctrl="doSomething">Do something</div>
使用系統修飾鍵設定修飾符的 keyup
事件只有在該系統鍵按住的狀態下才會觸發事件,例如:
<div id="app">
<input"
@keyup.ctrl="what='keyup.ctrl'"
@keyup.17="what='keyup.17'"
/>
<span>You trigger event by <strong>{{what}}</strong></span>
</div>
@keyup.ctrl
: 要在按住 Ctrl 鍵的狀況下釋放其他按紐才會觸發。@keyup.17
: 只要釋放 Ctrl 按鈕就會觸發。.exact
修飾符設定 .exact
修飾符代表一定要完全符合系統修飾鍵的設定才會觸發事件
<!-- 即使 Alt 或 Shift 被一同按下時也會觸發 -->
<button v-on:click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的時候才觸發 -->
<button v-on:click.ctrl.exact="onCtrlClick">A</button>
<!-- 沒有任何系統修飾符被按下的時候才觸發 -->
<button v-on:click.exact="onClick">A</button>
Vue 提供左中右三個滑鼠按鍵的修飾符
.left
.right
.middle
在 Vue Instance 中的選項物件屬性中,可設定 methods
這個屬性用來定義方法,執行一些動作。
methods
屬性中的每個 key 是一個方法的名稱,而 value 就是方法的函數。
我們常使用指令 v-on
來綁定 HTML DOM 元素的事件監聽器,以觸發要執行的方法。
範例:
<div id="app">
<button v-on:click="addCount">addCount</button>
<p>{{ count }}</p>
</div>
var vm = new Vue({
el: '#app',
data: {
count: 0
},
methods: {
addCount: function() {
this.count += 1;
}
}
});
方法中的
this
會指向 Vue Instance,所以不能使用會將this
指向上層內容的箭頭函式 arrow function 來定義 methods
@
.stop
: 呼叫 event.stopPropagation(),停止觸發上層 DOM 元素事件.prevent
: 呼叫 event.preventDefault(),避免瀏覽器預設行為.capture
: 不管觸發事件的目標是否是下層, 設定 capture
的事件一定會先觸發.self
: 僅觸發自己範圍的事件,不包含子層.{keyCode | keyAlias}
: 只在按下鍵盤任一鍵值才會觸發事件.native
: 監聽元件根元素的原生事件.once
: 此事件只觸發一次.left
: 只在點擊滑鼠左鍵才會觸發事件.right
: 只在點擊滑鼠右鍵才會觸發事件.middle
: 只在點擊滑鼠中鍵才會觸發事件.passive
: 以 { passive : true } 的模式添加事件監聽器,無視 prevent 功能關於修飾符的詳細用法,會在之後的篇章有完整介紹。
接下來針對 v-on
的表達方式用法做介紹:
<div id="app">
<button @click="count += 1">點我+1</button>
<p>{{ count }}</p>
</div>
var vm = new Vue({
el: '#app',
data: {
count: 0
}
});
當使用事件名稱綁定時,方法中的第一個參數會是原生的 DOM 事件物件,所以可以使用這個物件來操作叫用此事件的元素
<div id="app">
<div>
<button @click="aPlus1AndbMinus">a+ and b-</button>
{{a}}:{{b}}
</div>
</div>
var vm = new Vue({
el: '#app',
data: {
a: 1,
b: 10
},
methods: {
aPlus1AndbMinus: function(event) {
this.a += 1;
this.b -= 1;
console.log(`You clicked ${event.target.tagName}`);
}
}
});
方法內可以傳入參數,而當需要原生的 DOM 事件物件時,可以用 $event
變數當作參數傳入方法中使用。
<div id="app">
<div>
<button @click="clickWhat('hi', $event)">hi</button>
<button @click="clickWhat('yo', $event)">yo</button>
You click {{what}} {{tag}}
</div>
</div>
var vm = new Vue({
el: '#app',
data: {
what: '',
tag: '',
},
methods: {
clickWhat: function(what, event) {
this.what = what;
this.tag = event.target.tagName;
}
}
});
物件的設定方式不能使用縮寫 @ 和任何的修飾符
<div id="app">
<div>
<button v-on="{ mousedown: showDown, mouseup: showUp }">click me</button>
{{doWhat}}
</div>
</div>
var vm = new Vue({
el: '#app',
data: {
doWhat: ''
},
methods: {
showUp: function(event) {
this.doWhat = `up ${event.target.tagName}`;
},
showDown: function(event) {
this.doWhat = `down ${event.target.tagName}`;
}
}
});
<form @submit.prevent>
<button type="submit">submit</button>
</form>
在沒有 @submit.prevent
的情況下,頁面會閃一下,這時頁面已送出表單並重新載入了,而加上 @submit.prevent
後畫面不會重新載入
在 Vue Instance 中的選項物件屬性中,可設定 methods
這個屬性用來定義方法,執行一些動作。
methods
屬性中的每個 key 是一個方法的名稱,而 value 就是方法的函數。
我們常使用指令 v-on
來綁定 HTML DOM 元素的事件監聽器,以觸發要執行的方法。
範例:
<div id="app">
<button v-on:click="addCount">addCount</button>
<p>{{ count }}</p>
</div>
var vm = new Vue({
el: '#app',
data: {
count: 0
},
methods: {
addCount: function() {
this.count += 1;
}
}
});
方法中的
this
會指向 Vue Instance,所以不能使用會將this
指向上層內容的箭頭函式 arrow function 來定義 methods
@
.stop
: 呼叫 event.stopPropagation(),停止觸發上層 DOM 元素事件.prevent
: 呼叫 event.preventDefault(),避免瀏覽器預設行為.capture
: 不管觸發事件的目標是否是下層, 設定 capture
的事件一定會先觸發.self
: 僅觸發自己範圍的事件,不包含子層.{keyCode | keyAlias}
: 只在按下鍵盤任一鍵值才會觸發事件.native
: 監聽元件根元素的原生事件.once
: 此事件只觸發一次.left
: 只在點擊滑鼠左鍵才會觸發事件.right
: 只在點擊滑鼠右鍵才會觸發事件.middle
: 只在點擊滑鼠中鍵才會觸發事件.passive
: 以 { passive : true } 的模式添加事件監聽器,無視 prevent 功能關於修飾符的詳細用法,會在之後的篇章有完整介紹。
接下來針對 v-on
的表達方式用法做介紹:
<div id="app">
<button @click="count += 1">點我+1</button>
<p>{{ count }}</p>
</div>
var vm = new Vue({
el: '#app',
data: {
count: 0
}
});
當使用事件名稱綁定時,方法中的第一個參數會是原生的 DOM 事件物件,所以可以使用這個物件來操作叫用此事件的元素
<div id="app">
<div>
<button @click="aPlus1AndbMinus">a+ and b-</button>
{{a}}:{{b}}
</div>
</div>
var vm = new Vue({
el: '#app',
data: {
a: 1,
b: 10
},
methods: {
aPlus1AndbMinus: function(event) {
this.a += 1;
this.b -= 1;
console.log(`You clicked ${event.target.tagName}`);
}
}
});
方法內可以傳入參數,而當需要原生的 DOM 事件物件時,可以用 $event
變數當作參數傳入方法中使用。
<div id="app">
<div>
<button @click="clickWhat('hi', $event)">hi</button>
<button @click="clickWhat('yo', $event)">yo</button>
You click {{what}} {{tag}}
</div>
</div>
var vm = new Vue({
el: '#app',
data: {
what: '',
tag: '',
},
methods: {
clickWhat: function(what, event) {
this.what = what;
this.tag = event.target.tagName;
}
}
});
物件的設定方式不能使用縮寫 @ 和任何的修飾符
<div id="app">
<div>
<button v-on="{ mousedown: showDown, mouseup: showUp }">click me</button>
{{doWhat}}
</div>
</div>
var vm = new Vue({
el: '#app',
data: {
doWhat: ''
},
methods: {
showUp: function(event) {
this.doWhat = `up ${event.target.tagName}`;
},
showDown: function(event) {
this.doWhat = `down ${event.target.tagName}`;
}
}
});
<form @submit.prevent>
<button type="submit">submit</button>
</form>
在沒有 @submit.prevent
的情況下,頁面會閃一下,這時頁面已送出表單並重新載入了,而加上 @submit.prevent
後畫面不會重新載入
v-bind
常用在 class 和 style 的綁定。一般 v-bind
的表達式為字串,但用在 class 和 style 的綁定時,還可以用物件 { }
或 陣列[ ]
的寫法。
{key:value}
in HTMLkey
:Class 名稱。
value
:判斷 Class 名稱是否出現的條件式。若值為 truthiness 則該 Class 名稱就會被賦予。
可以有多組 key:value
組合,也可以與已經存在 Class 屬性共存。
value
由 data
賦予為 true or false。
<style>
.static {
color: black;
font-size: 16px;
}
.active {
background-color: blue;
color: white;
}
.error {
background-color: red;
color: white;
}
</style>
<div
class = "static"
:class="{ active: isActive, error: hasError }">
</div>
data: {
isActive: true,
hasError: false
}
{key:value}
in data
key:value
放在 data
內的 classObject
。<div
class = "static"
:class="classObject">
</div>
data: {
classObject: {
active: true,
error: false
}
}
{key:value}
in computed
computed
監聽 classObject
的值。value
由 data
賦予為 true or false。<div
class = "static"
:class="classObject">
</div>
data: {
isActive: true,
hasError: false
},
computed: {
classObject: function() {
return {
active: this.isActive,
error: this.hasError,
}
}
}
data
內寫陣列元素的 Class 名稱。<div :class="[activeClass, errorClass]">
</div>
data: {
activeClass: 'active',
errorClass: 'error'
}
activeClass
是否出現。<div :class="[isActive ? activeClass : '', errorClass]">
</div>
data: {
isActive: true,
activeClass: 'active',
errorClass: 'error'
}
{key:value}
{key:value}
判斷式。 <div :class="[{ active : isActive }, errorClass]">
</div>
data: {
isActive: true,
errorClass: 'error'
}
{property:value}
in HTMLvalue
由 data
賦予值。<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">
</div>
data: {
activeColor: 'red',
fontSize: 30
}
{property:value}
in data
property:value
放在 data
內的 styleObject
。<div :style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
{property:value}
in computed
computed
監聽 styleObject
的值。value
由 data
賦予值。<div :style="styleObject"></div>
data: {
fontSize: 12,
fontWeight: 'bold'
},
computed: {
styleObject: function() {
return {
fontSize: `${this.fontSize}px`,
fontWeight: this.fontWeight
}
}
}
data
內寫陣列元素的 Style 物件值。<div :style="[fontStyleObj, backgroundStyleObj]">
</div>
data: {
fontStyleObj: {
color: 'red',
fontStyle: 'italic'
},
backgroundStyleObj: {
background: 'blue'
}
}
-webkit-
, -moz-
... 等特定瀏覽器的特殊屬性所需的前綴字自動加上<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
v-bind
常用在 class 和 style 的綁定。一般 v-bind
的表達式為字串,但用在 class 和 style 的綁定時,還可以用物件 { }
或 陣列[ ]
的寫法。
{key:value}
in HTMLkey
:Class 名稱。
value
:判斷 Class 名稱是否出現的條件式。若值為 truthiness 則該 Class 名稱就會被賦予。
可以有多組 key:value
組合,也可以與已經存在 Class 屬性共存。
value
由 data
賦予為 true or false。
<style>
.static {
color: black;
font-size: 16px;
}
.active {
background-color: blue;
color: white;
}
.error {
background-color: red;
color: white;
}
</style>
<div
class = "static"
:class="{ active: isActive, error: hasError }">
</div>
data: {
isActive: true,
hasError: false
}
{key:value}
in data
key:value
放在 data
內的 classObject
。<div
class = "static"
:class="classObject">
</div>
data: {
classObject: {
active: true,
error: false
}
}
{key:value}
in computed
computed
監聽 classObject
的值。value
由 data
賦予為 true or false。<div
class = "static"
:class="classObject">
</div>
data: {
isActive: true,
hasError: false
},
computed: {
classObject: function() {
return {
active: this.isActive,
error: this.hasError,
}
}
}
data
內寫陣列元素的 Class 名稱。<div :class="[activeClass, errorClass]">
</div>
data: {
activeClass: 'active',
errorClass: 'error'
}
activeClass
是否出現。<div :class="[isActive ? activeClass : '', errorClass]">
</div>
data: {
isActive: true,
activeClass: 'active',
errorClass: 'error'
}
{key:value}
{key:value}
判斷式。 <div :class="[{ active : isActive }, errorClass]">
</div>
data: {
isActive: true,
errorClass: 'error'
}
{property:value}
in HTMLvalue
由 data
賦予值。<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">
</div>
data: {
activeColor: 'red',
fontSize: 30
}
{property:value}
in data
property:value
放在 data
內的 styleObject
。<div :style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
{property:value}
in computed
computed
監聽 styleObject
的值。value
由 data
賦予值。<div :style="styleObject"></div>
data: {
fontSize: 12,
fontWeight: 'bold'
},
computed: {
styleObject: function() {
return {
fontSize: `${this.fontSize}px`,
fontWeight: this.fontWeight
}
}
}
data
內寫陣列元素的 Style 物件值。<div :style="[fontStyleObj, backgroundStyleObj]">
</div>
data: {
fontStyleObj: {
color: 'red',
fontStyle: 'italic'
},
backgroundStyleObj: {
background: 'blue'
}
}
-webkit-
, -moz-
... 等特定瀏覽器的特殊屬性所需的前綴字自動加上<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
用 v-bind
來動態綁定 DOM 元素內的屬性值 ( Attributes )
可用 :
縮寫
<div id="app">
<img id="vueImg" v-bind:src="imgSrc" :class="className" :data="text" alt="">
</div>
var app = new Vue({
el: '#app',
data: {
imgSrc: 'https://images.unsplash.com/photo-1479568933336-ea01829af8de?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=d9926ef56492b20aea8508ed32ec6030&auto=format&fit=crop&w=2250&q=80',
className: 'img-fluid',
text: 'Hello!'
}
})
.prop
作為一個 DOM 特性 ( property ) 綁定,而不是作為 屬性 ( attribute ) 綁定。
兩者差別 property v.s. attribute
如果沒有設定修飾符 .prop
,綁在 DOM 上面的是 attribute。可以使用 getAttribute
取值。
let element = document.querySelector("#vueImg");
element.getAttribute('data'); // Hello!
但無法利用取 property 的方式取值,拿到的是undefined
element.data; // undefined
若希望只是存資料待之後運算,並且不希望過份汙染 HTML,通常會設為 property,利用 .prop
改將綁定的屬性設定為 DOM property。
<div id="app">
<img id="vueImg" v-bind:src="imgSrc" :class="className" :data.prop="text" alt="">
</div>
data 設為 property,在 HTML 上是看不到的。
這樣就可以使用取 property 的方式取值。
let element = document.querySelector("#vueImg");
element.getAttribute('data'); // null
element.data; // Hello!
.camel
若使用 .camel,就會將帶有「-」分隔 (kebab-case) 的屬性名稱轉為小駝峰 (camelCase)。
<div id="svg">
<svg :view-box.camel="id"></svg>
</div>
.sync
編譯時存在的語法糖,可以擴展成為自動更新父組件屬性的 v-on
監聽器。
待之後談到父子元件傳值時會有詳細介紹。
<!-- bind an attribute -->
<img v-bind:src="imageSrc">
<!-- dynamic attribute name (2.6.0+) -->
<button v-bind:[key]="value"></button>
<!-- shorthand -->
<img :src="imageSrc">
<!-- shorthand dynamic attribute name (2.6.0+) -->
<button :[key]="value"></button>
<!-- with inline string concatenation -->
<img :src="'/path/to/images/' + fileName">
<!-- class binding -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]">
<!-- style binding -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>
<!-- binding an object of attributes -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
<!-- DOM attribute binding with prop modifier -->
<div v-bind:text-content.prop="text"></div>
<!-- prop binding. "prop" must be declared in my-component. -->
<my-component :prop="someThing"></my-component>
<!-- pass down parent props in common with a child component -->
<child-component v-bind="$props"></child-component>
<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>
用 v-bind
來動態綁定 DOM 元素內的屬性值 ( Attributes )
可用 :
縮寫
<div id="app">
<img id="vueImg" v-bind:src="imgSrc" :class="className" :data="text" alt="">
</div>
var app = new Vue({
el: '#app',
data: {
imgSrc: 'https://images.unsplash.com/photo-1479568933336-ea01829af8de?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=d9926ef56492b20aea8508ed32ec6030&auto=format&fit=crop&w=2250&q=80',
className: 'img-fluid',
text: 'Hello!'
}
})
.prop
作為一個 DOM 特性 ( property ) 綁定,而不是作為 屬性 ( attribute ) 綁定。
兩者差別 property v.s. attribute
如果沒有設定修飾符 .prop
,綁在 DOM 上面的是 attribute。可以使用 getAttribute
取值。
let element = document.querySelector("#vueImg");
element.getAttribute('data'); // Hello!
但無法利用取 property 的方式取值,拿到的是undefined
element.data; // undefined
若希望只是存資料待之後運算,並且不希望過份汙染 HTML,通常會設為 property,利用 .prop
改將綁定的屬性設定為 DOM property。
<div id="app">
<img id="vueImg" v-bind:src="imgSrc" :class="className" :data.prop="text" alt="">
</div>
data 設為 property,在 HTML 上是看不到的。
這樣就可以使用取 property 的方式取值。
let element = document.querySelector("#vueImg");
element.getAttribute('data'); // null
element.data; // Hello!
.camel
若使用 .camel,就會將帶有「-」分隔 (kebab-case) 的屬性名稱轉為小駝峰 (camelCase)。
<div id="svg">
<svg :view-box.camel="id"></svg>
</div>
.sync
編譯時存在的語法糖,可以擴展成為自動更新父組件屬性的 v-on
監聽器。
待之後談到父子元件傳值時會有詳細介紹。
<!-- bind an attribute -->
<img v-bind:src="imageSrc">
<!-- dynamic attribute name (2.6.0+) -->
<button v-bind:[key]="value"></button>
<!-- shorthand -->
<img :src="imageSrc">
<!-- shorthand dynamic attribute name (2.6.0+) -->
<button :[key]="value"></button>
<!-- with inline string concatenation -->
<img :src="'/path/to/images/' + fileName">
<!-- class binding -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]">
<!-- style binding -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>
<!-- binding an object of attributes -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
<!-- DOM attribute binding with prop modifier -->
<div v-bind:text-content.prop="text"></div>
<!-- prop binding. "prop" must be declared in my-component. -->
<my-component :prop="someThing"></my-component>
<!-- pass down parent props in common with a child component -->
<child-component v-bind="$props"></child-component>
<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>
此篇筆記整理 2020/03/26 六角學院-大神來六角 線上直播的內容。
康晉暚/阿康
阿康人生路上的曲折,與多元職涯發展
求知 vs 求解
書單:
線上課程:
聽完演講後,到這次再次整理筆記,覺得讓自己印象最深刻的就是這句話:
人生方向是「 發展 」出來,不是「發現」而來的
雖然對於未來有很多不安與擔憂,但就是要去嘗試去做才知道。
而以下也是我覺得很值得自己去執行與反思的:
時間管理:不是在有限時間做更多事情,而是選擇什麼事情不要做
例如:不要一直滑手機、不要看 youtube等,無形中會浪費很多時間。
書是大量/多次/循環的閱讀,而不是一次性很緩慢地閱讀
反思:覺得這也可以套用到自己現在在線上課程的學習。不求一次性的就完全看懂課程內容,而是需要自己多次反覆觀看與練習。
持續輸出對人有價值的內容
反思:或許自己現在整理的每篇筆記或文章,不僅是幫助自己,也能幫助到跟我一樣在學習上有相同困擾的人
嘗試使用《辦到了日記》的方法,提升自我肯定!
此篇筆記整理 2020/03/26 六角學院-大神來六角 線上直播的內容。
康晉暚/阿康
阿康人生路上的曲折,與多元職涯發展
求知 vs 求解
書單:
線上課程:
聽完演講後,到這次再次整理筆記,覺得讓自己印象最深刻的就是這句話:
人生方向是「 發展 」出來,不是「發現」而來的
雖然對於未來有很多不安與擔憂,但就是要去嘗試去做才知道。
而以下也是我覺得很值得自己去執行與反思的:
時間管理:不是在有限時間做更多事情,而是選擇什麼事情不要做
例如:不要一直滑手機、不要看 youtube等,無形中會浪費很多時間。
書是大量/多次/循環的閱讀,而不是一次性很緩慢地閱讀
反思:覺得這也可以套用到自己現在在線上課程的學習。不求一次性的就完全看懂課程內容,而是需要自己多次反覆觀看與練習。
持續輸出對人有價值的內容
反思:或許自己現在整理的每篇筆記或文章,不僅是幫助自己,也能幫助到跟我一樣在學習上有相同困擾的人
嘗試使用《辦到了日記》的方法,提升自我肯定!
藉由改變 data 來改變畫面 view
更新文字內容,如同 js 中的 textContent
。
<div v-text="">
可用 {{ mustache }}
簡寫。
v-text
與{{ mustache }}
的不同之處在於,v-text
會更新整塊標籤的內容(包含本身),但{{ mustache }}
只會更新標籤內的局部內容。
<div id="app">
<p v-text="message">這是原本的文字,</p>
<p>這是原本的文字,{{message}}</p>
</div>
let app = new Vue({
el: "#app",
data: {
message: "這是後來的文字"
}
});
可渲染出 HTML,如同 js 中的 innerHtml
<div id="app">
{{ message }}
<div v-text="message"></div>
<div v-html="message2"></div>
</div>
var app = new Vue({
el: '#app',
data: {
message: '哈囉',
message2: '<span style="background-color: yellow;">hi</span>'
}
})
注意:任意在網站上動態渲染 HTML 是非常危險的,因為容易導致 XSS 攻擊。
XSS(Cross-site scripting,跨網站指令碼攻擊):藉由網頁開發時留下的漏洞,利用巧妙的方法注入惡意指令代碼到網頁,使用戶載入並執行攻擊者惡意製造的網頁程式。
關於XSS攻擊,可參考這篇文章,內有詳細的解說。
因此,盡量避免在表單或是留言區使用 v-html
,因為很有可能會被有心人力從外部寫入惡意程式碼。
單一元件(.vue)中
v-html
的內容不會套用有寫scoped
的 CSS style,因為v-html
的內容並沒有被 Vue 模板編譯器編譯過。
在不設為全域變數下,若想要讓 v-html
能套用 CSS scoped 樣式,有三種方式:
範例(使用 Deep Selectors):
<template>
<div class="a" v-html="content"></div>
</template>
<script>
export default {
data() {
return {
content: 'this is a <a class="b">Test</a>',
}
},
}
</script>
<style scoped>
.a >>> .b {
color: red;
}
</style>
藉由改變 data 來改變畫面 view
更新文字內容,如同 js 中的 textContent
。
<div v-text="">
可用 {{ mustache }}
簡寫。
v-text
與{{ mustache }}
的不同之處在於,v-text
會更新整塊標籤的內容(包含本身),但{{ mustache }}
只會更新標籤內的局部內容。
<div id="app">
<p v-text="message">這是原本的文字,</p>
<p>這是原本的文字,{{message}}</p>
</div>
let app = new Vue({
el: "#app",
data: {
message: "這是後來的文字"
}
});
可渲染出 HTML,如同 js 中的 innerHtml
<div id="app">
{{ message }}
<div v-text="message"></div>
<div v-html="message2"></div>
</div>
var app = new Vue({
el: '#app',
data: {
message: '哈囉',
message2: '<span style="background-color: yellow;">hi</span>'
}
})
注意:任意在網站上動態渲染 HTML 是非常危險的,因為容易導致 XSS 攻擊。
XSS(Cross-site scripting,跨網站指令碼攻擊):藉由網頁開發時留下的漏洞,利用巧妙的方法注入惡意指令代碼到網頁,使用戶載入並執行攻擊者惡意製造的網頁程式。
關於XSS攻擊,可參考這篇文章,內有詳細的解說。
因此,盡量避免在表單或是留言區使用 v-html
,因為很有可能會被有心人力從外部寫入惡意程式碼。
單一元件(.vue)中
v-html
的內容不會套用有寫scoped
的 CSS style,因為v-html
的內容並沒有被 Vue 模板編譯器編譯過。
在不設為全域變數下,若想要讓 v-html
能套用 CSS scoped 樣式,有三種方式:
範例(使用 Deep Selectors):
<template>
<div class="a" v-html="content"></div>
</template>
<script>
export default {
data() {
return {
content: 'this is a <a class="b">Test</a>',
}
},
}
</script>
<style scoped>
.a >>> .b {
color: red;
}
</style>
指令 (Directives) 是帶有 v-
前綴的特殊屬性 attribute。指令的值預期是單個 Javascript 表達式(Expression)。當表達式的值改變時,指令會響應式地將其產生的影響作用於 DOM 上。
常見的例如:v-text
, v-if
, v-on
等,後面會有篇章詳細的介紹這些常見的模板指令的用法。此篇文章主要在了解指令的配置方式。
另外,除了使用這些固定的模板語法外,我們也可以自定義指令。這個部分之後會有文章做專門的介紹。
Mustache 語法:取代頁面上的某個區塊 <div></div>
Directives 指令:放在 HTML 標籤內,影響該 DOM 元素
指令:[參數].修飾符="值"
Directive:[Argument].Modifier="Value"
不需要表達式。Directive 直接作用在元素上。
例如:v-once
。只渲染元素和元件一次。隨後的重新渲染,元素/元件及其所有的子節點將被視為靜態內容並跳過。可以用於優化更新性能。
<!-- 單個元素 -->
<span v-once>This will never change: {{msg}}</span>
Directive 依照 Value 作用在元素上。
例如:v-text="msg"
。更新元素的 textContent。
<span v-text="msg"></span>
<!-- 和下面的一樣 -->
<span>{{msg}}</span>
Directive 依照 Value 作用在 Argument 上。
例如:v-bind:src
,動態地綁定一個或多個特性,或是 v-on:click
,監聽 DOM 事件。
<!-- 綁定一個屬性 -->
<img v-bind:src="imageSrc">
<!-- 監聽 click 事件 -->
<a v-on:click="doSomething">...</a>
動態參數。
從 2.6.0 開始,可以用方括號括起來的 JavaScript 表達式作為一個指令的參數。
<a v-bind:[attributeName]="url"> ... </a>
這裡的 attributeName
會被作為一個 JavaScript 表達式進行動態求值,求得的值將會作為最終的參數來使用。例如,如果你的 Vue 實例有一個 data
屬性 attributeName
,其值為 "href"
,那麼這個綁定將等同於 v-bind:href
。
<a v-on:[eventName]="doSomething"> ... </a>
在這個範例中,當 eventName
的值為 "focus"
時,v-on:[eventName]
等同於 v-on:focus
。
動態參數的值預設為字串。若為 null
的話,則可以用來解除其綁定。其他非字串 或 null
型別的值就會出現錯誤警告。
Directive 依照 Modifier 設定的特殊方式將 Value 作用在 Argument 上。
例如:v-on:click.once
、v-on:submit.prevent
<!-- 點擊事件只會觸發一次 -->
<button v-on:click.once="doThis"></button>
<!-- 調用 event.preventDefault()-->
<form v-on:submit.prevent="onSubmit">...</form>
對於一些頻繁用到的指令來說,使用 v-
前綴會感到繁瑣。因此,
Vue 為 v-bind
和 v-on
這兩個最常用的指令,提供了特定縮寫:
省略 v-bind
,剩下:
<!-- 完整語法 -->
<a v-bind:href="url">...</a>
<!-- 縮寫 -->
<a :href="url">...</a>
<!-- 動態參數的縮寫 (2.6.0+) -->
<a :[key]="url"> ... </a>
v-on
縮寫為 @
<!-- 完整語法 -->
<a v-on:click="doSomething">...</a>
<!-- 縮寫 -->
<a @click="doSomething">...</a>
<!-- 動態參數的縮寫 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
藉由這篇文章的整理,才對 Vue 的這些指令有了全面的了解,清楚他是如何配置的。不然之前都是看到一個記一個,沒有特別清楚他的規則,常常到後來就會被搞混。現在經過整理,希望對於之後在使用這些指令時能更駕輕就熟。
指令 (Directives) 是帶有 v-
前綴的特殊屬性 attribute。指令的值預期是單個 Javascript 表達式(Expression)。當表達式的值改變時,指令會響應式地將其產生的影響作用於 DOM 上。
常見的例如:v-text
, v-if
, v-on
等,後面會有篇章詳細的介紹這些常見的模板指令的用法。此篇文章主要在了解指令的配置方式。
另外,除了使用這些固定的模板語法外,我們也可以自定義指令。這個部分之後會有文章做專門的介紹。
Mustache 語法:取代頁面上的某個區塊 <div></div>
Directives 指令:放在 HTML 標籤內,影響該 DOM 元素
指令:[參數].修飾符="值"
Directive:[Argument].Modifier="Value"
不需要表達式。Directive 直接作用在元素上。
例如:v-once
。只渲染元素和元件一次。隨後的重新渲染,元素/元件及其所有的子節點將被視為靜態內容並跳過。可以用於優化更新性能。
<!-- 單個元素 -->
<span v-once>This will never change: {{msg}}</span>
Directive 依照 Value 作用在元素上。
例如:v-text="msg"
。更新元素的 textContent。
<span v-text="msg"></span>
<!-- 和下面的一樣 -->
<span>{{msg}}</span>
Directive 依照 Value 作用在 Argument 上。
例如:v-bind:src
,動態地綁定一個或多個特性,或是 v-on:click
,監聽 DOM 事件。
<!-- 綁定一個屬性 -->
<img v-bind:src="imageSrc">
<!-- 監聽 click 事件 -->
<a v-on:click="doSomething">...</a>
動態參數。
從 2.6.0 開始,可以用方括號括起來的 JavaScript 表達式作為一個指令的參數。
<a v-bind:[attributeName]="url"> ... </a>
這裡的 attributeName
會被作為一個 JavaScript 表達式進行動態求值,求得的值將會作為最終的參數來使用。例如,如果你的 Vue 實例有一個 data
屬性 attributeName
,其值為 "href"
,那麼這個綁定將等同於 v-bind:href
。
<a v-on:[eventName]="doSomething"> ... </a>
在這個範例中,當 eventName
的值為 "focus"
時,v-on:[eventName]
等同於 v-on:focus
。
動態參數的值預設為字串。若為 null
的話,則可以用來解除其綁定。其他非字串 或 null
型別的值就會出現錯誤警告。
Directive 依照 Modifier 設定的特殊方式將 Value 作用在 Argument 上。
例如:v-on:click.once
、v-on:submit.prevent
<!-- 點擊事件只會觸發一次 -->
<button v-on:click.once="doThis"></button>
<!-- 調用 event.preventDefault()-->
<form v-on:submit.prevent="onSubmit">...</form>
對於一些頻繁用到的指令來說,使用 v-
前綴會感到繁瑣。因此,
Vue 為 v-bind
和 v-on
這兩個最常用的指令,提供了特定縮寫:
省略 v-bind
,剩下:
<!-- 完整語法 -->
<a v-bind:href="url">...</a>
<!-- 縮寫 -->
<a :href="url">...</a>
<!-- 動態參數的縮寫 (2.6.0+) -->
<a :[key]="url"> ... </a>
v-on
縮寫為 @
<!-- 完整語法 -->
<a v-on:click="doSomething">...</a>
<!-- 縮寫 -->
<a @click="doSomething">...</a>
<!-- 動態參數的縮寫 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
藉由這篇文章的整理,才對 Vue 的這些指令有了全面的了解,清楚他是如何配置的。不然之前都是看到一個記一個,沒有特別清楚他的規則,常常到後來就會被搞混。現在經過整理,希望對於之後在使用這些指令時能更駕輕就熟。
我在一開始學習 Vue 時,是直接進入最常見的指令,例如:v-text
、v-html
,所以一直以為 {{ mustache }}
等同於 v-text
(汗)....,直到後面學習 methods、computed 等語法{{ mustache }}
又出現時,就被搞混了。因此這次為了撰寫文章而重新學習,回頭看了官方文件說明,才更了解 {{ mustache }}
的用法 與 Vue 的運作。
Vue.js 使用了基於 HTML 的模板語法,讓開發者能聲明式地把 DOM 綁定至底層 Vue 實例的數據(Vue instance’s data)。所有 Vue.js 的模板(templates)都是有效的 HTML,所以能被遵循規範的瀏覽器和 HTML 解析器解析。
在底層的實現上,Vue 將模板編譯(compiles)成虛擬 DOM 渲染函數(Virtual DOM render functions)。結合響應式系統(reactivity system),Vue 能夠智能地計算出最少需要重新渲染多少組件,並把 DOM 操作次數減到最少。
{{ mustache }} 語法
v-
為前綴詞的特殊屬性最常見使用 {{ mustache }}
語法的就是文字插植
<span>Message: {{ msg }}</span>
只要綁定的資料對象上 msg 屬性發生了改變,插值處的內容就會更新。
加上 v-once 這個指令,可以讓 {{ mustache }}
語法只渲染一次
<span v-once>This will never change: {{ msg }}</span>
{{ mustache }}
語法除了可以直接使用實體中的屬性外,我們也可以使用 JavaScript 的陳述式寫一些運算或判斷。例如:
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
使用 JavaScript 陳述式的限制是,每個綁定都只能包含單個表達式,所以下面的例子都不會生效。
<!-- 這是語句 statement,不是表達式 expression -->
{{ var a = 1 }}
<!-- 流程控制也不會生效,請使用三元表達式 -->
{{ if (ok) { return message } }}
{{ mustache }}
語法的 JavaScript 陳述式雖然好用,但是由於不可復用及較差的可讀性,通常在開發時會用computed
或是methods
取代
藉由這次整理的筆記,才讓我對 {{ mustache }}
這位鬍子先生有了更清楚的認識,這樣每次見面時總算能熟識地打招呼,而非呼嚨地躲過惹(笑)。
我在一開始學習 Vue 時,是直接進入最常見的指令,例如:v-text
、v-html
,所以一直以為 {{ mustache }}
等同於 v-text
(汗)....,直到後面學習 methods、computed 等語法{{ mustache }}
又出現時,就被搞混了。因此這次為了撰寫文章而重新學習,回頭看了官方文件說明,才更了解 {{ mustache }}
的用法 與 Vue 的運作。
Vue.js 使用了基於 HTML 的模板語法,讓開發者能聲明式地把 DOM 綁定至底層 Vue 實例的數據(Vue instance’s data)。所有 Vue.js 的模板(templates)都是有效的 HTML,所以能被遵循規範的瀏覽器和 HTML 解析器解析。
在底層的實現上,Vue 將模板編譯(compiles)成虛擬 DOM 渲染函數(Virtual DOM render functions)。結合響應式系統(reactivity system),Vue 能夠智能地計算出最少需要重新渲染多少組件,並把 DOM 操作次數減到最少。
{{ mustache }} 語法
v-
為前綴詞的特殊屬性最常見使用 {{ mustache }}
語法的就是文字插植
<span>Message: {{ msg }}</span>
只要綁定的資料對象上 msg 屬性發生了改變,插值處的內容就會更新。
加上 v-once 這個指令,可以讓 {{ mustache }}
語法只渲染一次
<span v-once>This will never change: {{ msg }}</span>
{{ mustache }}
語法除了可以直接使用實體中的屬性外,我們也可以使用 JavaScript 的陳述式寫一些運算或判斷。例如:
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
使用 JavaScript 陳述式的限制是,每個綁定都只能包含單個表達式,所以下面的例子都不會生效。
<!-- 這是語句 statement,不是表達式 expression -->
{{ var a = 1 }}
<!-- 流程控制也不會生效,請使用三元表達式 -->
{{ if (ok) { return message } }}
{{ mustache }}
語法的 JavaScript 陳述式雖然好用,但是由於不可復用及較差的可讀性,通常在開發時會用computed
或是methods
取代
藉由這次整理的筆記,才讓我對 {{ mustache }}
這位鬍子先生有了更清楚的認識,這樣每次見面時總算能熟識地打招呼,而非呼嚨地躲過惹(笑)。
整個 Vue 應用程式都會從一個根實例 (Root Instance) 開始,這個 Vue 實例會用 建構式 new Vue({/* Options */})
建立,而根實例的下面可以引入各種可以重複使用的組件(Component),每個組件都是一個 Vue 實例,因此整個應用程式會是一個以根實例(下方圖中最上面的那個方塊)為起始所展開的組件樹(component tree)。(關於元件之後會有更詳細的介紹)
一個頁面可以有多個 Vue 的應用程式,但不能建立巢狀的 Vue 應用程式,且 Root 實例(
new Vue()
)只能有一個
Vue 在實體化時,可傳入一個選項物件(Options),此物件包含這個 Vue 實例需要用到的屬性,例如:掛載目標(el)、資料(data)、方法(methods)、模板(template)、生命週期鉤子(hooks)等等。
<div id="app">
{{ a }}
</div>
let vm = new Vue({ // 宣告一個 vm 變數,取得 Vue 實體化的物件
// options 選項物件。包含屬性:el, data, methods等等
el: "#app",
data: {
a: "text",
}
});
el
(element) 掛載目標:哪個範圍要有 Vue 的功能。一個 Vue 實例一次只能綁定一個 HTML 元素
data
資料:存放所有在 Vue 響應式系統 (reactivity system) 內的屬性與值。data
內屬性的值改變時,其相對應的 view 畫面也會跟著做改變。只有當實例被創建時就已經存在於
data
中的屬性才會是響應式的。
所以如果你知道你會在晚些時候才會需要某個屬性,那就在一開始時設置一些初始值(例如:空值、不存在或 0 等)。
data: {
newTodoText: '',
visitCount: 0,
hideCompletedTodos: false,
todos: [],
error: null
}
Vue 受 MVVM(Model - View - ViewModel)架構啟發
Vue 透過 ViewModel (View與Model的溝通橋樑) ,藉由 資料狀態(Model,Js 中的 data 物件)操作 畫面(View,畫面上的 DOM)。讓開發者只需關注在 Model 和 View 上,不用煩惱底層該如何實現
整個 Vue 應用程式都會從一個根實例 (Root Instance) 開始,這個 Vue 實例會用 建構式 new Vue({/* Options */})
建立,而根實例的下面可以引入各種可以重複使用的組件(Component),每個組件都是一個 Vue 實例,因此整個應用程式會是一個以根實例(下方圖中最上面的那個方塊)為起始所展開的組件樹(component tree)。(關於元件之後會有更詳細的介紹)
一個頁面可以有多個 Vue 的應用程式,但不能建立巢狀的 Vue 應用程式,且 Root 實例(
new Vue()
)只能有一個
Vue 在實體化時,可傳入一個選項物件(Options),此物件包含這個 Vue 實例需要用到的屬性,例如:掛載目標(el)、資料(data)、方法(methods)、模板(template)、生命週期鉤子(hooks)等等。
<div id="app">
{{ a }}
</div>
let vm = new Vue({ // 宣告一個 vm 變數,取得 Vue 實體化的物件
// options 選項物件。包含屬性:el, data, methods等等
el: "#app",
data: {
a: "text",
}
});
el
(element) 掛載目標:哪個範圍要有 Vue 的功能。一個 Vue 實例一次只能綁定一個 HTML 元素
data
資料:存放所有在 Vue 響應式系統 (reactivity system) 內的屬性與值。data
內屬性的值改變時,其相對應的 view 畫面也會跟著做改變。只有當實例被創建時就已經存在於
data
中的屬性才會是響應式的。
所以如果你知道你會在晚些時候才會需要某個屬性,那就在一開始時設置一些初始值(例如:空值、不存在或 0 等)。
data: {
newTodoText: '',
visitCount: 0,
hideCompletedTodos: false,
todos: [],
error: null
}
Vue 受 MVVM(Model - View - ViewModel)架構啟發
Vue 透過 ViewModel (View與Model的溝通橋樑) ,藉由 資料狀態(Model,Js 中的 data 物件)操作 畫面(View,畫面上的 DOM)。讓開發者只需關注在 Model 和 View 上,不用煩惱底層該如何實現
Vue 不支持 IE8 及以下版本,因為 Vue 使用了 IE8 無法模擬的 ECMAScript 5 特性。但它支持所有兼容 ECMAScript 5 的瀏覽器。
Vue 的開發環境建置有以下幾種方法:
<script>
引入下載的檔案或 CDNnpm
安裝vue-cli
請參考官網提供的最新版本資訊。
<script>
引入直接下載並用 <script>
標籤引入,Vue 會被註冊為一個全域變數。
分成 開發版本 與 生產版本
建議下載非壓縮的開發版本,才會跳出錯誤訊息的警告
對於開發中環境,可以引入最新版本。
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
對於生產環境,建議指名一個明確的版本號和構建文件,以避免新版本造成的不可預期的破壞。
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
在構建大型應用時推薦使用 NPM 安裝。NPM 能很好地和例如 Webpack 或 Browserify 模塊打包器配合使用。
# 最新穩定版
$ npm install vue
Vue-CLI 是一個快速建立 Vue.js 專案架構的工具。更多詳情可查閱 Vue CLI 的官方文件。在之後也會有更詳細的文章來介紹。
$ npm install -g @vue/cli
在瀏覽器上安裝 Vue Devtools,可以在開發者模式中檢視與調整 Vue 的應用。
以 Chrome 瀏覽器為例,安裝擴充工具:
在 VS Code 文字編輯器上安裝相關的擴充套件
Vue 的開發者工具建議在 web server 下運行,透過在本地開啟一個 web server 來將本地的網頁內容(HTML 、CSS、JavaScript )模擬成放在伺服器中。
在網址列輸入 http://localhost:3000 (port 可能會不一樣)網址後可以正確收到網頁內容,並在執行不同操作發出請求時,可以正確接收到對應的網頁內容,讓開發環境與伺服器環境接近。
Vue 不支持 IE8 及以下版本,因為 Vue 使用了 IE8 無法模擬的 ECMAScript 5 特性。但它支持所有兼容 ECMAScript 5 的瀏覽器。
Vue 的開發環境建置有以下幾種方法:
<script>
引入下載的檔案或 CDNnpm
安裝vue-cli
請參考官網提供的最新版本資訊。
<script>
引入直接下載並用 <script>
標籤引入,Vue 會被註冊為一個全域變數。
分成 開發版本 與 生產版本
建議下載非壓縮的開發版本,才會跳出錯誤訊息的警告
對於開發中環境,可以引入最新版本。
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
對於生產環境,建議指名一個明確的版本號和構建文件,以避免新版本造成的不可預期的破壞。
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
在構建大型應用時推薦使用 NPM 安裝。NPM 能很好地和例如 Webpack 或 Browserify 模塊打包器配合使用。
# 最新穩定版
$ npm install vue
Vue-CLI 是一個快速建立 Vue.js 專案架構的工具。更多詳情可查閱 Vue CLI 的官方文件。在之後也會有更詳細的文章來介紹。
$ npm install -g @vue/cli
在瀏覽器上安裝 Vue Devtools,可以在開發者模式中檢視與調整 Vue 的應用。
以 Chrome 瀏覽器為例,安裝擴充工具:
在 VS Code 文字編輯器上安裝相關的擴充套件
Vue 的開發者工具建議在 web server 下運行,透過在本地開啟一個 web server 來將本地的網頁內容(HTML 、CSS、JavaScript )模擬成放在伺服器中。
在網址列輸入 http://localhost:3000 (port 可能會不一樣)網址後可以正確收到網頁內容,並在執行不同操作發出請求時,可以正確接收到對應的網頁內容,讓開發環境與伺服器環境接近。
因為公司以 Vue 為開發主要框架,因此在此記錄學習 Vue 的筆記。
搭配六角學院的課程,使用 VS Code 文字編輯器。
在真正開始前,先來個前端歷史小回顧
JavaScript 誕生於1995年,由 Netscape 這家公司專門為其 Netscape 瀏覽器而發明的,目的是需要一種可以嵌入網頁的腳本語言。在 JavaScript 誕生之際,瀏覽器的世界還處於戰國時代,CSS 也才剛剛誕生,各家瀏覽器採用的標準不一,常有在某瀏覽器呈現的畫面,到另一個瀏覽器完全走樣的問題,當時前端工程師的主要工作,通常是維持網頁在各瀏覽器的一致性。
以下是 Wikipedia 整理的瀏覽器年代表:
從這張圖上,可以觀察到在 1995 年前後,有許多五花八門的瀏覽器,進入 2010 左右才慢慢由 Chrome、Firefox、IE、Safari 等幾大家獨佔鰲頭。
在這個混亂的時期,一個叫 ECMA 的國際標準化組織致力於統一標準,他們推出的標準稱為 ECMAScript,例如 ECMAScript 第 5 版會簡稱為 ES5。1999~2010 年之間,JavaScript 通行標準得到廣泛支持,也慢慢轉變成一個成熟的程式語言。今天坊間 JavaScript 學習教材大多採用 ES5 或 ES6,ES6 又稱為 ES2015。
Google 在 2004 年推出 Gmail 服務,以及次年的 Google Map,達成了高度的網頁互動性,可說是 AJAX 躍入舞台的重要時刻,大家知道了 AJAX 的異步請求竟能帶來如此流暢的網頁體驗。
然而當時仍處於瀏覽器與 JavaScript 標準都很紛亂的時期,想要在網頁上實現更強大的功能,就要撰寫更多的 JavaScript,也代表有更多跨瀏覽器校調的苦工。最後就有了 jQuery 在 2006 年出場,統合校調 JavaScript 的各種重覆性作業,讓開發者在操作 DOM 元素減少麻煩,且較不容易發生錯誤。
jQuery 函式庫的出現推動了 AJAX 技術的流行,而 AJAX 技術讓網頁畫面可以透過 JavaScript 在前端動態產生,瀏覽器不需要重新跳頁,因此大大提升使用者體驗。後來就把這種設計原則稱為 Single Page Application,簡稱 SPA。
AJAX 讓 SPA 的概念成形,但 SPA 的實作未必一定只能用 AJAX,由於直接使用 JavaScript 來動態產生畫面,會遇到一些瓶頸,例如一直沒有跳頁,網址不改變,不利於 SEO 等等。
為了在實現 SPA 設計原則的同時解決問題,開始有人提出一套完整的軟體框架,例如 Backbone.js、Angular JS、Vue JS 等等,迎來了前端技術的大爆炸,每個框架有不同的優缺點,但整體來說,都是在面對以下 3 件事:
接下來將介紹這次的主角 Vue.js。
先了解什麼是 Vue,以及為什麼要使用它。
Vue 由前 Google 工程師尤雨溪(Evan You)在 2014 年 2 月所建立。
Vue 是一套開放源碼(Open Source)的漸進式框架(Progressive JavaScript Framework)(階段性使用 Vue,不需要一開始就使用所有的東西)。以操作資料狀態來管理畫面的 MVVM 架構函式庫。由於 MVVM 雙向綁定的好處,讓開發人員專注在 Javascript 資料 (data) 的操作而不用花費心思管理維護畫面 (view) 的 DOM 元素,因此相比 jQuery 減少很多操作 DOM 元素程式碼。不僅易於上手,還便於與第三方庫或既有項目整合。
Vue 提供的特色如下:
Vue 提供的好處真的很多,讓開發者只需關注在 Model 和 View 上,不用煩惱底層該如何實現。雖然大家都說 Vue 入門門檻低,但對前端超新手的我來說,學習上還是要花許多精力去理解與消化。希望接下來能一步一腳印扎實的學習,跟它成為好朋友 XD
]]>因為公司以 Vue 為開發主要框架,因此在此記錄學習 Vue 的筆記。
搭配六角學院的課程,使用 VS Code 文字編輯器。
在真正開始前,先來個前端歷史小回顧
JavaScript 誕生於1995年,由 Netscape 這家公司專門為其 Netscape 瀏覽器而發明的,目的是需要一種可以嵌入網頁的腳本語言。在 JavaScript 誕生之際,瀏覽器的世界還處於戰國時代,CSS 也才剛剛誕生,各家瀏覽器採用的標準不一,常有在某瀏覽器呈現的畫面,到另一個瀏覽器完全走樣的問題,當時前端工程師的主要工作,通常是維持網頁在各瀏覽器的一致性。
以下是 Wikipedia 整理的瀏覽器年代表:
從這張圖上,可以觀察到在 1995 年前後,有許多五花八門的瀏覽器,進入 2010 左右才慢慢由 Chrome、Firefox、IE、Safari 等幾大家獨佔鰲頭。
在這個混亂的時期,一個叫 ECMA 的國際標準化組織致力於統一標準,他們推出的標準稱為 ECMAScript,例如 ECMAScript 第 5 版會簡稱為 ES5。1999~2010 年之間,JavaScript 通行標準得到廣泛支持,也慢慢轉變成一個成熟的程式語言。今天坊間 JavaScript 學習教材大多採用 ES5 或 ES6,ES6 又稱為 ES2015。
Google 在 2004 年推出 Gmail 服務,以及次年的 Google Map,達成了高度的網頁互動性,可說是 AJAX 躍入舞台的重要時刻,大家知道了 AJAX 的異步請求竟能帶來如此流暢的網頁體驗。
然而當時仍處於瀏覽器與 JavaScript 標準都很紛亂的時期,想要在網頁上實現更強大的功能,就要撰寫更多的 JavaScript,也代表有更多跨瀏覽器校調的苦工。最後就有了 jQuery 在 2006 年出場,統合校調 JavaScript 的各種重覆性作業,讓開發者在操作 DOM 元素減少麻煩,且較不容易發生錯誤。
jQuery 函式庫的出現推動了 AJAX 技術的流行,而 AJAX 技術讓網頁畫面可以透過 JavaScript 在前端動態產生,瀏覽器不需要重新跳頁,因此大大提升使用者體驗。後來就把這種設計原則稱為 Single Page Application,簡稱 SPA。
AJAX 讓 SPA 的概念成形,但 SPA 的實作未必一定只能用 AJAX,由於直接使用 JavaScript 來動態產生畫面,會遇到一些瓶頸,例如一直沒有跳頁,網址不改變,不利於 SEO 等等。
為了在實現 SPA 設計原則的同時解決問題,開始有人提出一套完整的軟體框架,例如 Backbone.js、Angular JS、Vue JS 等等,迎來了前端技術的大爆炸,每個框架有不同的優缺點,但整體來說,都是在面對以下 3 件事:
接下來將介紹這次的主角 Vue.js。
先了解什麼是 Vue,以及為什麼要使用它。
Vue 由前 Google 工程師尤雨溪(Evan You)在 2014 年 2 月所建立。
Vue 是一套開放源碼(Open Source)的漸進式框架(Progressive JavaScript Framework)(階段性使用 Vue,不需要一開始就使用所有的東西)。以操作資料狀態來管理畫面的 MVVM 架構函式庫。由於 MVVM 雙向綁定的好處,讓開發人員專注在 Javascript 資料 (data) 的操作而不用花費心思管理維護畫面 (view) 的 DOM 元素,因此相比 jQuery 減少很多操作 DOM 元素程式碼。不僅易於上手,還便於與第三方庫或既有項目整合。
Vue 提供的特色如下:
Vue 提供的好處真的很多,讓開發者只需關注在 Model 和 View 上,不用煩惱底層該如何實現。雖然大家都說 Vue 入門門檻低,但對前端超新手的我來說,學習上還是要花許多精力去理解與消化。希望接下來能一步一腳印扎實的學習,跟它成為好朋友 XD
]]>Leaflet 是一套開放原始碼的輕量級 JavaScript 網頁地圖函式庫。主要特色:簡單、方便、跨平台
OpenStreetMap (開放街圖,簡稱OSM) 採用類似Wiki的協作編輯以及開放的授權與格式,因而被稱之為「維基版的地圖」,也被視為Google最強大的競爭者。
地圖由多個圖層組成,又每個圖層由多個圖磚(PNG 圖片)所組成
先載入其 css 與 js
var map = L.map('map', {
center: [22.604799,120.2976256],
zoom: 3
});
// 設定地圖,把map定位在 #map,先定位在 center 座標,其縮放等級為 3
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
L.marker([22.604799,120.2976256]).addTo(map)
.bindPopup('<h1>測試藥局</h1><p>成人口罩:50<br>兒童口罩:50</p>')
.openPopup();
// 我要加上一個 marker,並設定他的座標,同時將這個座標放入對應的地圖裡
https://github.com/pointhi/leaflet-color-markers
var greenIcon = new L.Icon({
iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
L.marker([51.5, -0.09], {icon: greenIcon}).addTo(map);
L.marker([22.604799,120.2976256], {icon: greenIcon}).addTo(map)
.bindPopup('<h1>測試藥局</h1><p>成人口罩:50<br>兒童口罩:50</p>')
L.marker([22.6066728,120.3015429]).addTo(map)
.bindPopup('<h1>IKEA</h1><p>成人口罩:50<br>兒童口罩:50</p>')
建立兩個 marker 物件
var data = [
{'name':'軟體園區',lat:22.604799,lng:120.2976256},
{'name':'ikea',lat:22.6066728,lng:120.3015429}
]
for(var i =0;data.length>i;i++){
L.marker([data[i].lat,data[i].lng], {icon: greenIcon}).addTo(map)
.bindPopup('<h1>'+ data[i].name +'</h1>')
}
1.載入額外的Js插件 Leaflet.markercluster => 讓 Marker 群組化
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/MarkerCluster.css"></link>
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/MarkerCluster.Default.css"></link>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/leaflet.markercluster.js"></script>
2.新增一圖層,這圖層專門放 Marker 群組
var markers = new L.MarkerClusterGroup().addTo(map);;
3.在該圖層上放入各個 Marker
for(let i =0;data.length>i;i++){
console.log(data[i].name)
markers.addLayer(L.marker([data[i].lat,data[i].lng], {icon: greenIcon}));
// add more markers here...
// L.marker().addTo(map)
// )
}
map.addLayer(markers);
var markers = new L.MarkerClusterGroup().addTo(map);;
// 開啟一個網路請求
var xhr = new XMLHttpRequest();
// 準備跟某伺服器要什麼資料
xhr.open("get","https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json");
// 執行要資料的動作
xhr.send();
// 當資料回傳時,下面語法就會自動觸發
xhr.onload = function(){
// 把字串String轉成物件陣列的Json格式,我要的是features內的陣列資料
var data = JSON.parse(xhr.responseText).features
// 依序把 marker 放入圖層內
for(let i =0;data.length>i;i++){ markers.addLayer(L.marker([data[i].geometry.coordinates[1],data[i].geometry.coordinates[0]], {icon: greenIcon}).bindPopup(data[i].properties.name));
}
map.addLayer(markers);
}
下判斷,若無剩餘口罩,就顯示為紅色Marker,若還有則是綠色Marker
var map = L.map('map', {
center: [22.604799,120.2976256],
zoom: 16
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
var greenIcon = new L.Icon({
iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var redIcon = new L.Icon({
iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var markers = new L.MarkerClusterGroup().addTo(map);;
var xhr = new XMLHttpRequest();
xhr.open("get","https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json");
xhr.send();
xhr.onload = function(){
var data = JSON.parse(xhr.responseText).features
for(let i =0;data.length>i;i++){
var mask;
if(data[i].properties.mask_adult == 0){
mask = redIcon;
}else{
mask = greenIcon;
} markers.addLayer(L.marker([data[i].geometry.coordinates[1],data[i].geometry.coordinates[0]], {icon: mask}).bindPopup('<h1>'+data[i].properties.name+'</h1>'+'<p>成人口罩數量'+data[i].properties.mask_adult+'</p>'));
// add more markers here...
// L.marker().addTo(map)
// )
}
map.addLayer(markers);
}
HTML5 提供了 Geolocation API 讓使用者可以由 Web Apps 取得目前的位置。而基於隱私權的考量,這些 Web Apps 均必須取得使用者的許可之後,才能發佈位置資訊。
Leaflet 是一套開放原始碼的輕量級 JavaScript 網頁地圖函式庫。主要特色:簡單、方便、跨平台
OpenStreetMap (開放街圖,簡稱OSM) 採用類似Wiki的協作編輯以及開放的授權與格式,因而被稱之為「維基版的地圖」,也被視為Google最強大的競爭者。
地圖由多個圖層組成,又每個圖層由多個圖磚(PNG 圖片)所組成
先載入其 css 與 js
var map = L.map('map', {
center: [22.604799,120.2976256],
zoom: 3
});
// 設定地圖,把map定位在 #map,先定位在 center 座標,其縮放等級為 3
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
L.marker([22.604799,120.2976256]).addTo(map)
.bindPopup('<h1>測試藥局</h1><p>成人口罩:50<br>兒童口罩:50</p>')
.openPopup();
// 我要加上一個 marker,並設定他的座標,同時將這個座標放入對應的地圖裡
https://github.com/pointhi/leaflet-color-markers
var greenIcon = new L.Icon({
iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
L.marker([51.5, -0.09], {icon: greenIcon}).addTo(map);
L.marker([22.604799,120.2976256], {icon: greenIcon}).addTo(map)
.bindPopup('<h1>測試藥局</h1><p>成人口罩:50<br>兒童口罩:50</p>')
L.marker([22.6066728,120.3015429]).addTo(map)
.bindPopup('<h1>IKEA</h1><p>成人口罩:50<br>兒童口罩:50</p>')
建立兩個 marker 物件
var data = [
{'name':'軟體園區',lat:22.604799,lng:120.2976256},
{'name':'ikea',lat:22.6066728,lng:120.3015429}
]
for(var i =0;data.length>i;i++){
L.marker([data[i].lat,data[i].lng], {icon: greenIcon}).addTo(map)
.bindPopup('<h1>'+ data[i].name +'</h1>')
}
1.載入額外的Js插件 Leaflet.markercluster => 讓 Marker 群組化
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/MarkerCluster.css"></link>
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/MarkerCluster.Default.css"></link>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/leaflet.markercluster.js"></script>
2.新增一圖層,這圖層專門放 Marker 群組
var markers = new L.MarkerClusterGroup().addTo(map);;
3.在該圖層上放入各個 Marker
for(let i =0;data.length>i;i++){
console.log(data[i].name)
markers.addLayer(L.marker([data[i].lat,data[i].lng], {icon: greenIcon}));
// add more markers here...
// L.marker().addTo(map)
// )
}
map.addLayer(markers);
var markers = new L.MarkerClusterGroup().addTo(map);;
// 開啟一個網路請求
var xhr = new XMLHttpRequest();
// 準備跟某伺服器要什麼資料
xhr.open("get","https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json");
// 執行要資料的動作
xhr.send();
// 當資料回傳時,下面語法就會自動觸發
xhr.onload = function(){
// 把字串String轉成物件陣列的Json格式,我要的是features內的陣列資料
var data = JSON.parse(xhr.responseText).features
// 依序把 marker 放入圖層內
for(let i =0;data.length>i;i++){ markers.addLayer(L.marker([data[i].geometry.coordinates[1],data[i].geometry.coordinates[0]], {icon: greenIcon}).bindPopup(data[i].properties.name));
}
map.addLayer(markers);
}
下判斷,若無剩餘口罩,就顯示為紅色Marker,若還有則是綠色Marker
var map = L.map('map', {
center: [22.604799,120.2976256],
zoom: 16
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
var greenIcon = new L.Icon({
iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var redIcon = new L.Icon({
iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var markers = new L.MarkerClusterGroup().addTo(map);;
var xhr = new XMLHttpRequest();
xhr.open("get","https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json");
xhr.send();
xhr.onload = function(){
var data = JSON.parse(xhr.responseText).features
for(let i =0;data.length>i;i++){
var mask;
if(data[i].properties.mask_adult == 0){
mask = redIcon;
}else{
mask = greenIcon;
} markers.addLayer(L.marker([data[i].geometry.coordinates[1],data[i].geometry.coordinates[0]], {icon: mask}).bindPopup('<h1>'+data[i].properties.name+'</h1>'+'<p>成人口罩數量'+data[i].properties.mask_adult+'</p>'));
// add more markers here...
// L.marker().addTo(map)
// )
}
map.addLayer(markers);
}
HTML5 提供了 Geolocation API 讓使用者可以由 Web Apps 取得目前的位置。而基於隱私權的考量,這些 Web Apps 均必須取得使用者的許可之後,才能發佈位置資訊。
結合認知心理學與設計心理學,把技術變得更普及化
Don Norman,美國認知科學、人因工程等設計領域的著名學者 [Wiki]
設計只是依照客戶需求畫出設計稿
設計是種信仰:讓開發的產品體貼使用者,進而讓使用者的生活變得更好
以視覺化的方式,將使用者與某件產品或服務進行互動時的體驗分階段呈現出來,讓旅程中的每一個時刻都可接受個別評估和改善
給設計師、前後端工程師看和溝通
10 Usability Heuristics for User Interface Design
這是第一次參與六角學院的線上直播課程。感覺就像是聊天,聽講師的經驗分享。這次聽直播讓我對於一個產品在被給工程師之前的工作流程,有了更清晰的認識,例如需求投點法等。也使我對於設計有不一樣的看法。設計是為了讓人們有更好的生活而存在。而許多相關知識是線下在整理筆記時才有更多了解。在看這些專業知識時,覺得就好像回到以前修設計心理學時老師教授的內容,其中涉及知覺心理學、認知心理學、完形心理學等等。設計,不只是"感覺"好看、好用而已,其背後是有科學理論根據所支持的。而我對於 Don Norman 所提出的情感化設計價值的重要性很感興趣。一個商品帶給人們的喜悅性或許遠重要於其功能性。
]]>結合認知心理學與設計心理學,把技術變得更普及化
Don Norman,美國認知科學、人因工程等設計領域的著名學者 [Wiki]
設計只是依照客戶需求畫出設計稿
設計是種信仰:讓開發的產品體貼使用者,進而讓使用者的生活變得更好
以視覺化的方式,將使用者與某件產品或服務進行互動時的體驗分階段呈現出來,讓旅程中的每一個時刻都可接受個別評估和改善
給設計師、前後端工程師看和溝通
10 Usability Heuristics for User Interface Design
這是第一次參與六角學院的線上直播課程。感覺就像是聊天,聽講師的經驗分享。這次聽直播讓我對於一個產品在被給工程師之前的工作流程,有了更清晰的認識,例如需求投點法等。也使我對於設計有不一樣的看法。設計是為了讓人們有更好的生活而存在。而許多相關知識是線下在整理筆記時才有更多了解。在看這些專業知識時,覺得就好像回到以前修設計心理學時老師教授的內容,其中涉及知覺心理學、認知心理學、完形心理學等等。設計,不只是"感覺"好看、好用而已,其背後是有科學理論根據所支持的。而我對於 Don Norman 所提出的情感化設計價值的重要性很感興趣。一個商品帶給人們的喜悅性或許遠重要於其功能性。
]]>