Vue是一個前端框架,簡單來說,其目標是通過盡可能簡單的 API 實現響應的數據綁定和組合的視圖組件。
國際慣例HelloWorld
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{ msg }}
</div>
<script>
var app=new Vue({
el:'#app',
data:{
msg:'Hello World!'
}
});
</script>
</body>
</html>
[1]Vue實例
創建一個Vue實例
Var vm = new Vue({
//選項
})
當創建一個Vue實例時,你可以傳入一個選項對象,該對象可以創建你想要的行為。
一個Vue應用由一個通過new Vue創建的根Vue實例,以及可選的嵌套的,可復用的組件樹組成。所有的Vue組件都是Vue實例,并且接受相同的選項對象(一些根實例特有的選項除外)。
數據響應
當一個 Vue 實例被創建時,它向 Vue 的響應式系統中加入了其 data 對象中能找到的所有的屬性。當這些屬性的值發生改變時,視圖將會產生“響應”,即匹配更新為新的值。
// 我們的數據對象
var data = { a: 1 }
// 該對象被加入到一個 Vue 實例中
var vm = new Vue({
data: data
})
// 獲得這個實例上的屬性
// 返回源數據中對應的字段
vm.a == data.a // => true
// 設置屬性也會影響到原始數據
vm.a = 2
data.a // => 2
// ……反之亦然
data.a = 3
vm.a // => 3
值得注意的是只有當實例創建時data中存在的屬性才是響應式的。
實例生命周期鉤子
每個 Vue 實例在被創建時都要經過一系列的初始化過程——例如,需要設置數據監聽、編譯模板、將實例掛載到 DOM 并在數據變化時更新 DOM 等。同時在這個過程中也會運行一些叫做生命周期鉤子的函數,這給了用戶在不同階段執行自己的代碼的機會。
比如 created
鉤子可以用來在一個實例被創建之后執行代碼:
new Vue({
data: {
a: 1
},
created: function () {
// `this` 指向 vm 實例
console.log('a is: ' + this.a)
}
})
// => "a is: 1"
也有一些其它的鉤子,在實例生命周期的不同階段被調用,如 mounted
、updated
和 destroyed
。生命周期鉤子的 this
上下文指向調用它的 Vue 實例。
[2]模板語法
插值
- 文本
<span>Message: {{ msg }}</span>
Mustache 標簽將會被替代為對應數據對象上 msg 屬性的值。無論何時,綁定的數據對象上 msg 屬性發生了改變,插值處的內容都會更新。
-
原始HTML
雙大括號會將數據解釋為普通文本,而非 HTML 代碼。為了輸出真正的 HTML,你需要使用 v-html 指令 -
HTML屬性
Mustache 語法不能作用在 HTML 屬性上,遇到這種情況應該使用 v-bind 指令:
<div v-bind:id="dynamicId"></div>
-
使用JavaScript表達式
迄今為止,在我們的模板中,我們一直都只綁定簡單的屬性鍵值。但實際上,對于所有的數據綁定,Vue.js 都提供了完全的 JavaScript 表達式支持。
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
這些表達式會在所屬 Vue 實例的數據作用域下作為 JavaScript 被解析。有個限制就是,每個綁定都只能包含單個表達式。
指令
指令 (Directives) 是帶有 v- 前綴的特殊特性。指令特性的值預期是單個 JavaScript 表達式 (v-for 是例外情況,稍后我們再討論)。指令的職責是,當表達式的值改變時,將其產生的連帶影響,響應式地作用于 DOM。比如:
<p v-if="seen">現在你看到我了</p>
這里,v-if 指令將根據表達式 seen 的值的真假來插入/移除 <p> 元素。
-
參數
一些指令能夠接收一個“參數”,在指令名稱之后以冒號表示。例如,v-bind 指令可以用于響應式地更新 HTML 特性:
<a v-bind:href="url">...</a>
在這里 href 是參數,告知 v-bind 指令將該元素的 href 特性與表達式 url 的值綁定。
另一個例子是 v-on 指令,它用于監聽 DOM 事件:
<a v-on:click="doSomething">...</a>
在這里參數是監聽的事件名。我們也會更詳細地討論事件處理。
-
修飾符
修飾符 (Modifiers) 是以半角句號. 指明的特殊后綴,用于指出一個指令應該以特殊方式綁定。例如,.prevent 修飾符告訴 v-on 指令對于觸發的事件調用 event.preventDefault():
<form v-on:submit.prevent="onSubmit">...</form>
縮寫
Vue.js 為 v-bind 和 v-on 這兩個最常用的指令,提供了特定簡寫:
<!-- 完整語法 -->
<a v-bind:href="url">...</a>
<!-- 縮寫 -->
<a :href="url">...</a>
<!-- 完整語法 -->
<a v-on:click="doSomething">...</a>
<!-- 縮寫 -->
<a @click="doSomething">...</a>
[3]計算屬性和偵聽器
計算屬性(computed properties)
模板內的表達式非常便利,但是設計它們的初衷是用于簡單運算的。在模板中放入太多的邏輯會讓模板過重且難以維護。對于任何復雜邏輯,都應該使用計算屬性。
<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: {
// 計算屬性的 getter
reversedMessage: function () {
// `this` 指向 vm 實例
return this.message.split('').reverse().join('')
}
}
})
這里我們聲明了一個計算屬性 reversedMessage。我們提供的函數將用作屬性 vm.reversedMessage 的 getter 函數.
你可以像綁定普通屬性一樣在模板中綁定計算屬性。Vue 知道 vm.reversedMessage 依賴于 vm.message,因此當 vm.message 發生改變時,所有依賴 vm.reversedMessage 的綁定也會更新。
方法
我們也可以在表達式中調用方法來達到同樣的效果:
<p>Reversed message: "{{ reversedMessage() }}"</p>
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
然而,不同的是計算屬性是基于它們的依賴進行緩存的。只在相關依賴發生改變時它們才會重新求值。這就意味著只要 message 還沒有發生改變,多次訪問 reversedMessage 計算屬性會立即返回之前的計算結果,而不必再次執行函數。
偵聽屬性
Vue 提供了一種更通用的方式來觀察和響應 Vue 實例上的數據變動:偵聽屬性
<div id="app">
{{ msg }}
</div>
<script>
var app=new Vue({
el:'#app',
data:{
msg:'Hello World!',
},
watch:{
msg:function(val){
console.log("val now is changing to:"+val);
}
}
});
</script>
然而,當你有一些數據需要隨著其它數據變動而變動時,通常更好的做法是使用計算屬性。
Class與Style的數據綁定
操作元素的 class 列表和內聯樣式是數據綁定的一個常見需求。因為它們都是屬性,所以我們可以用 v-bind 處理它們:只需要通過表達式計算出字符串結果即可。不過,字符串拼接麻煩且易錯。因此,在將 v-bind 用于 class 和 style 時,Vue.js 做了專門的增強。表達式結果的類型除了字符串之外,還可以是對象或數組。此處不進行贅述。
[4]條件渲染
<h1 v-if="ok">Yes</h1> //此處的ok是一個屬性
<h1 v-else>No</h1>
在<template>元素上使用v-if條件渲染分組
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
v-else-if
<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>
v-show
<h1 v-show="ok">Hello!</h1>
不同的是帶有 v-show 的元素始終會被渲染并保留在 DOM 中。v-show 只是簡單地切換元素的 CSS 屬性 display
[5]列表渲染
我們用 v-for 指令根據一組數組的選項列表進行渲染。v-for 指令需要使用 item in items 形式的特殊語法,items 是源數據數組并且 item 是數組元素迭代的別名。
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
<ul id="example-2">
<li v-for="(item, index) of items"> //支持一個可選的第二參數作為索引,of和in可以互換
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
v-for還可以迭代一個對象的屬性:
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>
<div v-for="(value, key, index) in object"> //同樣具有多個可選參數
{{ index }}. {{ key }}: {{ value }}
</div>
new Vue({
el: '#v-for-object',
data: {
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
})
調用一些數組的方法將會觸發視圖更新,值得注意的是,利用索引直接設置一個項或者修改數組長度的時候不能被Vue檢測觸發更新。
除此以外,對于對象更改的檢測,以及顯示過濾結果,此處不贅述
[6]事件處理
可以用 v-on 指令監聽 DOM 事件,并在觸發時運行一些 JavaScript 代碼。
<div id="example-1">
<button v-on:click="counter += 1">Add 1</button>
<p>The button above has been clicked {{ counter }} times.</p>
</div>
對于更加復雜的事件邏輯,v-on可以接收一個需要調用的方法名稱:
<div id="app">
<button v-on:click="greet">Add</button>
</div>
<script>
var app=new Vue({
el:'#app',
methods:{
greet:function(event){
alert(event);
}
},
});
</script>
Vue.js為v-on提供了事件修飾符:
<!-- 阻止單擊事件繼續傳播 -->
<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 是當前元素自身時觸發處理函數 -->
<!-- 即事件不是從內部元素觸發的 -->
<div v-on:click.self="doThat">...</div>
[7]表單輸入綁定
你可以用 v-model 指令在表單 <input>、<textarea> 及 <select> 元素上創建雙向數據綁定。它會根據控件類型自動選取正確的方法來更新元素
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
此處對于不同的輸入控件均有類似的用法,此處不贅述
[8]組件基礎
new Vue({ el: '#components-demo' })
// 定義一個名為 button-counter 的新組件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
組件是可復用的 Vue 實例,且帶有一個名字:在這個例子中是 <button-counter>。我們可以在一個通過 new Vue 創建的 Vue 根實例中,把這個組件作為自定義元素來使用。
因為組件是可復用的 Vue 實例,所以它們與 new Vue 接收相同的選項,例如 data、computed、watch、methods 以及生命周期鉤子等。僅有的例外是像 el 這樣根實例特有的選項。
data必須是一個函數
之前我們所創建的Vue根實例,data直接提供一個對象即可。
但一個組件的 data 選項必須是一個函數,因此每個實例可以維護一份被返回對象的獨立的拷貝:
data: function () {
return {
count: 0
}
}
組件組織
為了能在模板中使用,這些組件必須先注冊以便 Vue 能夠識別。這里有兩種組件的注冊類型:全局注冊和局部注冊。至此,我們的組件都只是通過 Vue.component 全局注冊的:
Vue.component('my-component-name', {
// ... options ...
})
全局注冊的組件可以用在其被注冊之后的任何 (通過 new Vue) 新創建的 Vue 根實例,也包括其組件樹中的所有子組件的模板中。
通過Prop向子組件傳遞數據
Prop實際上是你可以在組件上注冊的一些自定義屬性(屬性就是class之類)。
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
一個組件默認可以擁有任意數量的 prop,任何值都可以傳遞給任何 prop。在上述模板中,你會發現我們能夠在組件實例中訪問這個值,就像訪問 data 中的值一樣。
一個 prop 被注冊之后,你就可以像這樣把數據作為一個自定義屬性傳遞進來:
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>