vue.js 起步式(一)

學習vue.js的詳細介紹能夠在這裏找到:http://cn.vuejs.org/guide/html

1.概述

響應的數據綁定
Vue.js 的核心是一個響應的數據綁定系統,它讓數據與 DOM 保持同步很是簡單。在使用 jQuery 手工操做 DOM 時,咱們的代碼經常是命令式的、重複的與易錯的。Vue.js 擁抱數據驅動的視圖概念。通俗地講,它意味着咱們在普通 HTML 模板中使用特殊的語法將 DOM 「綁定」到底層數據。一旦建立了綁定,DOM 將與數據保持同步。每當修改了數據,DOM 便相應地更新。這樣咱們應用中的邏輯就幾乎都是直接修改數據了,沒必要與 DOM 更新攪在一塊兒。這讓咱們的代碼更容易撰寫、理解與維護。
圖片描述
組件系統
組件系統是 Vue.js 另外一個重要概念,由於它提供了一種抽象,讓咱們能夠用獨立可複用的小組件來構建大型應用。
圖片描述vue

2.建立實例

構造器
每一個 Vue.js 應用的起步都是經過構造函數 Vue 建立一個 Vue 的根實例算法

var vm = new Vue({
  // 選項
})

一個 Vue 實例其實正是一個 MVVM 模式中所描述的 ViewModel - 所以在文檔中常常會使用 vm 這個變量名。
在實例化 Vue 時,須要傳入一個選項對象,它能夠包含數據、模板、掛載元素、方法、生命週期鉤子等選項。
實例生命週期
Vue 實例在建立時有一系列初始化步驟——例如,它須要創建數據觀察,編譯模板,建立必要的數據綁定。在此過程當中,它也將調用一些生命週期鉤子,給自定義邏輯提供運行機會。例如 created 鉤子在實例建立後調用:api

var vm = new Vue({
  data: {
    a: 1
  },
  created: function () {
    // `this` 指向 vm 實例
    console.log('a is: ' + this.a)
  }
})
// -> "a is: 1"

也有一些其它的鉤子,在實例生命週期的不一樣階段調用,如 compiled、 ready 、destroyed。鉤子的 this 指向調用它的 Vue 實例。一些用戶可能會問 Vue.js 是否有「控制器」的概念?答案是,沒有。組件的自定義邏輯能夠分割在這些鉤子中。
生命週期圖示
圖片描述數組

3.數據綁定語法

Vue.js 的模板是基於 DOM 實現的。這意味着全部的 Vue.js 模板都是可解析的有效的 HTML,且經過一些特殊的特性作了加強。Vue 模板於是從根本上不一樣於基於字符串的模板,請記住這點。
插值
(1)文本
數據綁定最基礎的形式是文本插值,使用 「Mustache」 語法(雙大括號):瀏覽器

<span>Message: {{ msg }}</span>

Mustache 標籤會被相應數據對象的 msg 屬性的值替換。每當這個屬性變化時它也會更新。
你也能夠只處理單次插值,從此的數據變化就不會再引發插值更新了:緩存

<span>This will never change: {{* msg }}</span>

(2)原始的 HTML
雙 Mustache 標籤將數據解析爲純文本而不是 HTML。爲了輸出真的 HTML 字符串,須要用三 Mustache 標籤:dom

<div>{{{ raw_html }}}</div>

內容以 HTML 字符串插入——數據綁定將被忽略。若是須要複用模板片段,應當使用 partials。ide

注:在網站上動態渲染任意 HTML 是很是危險的,由於容易致使 XSS 攻擊。記住,只對可信內容使用 HTML 插值,永不用於用戶提交的內容。

(3)HTML 特性
Mustache 標籤也能夠用在 HTML 特性 (Attributes) 內:函數

<div id="item-{{ id }}"></div>

注意在 Vue.js 指令和特殊特性內不能用插值。沒必要擔憂,若是 Mustache 標籤用錯了地方 Vue.js 會給出警告。
綁定表達式
放在 Mustache 標籤內的文本稱爲綁定表達式。在 Vue.js 中,一段綁定表達式由一個簡單的 JavaScript 表達式和可選的一個或多個過濾器構成。
(1)JavaScript 表達式
到目前爲止,咱們的模板只綁定到簡單的屬性鍵。不過實際上 Vue.js 在數據綁定內支持全功能的 JavaScript 表達式:

{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}

這些表達式將在所屬的 Vue 實例的做用域內計算。一個限制是每一個綁定只能包含單個表達式,所以下面的語句是無效的:

<!-- 這是一個語句,不是一個表達式: -->
{{ var a = 1 }}
<!-- 流程控制也不能夠,可改用三元表達式 -->
{{ if (ok) { return message } }}

(2)過濾器
Vue.js 容許在表達式後添加可選的「過濾器 (Filter) 」,以「管道符」指示:

{{ message | capitalize }}

這裏咱們將表達式 message 的值「管輸(pipe)」到內置的 capitalize 過濾器,這個過濾器其實只是一個 JavaScript 函數,返回大寫化的值。Vue.js 提供數個內置過濾器,在後面咱們會談到如何開發本身的過濾器。
注意管道語法不是 JavaScript 語法,所以不能在表達式內使用過濾器,只能添加到表達式的後面。
過濾器能夠串聯:

{{ message | filterA | filterB }}

過濾器也能夠接受參數:

{{ message | filterA 'arg1' arg2 }}

過濾器函數始終以表達式的值做爲第一個參數。帶引號的參數視爲字符串,而不帶引號的參數按表達式計算。這裏,字符串 'arg1' 將傳給過濾器做爲第二個參數,表達式 arg2 的值在計算出來以後做爲第三個參數。
指令
指令 (Directives) 是特殊的帶有前綴 v- 的特性。指令的值限定爲綁定表達式,所以上面提到的 JavaScript 表達式及過濾器規則在這裏也適用。指令的職責就是當其表達式的值改變時把某些特殊的行爲應用到 DOM 上。咱們來回頭看下「概述」裏的例子:

<p v-if="greeting">Hello!</p>

這裏 v-if 指令將根據表達式 greeting 值的真假刪除/插入 <p> 元素。
(1)參數
有些指令能夠在其名稱後面帶一個「參數」 (Argument),中間放一個冒號隔開。例如,v-bind 指令用於響應地更新 HTML 特性:

<a v-bind:href="url"></a>

這裏 href 是參數,它告訴 v-bind 指令將元素的 href 特性跟表達式 url 的值綁定。可能你已注意到能夠用特性插值 href="{{url}}" 得到一樣的結果:這樣沒錯,而且實際上在內部特性插值會轉爲 v-bind 綁定。

另外一個例子是 v-on 指令,它用於監聽 DOM 事件:

<a v-on:click="doSomething">

這裏參數是被監聽的事件的名字。咱們也會詳細說明事件綁定。
(2)修飾符
修飾符 (Modifiers) 是以半角句號 . 開始的特殊後綴,用於表示指令應當以特殊方式綁定。例如 .literal 修飾符告訴指令將它的值解析爲一個字面字符串而不是一個表達式:

<a v-bind:href.literal="/a/b/c"></a>

固然,這彷佛沒有意義,由於咱們只須要使用 href="/a/b/c" 而沒必要使用一個指令。這個例子只是爲了演示語法。後面咱們將看到修飾符更多的實踐用法。
(4)縮寫
v- 前綴是一種標識模板中特定的 Vue 特性的視覺暗示。當你須要在一些現有的 HTML 代碼中添加動態行爲時,這些前綴能夠起到很好的區分效果。但你在使用一些經常使用指令的時候,你會感受一直這麼寫實在是囉嗦。並且在構建單頁應用(SPA )時,Vue.js 會管理全部的模板,此時 v- 前綴也沒那麼重要了。所以Vue.js 爲兩個最經常使用的指令 v-bind 和 v-on 提供特別的縮寫:
v-bind 縮寫

<!-- 完整語法 -->
<a v-bind:href="url"></a>
<!-- 縮寫 -->
<a :href="url"></a>
<!-- 完整語法 -->
<button v-bind:disabled="someDynamicCondition">Button</button>
<!-- 縮寫 -->
<button :disabled="someDynamicCondition">Button</button>
v-on 縮寫
<!-- 完整語法 -->
<a v-on:click="doSomething"></a>
<!-- 縮寫 -->
<a @click="doSomething"></a>

它們看起來跟「合法」的 HTML 有點不一樣,可是它們在全部 Vue.js 支持的瀏覽器中都能被正確地解析,而且不會出如今最終渲染的標記中。縮寫語法徹底是可選的,不過隨着一步步學習的深刻,你會慶幸擁有它們。

4.計算屬性

在模板中綁定表達式是很是便利的,可是它們實際上只用於簡單的操做。模板是爲了描述視圖的結構。在模板中放入太多的邏輯會讓模板太重且難以維護。這就是爲何 Vue.js 將綁定表達式限制爲一個表達式。若是須要多於一個表達式的邏輯,應當使用計算屬性。
基礎例子

<div id="example">
  a={{ a }}, b={{ b }}
</div>

var vm = new Vue({
  el: '#example',
  data: {
    a: 1
  },
  computed: {
    // 一個計算屬性的 getter
    b: function () {
      // `this` 指向 vm 實例
      return this.a + 1
    }
  }
})

結果:a=1,b=2

這裏咱們聲明瞭一個計算屬性 b。咱們提供的函數將用做屬性 vm.b的 getter。

console.log(vm.b) // -> 2
vm.a = 2
console.log(vm.b) // -> 3

你能夠打開瀏覽器的控制檯,修改 vm。vm.b 的值始終取決於 vm.a 的值。
你能夠像綁定普通屬性同樣在模板中綁定計算屬性。Vue 知道 vm.b 依賴於 vm.a,所以當 vm.a 發生改變時,依賴於 vm.b 的綁定也會更新。並且最妙的是咱們是聲明式地建立這種依賴關係:計算屬性的 getter 是乾淨無反作用的,所以也是易於測試和理解的。
計算屬性 vs. $watch
Vue.js 提供了一個方法 $watch,它用於觀察 Vue 實例上的數據變更。當一些數據須要根據其它數據變化時, $watch 很誘人 —— 特別是若是你來自 AngularJS。不過,一般更好的辦法是使用計算屬性而不是一個命令式的 $watch 回調。考慮下面例子:

<div id="demo">{{fullName}}</div>
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  }
})
vm.$watch('firstName', function (val) {
  this.fullName = val + ' ' + this.lastName
})
vm.$watch('lastName', function (val) {
  this.fullName = this.firstName + ' ' + val
})

API:computed
類型: Object
詳細:實例計算屬性。getter 和 setter 的 this 自動地綁定到實例。

上面代碼是命令式的重複的。跟計算屬性對比:

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

這樣更好,不是嗎?
計算 setter
計算屬性默認只是 getter,不過在須要時你也能夠提供一個 setter:

// ...
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 也會有相應更新。

5.Class 與 Style 綁定

數據綁定一個常見需求是操做元素的 class 列表和它的內聯樣式。由於它們都是 attribute,咱們能夠用 v-bind 處理它們:只須要計算出表達式最終的字符串。不過,字符串拼接麻煩又易錯。所以,在 v-bind 用於 class 和 style 時,Vue.js 專門加強了它。表達式的結果類型除了字符串以外,還能夠是對象或數組。
綁定 HTML Class
儘管能夠用 Mustache 標籤綁定 class,好比 class="{{ className }}",可是咱們不推薦這種寫法和 v-bind:class 混用。二者只能選其一!

對象語法
咱們能夠傳給 v-bind:class 一個對象,以動態地切換 class。注意 v-bind:class 指令能夠與普通的 class 特性共存:

<div class="static" v-bind:class="{ 'class-a': isA, 'class-b': isB }"></div>

data: {
  isA: true,
  isB: false
}

渲染爲:

<div class="static class-a"></div>

當 isA 和 isB 變化時,class 列表將相應地更新。例如,若是 isB 變爲 true,class 列表將變爲 "static class-a class-b"。

你也能夠直接綁定數據裏的一個對象:

<div v-bind:class="classObject"></div>

data: {
  classObject: {
    'class-a': true,
    'class-b': false
  }
}

咱們也能夠在這裏綁定一個返回對象的計算屬性。這是一個經常使用且強大的模式。
數組語法
咱們能夠把一個數組傳給 v-bind:class,以應用一個 class 列表:

<div v-bind:class="[classA, classB]">

data: {
  classA: 'class-a',
  classB: 'class-b'
}

渲染爲:

<div class="class-a class-b"></div>

若是你也想根據條件切換列表中的 class,能夠用三元表達式:

<div v-bind:class="[classA, isB ? classB : '']">

此例始終添加 classA,可是隻有在 isB 是 true 時添加 classB 。

不過,當有多個條件 class 時這樣寫有些繁瑣。在 1.0.19+ 中,能夠在數組語法中使用對象語法:

<div v-bind:class="[classA, { classB: isB, classC: isC }]">

綁定內聯樣式
對象語法
v-bind:style 的對象語法十分直觀——看着很是像 CSS,其實它是一個 JavaScript 對象。CSS 屬性名能夠用駝峯式(camelCase)或短橫分隔命名(kebab-case):

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

data: {
  activeColor: 'red',
  fontSize: 30
}

直接綁定到一個樣式對象一般更好,讓模板更清晰:

<div v-bind:style="styleObject"></div>

data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}

一樣的,對象語法經常結合返回對象的計算屬性使用。
數組語法

v-bind:style 的數組語法能夠將多個樣式對象應用到一個元素上:

<div v-bind:style="[styleObjectA, styleObjectB]">

自動添加前綴

當 v-bind:style 使用須要廠商前綴的 CSS 屬性時,如 transform,Vue.js 會自動偵測並添加相應的前綴。

6.條件渲染

v-if

在字符串模板中,如 Handlebars,咱們得像這樣寫一個條件塊:

<!-- Handlebars 模板 -->
{{#if ok}}
  <h1>Yes</h1>
{{/if}}

在 Vue.js,咱們使用 v-if 指令實現一樣的功能:

<h1 v-if="ok">Yes</h1>

也能夠用 v-else 添加一個 「else」 塊:

<h1 v-if="ok">Yes</h1>
<h1 v-else>No</h1>

template v-if

由於 v-if 是一個指令,須要將它添加到一個元素上。可是若是咱們想切換多個元素呢?此時咱們能夠把一個 <template> 元素當作包裝元素,並在上面使用 v-if,最終的渲染結果不會包含它。

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

v-show

另外一個根據條件展現元素的選項是 v-show 指令。用法大致上同樣:

<h1 v-show="ok">Hello!</h1>

不一樣的是有 v-show 的元素會始終渲染並保持在 DOM 中。v-show 是簡單的切換元素的 CSS 屬性 display。

注意 v-show 不支持 <template> 語法。
v-else
能夠用 v-else 指令給 v-if 或 v-show 添加一個 「else 塊」:

<div v-if="Math.random() > 0.5">
  Sorry
</div>
<div v-else>
  Not sorry
</div>

v-else 元素必須當即跟在 v-if 或 v-show 元素的後面——不然它不能被識別。
組件警告

將 v-show 用在組件上時,由於指令的優先級 v-else 會出現問題。所以不要這樣作:

<custom-component v-show="condition"></custom-component>

<p v-else>這可能也是一個組件</p>

用另外一個 v-show 替換 v-else:

<custom-component v-show="condition"></custom-component>
<p v-show="!condition">這可能也是一個組件</p>

這樣就能夠達到 v-if 的效果。

v-if vs. v-show

在切換 v-if 塊時,Vue.js 有一個局部編譯/卸載過程,由於 v-if 之中的模板也可能包括數據綁定或子組件。v-if 是真實的條件渲染,由於它會確保條件塊在切換當中合適地銷燬與重建條件塊內的事件監聽器和子組件。
v-if 也是惰性的:若是在初始渲染時條件爲假,則什麼也不作——在條件第一次變爲真時纔開始局部編譯(編譯會被緩存起來)。
相比之下,v-show 簡單得多——元素始終被編譯並保留,只是簡單地基於 CSS 切換。
通常來講,v-if 有更高的切換消耗而 v-show 有更高的初始渲染消耗。所以,若是須要頻繁切換 v-show 較好,若是在運行時條件不大可能改變 v-if 較好。

7.列表渲染

v-for
可使用 v-for 指令基於一個數組渲染一個列表。這個指令使用特殊的語法,形式爲 item in items,items 是數據數組,item 是當前數組元素的別名:
示例:

<ul id="example-1">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>

var example1 = new Vue({
  el: '#example-1',
  data: {
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})

結果:

·Foo
·Bar

在 v-for 塊內咱們能徹底訪問父組件做用域內的屬性,另有一個特殊變量 $index,正如你猜到的,它是當前數組元素的索引:

<ul id="example-2">
  <li v-for="item in items">
    {{ parentMessage }} - {{ $index }} - {{ item.message }}
  </li>
</ul>

var example2 = new Vue({
  el: '#example-2',
  data: {
    parentMessage: 'Parent',
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})

結果:

·Parent-0-Foo
·Parent-1-Bar

另外,你能夠爲索引指定一個別名(若是 v-for 用於一個對象,則能夠爲對象的鍵指定一個別名):

<div v-for="(index, item) in items">
  {{ index }} {{ item.message }}
</div>

從 1.0.17 開始可使用 of 分隔符,更接近 JavaScript 遍歷器語法:

<div v-for="item of items"></div>

template v-for

相似於 template v-if,也能夠將 v-for 用在 <template> 標籤上,以渲染一個包含多個元素的塊。例如:

<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider"></li>
  </template>
</ul>

數組變更檢測
(1)變異方法

Vue.js 包裝了被觀察數組的變異方法,故它們能觸發視圖更新。被包裝的方法有:

push()
pop()
shift()
unshift()
splice()
sort()
reverse()

你能夠打開瀏覽器的控制檯,用這些方法修改上例的 items 數組。例如:example1.items.push({ message: 'Baz' })

(2)替換數組
變異方法,如名字所示,修改了原始數組。相比之下,也有非變異方法,如 filter(), concat() 和 slice(),不會修改原始數組而是返回一個新數組。在使用非變異方法時,能夠直接用新數組替換舊數組:

example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

可能你以爲這將致使 Vue.js 棄用已有 DOM 並從新渲染整個列表——幸運的是並不是如此。 Vue.js 實現了一些啓發算法,以最大化複用 DOM 元素,於是用另外一個數組替換數組是一個很是高效的操做。
(3)track-by

有時須要用全新對象(例如經過 API 調用建立的對象)替換數組。由於 v-for 默認經過數據對象的特徵來決定對已有做用域和 DOM 元素的複用程度,這可能致使從新渲染整個列表。可是,若是每一個對象都有一個惟一 ID 的屬性,即可以使用 track-by 特性給 Vue.js 一個提示,Vue.js 於是能儘量地複用已有實例。

例如,假定數據爲:

{
  items: [
    { _uid: '88f869d', ... },
    { _uid: '7496c10', ... }
  ]
}

而後能夠這樣給出提示:

<div v-for="item in items" track-by="_uid">
  <!-- content -->
</div>

而後在替換數組 items 時,若是 Vue.js 遇到一個包含 _uid: '88f869d' 的新對象,它知道它能夠複用這個已有對象的做用域與 DOM 元素。

track-by $index

若是沒有惟一的鍵供追蹤,可使用 track-by="$index",它強制讓 v-for 進入原位更新模式:片段不會被移動,而是簡單地以對應索引的新值刷新。這種模式也能處理數據數組中重複的值。

這讓數據替換很是高效,可是也會付出必定的代價。由於這時 DOM 節點再也不映射數組元素順序的改變,不能同步臨時狀態(好比 <input> 元素的值)以及組件的私有狀態。所以,若是 v-for 塊包含 <input> 元素或子組件,要當心使用 track-by="$index"
問題

由於 JavaScript 的限制,Vue.js 不能檢測到下面數組變化:

直接用索引設置元素,如 vm.items[0] = {};
修改數據的長度,如 vm.items.length = 0。

爲了解決問題 (1),Vue.js 擴展了觀察數組,爲它添加了一個 $set() 方法:

// 與 example1.items[0] = ... 相同,可是能觸發視圖更新
example1.items.$set(0, { childMsg: 'Changed!'})

至於問題 (2),只需用一個空數組替換 items。

除了 $set(), Vue.js 也爲觀察數組添加了 $remove() 方法,用於從目標數組中查找並刪除元素,在內部它調用 splice() 。所以,沒必要這樣:

var index = this.items.indexOf(item)
if (index !== -1) {
  this.items.splice(index, 1)
}

只用這樣:

this.items.$remove(item)

(4)使用 Object.freeze()

在遍歷一個數組時,若是數組元素是對象而且對象用 Object.freeze() 凍結,你須要明確指定 track-by。在這種狀況下若是 Vue.js 不能自動追蹤對象,將給出一條警告。
對象 v-for

也可使用 v-for 遍歷對象。除了 $index 以外,做用域內還能夠訪問另一個特殊變量 $key。

<ul id="repeat-object" class="demo">
  <li v-for="value in object">
    {{ $key }} : {{ value }}
  </li>
</ul>

new Vue({
  el: '#repeat-object',
  data: {
    object: {
      FirstName: 'John',
      LastName: 'Doe',
      Age: 30
    }
  }
})

結果:

·FirstName:'John'
·LastName:'Doe'
·Age:30

也能夠給對象的鍵提供一個別名:

<div v-for="(key, val) in object">
  {{ key }} {{ val }}
</div>

在遍歷對象時,是按 Object.keys() 的結果遍歷,可是不能保證它的結果在不一樣的 JavaScript 引擎下是一致的。
(5)值域 v-for

v-for 也能夠接收一個整數,此時它將重複模板數次。

<div>
  <span v-for="n in 10">{{ n }} </span>
</div>

結果:

0123456789

顯示過濾/排序的結果

有時咱們想顯示過濾/排序過的數組,同時不實際修改或重置原始數據。有兩個辦法:

建立一個計算屬性,返回過濾/排序過的數組;
使用內置的過濾器 filterBy 和 orderBy。

計算屬性有更好的控制力,也更靈活,由於它是全功能 JavaScript。可是一般過濾器更方便,詳細見 API。

相關文章
相關標籤/搜索