1. Vue例項及選項
1.1 建立Vue例項(new Vue instance)
每個Vue Application必須建立一個root Vue Instance。
<script> var vm = new Vue({ }); </script>
一個Vue例項相當於一個MVVM模式中的ViewModel。在建立Vue例項時,可以傳入一個選項物件,包含資料、模板、掛載元素、方法、生命週期鉤子等選項。
Vue.js通過建構函式Vue{ option }建立一個Vue例項:
var vm = new Vue({ option });
1.2 元素選項(The Element Option)
<div id="app"></div> <script> 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 生命週期鉤子
每個Vue例項建立時,都會經歷一些列的初始化過程,呼叫相應的生命週期鉤子。
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>
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 屬性上使用{{}}語法。
HTML 屬性中的值應使用 v-bind 指令。
<div id="app"> <div v-bind:title="title">Content</div> </div> <script> var vm = new Vue({ el: "#app", data: { title: "Todo List" } }); </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] )
2.2.2 雙向過濾器
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)。
<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>
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>
計算屬性依賴一個或多個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 呼叫方式將總是再次執行函式。
在某些場景下,不希望有快取,使用 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' }, watch: { 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 只阻止元素自身的點選