基本使用
MVVM架構
MVVM(Model–view–viewmodel)是一種軟體架構模式,分別代表
- Model:模型是指代表真實狀態內容的領域模型(物件導向),或指代表內容的資料存取層(以資料為中心)。
- View:就像在MVC和MVP模式中一樣,視圖是用戶在螢幕上看到的結構、布局和外觀(UI)。
- ViewModel:從Model取得View所需的資料。
Vue.js 是以資料狀態在操作畫面。
應用程式建立
<div id="app"></div> <!-- 建立一個 id="app" 的元素。 --> |
宣告一個變數叫 app,並 new 一個新的 vue 的應用程式( Vue({})
),每個 Vue 應用都是通過用 Vue 函數創建一個新的 Vue 實例。
透過 el 來選擇要綁定的元素(上述建立的 id="app"
元素)。
Vue 可建立兩個以上的應用程式,但無法建立巢狀應用程式。
雙向綁定的資料
Vue,並不完全是 MVVM 的架構,只是受到 MVVM 的啟發。
怎麼透過 vue 來做資料的雙向綁定,建立新的 vue 應用程式。
透過Vue 的指令,v-model
、v-text
、v-html
。
<div id="app"> |
v-model
綁定在表單元件
<input>
、<textarea>
及<select>
或自訂元件上,為實現雙向綁定用的。
<input type="text" v-model='綁定的資料'> |
- 修飾符
.lazy
: 使用.lazy會改用 change 事件監聽,event trigger 才更新。更改 input 內的值並不會馬上變更 model 的資料,而是等到滑鼠移到輸入框外,觸發 change 事件才更新。.number
: 將字串轉為數字。我們在v-model
所得到的值的資料型態是 string。使用.number
將型別改為 number。.trim
: 去除首尾空白。
v-text
更新元素的
textContent
。
<div v-text='綁定的資料'></div> |
v-html
不建議使用,容易導致 XSS 攻擊。更新元素的
innerHTML
。
<div v-html='綁定的資料'></div> |
指令
v-bind 動態屬性指令
用於綁定 HTML 元素上的屬性(attribute)
-
縮寫:
:
-
Modifiers 修飾符
.prop
:將綁定的屬性設定為 DOM property 而非 attribute。.camel
:將帶有「-」分隔 (kebab-case) 的屬性名稱轉為小駝峰 (camelCase)。
<!-- 綁定一個屬性 -->
<img v-bind:src="imageSrc">
<!-- 縮寫 -->
<img :src="imageSrc">
<!-- 通過 prop 修飾符綁定 DOM 屬性 -->
<div v-bind:text-content.prop="text"></div> -
動態 Class 與 Style 的幾種寫法
- 物件寫法 - class 名稱直接寫於行內
<!-- class 綁定 -->
<div :class="{ active: isActive }"></div>
<div :class="[classA, { active: isActive, hasError: isError }]">data: {
isActive: false,
isError: false
} - 物件寫法 - 預先定義資料 class 名稱
<div class="box" :class='objectClass'></div>
<button @click.prevent="objectClass.rotate = !objectClass.rotate">選轉物件</button>
<input type="checkbox" v-model="objectClass['bg-danger']"> <!-- 有出現 - 與使用中括號包住 -->data: {
objectClass: {
'rotate': false,
'bg-danger': false,
},
} - 陣列寫法
<div class="box" :class='arrayClass'></div>
<!-- 與物件不同,需使用 value 將值寫入陣列中 -->
<input type="checkbox" v-model='arrayClass' value ='btn-outline-primary'>
<input type="checkbox" v-model='arrayClass' value ='active'>data: {
arrayClass: []
} - style 綁定
<!-- style 綁定 -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObject, styleObject2]"></div>data: {
styleObject: {
backgroundColor: 'red',
borderWidth: '5px'
},
styleObject2: {
boxShadow: '3px 3px 5px rgba(0, 0, 0, 0.16)'
},
}
- 物件寫法 - class 名稱直接寫於行內
v-for
迭代陣列或者物件中的元素,必須使用特定語法
alias in expression
,為當前迭代的元素提供別名。
<div v-for="item in items"> |
- 陣列
<div v-for="(item, index) in items"></div>
- 物件
<div v-for="(val, key) in object"></div>
<div v-for="(val, name, index) in object"></div>
v-for
迭代陣列或物件時需要設定 key ,是為了避免重複產生 DOM 元素而浪費資源,因此將 key 視為一個辨識的依據,所有的 key 必須保持唯一。
<div v-for="item in items" :key="item.id"> |
- 使用細節
- 建議使用
v-for
都加上key
。使用經常會使用
index
來作為key
,但其實這是不推薦的一種使用方法。 - 不能運作的狀況
- 直接修改 data 內陣列的 length 值,畫面不會變化。
- 直接修改 data 內陣列 or 物件的值,畫面不會變化,如果要強制修改可以使用
Vue-set
API。
- 經常與
Template
一起使用,Template
標籤不會渲染到網頁上。<template v-for="item in 10"></template>
- 與
v-if
一起使用的情況下,v-for
的優先度大於v-if
。
- 建議使用
v-if 判斷
根據表達式 or 判斷式的值的 truthiness 來有條件地渲染元素。
當 truthiness 為 true 時會渲染此元素, flase 則否。
<div v-if="true"></div> |
- 使用細節
- 可以用
v-else
指令给v-if
添加一個 “else”,v-else
元素必須立即跟在v-if
元素的後面——否則它不能被識別。 - 可以把一個
template
元素當做包裝元素,並在上面使用v-if
,Template
標籤不會渲染到網頁上。 v-if
與v-show
的差異v-show
: 元素會始終渲染並保持在 DOM 中。v-show
是簡單的切換元素的 CSS 屬性 display。注意:
v-show
不支持template
語法。v-if
:v-if
是真實的條件渲染,因為它會確保條件塊在切換當中合適地銷毀與重建條件塊內的事件監聽器和子組件。
- 可以用
當和 v-if
一起使用時,v-for
的優先級比 v-if
更高。
v-on
綁定事件監聽器。事件類型由參數指定。
用在普通元素上時,只能監聽原生 DOM 事件。用在自定義元素元件上時,也可以監聽子元件觸發的自定義事件。
-
縮寫:
@
-
事件:
click
- 點擊滑鼠時觸發。dblclick
- 雙點擊滑鼠時觸發。blur
- 失去焦點時觸發。keyup
- 放開按鍵時觸發。
-
事件修飾符:
.stop
- 調用event.stopPropagation()
。.prevent
- 調用event.preventDefault()
。.capture
- 添加事件偵聽器時使用 capture 模式,可將事件的傳遞改由父層往子層傳遞。.self
- 僅僅觸發自己範圍的事件,不包含子層。.once
- 僅在按下第一次時執行 callback function。.native
- 監聽元件根元素的原生事件。
-
按鍵修飾符:
.{keyCode | keyAlias}
- 只當事件是從特定鍵觸發時才觸發回調。- 別名修飾 - .enter, .tab, .delete, .esc, .space, .up, .down, .left, .right
- 修飾符來實現僅在按下相應按鍵時才觸發鼠標或鍵盤事件的監聽器 - .ctrl, .alt, .shift, .meta
.left
- (2.2.0) 只當點擊鼠標左鍵時觸發。.right
- (2.2.0) 只當點擊鼠標右鍵時觸發。.middle
- (2.2.0) 只當點擊鼠標中鍵時觸發。
<!-- 方法處理器 -->
<button v-on:click="doThis"></button>
<!-- 縮寫 -->
<button @click="doThis"></button>
<!-- 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 阻止默認行為 -->
<button @click.prevent="doThis"></button>
<button @click.prevent></button>
<!-- 物件語法 (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
<!-- 動態事件 (2.6.0+) -->
<button v-on:[event]="doThis"></button>
<button @:[event]="doThis"></button>
Methods
- methods 就是互動的函式,需要觸發才會運作,用來修改資料內容。
- computed 是在監控資料更動後,重新運算結果呈現於畫面上,一般來說不會修改資料,只會回傳用於畫面呈現的資料。
- 效能
- 如果資料量大,computed 自然會比較慢,且只要資料變動就會觸發,無形之中執行次數也會增加。
- 建議在大量資料時,透過 methods 。
computed 運算功能
當其依賴的屬性的值發生變化的時,computed 會重新計算。反之則使用記憶體中的屬性值。
{{ aDouble }} |
computed: { |
watch 監聽
監控特定變數,當變數改變時可以執行相對應的 function。
data: { |
表單綁定
使用
v-model
將表單與 data 綁定
input
- 於input
輸入的字串可及時寫入 data 內的text
,並透過雙向綁定將結果輸出至畫面 。textarea
亦同。
<input type="text" v-model='text'>
{{ text }}
<script>
var app = new Vue({
el: '#app',
data: {
text: '',
},
});
</script>checkbox
- 透過v-model
更改 data 內checkbox1
的 boolean 值。- 預設值為 true or false
<input type="checkbox" id="check1" v-model="checkbox1">
<label for="check1"> {{checkbox1}} </label> <!-- true or false -->
<script>
var app = new Vue({
el: '#app',
data: {
checkbox1: false,
},
});
</script> - 自定義值 - 如想使用自定義的值情況下,可使用
true-value
&false-value
。<input type="checkbox" id="check1" v-model="checkbox1" true-value="1" false-value="2">
<label for="check1"> {{checkbox1}} </label> <!-- 1 or 2 -->
<script>
var app = new Vue({
el: '#app',
data: {
checkbox1: false,
},
});
</script>
- 預設值為 true or false
checkbox(value)
-checkbox
為複選項,透過v-model
將checkbox
內的value
push 進 data 內checkboxArray
的陣列中。<div class="form-check">
<input type="checkbox" id="check2" value="雞" v-model='checkboxArray'>
<label for="check2">雞</label>
</div>
<div class="form-check">
<input type="checkbox" id="check3" value="豬" v-model='checkboxArray'>
<label for="check3">豬</label>
</div>
<div class="form-check">
<input type="checkbox" id="check4" value="牛" v-model='checkboxArray'>
<label for="check4">牛</label>
</div>
<p>晚餐火鍋裡有 <span v-for="item in checkboxArray">{{item}} </span>。</p>
<script>
var app = new Vue({
el: '#app',
data: {
checkboxArray: [],
},
});
</script>radio
-radio
為單選項,透過v-model
將singleRadio
內的value
修改並寫入 data 內singleRadio
的資料中。<div class="form-check">
<input type="radio" id="radio2" value="雞" v-model="singleRadio">
<label for="radio2">雞</label>
</div>
<div class="form-check">
<input type="radio" id="radio3" value="豬" v-model="singleRadio">
<label for="radio3">豬</label>
</div>
<div class="form-check">
<input type="radio" id="radio4" value="牛" v-model="singleRadio">
<label for="radio4">牛</label>
</div>
<p>晚餐火鍋裡有 {{ singleRadio }}。</p>
<script>
var app = new Vue({
el: '#app',
data: {
singleRadio: '',
},
});
</script>select
- 選單,透過v-model
將option
內的value
修改並寫入 data 內selected
的資料中。<select name="" id="" class="form-control" v-model="selected">
<option value="" disabled>-- default --</option>
<option value="1"> 1 </option>
<option value="2"> 2 </option>
<option value="3"> 3 </option>
<script>
var app = new Vue({
el: '#app',
data: {
selected: '',
},
});
</script>
生命週期
|
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
Component 元件
在一個頁面中,可能會有頁頭、側邊欄、內容區等等內容。
regist
元件註冊的方式有兩種,分別為 global component(全局註冊) 與 local component(局部註冊)。
-
global - 使用
Vue.component
註冊的 component ,任何 Vue 實例都可以使用。第一個參數為 組件名稱。<my-component></my-component>
<script>
//component註冊要在Vue實例宣告之前
Vue.compoenet('my-component',{
props:[],
});
</script>
props
為外層傳遞至元件內的資料。
tamplate
為要渲染出的HTML內容,可以直接寫在內部,或者建立一個text/x-template
的區塊,再指向此區塊。<script type="text/x-template" id="Xcomponent">
</script>
<script>
//component註冊要在Vue實例宣告之前
Vue.compoenet('my-component',{
props:[],
tamplate:"#Xcomponent"
});
</script> -
lacal - 使用變數註冊的 component ,只有註冊此 component 的 Vue 實例才可以使用。
<script>
var child = {
props:{},
}
new Vue({
el:"#app1",
components: {"my-component": child}
});
</script>
data
一個元件的
data
選項必須是一個函數,如此每個元件內的資料才能獨立,不互相干擾。
<script> |
props
Prop 是你可以在元件上註冊的一些自定義 attribute。當一個值傳遞給一個 prop attribute 的時候,它就變成了那個元件實例的一個屬性。
用一個props
選項,為一個陣列,內為自定義的 attribute。作為傳遞至元件內的 attribute 。
props:[], |
靜態與動態傳遞參數
Vue.component('blog-post', { |
單向數據流
數據從父級元件傳遞給子元件,子元件內部不能直接修改從父級傳遞過來的數據,console 會出現錯誤。
但這個子元件接下來希望將其作為一個本地的 prop 數據來使用。在這種情況下,
- 定義一個本地的 data 屬性並將這個 prop 用作其初始值。
props: ['propData'],
data: function () {
return {
newData: this.propData
}
} - 這個 prop 以一種原始的值傳入且需要進行轉換。使用 computed 屬性。
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
尚未宣告的變數
在使用非同步方式拉取資料時,因資料尚未完全抓取完畢,但畫面已開始渲染,可以使用 v-if
判斷資料是否已經抓取完畢後再渲染此元件。
維持狀態與生命週期
當我們需要保留狀態的時候用 keep-alive
這個標籤,包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。
<keep-alive> |
型別
有時,希望每個 prop 都有指定的值類型。這時,你可以以物件形式列出 prop,這些屬性的名稱和值分別是 prop 各自的名稱和類型。
props: { |
- 使用靜態傳入參數方式,傳入的值型別皆為
string
。 - 使用動態傳入方式,來告訴 Vue ,這是一個 JavaScript 表達式而不是一個字符串。
依資料型態來決定型別。
預設值
在未傳入 prop 時,希望此 prop 預先帶有一個值,可以使用物件方式新增一個 default
屬性,賦予此 prop 一個預設值。
props: { |
emit
透過「事件」來觸發父元件的函式。
vm.$emit( eventName, […args] )
-
參數
{string} eventName
: 事件的命名不能為大寫,所以能夠採用 kebab-case 命名。[...args]
-
只配合一個事件名使用
$emit
子元件內methods: {
demoDun() {
this.$emit('自定義的emit事件名稱')
}
}父元件中
<button @自定義的emit事件名稱 = "要呼叫的 function"></button>
-
配合額外的參數使用
$emit
子元件內methods: {
demoDun() {
this.$emit('自定義的emit事件名稱', 帶入的參數)
}
}父元件中
<button @自定義的emit事件名稱 = "要呼叫的 function"></button>
<script>
methods: {
要呼叫的function(newData) {
console.log(newData)
}
}
</script>
slot
可以在父元件新增內容,插入至子元件中。
- 基本使用
- 有一個
mybtn
的子元件。<button>
<slot>submit</slot>
</button> - 父元件未傳入內容時,此元件會顯示預設的文字,當傳入內容時則會替代原本的內容。
- 父元件使用
mybtn
元件,並傳入文字 “送出”。<template>
<mybtn>送出</mybtn>
</template>
- 有一個
- 具名插槽
當要傳入的內容有多個的情況下,可以為每一個插槽命名並個別插入內容。
對於這樣的情況,<slot>
元素有一個特殊的 attribute:name
。這個 attribute 可以用來定義額外的插槽。- 有一個
base-layer
的元件<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div> - 向具名插槽提供內容的時候,我們可以在一個
<template>
元素上使用v-slot
指令,並以v-slot
的參數的形式提供其名稱<base-layout>
<template v-slot:header>
<h1>希望把頁頭放這裡</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:default>
<!-- 任何沒有被包裹在帶有 v-slot 的 <template> 中的內容都會被視為默認插槽的內容。 -->
</template>
<template v-slot:footer>
<p>希望把頁腳放這裡</p>
</template>
</base-layout>
注意:
v-slot
只能添加在<template>
上- 具名插槽的縮寫
v-slot
也有縮寫,即把參數之前的所有內容 (v-slot:
) 替換為字符#
。<base-layout>
<template #header>
<h1>希望把頁頭放這裡</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template #footer>
<p>希望把頁腳放這裡</p>
</template>
</base-layout>
- 有一個
is
解析 DOM 模板時,有些 HTML 元素,諸如
<ul>
、<ol>
、<table>
和<select>
,對於哪些元素可以出現在其內部是有嚴格限制的。
而有些元素,諸如<li>
、<tr>
和<option>
,只能出現在其它某些特定的元素內部。
此時可以將原本元件的寫法改用is
。
<table> |
動態組件
有的時候,在不同組件之間進行動態切換是非常有用的。
<!-- 組件會在 `currentComponent` 改變時改變 --> |
currentTabComponent
可以包括
- 已註冊組件的名字
- 一個組件的選項物件
v-model
在 vue2.x 裡 v-model
其實是一種用單向綁定與事件而實現的雙向綁定語法,可將此方法實現於元件中。
- 解析
v-model
等同於<input v-model="inputData">
<input :value="inputData"
@input="inputData = $event.target.value"> - 實作
- parents
<my-component v-model="inputData">
</my-component> - child
:value
在 component 裡要 props@input
在 component 裡要 $emit<input :value="inputData"
@input="$emit('input', $event.target.inputData)">
<script>
export default {
props: ['value'],
}
</script>
- parents
Vue 常用 API
Extend
extend 是基礎建構的概念
// 創建構造器 |
- 可以從元件內引用 - 使用
extends
屬性,但只能指定1個。Vue.component('myComponent',{
props: ['props'],
extends: newExtend
}) - 可以新增資料,不會取代從 extend 的繼承的資料。
但是有相同的資料下會取代舊有的資料。Vue.component('myComponent',{
props: ['props'],
data: function() {
return {
newData: '這是新增的資料' // 新增的資料,可以並存
data: '這是元件取代的資料' // 會取代從 extent 取得的資料
}
},
extends: newExtend
})
Filter
自定義過濾器,可被用於一些常見的字串格式化。
過濾器可以用在兩個地方:
- 雙大括號插值
- v-bind 表達式 (後者從 2.1.0+ 開始支持)。
過濾器應該被添加在 JavaScript 表達式的尾部,由“管道”符號指示
<!-- 在雙大括號中 --> |
// 全域註冊 |
Example:
// 數值前方加入 $ 符號 |
set
在有些情況下,Vue 的資料無法預先定義,此時將資料寫入的話,無法觸發視圖更新。
於此情形下,可以使用vue.$set()
方法添加資料,並確保這個新屬性同樣是響應式的,且可觸發視圖更新。
// 全域註冊 |
- 參數
target {Object | Array}
- 目標。如this.data
。propertyName {string | number}
- 屬性名稱。value {any}
- 要添加的值。
Mixin
mixin 是多個混合的概念,可用來分發 Vue 組件中的可重複功能。
var myMixin = { |
Directive
Vue 允許註冊自定義指令。(Directive - 自定義指令)
// 註冊一個全局自定義指令 |
el
:指令所綁定的元素,可以用來直接操作 DOM。binding
:一個對象,包含以下屬性:name
:指令名,不包括v-
前綴。value
:指令的綁定值oldValue
:指令綁定的前一個值,僅在update
和componentUpdated
鉤子中可用。expression
:字符串形式的指令表達式。arg
:傳給指令的參數,可選。modifiers
:一個包含修飾符的對象。
vnode
:Vue 編譯生成的虛擬節點。
<!-- 使用 --> |