1. Vue實例及選項
1.1 創建Vue實例(new Vue instance)
每個Vue Application必須創建一個root Vue Instance。
<script>
var vm = new Vue({
});
</script>
一個Vue實例相當於一個MVVM模式中的ViewModel。在創建Vue實例時,可以傳入一個選項對象,包括掛載元素(el)、數據(data)、方法(methods)、模板(template)、生命周期鈎子等選項。

Vue.js通過構造函數Vue{ option }創建一個Vue實例:
var vm = new Vue({ option });
1.2 元素選項(The Element Option)
<div id="app"></div> <script> /** * 實例化vue對象 * 每個Vue.js應用都是通過構造函數Vue創建一個Vue的根實例啟動的 * 實例化Vue時,需要傳入一個選項對象 * el:elment需要獲取的對象,一定是html中的根容器元素 * data:用於存儲數據 */ var vm = new Vue({ el: "#app" }); </script>
1.3 數據選項(The Data Option)
<div id="app">{{ title }}</div> <script> var vm = new Vue({ el: "#app", data: { title: "標題" } }); </script>
1.4 方法methods
<div id="app"> {{ title }} {{ hello() }} <button @click="say">Hello</button> </div> <script> var vm = new Vue({ el: "#app", data: { title: "Hello World!" }, methods: { hello() { return "Hello Vue.js"; }, say() { console.log("Hello World!"); } } }); </script>
1.5 生命周期鈎子
每個Vue實例創建時,都會經歷一些列的初始化過程,調用相應的生命周期鈎子。
Vue生命周期分為8個階段:beforeCreate(創建前)、created(創建后)、beforeMount(掛載前)、mounted(掛載后)、beforeUpdate(更新前)、updated(更新后)、beforeDestroy(銷毀前)、destroyed(銷毀后)。
Vue生命周期鈎子:
◊ created:實例創建完成后調用,此階段完成數據監測等,但尚未掛載,$el 還不可用。
◊ mounted:el 掛載到實例后調用。
<div id="app">{{ title }}</div> <script> var vm = new Vue({ el: "#app", data: { title: "標題" }, created: function () { console.log("Vue instance has been created!"); } }); </script>
<div id="app">{{ title }}</div> <script> var vm = new Vue({ el: "#app", data: { title: "標題" }, created() { console.log("Vue instance has been created!"); }, mounted() { console.log("mounted:" + this.$el); // <div id="app"></div> // console.log("mounted:" + this.$el.id); } }); </script>
Vue各生命周期在真實場景的業務邏輯應用:
◊ created:進行Ajax請求異步數據的獲取、初始化數據。
◊ mounted:掛載元素內DOM節點的獲取。
◊ nextTick:針對單一事件更新數據后立即操作DOM。
◊ updated:數據更新的統一業務邏輯處理。
◊ watch:監聽具體數據變化,並做相應的處理。
2. 模板語法
Vue.js創建實例對象的選項中影響模板或DOM的選項:el 和 template。
◊ el :類型為字符串,DOM 元素或函數。其作用是為實例提供掛載元素。
◊ template:類型為字符串。默認會將template 值替換掛載元素(即el 值對應的元素),並合並掛載元素和模板根節點的屬性。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>libing.vue</title> <script src="node_modules/vue/dist/vue.min.js"></script> </head> <body> <div id="app"> <h1>將被模板內容替換</h1> </div> <template id="tpl"> <div class="tpl">Todo List</div> </template> <script> var vm = new Vue({ el: "#app", template: "#tpl" }); </script> </body> </html>
渲染輸出HTML:
<body> <div class="tpl">Todo List</div> <template id="tpl"> <div class="tpl">Todo List</div> </template> <script> var vm = new Vue({ el: "#app", template: "#tpl" }); </script> </body>
Vue.js使用基於HTML的模版語法,允許聲明式地將DOM綁定至Vue實例的數據。
Vue.js的核心:采用模板語法聲明式的將數據渲染到DOM。
2.1 插值(Interpolations)
2.1.1 文本(Text)
Vue.js 實例中通過 data 屬性定義數據,這些數據可以在實例對應的模板中進行綁定並使用。
數據綁定:{{ }}
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>libing.vue</title> <script src="node_modules/vue/dist/vue.min.js"></script> </head> <body> <div id="app"> <h1>{{ title }}</h1> </div> <script> var vm = new Vue({ el: "#app", data: { title: "Todo List" } }); </script> </body> </html>
2.1.2 原始HTML(Raw HTML)
{{ }}:將數據中的 HTML 轉為純文本后再進行插值。
v-html :輸出 HTML 代碼
<div id="app"> <div v-html="title"></div> </div> <script> var vm = new Vue({ el: "#app", data: { title: "<h1>Todo List</h1>" } }); </script>
2.1.3 屬性(Attributes)
不能在 Vue 模板中的 HTML 屬性上使用{{}}語法。
<div id="app"> <a href="{{url}}">鏈接</a><!-- 錯誤 --> </div> <script> var vm = new Vue({ el: "#app", data: { url: "https://www.baidu.com/" } }); </script>
HTML 屬性中的值應使用 v-bind 指令。
<div id="app"> <a v-bind:href="url">鏈接</a> </div> <script> var vm = new Vue({ el: "#app", data: { url: "https://www.baidu.com/" } }); </script>
2.1.4 表達式
<div id="app"> {{ status ? "是" : "否" }} <div v-bind:title="status?'是':'否'">Content</div> </div> <script> var vm = new Vue({ el: "#app", data: { status: true } }); </script>
2.2 過濾器(Filters)
2.2.1 注冊過濾器
Vue.js 允許在表達式后添加可選的過濾器,以管道符 “|” 指示。
<div id="app"> <h1>{{ title | uppercase }}</h1> </div> <script> var vm = new Vue({ el: "#app", data: { title: "Todo List" }, filters: { uppercase: function (value) { return value.toUpperCase(); } } }); </script>
多個過濾器鏈式使用:
{{ name | filterA | filterB }}
傳入多個參數:
{{ name | filterA arg1 arg2}}
此時,filterA 將 name 的值做為第一個參數,arg1,arg2 做為第二、第三個參數傳入過濾器函數中。
Vue.js 提供全局方法Vue.filter() 注冊一個自定義過濾器,接受過濾器ID 和過濾器函數兩個參數。
過濾器注冊語法格式:
Vue.filter( id, [definition] )
示例:日期格式過濾器
引入moment.js:
npm install -S moment
import Vue from 'vue' import moment from 'moment' Vue.filter('datefmt', function (input, fmtstring) { return moment(input).format(fmtstring); }); new Vue({ el: '#app', data: { now: new Date() } })
{{ now | datefmt('YYYY-MM-DD HH:mm:ss') }}
2.3 指令(Directives)
指令是帶有 v- 前綴的特殊屬性。
指令用於在表達式的值改變時,將某些行為應用到 DOM 上。
v-bind指令:用於響應式地更新 HTML 屬性。
v-on 指令:用於監聽 DOM 事件。
<div id="app"> <h1 v-if="status">{{ title }}</h1> </div> <script> var vm = new Vue({ el: "#app", data: { title: "Todo List", status: true } }); </script>
2.3.1 參數(Arguments)
一些指令能夠接受一個參數,參數在指令后以冒號(:)表示。
<div id="app"> <a v-bind:href="url">libingql</a> </div> <script> var vm = new Vue({ el: "#app", data: { url: "https://www.cnblogs.com/libingql" } }); </script>
2.3.2 修飾符(Modifiers)
修飾符:以句號 . 表示的特殊后綴,用於指出一個指定應該以特殊方式綁定。
示例:.prevent 修飾符告訴 v-on 指令對於觸發的事件調用 event.preventDefault()
<form v-on:submit.prevent="onSubmit"></form>
2.4 用戶輸入
在 input 輸入框中使用 v-model 指令來實現雙向數據綁定。
<div id="app"> <div>{{ title }}</div> <input type="text" v-model="title" /> </div> <script> var vm = new Vue({ el: "#app", data: { title: "Todo List" } }); </script>
2.5 簡寫(Shorthands)
Vue.js 為 v-bind 和 v-on 這兩個最常用的指令,提供特定簡寫。
2.5.1 v-bind 簡寫
<!-- 完整語法 --> <a v-bind:href="url"> ... </a> <!-- 簡寫 --> <a :href="url"> ... </a>
2.5.2 v-on 簡寫
<!-- 完整語法 --> <a v-on:click="doSomething"> ... </a> <!-- 簡寫 --> <a @click="doSomething"> ... </a>
3. 條件語句
3.1 v-if
v-if指令:條件判斷
在 <template> 上使用 v-if 進行條件分組
<div id="app"> <h1 v-if="seen">Todo List</h1> <template v-if="ok"> <ul> <li>Todo Item</li> <li>Todo Item</li> <li>Todo Item</li> </ul> </template> </div> <script> var vm = new Vue({ el: "#app", data: { seen: true, ok: true } }); </script>
3.2 v-else
v-if / v-else語句塊:
<div id="app"> <h1 v-if="ok">是</h1> <h1 v-else>否</h1> </div> <script> var vm = new Vue({ el: "#app", data: { ok: true } }); </script>
3.3 v-if-else
v-if-else:v-if 之后的“else-if 塊”,可以多次鏈式地調用。
<div id="app"> <div v-if="type === 'A'"> A </div> <div v-else-if="type === 'B'"> B </div> <div v-else-if="type === 'C'"> C </div> <div v-else> Not A/B/C </div> </div> <script> new Vue({ el: '#app', data: { type: 'C' } }); </script>
3.4 v-show
v-show:根據條件展示元素
v-show 的元素會始終渲染並保留在 DOM 中。v-show 只會切換元素的 display 這個 CSS 屬性。
<div id="app"> <h1 v-show="ok">Todo List</h1> </div> <script> var vm = new Vue({ el: "#app", data: { ok: true } }); </script>
注:v-show 無法用於 <template> 元素,也不能和 v-else 配合使用。
3.5 v-if 和 v-show
v-if 是“真實”的條件渲染,因為它會確保條件塊(conditional block)在切換的過程中,完整地銷毀(destroy)和重新創建(re-create)條件塊內的事件監聽器和子組件。
v-if 是惰性的(lazy):如果在初始渲染時條件為 false,它不會執行任何操作 - 在條件第一次變為 true 時,才開始渲染條件塊。
v-show 不管初始條件如何,元素始終渲染,並且只是基於 CSS 的切換。
通常來說,v-if 在切換時有更高的性能開銷,而 v-show 在初始渲染時有更高的性能開銷。
如果需要頻繁切換,推薦使用 v-show,如果條件在運行時改變的可能性較少,推薦使用 v-if。
4. 循環語句
4.1 v-for遍歷數組
v-for 遍歷數組格式:
item in items
其中,
items 是原始數據數組(source data array),
item 是數組中每個迭代元素的指代別名(alias)。
可以使用of代替in作為分隔符,of是最接近JavaScript迭代器的語法。
item of items
<div id="app"> <ul> <li v-for="item in items">{{ item.text }}</li> </ul> </div> <script> var vm = new Vue({ el: "#app", data: { items: [{ id: 1, text: "Vue" }, { id: 2, text: "Angular" }, { id: 3, text: "React" }] } }); </script>
<div id="app"> <ul> <li v-for="item in list">{{ item.text }}</li> </ul> </div> new Vue({ el: '#app', data: { list: [{ id: 1, text: 'Vue' }, { id: 2, text: 'Angular' }, { id: 3, text: 'React' }] } });
v-for索引參數:
<li v-for="(item, index) in items">{{ index }}-{{ item.text }}</li>
其中,index從0開始。
4.2 v-for遍歷對象
v-for 可以遍歷對象的屬性。
<div id="app"> <ul> <li v-for="value in item">{{ value }}</li> </ul> </div> <script> var vm = new Vue({ el: "#app", data: { item: { id: 1, text: "Vue" } } }); </script>
v-for遍歷對象屬性:兩個參數key、value
<div id="app"> <ul> <li v-for="(value, key) in item">{{ key }}:{{ value }}</li> </ul> </div> <script> var vm = new Vue({ el: "#app", data: { item: { id: 1, text: "Vue" } } }); </script>
v-for遍歷對象屬性:3個參數index、key、value,索引(index)從0開始。
<div id="app"> <ul> <li v-for="(value, key, index) in item">{{ index }}-{{ key }}:{{ value }}</li> </ul> </div> <script> var vm = new Vue({ el: "#app", data: { item: { id: 1, text: "Vue" } } }); </script>
4.3 key
為便於 Vue 跟蹤每個節點的身份,重新復用(reuse)和重新排序(reorder)現有元素,需要為每項提供唯一的 key 屬性,從而給 Vue 一個提示。
理想的 key 值是每項都有唯一的 id。
推薦:在使用 v-for 時,盡可能提供一個 key,除非迭代的 DOM 內容足夠簡單,或者是故意依賴於默認行為來獲得性能提升。
<div id="app"> <ul> <li v-for="item in items" v-bind:key="item.id">{{ item.text }}</li> </ul> </div> <script> var vm = new Vue({ el: "#app", data: { items: [{ id: 1, text: "Vue" }, { id: 2, text: "Angular" }, { id: 3, text: "React" }] } }); </script>
簡寫:
<li v-for="item in items" :key="item.id">{{ item.text }}</li>
4.4 v-for遍歷整數
v-for可以在整數值范圍內迭代。
<div id="app"> <ul> <li v-for="n in 10">{{ n }}</li> </ul> </div> <script> new Vue({ el: '#app' }); </script>
4.5 計算(computed)屬性與監聽(watch)屬性
4.5.1 計算(computed)屬性
在模板中使用表達式是非常方便直接的,只適用於簡單的操作,不適於加入過多的邏輯。
對於復雜的邏輯,使用 computed 屬性(computed property)。
計算屬性都以函數的形式,在Vue實例的computed選項中,最終返回計算后的結果。
<div id="app"> {{ fullName }} </div> <script> new Vue({ el: '#app', data: { firstName: "bing", lastName: "li" }, computed: { fullName: function () { return this.lastName + ' ' + this.firstName; } } }); </script>
計算屬性內部的this指向Vue實例。
計算屬性依賴一個或多個Vue實例的數據,只要其中任一數據變化,計算屬性就會重新執行,視圖(vm)也會更新。
<div id="app"> <table> <tr> <th>商品ID</th> <th>商品名稱</th> <th>單價</th> <th>數量</th> </tr> <tr v-for="item in products"> <td>{{ item.ID }}</td> <td>{{ item.ProductName }}</td> <td>{{ item.UnitPrice }}</td> <td> <input type="text" v-model="item.Quantity" /> </td> </tr> <tr> <td colspan="4" style="text-align: right;">總計:{{ total }}</td> </tr> </table> </div> <script> var vm = new Vue({ el: "#app", data: { products: [{ ID: 1, ProductName: "手機", UnitPrice: 1000, Quantity: 2 }, { ID: 2, ProductName: "電腦", UnitPrice: 5000, Quantity: 5 }] }, computed: { total: function () { var total = 0; for (var i = 0; i < this.products.length; i++) { total += this.products[i].Quantity * this.products[i].UnitPrice; } return total; } } }); </script>
computed 屬性默認只有 getter ,可以在需要時提供一個 setter 。
<div id="app"> {{ fullName }} </div> <script> var vm = new Vue({ el: '#app', data: { firstName: "Bing", lastName: "Li" }, computed: { fullName: { get: function () { return this.lastName + ' ' + this.firstName; }, set: function (value) { var names = value.split(' ') this.lastName = names[0] this.firstName = names[names.length - 1] } } } }); vm.fullName = "Li Bing2018"; </script>
4.5.2 computed 緩存 vs method 方法
computed屬性會基於它所依賴的數據進行緩存。每個 computed 屬性,只有在它所依賴的數據發生變化時,才會重新取值(re-evaluate)。
<div id="app"> {{ now }} </div> <script> new Vue({ el: '#app', computed: { now: function () { return Date.now() } } }); </script>
method方法:每當觸發重新渲染(re-render)時,method 調用方式將總是再次執行函數。不管依賴的數據是否改變,methods都會重新計算。
在某些場景下,不希望有緩存,使用 method 方法替代。
<div id="app"> {{ now() }} </div> <script> new Vue({ el: '#app', methods: { now: function () { return Date.now() } } }); </script>
4.5.3 computed 屬性和 watch 屬性
watch 屬性:Vue 提供的一種更加通用的方式,來觀察和響應 Vue 實例上的數據變化。
過度濫用 watch 屬性會造成一些問題,更推薦的方式是,使用 computed 屬性。
<div id="app"> <input type="text" v-model="firstName"> <input type="text" v-model="lastName"> <div>{{ fullName }}</div> </div> <script> new Vue({ el: '#app', data: { firstName: 'Bing', lastName: 'Li', fullName: 'Li Bing' }, computed: { firstName: function (val) { this.fullName = this.lastName + ' ' + val; }, lastName: function (val) { this.fullName = val + ' ' + this.firstName; } } }); </script>
<script> new Vue({ el: '#app', data: { firstName: 'Bing', lastName: 'Li', fullName: 'Li Bing' }, watch: { firstName: function () { this.fullName = this.lastName + ' ' + this.firstName; }, lastName: function () { this.fullName = this.lastName + ' ' + this.firstName; } } }); </script>
5. 樣式綁定:class和style
5.1 class綁定
5.1.1 對象語法
向 v-bind:class 傳入一個對象,來動態地切換 class。
<div id="app"> <div v-bind:class="{ active: isActive }"></div> </div> <script> new Vue({ el: '#app', data: { isActive: true } }); </script>
渲染:
<div class="active"></div>
active 這個 class 的存在與否,取決於 isActive 這個 data 屬性的 truthy 值。
v-bind:class 指令可以和普通 class 屬性共存。可以通過在對象中添加多個字段,來切換多個 class。
<div id="app"> <div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"></div> </div> <script> new Vue({ el: '#app', data: { isActive: true, hasError: false } }); </script>
渲染:
<div class="static active"></div>
綁定對象,可以無需內聯。
<div id="app"> <div v-bind:class="className"></div> </div> <script> new Vue({ el: '#app', data: { className: { active: true, 'text-danger': true } } }); </script>
渲染:
<div class="active text-danger"></div>
綁定返回對象的計算屬性。
<div id="app"> <div v-bind:class="className"></div> </div> <script> new Vue({ el: '#app', data: { isActive: true, hasError: true }, computed: { className: function () { return { active: this.isActive, 'text-danger': this.hasError } } } }); </script>
5.1.2 數組語法
可以向 v-bind:class 傳入一個數組,來與 class 列表對應。
<div id="app"> <div v-bind:class="[activeClass, errorClass]"></div> </div> <script> new Vue({ el: '#app', data: { activeClass: 'active', errorClass: 'text-danger' } }); </script>
三元表達式:
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
數組語法中使用對象語法:
<div id="app"> <div v-bind:class="[{ active: isActive }, errorClass]"></div> </div> <script> new Vue({ el: '#app', data: { isActive: true, errorClass: 'text-danger' } }); </script>
5.2 style綁定
5.2.1 對象語法
v-bind:style 直接設置樣式
<div id="app"> <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> </div> <script> new Vue({ el: '#app', data: { activeColor: 'red', fontSize: 30 } }); </script>
渲染:
<div style="color: red; font-size: 30px;"></div>
綁定對象
<div id="app"> <div v-bind:style="style"></div> </div> <script> new Vue({ el: '#app', data: { style: { color: 'red', fontSize: '13px' } } }); </script>
v-bind:style 的對象語法,可以和 computed 屬性結合使用,此 computed 屬性所對應的 getter 函數需要返回一個對象。
5.2.2 數組語法
v-bind:style 的數組語法,可以在同一個元素上,使用多個 style 對象。
<div id="app"> <div v-bind:style="[baseStyles, overridingStyles]"></div> </div> <script> new Vue({ el: '#app', data: { baseStyles: { color: 'red', fontSize: '30px' }, overridingStyles: { 'font-weight': 'bold' } } }); </script>
渲染:
<div style="color: red; font-size: 30px; font-weight: bold;"></div>
6. 事件處理
6.1 監聽事件
v-on 指令:監聽 DOM 事件,並在事件被觸發時執行 JavaScript 代碼。
<div id="app"> <button v-on:click="counter += 1">增加 1</button> <div>按鈕點擊次數:{{ counter }}次</div> </div> <script> new Vue({ el: '#app', data: { counter: 0 } }); </script>
6.2 定義在 methods 對象中的事件處理器
用於處理邏輯復雜事件
<div id="app"> <button v-on:click="greet">greet</button> </div> <script> var vm = new Vue({ el: '#app', data: { name: "Li Bing" }, methods: { greet: function (event) { // `this` 在方法里指當前 Vue 實例 alert('Hello ' + this.name + '!') // `event` 是原生 DOM 事件 if (event) { alert(event.target.tagName) } } } }); // 可以用 JavaScript 直接調用方法 vm.greet() // -> 'Hello Li Bing!' </script>
6.3 定義在行內的事件處理器
<div id="app"> <button v-on:click="greet('Li Bing')">greet</button> </div> <script> var vm = new Vue({ el: '#app', methods: { greet: function (name) { alert('Hello ' + name + '!'); } } }); </script>
6.4 事件修飾符(Event Modifiers)
在事件處理程序中常見調用 event.preventDefault() 或 event.stopPropagation()
v-on 提供事件修飾符,以點(.)開頭的指令后綴來表示。
◊ .stop
◊ .prevent
◊ .capture
◊ .self
◊ .once
<!-- 停止點擊事件冒泡 --> <a v-on:click.stop="doThis"></a> <!-- 提交事件不再重新載入頁面 --> <form v-on:submit.prevent="onSubmit"></form> <!-- 修飾符可以鏈式調用 --> <a v-on:click.stop.prevent="doThat"></a> <!-- 只有修飾符 --> <form v-on:submit.prevent></form> <!-- 添加事件監聽器時,使用事件捕獲模式 --> <!-- 內部元素觸發的事件先在此處處理,然后才交給內部元素進行處理 --> <div v-on:click.capture="doThis">...</div> <!-- 只有在 event.target 是元素自身時,才觸發處理函數。 --> <!-- 也就是說,event.target 是子元素時,不觸發處理函數 --> <div v-on:click.self="doThat">...</div>
v-on:click.prevent.self 阻止所有點擊
v-on:click.self.prevent 只阻止元素自身的點擊
