Vue官方教程筆記(Vue 1 X)

1.安裝

能夠簡單地在頁面引入Vue.js做爲獨立版本,Vue即被註冊爲全局變量,能夠在頁面使用了。javascript

若是但願搭建大型應用,則可使用npm安裝Vue.js:css

# 最新穩定版本
$ npm install vue
# 最新穩定 CSP 兼容版本
$ npm install vue@csp
複製代碼

甚至可使用vue官方推薦的項目模板來建立新的大型項目,這就須要使用vue命令行工具vue-cli:html

# 全局安裝 vue-cli
$ npm install -g vue-cli
# 建立一個基於 "webpack" 模板的新項目
$ vue init webpack my-project
# 安裝依賴,走你
$ cd my-project
$ npm install
$ npm run dev
複製代碼

2.概述

Vue的目標是實現響應的數據綁定和組合的視圖組件,因此其核心只有兩塊:vue

  • 數據綁定系統
  • 組件系統

數據經過在HTML模板中的指令和「Mustache」語法,綁定到對應的HTML元素上,其底層是JavaScript對象的存取器屬性和原生javascript事件。java

組件系統則經過擴展的Vue實例,來渲染位於HTML中的相似於自定義元素的Vue組件,從而實現獨立可複用的組件。webpack

3.Vue實例

每一個Vue應用的起步都是從一個Vue的根實例開始:web

var vm = new Vue({
	//選項,包含數據、模板、掛載元素等
})
複製代碼

而每一個組件,也是一個擴展的vue實例:ajax

var myCompnent = Vue.extend({
	//選項,包含組件的數據、模板、掛載元素等
})
複製代碼

Vue實例會代理設置在data選項中的數據,全部data選項中的數據均可以經過vm自己進行訪問:算法

var vm = new Vue({
	data: {
		name: 'chen'
	}
})
data.name  // -> chen
vm.name = 'wei'
data.name // -> wei
複製代碼

除了數據屬性,Vue實例還暴露了一些有用的實例屬性與方法,這些屬性與方法都有前綴$,區別於數據屬性(參考API文檔):vue-router

vm.$watch
vm.$data
vm.$el
複製代碼

在一個Vue實例的生命週期的不一樣時間,能夠調用相應的回調函數:

實例生命週期

4.數據綁定

有兩種方式能夠進行數據綁定:插值和指令。

4.1 插值

使用雙大括號語法來綁定數據到HTML中,使用三大括號語法來輸出HTML字符(不經常使用)。插值也能夠用在HTML屬性中:

<span> {{msg }}</span>
<div>{{{ raw_html }}}</div>
<div id="item-{{ id }}"></div>
複製代碼

4.2 指令

使用指令 (Directives,是特殊的帶有前綴v-的特性)來將數據綁定到HTML,一般用於應用特殊行爲到DOM上:

<p v-if="greeting">Hello!</p>   <!--當greeting爲真時p存在-->
複製代碼

指令有三個須要記住的特徵:

  • 參數:v-on:click="doSomething" ,這裏clickv-on指令的參數
  • 修飾符:v-on:click.stop="doSomething",這裏.stop是修飾符,表示阻止冒泡
  • 縮寫:v-bind指令可縮寫爲簡單的:號,v-on指令能夠縮寫爲@
<a :href="url"></a>
<a @click="doSomething"></a>
複製代碼

插值的內容和指令的值,都被限定爲只能使用綁定表達式,它由一個JavaScript表達式和可選的一個或多個過濾器構成。須要注意JavaScript表達式和語句的區別,而過濾器則是一個JavaScript函數,Vue提供了不少內置的過濾器,也能夠本身編寫自定義過濾器:

{{ message | filterA | filterB }}
{{ message | filterA 'arg1' arg2 }} // 過濾器也能夠接受參數
複製代碼

5.計算屬性

綁定表達式被限定只能使用一個JavaScript表達式,目的是爲了限制在數據綁定中放入過多的邏輯。若是須要更復雜的數據處理邏輯,則應該使用計算屬性:

var vm = new Vue({
  el: '#example',
    data: {
      a: 1
    },
    conmpued: {
      a () {
        return this.a+1
      }
    }
})
複製代碼

5.1 getter和setter

Vue默認將提供的回調函數做爲計算屬性的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]
    }
  }
}
複製代碼

5.2 $watch

Vue還提供了一個$watch方法用於監視數據變更:

vm.$watch('a', val => {
  console.log(val)
})
// 或者寫成:
var vm = new Vue({
  … …
  watch: {
    'a' (val) { // 以須要監測的屬性爲屬性名
      console.log(val)
    }
  }
})
複製代碼

可是由於可讀性,推薦使用計算屬性而不是watch方法。

6.Class與Style綁定

因爲其經常使用性,Vue加強了classstyle兩個HTML屬性的綁定,不只僅能夠接受字符串值,還能夠接受數組和對象兩種類型的值。

6.1 class綁定

v-bind:class="value",接受字符串,也能夠接受對象和數組,而且還能夠和普通的class屬性共存:

<!-- 接受字符串 -->
v-bind:class="classA"
<!-- 接受對象 -->
v-bind:class="{ 'class-a': isA, 'class-b': isB }"
<!-- 直接綁定數據裏的對象,或者計算屬性返回的對象 -->
v-bind:class="classObject"
<!-- 與普通class屬性共存 -->
class="some-class" v-bind:class="{ 'class-a': isA, 'class-b': isB }"
<!-- 接受數組 -->
v-bind:class="[classA, classB]"
<!--直接綁定數據裏的數組,或者計算屬性返回的數組 -->
v-bind:class="classArray"
<!--數組語法與對象語法混用 1.0.19+ -->
v-bind:class="[classA, { 'class-b': isB, 'class-c': isC}]"
複製代碼

6.2 style綁定

內聯樣式綁定也能夠接受對象或者數組,當接受對象時語法很是直觀(看着很是像CSS語法),當接受數組時能夠將多個樣式對象應用到元素上。對象和數組均可以直接來自數據data或者computed或者props

同時內聯樣式的綁定Vue會自動偵測瀏覽器並添加相應瀏覽器前綴。

<!-- 接受對象 -->
v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"
<!-- 直接綁定數據裏的對象,或者計算屬性返回的對象 -->
v-bind:style="styleObject"

v-bind:style="[styleObjectA, styleObjectB]"
複製代碼

7.條件渲染

Vue能夠根據指定的條件來決定是否渲染元素,有兩個指令v-ifv-show,用法基本一致。

7.1 條件渲染一個元素

<h1 v-if="isOk">Hello</h1>
複製代碼

7.2 條件渲染多個元素

使用一個template 元素包裹多個元素並條件渲染它。

<template v-if="isOk">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template >
複製代碼

7.3 v-else

還可使用v-else來爲條件渲染添加一個else塊:

<div v-if="isOk">hello</div>
<!-- v-else指令必須緊跟v-if或v-show不然不生效 -->
<div v-else>fuck off</div>
<!-- 這兩個元素僅會顯示一個 -->
複製代碼

7.4 組件中的條件渲染

組件也可以使用條件渲染,可是將v-show用在組件中時,因爲指令的優先級問題,不能在後面使用v-else指令,而應該使用另外一個v-show來替代:

<my-compnent v-show="condition"></my-component>
<p v-else>這可能也是一個組件</p> <!--錯誤用法-->
		
<my-compnent v-show="condition"></my-component>
<p v-show="!condition">這可能也是一個組件</p> <!--正確用法-->
複製代碼

7.5 v-if和v-show的區別

編譯區別v-if是惰性的,若是初始條件爲假則這個元素不會被編譯,只有當條件第一次爲真時,Vue才編譯並緩存編譯結果以供後續使用;v-show的元素則直接編譯。

顯示區別v-if是真實的在HTML中重建或者銷燬這個元素,v-show則只是經過display來控制,簡單得多。

結論v-if有更高的切換消耗而v-show有更高的初始渲染消耗,頻繁切換用v-show,條件穩定用v-if

8.列表渲染

使用v-for指令,Vue能夠根據一個數組,渲染一組列表元素。

8.1 數組渲染

<li v-for="item in items">{{ item.message + ":" + $index }}</li>
<!-- items是數據中的一個數組,item是數組元素的別名 -->
<!-- 有一個特殊變量:$index,是數組元素的索引 -->
複製代碼

8.2 變異方法:

Vue會更新被觀察的數組items的大部分修改自身的方法:push()pop()shift()unshift()splice()sort()reverse()調用這些方法時數組的變更會被實時反映在數據綁定中,而那些不會修改原數組而是返回新數組的方法:filter()concat()slice()則須要使用其結果替換原數組,數據變更才能反映在數據綁定中。

8.3 追蹤指令:

數組替換並不會徹底從新渲染整個列表,Vue使用了一些啓發算法提升了性能。默認這個算法是根據數組元素自己的值來追蹤和複用DOM,這會致使數組中重複的值只會渲染一次,這時可使用track-by="$index"指令強制Vue進入原位更新模式(只有$index位置的值與上次位置的值一致時才複用DOM元素,不然馬上從新生成並渲染新的DOM元素),但在須要同步臨時狀態和組件的私有狀態時需謹慎使用。

若是數組中每一個元素都有一個相同但值惟一的屬性,好比下面這樣

{
  items: [
    { _uid: '88f869d', ... },
    { _uid: '7496c10', ... }
  ]
}
複製代碼

則能夠指定track-by="_uid"來讓Vue儘量地複用DOM以提升性能。

另外,若是數組元素是已經被Object.freeze()方法凍結的對象,則須要使用track-by指令明確指定追蹤屬性,不然將不能自動追蹤(被凍結的對象沒法設置存取器屬性)

8.4 檢測盲點:

因爲JavaScript自己的限制,Vue不能檢測到兩種數據變更:

  1. 直接使用索引賦值:vm.items[0] = {}
  2. 修改數組的長度:vm.items.length = 0

應該使用下面兩種技術進行替換:

  1. 數組的Vue擴展方法:
var item = { changeMsg: 'changed!' }
vm.items.$set(0, item)
vm.items.$remove(item)
複製代碼
  1. 使用空數組替換:vm.items = []

8.5 對象渲染

遍歷對象時可訪問一個特殊變量$key,表示對象的鍵名

<ul>
  <li v-for="value in object"> <!-- value是對象鍵值的別名,object是數據對象的別名 -->
    {{ $key }} : {{ value }}
  </li>
</ul>
複製代碼

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

<ul>
  <li v-for="(key, value) in object"> <!-- value是對象鍵值的別名,object是數據對象的別名 -->
    {{ key }} : {{ value }}
  </li>
</ul>
複製代碼

對象遍歷的結果是按Object.keys()的結果來的,不保證在全部引擎中都一致。

8.6 值域渲染

v-for也能夠接受一個整數表示值域,即簡單重複渲染元素:

<div>
  <span v-for="n in 10">{{ n }}</span> /* 渲染10個span */
</div>
複製代碼

8.7 渲染多個元素

將v-for指令用在 元素上,能夠重複渲染多個元素:

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

8.8 過濾和排序

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

  1. 建立一個計算屬性,返回過濾/排序過的數組;
  2. 使用內置的過濾器filterByorderBy

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

9.方法與事件處理器

9.1 用法

使用v-on指令監聽DOM事件,v-on後接冒號傳入事件類型名稱,指令的值爲事件處理器,事件處理器只能指定爲methods中的一個方法或者一個JavaScript語句(一般是方法調用語句,方便傳值):

<button v-on:click="sayHi">click me</button>
<button v-on:click="say('Hello!')">click me</button>
複製代碼

9.2 事件對象

事件處理器能夠接受一個特殊參數即爲事件對象,使用$event表示:

<button v-on:click="say('hello', $event)">click me</button>
複製代碼

9.3 修飾符

v-on指令支持兩類修飾符:事件修飾符和按鍵修飾符

事件修飾符有四個(1.0.16+):

  • prevent用於阻止默認事件(至關於event.preventDefault());
  • stop用於阻止冒泡(至關於event.stopPropagation());
  • capture表示添加偵聽事件時使用捕獲模式;
  • self表示只當事件是從偵聽器綁定的元素自己觸發時才觸發回調。

按鍵修飾符則表示只在指定按鍵上觸發事件(一般在監聽鍵盤事件時使用,keyupkeydownkeypress

<input v-on:keyup.13="submit">
複製代碼

除了使用keycode,按鍵修飾符還可使用vue提供的按鍵別名:

entertabdeleteescspaceupdownleft``right

1.0.8+可使用單字母別名,全部26個字母均可以做爲按鍵別名使用,1.0.17能夠自定義按鍵別名:

Vue.directive('on').keyCodes.f1 = 112
複製代碼

10.表單控件綁定

10.1 用法

使用v-model指令在表單控件中建立雙向數據綁定。

  1. 文本輸入框input中的輸入與model.text的值實時雙向同步
<input type="text" v-model="model.text" />
複製代碼
  1. 單選按鈕:選中則model.ratio的值爲true,取消選中則model.ratio值變爲false;反過來model.ratio值也改變選中狀態
<input type="ratio" v-model="model.ratio" />
複製代碼
  1. 多選框:單個多選框與單選框同樣,多個多選框則須要綁定到一個數組上,並寫好它們的value值以便填充到數組或從數組中刪除
<input type="checkbox" value="jack" v-model="model.anArray" />
<input type="checkbox" value="john" v-model="model.anArray" />
<input type="checkbox" value="awey" v-model="model.anArray" />
複製代碼
  1. 下拉框:單選的下拉框直接綁定便可,選中的選項的value或text也即該下拉框的value會與綁定的數據實時雙向同步,多選的下拉框則須要綁定到一個數組上,選中的選項的value會添加到數組中。即便選項是v-for動態生成的,也不影響數據的雙向綁定。
<select v-model="model.anArray" multiple>
  <option selected>A</option>
  <option>B</option>
  <option>C</option>
</select>
複製代碼

10.2 綁定value

全部表單控件都只能使用v-model而不能使用v-bind:value來進行數據雙向綁定,由於v-bind指令在綁定普通屬性(除了子組件的prop,它可使用async修飾符)時,是數據到HTML的單向數據綁定,HTML中的變化是不會同步到數據中的。

可是若是但願v-model雙向綁定的HTML和數據屬性,指向的是vue實例中的另外一個數據屬性(好比有兩個屬性a和b,其中a綁定到v-mode上,b是另外一個屬性,若是但願radio和checkbox選中時,a的值爲b,不選中時a的值爲默認值),則可使用v-bind:value來實現

  1. 單選按鈕:若是單選按鈕選中,則isPicked指向anotherDataProperty(兩個屬性都是vue實例的data)
<input type="radio" v-model="isPicked" v-bind:value="anotherDataProperty">
複製代碼
  1. 多選框:若是勾選則isSelected指向a,不然指向b,多選則是數組的元素指向a或b、
<input type="checkbox" v-model="isSelected" v-bind:true-value="a" v-bind:false-value="b">
複製代碼
  1. 下拉框:若是選中a項,則selected的值指向a,多選則是數組的元素指向a
<select v-model="selected"><option v-bind:value="a">a</option></select>
複製代碼

在這種狀況下使用v-bind:value指令,其值不限於字符串,能夠是任意JavaScript值:

<input type="radio" v-model="isPicked" v-bind:value="{ name: awey, age: 26 }">
複製代碼

10.3 三個特性

v-model可使用三個特性,lazydebouncenumber

  • lazy:v-model在同步數據時使用的是input事件(多是keyup事件,待考證)來進行同步,若是以爲太過頻繁可以使用lazy特性將同步改到change事件中
<input type="text" v-model="inputValue" lazy />
複製代碼
  • debounce:設置一個最小延時,在每次敲擊以後延時同步輸入框的值與數據,(若是已經使用lazy則無效)
<input type="text" v-model="inputValue" debounce="500"/>
複製代碼
  • number:將用戶輸入的值轉爲number,不能轉爲Number類型則返回原值
<input type="text" v-model="inputValue" number />
複製代碼

表單控件有一些諸如checkeddisabled這類HTML屬性,不管賦值與否只要存在該屬性便可生效。可是在使用v-bind綁定這類屬性時,vue對其作了處理,值爲真假值便可讓屬性生效或不生效,無需再有上述顧慮。

11.過渡動畫

在插入和移除或者顯示和隱藏DOM元素時,經過Vue的過渡動畫系統,能夠給元素添加三種類型的動畫:CSS過渡(trasition或者animateframe),JavaScript過渡和漸進過渡。v-if、v-show、v-for(可使用 vue-animated-list插件)三個指令可使用過渡動畫。

只須要在元素上添加transition屬性便可應用過渡動畫

<div v-if="show" transition="my-transition"></div>
複製代碼

11.1 CSS transition

在元素上添加transition屬性

<div v-if="show" transition="expand"></div>
複製代碼

而後添加CSS過渡動畫

/* 必需 */
.expand-transition {
  transition: all .3s ease;
  height: 30px;
  padding: 10px;
  background-color: #eee;
  overflow: hidden;
}
/* .expand-enter 定義進入的開始狀態 */
/* .expand-leave 定義離開的結束狀態 */
.expand-enter, .expand-leave {
  height: 0;
  padding: 0 10px;
  opacity: 0;
}
複製代碼

若是transition屬性沒有值,則默認的CSS類名是.v-transition, .v-enter.v-leave。默認的進入和退出動畫都是*-leave的形式,若是但願使用其它的CSS類名,則能夠自定義,這樣便能很好配合第三方CSS庫好比animate.css

Vue.transition('bounce', {
	enterClass: 'bounceInLeft',
	leaveClass: 'bounceOutRight'
});
複製代碼
<div v-show="ok" class="animated" transition="bounce">Watch me bounce</div>
複製代碼

11.2 CSS animation

用法與CSS transition同樣,惟一的區別是CSS transition依靠刪除類名來觸發transition,元素一插入文檔便即刻刪除類名;而CSS animation則是在CSS動畫的animationend事件中來刪除類名,由於它須要等到動畫運行結束才能刪除,不然動畫不起效

<span v-show="show" transition="bounce">Look at me!</span>
複製代碼
.bounce-transition {
  display: inline-block; /* 不然 scale 動畫不起做用 */
}
.bounce-enter {
  animation: bounce-in .5s;
}
.bounce-leave {
  animation: bounce-out .5s;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.5);
  }
  100% {
    transform: scale(1);
  }
}
@keyframes bounce-out {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.5);
  }
  100% {
    transform: scale(0);
  }
}

複製代碼

11.3 顯示地聲明是CSS過渡仍是CSS動畫

若是隻使用了css transtion或者css animation其中一個來實現動畫,則vue會根據css樣式自動判斷是哪一種類型的動畫,從而監聽對應的事件(transitionend或者animationend)。

可是有時會出現衝突,好比你使用了css animation來實現動畫,可是又定義了鼠標懸停時的css transition動畫,這時這兩類事件都會被該元素觸發,則你須要顯示地聲明vue應該監聽哪類事件:

Vue.transition('bounce', {
  // 該過渡效果將只偵聽 `animationend` 事件
  type: 'animation'
})
複製代碼

11.4 動畫各階段回調函數

在動畫的各個階段均可以提供回調函數,vue會在相應的動畫階段調用它們:

Vue.transition('expand', {
  beforeEnter: function (el) {
    el.textContent = 'beforeEnter'
  },
  enter: function (el) {
    el.textContent = 'enter'
  },
  afterEnter: function (el) {
    el.textContent = 'afterEnter'
  },
  enterCancelled: function (el) {
    // handle cancellation
  },

  beforeLeave: function (el) {
    el.textContent = 'beforeLeave'
  },
  leave: function (el) {
    el.textContent = 'leave'
  },
  afterLeave: function (el) {
    el.textContent = 'afterLeave'
  },
  leaveCancelled: function (el) {
    // handle cancellation
  }
})
複製代碼

11.5 JavaScript過渡

既然在動畫的各個階段都有回調函數,天然,咱們徹底能夠不定義任何CSS,直接使用JavaScript來定義元素動畫。注意,enter和leave須要調用done回調函數,不然動畫將當即結束。

Vue.transition('fade', {
  css: false, // 顯示地聲明爲非css回調,vue將跳過css檢測,同時也能防止css規則干擾過渡
  enter: function (el, done) {
    // 元素已被插入 DOM
    // 在動畫結束後調用 done
    $(el)
      .css('opacity', 0)
      .animate({ opacity: 1 }, 1000, done)
  },
  enterCancelled: function (el) {
    $(el).stop()
  },
  leave: function (el, done) {
    // 與 enter 相同
    $(el).animate({ opacity: 0 }, 1000, done)
  },
  leaveCancelled: function (el) {
    $(el).stop()
  }
})
複製代碼

11.6 動態綁定transition

你能夠在同一元素上經過動態綁定實現不一樣的過渡:

<div v-if="show" :transition="transitionName">hello</div>
複製代碼
new Vue({
  el: '...',
  data: {
    show: false,
    transitionName: 'fade'
  }
})
複製代碼

11.7 漸進過渡

transitionv-for一塊兒用時能夠建立漸近過渡。所謂漸進過渡,即每一個元素進入或退出都比上一元素延遲一點,不是同時進入或退出。只須要給過渡元素添加一個特性staggerenter-staggerleave-stagger,便可添加漸進過渡:

<div v-for="item in list" transition="stagger" stagger="100"></div>
複製代碼

或者提供一個鉤子 stagger, enter-stagger 或 leave-stagger,以更好的控制:

Vue.transition('stagger', {
  stagger: function (index) {
    // 每一個過渡項目增長 50ms 延時
    // 可是最大延時限制爲 300ms
    return Math.min(300, index * 50)
  }
})
複製代碼

12.組件

使用組件來封裝可重用的代碼,使用Vue.extend()來構造組件,使用Vue.component()或者選項對象中的components屬性來註冊組件,使用自定義標籤<component-name></component-name>來使用組件

12.1 基本使用

組件的使用分爲3個步驟:

  1. 定義組件
var MyComponent = Vue.extend({
		  template: '<div>A custom component!</div>'
		})
複製代碼
  1. 註冊組件
Vue.component('my-component', MyComponent) // 全局註冊
var Parent = Vue.extend({
  template: '...',
  components: {
    // <my-component> 只能用在父組件模板內
    'my-component': Child
  }
})
複製代碼

組件能夠註冊在全局,也能夠註冊在另外一個組件內。在哪註冊則僅能在該做用域使用

Vue.extend()能夠將組件的註冊和定義一次寫完,只須要將定義組件時傳入給extend()的對象直接傳遞給components內便可

var Parent = Vue.extend({
  template: '...',
  components: {
    // <my-component> 只能用在父組件模板內
    'my-component': {
        template: '<div>A custom component!</div>'
    }
  }
})
複製代碼
  1. 使用組件
<div id="example">
  <my-component></my-component>
</div>
複製代碼

12.2 選項和模板解析注意事項:

  • 組件選項。大部分用於new Vue()的選項均可以在構造組件時使用,但有兩個特例:datael,它們在vue()構造器中是對象或者對象的引用,若是組件也這麼用,將形成全部組件共享一個對象引用的結果,組件之間存在干擾,因此這兩個選項須要使用函數返回新對象
var MyComponent = Vue.extend({
  data: function () {
    return { a: 1 }
  }
})
複製代碼
  • Vue使用的是DOM模板而非字符串模板,也就是說Vue內部處理的是真正的DOM元素而不是處理字符串。而DOM模板的一個重要限制就是它必須是有效的HTML片斷,而不少DOM元素都對內部的子元素類型有限制,好比:
a 不能包含其它的交互元素(如按鈕,連接)
ul 和 ol 只能直接包含 li
select 只能包含 option 和 optgroup
table 只能直接包含 thead, tbody, tfoot, tr, caption, col, colgroup
tr 只能直接包含 th 和 td
複製代碼

因此對模板的使用限制就很明顯了,自定義元素和特殊元素不能做爲像table這樣對內部元素有限制的元素的直接子元素,也不能做爲像option這樣只能做爲select子元素的元素的父元素(違反這個規則將渲染不正確)

當須要將某個限制類的元素用做模板時,使用is指令來規避以上限制:

<table>
  <tr is='my-component'></tr>
</table>
複製代碼

12.3 向組件傳遞數據

12.3.1 基本用法

組件實例的做用域是孤立的,但能夠經過組件的props屬性向組件傳遞數據:

Vue.component('child', {
  template: "<p>msg</p>",
  props: ['msg'] // props中數據的讀寫與data屬性中的數據一致
});
複製代碼
<child msg='hello!'></child> <!--在父組件中向子組件傳遞數據-->
複製代碼
12.3.2 駝峯和短橫線

當使用駝峯寫法聲明props屬性時,在使用該屬性傳遞數據時須要寫爲短橫線格式:

...
props: ['myProp'],
...
複製代碼
<child my-prop='hello!'></child>
複製代碼
12.3.3 動態綁定和單向/雙向綁定

使用v-bind能夠在父組件向子組件中傳遞動態數據或者實際的值而不是字符串:

<child :my-prop="someDataFromFather"></child> <!--傳遞動態數據-->
<child :my-prop="{ a:1, b:2 }"></child> <!--傳遞實際的值-->
複製代碼

綁定動態數據時,props默認是單向綁定,父組件的數據變化會傳遞並反映在子組件中,也可使用.async修飾符強制雙向綁定,子組件中改變props的值也會反映在父組件中,單並不推薦,由於會讓數據流很差理解

<child :my-prop.async="someDataFromFather"></child> <!--傳遞實際的值-->
複製代碼
12.3.4 驗證規則

能夠爲props指定驗證規則,props設置再也不是數組而是對象,每一個prop都是一個規定了驗證要求的對象,能夠設置的驗證要求包括: * type:基礎類型檢測,能夠設置爲String、Number、Boolean、Function、Object、Array,當只須要這一個驗證時可直接設置prop: String,若是能夠是多種類型,則可設置prop: [Number, String] * required:是否必須,boolean * default:默認值 * twoWay:是否雙向 * validator:自定義驗證函數 * coerce:自定義轉換函數,在設置以前轉換值

當prop驗證失敗了,Vue將拒絕在子組件上設置此值,若是使用的是開發版本會拋出一條警告 另外須要注意,propsdefalut可使用一個function動態返回一個值,因此若是指望一個prop是function類型,則應當在匿名函數中返回這個function

12.4 組件樹通訊

除了props屬性可以讓父子組件之間通訊外,還有下面的一些方式可以在組件樹種進行通訊

12.4.1 父鏈——父子組件互相訪問
* 子組件能夠經過this.$parent訪問父組件
* 父組件經過this.$children訪問包含了全部子組件的數組
* 根實例後代經過this.$root訪問根實例(也即new Vue())
* 儘量避免使用父鏈進行通訊,應當儘量使用props顯示聲明
複製代碼
12.4.2 自定義事件——異步事件通訊機制

Vue實現了一套自定義事件接口用於組件樹通訊,獨立於DOM事件 * 觸發事件: * emit() 觸發事件,子組件事件只能在子組件中被監聽
	    *dispatch() 派發事件,事件沿着父鏈冒泡,子組件事件能夠在父組件中監聽 * broadcast() 廣播事件,事件向下傳遞給全部後代,父組件事件能夠在子組件中被監聽
    * 監聽事件:
	    *on() 監聽事件 * events選項監聽事件 * v-on指令監聽事件

注意,Vue事件會在冒泡後第一次觸發執行事件處理函數後中止冒泡,除非在事件處理函數中顯式返回true

Vue官方推薦當一個子組件派發事件後,在父組件中使用子組件的時候v-on監聽,是最直觀的方式,由於這樣可以直觀知道事件來自哪裏:

<child :msg="hello!" v-on:customEvent="handler"></child>
複製代碼
12.4.3 子組件索引——父組件直接訪問子組件

有時仍須要在JavaScript中直接訪問子組件,可使用v-ref指令指定子組件索引

<child v-ref:profile></child>
複製代碼

而後在註冊它的父級中直接訪問:

var child =  parent.$refs.profile
複製代碼

當和v-for一塊兒使用時是一個數組或者對象,包含相應的子組件

12.4.4 使用slot分發內容——父組件向子組件下發內容

當你的子組件有容器的功能時,子組件的部份內容(一般是html結構)就不肯定了,好比你定義了一個列表組件,可是你但願你的列表中每一項的內容可以在使用組件的時候給定,而不是寫死在組件中,這時就須要用到slot來向組件內分發內容,惟一須要記住的是:

父組件模板的內容在父組件做用域內編譯,子組件模板中的內容在子組件做用域內編譯 slot中的分發內容是在父組件中編譯的

  • 定義slot接口(在組件內):
<!-- 單個slot -->
<template>
  <div>
    <slot></slot>
  </div>
</template>
複製代碼
<template>
<!-- 多個slot(具名slot) -->
  <div>
    <slot name="title"></slot>
    <p>ajsf  ah  askhjdf a askjfh a fhasdkfu9fa ajsh ia uiasd gak jgasdfh la ioa akjsflai a</p>
    <slot name="footer"></slot>
  </div>
</template>
複製代碼
  • 使用slot接口(使用組件時):
<!-- 單個slot -->
<my-component>
  <p>這裏的全部內容都將插入組件的slot中<p>
  <div>這裏的全部內容都將插入組件的slot中</div>
</my-component>
複製代碼
<!-- 多個slot(具名slot) -->
<my-component>
  <p slot="title">這裏的內容將插入組件的name="title"的slot中<p>
  <div slot="footer">這裏的全部內容將插入組件的name="footer"的slot中</div>
  <p>這裏的內容將被插入組件中未署名的slot中,若是沒有未署名的slot則將被忽略</p>
</my-component>
複製代碼
12.4.5 動態組件

能夠將多個組件掛在到同一個掛載點上,而後動態切換它們。使用保留的元素,將組件動態地綁定到它的is屬性上:

new Vue({
  el: 'body',
  data: {
    currentView: 'home'
  },
  components: {
    home: { /* ... */ },
    posts: { /* ... */ },
    archive: { /* ... */ }
  }
})
複製代碼
<component :is="currentView">
  <!-- 組件在 vm.currentview 變化時改變 -->
</component>
複製代碼

可使用keep-alive指令將切換出去的組件保留在內存中,避免從新渲染而且保留它的狀態

<component :is="currentView" keep-alive></component>
複製代碼

組件中可使用activate鉤子來在切入前作一些事情,一般是異步操做好比加載數據等等:

Vue.component('activate-example', {
  activate: function (done) {
    var self = this
    loadDataAsync(function (data) {
      self.someData = data
      done()
    })
  }
})
複製代碼

組件還可使用transitiontransition-mode兩個屬性來指定動態組件的過場動畫,transition的使用和普通元素一致,trnasition-mode爲可選項,不指定時默認是進入與離開的組件同時開始過渡,指定爲in-outout-in則分別是先進後出或先出後進。惟一須要注意的是,動態組件不能是片斷實例(沒有惟一的父級元素),不然transition將不起做用

vue-router的<route-view></route-view>即是利用了動態組件的特性,全部用於動態組件的屬性均可以用於route-view

12.5 雜項

12.5.1 組件和v-for

組件可使用v-forv-for中的item數據應當也只能使用組件的props屬性傳遞給組件

12.5.2 編寫可複用組件

若是你的組件是須要複用的,則應當儘量與其它組件解耦,定義好清晰的公開接口:props、事件、slot,使用組件時使用v-bindv-on的簡寫@:,並清晰的進行縮進

12.5.3 異步組件

可讓組件只在須要時從服務器下載,vue容許將組建定義爲一個工廠函數,只在第一次須要渲染時觸發工廠函數從服務器下載並緩存結果供屢次渲染使用

Vue.component('async-component-example', (resolve, reject) => {
  setTimeout(() => { // 僞裝是在從服務器下載 O(∩_∩)O哈哈哈~
    resolve({ // 將下載好的組件傳遞出去
      template: '<div>I am async!</div>'
    })
    // 固然也能夠調用reject()提示加載失敗
  }, 1000)
})
複製代碼

這個功能能夠與Webpack的代碼分隔功能配合使用

Vue.component('async-webpack-example', function (resolve) {
  // 這個特殊的 require 語法告訴 webpack
  // 自動將編譯後的代碼分割成不一樣的塊,
  // 這些塊將經過 ajax 請求自動下載。
  require(['./my-async-component'], resolve)
})
複製代碼
12.5.4 命名約定

HTML中元素的屬性名是不區分大小寫的,可是當在定義組件掛載名稱、props屬性和事件名等等須要在HTML中使用的資源時,也可使用駝峯命名(camelCase),只是使用的時候須要轉成中劃線命名(kebab-case)

12.5.5 遞歸調用

組件能夠在本身的template中遞歸調用本身,可是須要注意,只有擁有name屬性的組件才能遞歸調用本身(不然在本身的模板中沒有掛載名可以使用),而且要確保遞歸調用有終止條件

12.5.6 片斷實例

當一個組件知足如下條件時,即爲片斷實例

  • 模板包含多個頂級元素。
  • 模板只包含普通文本。
  • 模板只包含其它組件(其它組件多是一個片斷實例)。
  • 模板只包含一個元素指令,如 或 vue-router 的 。
  • 模板根節點有一個流程控制指令,如 v-if 或 v-for。

片斷實例雖然能夠正確渲染,可是存在以下問題:

  • 非流程控制指令將被忽略
  • 非props特性將被忽略
  • transition屬性將被忽略 內聯模板

若是組件有inline-template屬性,則掛載組件時組件標籤之間中內容將被做爲組件的模板進行渲染,也就是說,你能夠在調用組件時動態地定義組件的模板,這給了組件極大的靈活性。但缺點是模板編譯結果不能被緩存,而且模板的做用域也很差理解了

13.深刻響應式原理

13.1 追蹤數據變化

在初始化vue實例時,vue會遍歷實例的data選項並使用Object.defineProperty()來將data的各個屬性轉換爲getter/setter(存取器屬性,這也是vue不支持IE8及更早版本的緣由)

使用vm.$log()方法能夠將實例的data更爲友好地打印到控制檯

綁定到DOM中的每一個數據或指令都有一個對應的watcher,它將數據和DOM中的綁定聯繫起來(把屬性記錄爲依賴):每次數據變化時,它的setter都會通知watcher,watcher再通知DOM進行更新

13.2 檢測數據變化的問題

實例化以後響應式屬性的添加:

vue只能在初始化vue實例的時候將數據轉換爲響應式的,若是初始化以後再向data中添加屬性,則該屬性不會是響應的而是普通屬性,因此vue提供了在實例建立後繼續向data添加響應屬性的方法:vm.$set()Vue.set() vue實例可使用$set()來繼續添加響應屬性

vm.$set(propName, value)
複製代碼

對於普通的數據對象,可使用全局方法Vue.set()來添加響應屬性

Vue.set(object, key, value)
複製代碼

另外,若是向data中已有的對象上添加新的屬性,好比使用Object.assign()或_.extend()添加屬性,新添加的屬性也不會是動態的,這時能夠建立一個包含該屬性的新對象,替換原有的data中對象

13.3 事先聲明全部屬性(數據)

儘量不要使用$set在實例化後再次添加新的屬性,而是應該在vue實例選項中事先所有聲明好,這會讓代碼更易於理解。

另外添加一個頂級響應屬性會強制全部watcher從新計算,由於添加以前它不存在,也沒有watcher追蹤它,添加它之後以前的依賴須要從新計算,雖然這對比Angular1的髒檢查性能仍是能夠接受的,但仍舊能夠在初始化以前所有聲明好來避免這部分性能開銷

13.4 異步隊列更新

vue內部使用一個隊列來異步地更新DOM,若是一個watcher被屢次觸發,只會推入一次到隊列中,只進行必要的DOM更新。異步隊列中優先使用MutationObserver,若是不支持則使用setTimeout(fn, 0)

本次隊列裏的全部DOM更新操做,不會當即執行,而是在下次事件循環清空隊列前更新。明白這一點,咱們即可以合理地使用vue給出的Vue.nextTick(callback)方法,在更新完成DOM後作一些事情

該方法在vue實例上也有,而且更方便,由於回調的this自動指向了當前的vue實例對象

13.5 計算屬性

計算屬性不是簡單的getter,計算屬性持續追蹤它的依賴,只要依賴變化了,計算屬性就變化。

而且計算屬性會緩存計算結果,除非依賴發生變化,不然讀取計算屬性時只從緩存讀取(性能最優)

明白這一點,就能明白爲何計算屬性的getter不是每次都會被調用:當你在計算屬性的getter中new Date()時,並非每次的值都是當前時間,它可能不會變化,仍是過去的某個時間。若是不但願緩存,能夠在設置計算屬性時關閉緩存:

computed: {
  example: {
    cache: false,
    get: function () {
      return Date.now() + this.msg
    }
  }
}
複製代碼

然而即便關閉緩存,也僅僅是在js中讀取這個屬性時是實時的,DOM中的數據綁定仍舊是依賴驅動的,只有計算屬性的依賴發生了變化,DOM纔會更新。

14.自定義指令

除了內置指令,還能夠自定義指令。使用Vue.directive(id, definition)方法註冊全局自定義指令 使用組件的directives選項註冊局部自定義指令

14.1 鉤子函數

  • bind:只調用一次,在指令第一次綁定到元素時調用
  • update:當綁定值變化時調用,參數爲新值與舊值,第一次調用(bind以後會當即調用一次)時只有初始值,沒有舊值 *unbind:只調用一次,在指令從元素上解綁是調用
Vue.directive('my-directive', {
  bind: function () {
    // 準備工做
    // 例如,添加事件處理器或只須要運行一次的高耗任務
  },
  update: function (newValue, oldValue) {
    // 值更新時的工做
    // 也會以初始值爲參數調用一次
  },
  unbind: function () {
    // 清理工做
    // 例如,刪除 bind() 添加的事件監聽器
  }
})
複製代碼

當註冊之後,即可以在模板中像使用內置指令同樣使用自定義指令:

<div v-my-directive="someValue"></div>
複製代碼

當只須要update函數時,能夠只傳入一個函數替代definition對象

14.2 指令實例屬性

在鉤子函數中,this指向當前的指令實例,指令實例上暴露了一些有用的屬性:

  • el: 指令綁定的元素。
  • vm: 擁有該指令的上下文 ViewModel。
  • expression: 指令的表達式,不包括參數和過濾器,表達式能夠是任意合法的JavaScript表達式
  • arg: 指令的參數。
  • name: 指令的名字,不包含前綴。
  • modifiers: 一個對象,包含指令的修飾符。
  • descriptor: 一個對象,包含指令的解析結果。

這些屬性應當被當作只讀的,不該該修改他們,即便你給指令對象添加自定義屬性,也要注意不要覆蓋這些內部屬性

14.3 元素指令

元素指令能夠看作是一個輕量的組件,它是以自定義元素的形式使用指令,而不是以特性的形式。使用Vue.elementDirective(id, discription)來註冊自定義指令

Vue.elementDirective('my-directive', {
  // API 同普通指令
  bind: function () { // 注意使用簡寫函數時this的指向
    // 操做this.el
  }
})
複製代碼

使用時便如同自定義元素:

<my -directive></my-directive>
複製代碼

因此元素指令不接受參數或表達式,只能讀取元素屬性來進行操做

元素指令是終結性的,一旦Vue遇到一個元素指令它將跳過該院故事及其子元素,而將它們留給指令自己去操做

14.4 高級選項

14.4.1 params特性列表

自定義指令能夠接收一個params數組,指定一個特性列表,Vue編譯器將自動提取這些特性:

<div v-example a="hi"></div>
複製代碼
Vue.directive('example', {
  params: ['a'],
  bind: function () {
    console.log(this.params.a)
  }
})
複製代碼

params中的屬性也支持動態屬性:

<div v-example :a="msg"></div>
複製代碼
Vue.directive('example', {
  params: ['a'],
  paramWatchers: {
  a: function (val, oldVal) {
    console.log('a changed!')
  }
  }
})
複製代碼
14.4.2 deep深度檢測

若是自定義屬性的值爲一個對象,當但願對象內部屬性發生變化時觸發update,則在定義指令時指定deep:true

<div v-my-directive="obj"></div>
複製代碼
Vue.directive('my-directive', {
  deep: true,
  update: function (obj) {
    // 在obj的內部屬性變化時調用
  }
})
複製代碼
14.4.3 twoWay回寫數據

默認狀況下指令中是不能向vm寫入數據的,可是可使用twoWay選項開啓,這樣指令中就可使用set()方法向vm回寫數據,前提是指令綁定的是vm中的數據屬性

Vue.directive('example', {
  towWay: true,
  bind: function () {
    this.handler = function () {
      // 將數據寫回 vm
      // 若是指令這樣綁定 v-example="a.b.c"
      // 它將用給定值設置 `vm.a.b.c`
      this.set(this.value)
    }.bind(this)
    this.el.addEventListener('input', this.handler)
  },
  unbind: function () {
    this.el.removeEventListener('input', this.handler)
  }
})
複製代碼
14.4.4 acceptStatement

acceptStatement:true可讓自定義指令接受內聯js語句(好比v-on),但須要注意內聯語句的反作用

Vue.directive('my-directive', {
  acceptStatement: true,
  update: function (fn) {
    // 傳入值是一個函數
    // 在調用它時將在所屬實例做用域內計算 "a++" 語句
  }
})
複製代碼

14.4.5 terminal

(1.0.19+)terminal: true指定由指令來接管元素的編譯(好比v-ifv-for)。可能還須要Vue.FragmentFactory來編譯partial。須要較好了解Vue的編譯流程(2.X中編譯流程略有變化),建議通讀v-ifv-for源碼來寫terminal指令

14.4.6 優先級

普通指令默認1000,terminal指令默認2000。在API文檔中查看指令優先級。流程控制指令使用用友最高優先級。

15. 自定義過濾器

15.1 註冊單向過濾器

使用Vue.filter()來註冊自定義過濾器,第一個參數爲過濾器名稱,第二個參數爲過濾器函數:

Vue.filter('wrap', function (value, begin, end) { // 過濾器函數接受任意數量參數
  return begin + value + end
})
複製代碼
<!-- 'hello' => 'before hello after' -->
<span v-text="message | wrap 'before' 'after'"></span>
複製代碼

這個過濾器會未來自vm的數據處理後交給view顯示。

15.2 註冊雙向過濾器

過濾器不只能夠處理從vm到view的數據,也能夠處理從view到vm的數據。傳遞給Vue.filter()的第二個參數變爲一個含有readwrite方法的對象:

Vue.filter('currencyDisplay', {
  // model -> view
  // 在更新 `<input>` 元素以前格式化值
  read: function(val) {
    return '$'+val.toFixed(2)
  },
  // view -> model
  // 在寫回數據以前格式化值
  write: function(val, oldVal) {
    var number = +val.replace(/[^\\\\\\\\d.]/g, '')
    return isNaN(number) ? 0 : parseFloat(number.toFixed(2))
  }
})
複製代碼

注意:

  • 使用過濾器時的參數若是沒有使用引號,則會在vm做用域內編譯,使用引號則做爲字符串傳遞給過濾器
  • 過濾器只推薦簡單邏輯使用,複雜的邏輯應當使用計算屬性
  • 過濾器函數中的this始終指向當前vm實例
  • 內置過濾器filterByorderBy根據指定的方法過濾/排序傳入的數組

16. 混合

16.1 基本使用

定義一個選項對象,而後在實例化vue時使用mixins: [optionObj1, optionObj12]來將選項混合到當前的vue實例選項中:

// 定義一個混合對象
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}

// 定義一個組件,使用這個混合對象
var Component = Vue.extend({
  mixins: [myMixin]
})

var component = new Component() // -> "hello from mixin!"
複製代碼

默認的合併策略是:

  • 同名鉤子函數被併入一個數組,依次執行,混合的鉤子先於組件本身的鉤子執行
  • 值爲對象的選項將合併到同一個對象內,鍵名衝突則組件本身的選項優先
  • Vue.extend()一樣使用上述策略進行合併

16.2 自定義選項

所謂自定義選項,是除開相似datamethods這樣vue官方提供的選項,你但願使用的由你本身命名的選項。 一般狀況下你在某個vue實例中使用了自定義選項,你可能對選項進行處理。可是若是你但願全部的vue實例在使用這個自定義選項時都作一樣處理,這時你可使用全局混合。

16.2.1 全局混合

可使用Vue.mixin()來註冊全局混合。所謂全局混合就是一旦註冊,會應用到以後建立的全部vue實例上,因此須要當心使用。但這個特性特別適合用於爲自定義選項注入處理邏輯,讓它表現得像官方選項同樣:

// 爲 `myOption` 自定義選項注入一個處理器
Vue.mixin({
  created: function () {
    var myOption = this.$options.myOption
    if (myOption) {
      console.log(myOption)
    }
  }
})

new Vue({
  myOption: 'hello!'
})
// -> "hello!"
複製代碼

16.2.2 自定義選項合併策略

混合時對自定義選項的處理只是簡單地覆蓋已有值,若是想用自定義邏輯合併自定義選項,則向Vue.config.optionMergeStrategies添加一個函數:

Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
  // 返回 mergedVal
}
複製代碼

對於多數值爲對象的選項,能夠簡單地使用 methods 所用的合併策略:

var strategies = Vue.config.optionMergeStrategies
strategies.myOption = strategies.methods
複製代碼

17.其它

插件、構建和對比其它框架三個主題略過,可去官方文檔查看詳細信息

相關文章
相關標籤/搜索