<script>
引入(本地或者cdn)npm install vue
# 全局安裝 vue-cli $ npm install --global vue-cli # 建立一個基於 webpack 模板的新項目 $ vue init webpack my-project # 安裝依賴,走你 $ cd my-project $ npm install $ npm run dev
Vue (讀音 /vjuː/,相似於 view) 是一套用於構建用戶界面的漸進式框架。Vue 的核心庫只關注視圖層,對應view。css
Vue數據驅動,jQuery是結構驅動html
內部使用Object.defineProperty(最低支持IE9)把全部屬性所有轉爲 getter/setter,爲每一個組件綁定了watcher 實例對象,而且把屬性做爲依賴項,當依賴項的setter調用時,watcher將會從新計算,從而更新組件。vue
.png)node
<!--html--> <div id="app"> {{ message }} </div>
//js var vm = new Vue({ el: '#app', data: { message: 'Hello Vue!' } })
當一個 Vue 實例被建立時,它向 Vue 的響應式系統中加入了其 data 對象中能找到的全部的屬性。當這些屬性的值發生改變時,視圖將會產生「響應」,即匹配更新爲新的值。react
// 咱們的數據對象 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 中存在的屬性是響應式的。也就是說若是你添加一個新的屬性,將不會觸發任何視圖的更新。若是你知道你會在晚些時候須要一個屬性,可是一開始它爲空或不存在,那麼你僅須要設置一些初始值。webpack
var data = { a: 1 } var vm = new Vue({ el: '#example', data: data }) vm.$data === data // => true vm.$el === document.getElementById('example') // => true // $watch 是一個實例方法 vm.$watch('a', function (newValue, oldValue) { // 這個回調將在 `vm.a` 改變後調用 })
vue實例自身暴露的屬性和方法經過前綴$來獲取git
var data = { a: 1 } var vm = new Vue({ el: '#example', data: data }) vm.$data === data // => true vm.$el === document.getElementById('example') // => true
每一個 Vue 實例在被建立以前都要通過一系列的初始化過程(生命週期)。在這個過程當中會運行一些叫作生命週期鉤子的函數,用戶能夠在不一樣階段添加本身的代碼來作一些事情。github
beforeCreate:
在實例初始化以後,數據觀測 (data observer) 和 event/watcher 事件配置以前被調用。created:
在實例建立完成後被當即調用。在這一步,實例已完成如下的配置:數據觀測 (data observer),屬性和方法的運算,watch/event 事件回調。然而,掛載階段還沒開始,$el 屬性目前不可見。beforeMount:
在掛載開始以前被調用:相關的 render 函數首次被調用。mounted:
el 被新建立的 vm.$el 替換,並掛載到實例上去以後調用該鉤子。beforeUpdate:
數據更新時調用,發生在虛擬 DOM 從新渲染和打補丁以前。updated:
因爲數據更改致使的虛擬 DOM 從新渲染和打補丁,在這以後會調用該鉤子beforeDestroy:
實例銷燬以前調用。在這一步,實例仍然徹底可用。destroyed:
Vue 實例銷燬後調用。調用後,Vue 實例指示的全部東西都會解綁定,全部的事件監聽器會被移除,全部的子實例也會被銷燬。activated/deactivated:
keep-alive 組件激活/停用時調用,errorCaptured:
當捕獲一個來自子孫組件的錯誤時被調用。此鉤子會收到三個參數:錯誤對象、發生錯誤的組件實例以及一個包含錯誤來源信息的字符串。此鉤子能夠返回 false 以阻止該錯誤繼續向上傳播。注意:web
//錯誤,會致使this不會指向Vue 實例 created: () => console.log(this.a) vm.$watch('a', newValue => this.myMethod())
var vm = new Vue({ // 數據 data: "聲明須要響應式綁定的數據對象", props: "接收來自父組件的數據", propsData: "建立實例時手動傳遞props,方便測試props", computed: "計算屬性", methods: "定義能夠經過vm對象訪問的方法", watch: "Vue實例化時會調用$watch()方法遍歷watch對象的每一個屬性", // DOM el: "將頁面上已存在的DOM元素做爲Vue實例的掛載目標", template: "能夠替換掛載元素的字符串模板", render: "渲染函數,字符串模板的替代方案", renderError: "僅用於開發環境,在render()出現錯誤時,提供另外的渲染輸出", // 生命週期鉤子 beforeCreate: "發生在Vue實例初始化以後,data observer和event/watcher事件被配置以前", created: "發生在Vue實例初始化以及data observer和event/watcher事件被配置以後", beforeMount: "掛載開始以前被調用,此時render()首次被調用", mounted: "el被新建的vm.$el替換,並掛載到實例上以後調用", beforeUpdate: "數據更新時調用,發生在虛擬DOM從新渲染和打補丁以前", updated: "數據更改致使虛擬DOM從新渲染和打補丁以後被調用", activated: "keep-alive組件激活時調用", deactivated: "keep-alive組件停用時調用", beforeDestroy: "實例銷燬以前調用,Vue實例依然可用", destroyed: "Vue實例銷燬後調用,事件監聽和子實例所有被移除,釋放系統資源", // 資源 directives: "包含Vue實例可用指令的哈希表", filters: "包含Vue實例可用過濾器的哈希表", components: "包含Vue實例可用組件的哈希表", // 組合 parent: "指定當前實例的父實例,子實例用this.$parent訪問父實例,父實例經過$children數組訪問子實例", mixins: "將屬性混入Vue實例對象,並在Vue自身實例對象的屬性被調用以前獲得執行", extends: "用於聲明繼承另外一個組件,從而無需使用Vue.extend,便於擴展單文件組件", provide&inject: "2個屬性須要一塊兒使用,用來向全部子組件注入依賴,相似於React的Context", // 其它 name: "容許組件遞歸調用自身,便於調試時顯示更加友好的警告信息", delimiters: "改變模板字符串的風格,默認爲{{}}", functional: "讓組件無狀態(沒有data)和無實例(沒有this上下文)", model: "容許自定義組件使用v-model時定製prop和event", inheritAttrs: "默認狀況下,父做用域的非props屬性綁定會應用在子組件的根元素上。當編寫嵌套有其它組件或元素的組件時,能夠將該屬性設置爲false關閉這些默認行爲", comments: "設爲true時會保留而且渲染模板中的HTML註釋" });
Vue.js 使用了基於 HTML 的模板語法,必須是合法的 HTML。在底層的實現上,Vue 將模板編譯成虛擬 DOM 渲染函數。正則表達式
<!--Mustache--> <span>Message: {{ msg }}</span> <!--v-text--> <span v-text="msg"></span> <!--v-once:一次性插值--> <span v-once>這個將不會改變: {{ msg }}</span>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
只對可信內容使用 HTML 插值,毫不要對用戶提供的內容使用插值。
<div v-bind:id="dynamicId"></div>
在插值中可使用表達式,但只限簡單表達式。
{{ message.split('').reverse().join('') }} <div v-bind:id="'list-' + id"></div>
指令 (Directives) 是帶有 v- 前綴的特殊屬性。
指令的職責是,當表達式的值改變時,將其產生的連帶影響,響應式地做用於 DOM。
<p v-if="seen">如今你看到我了</p> <a v-on:click="doSomething">...</a>
指令 | 預期/限制 | 做用 |
---|---|---|
v-text | string | 文本插值 |
v-html | string | html插值 |
v-show | any | 條件顯示 |
v-if、v-else、v-else-if | any | 條件渲染 |
v-for | Array/Object/number/string | 列表渲染 |
v-on(@) | Function/Inline Statement/Object | 事件綁定 |
v-bind(:) | any (with argument)/Object (without argument) | 特性綁定 |
v-model | 僅限<input>/<select>/<textarea>/components元素使用 | 雙向綁定 |
v-pre | 忽略編譯 | |
v-cloak | 避免顯示Mustache | |
v-once | 一次性渲染 |
修飾符 (Modifiers) 是以半角句號 . 指明的特殊後綴,用於指出一個指令應該以特殊方式綁定。
<form v-on:submit.prevent="onSubmit">...</form>
修飾符 | 做用 |
---|---|
.stop | 調用 event.stopPropagation()。 |
.prevent | 調用 event.preventDefault()。 |
.capture | 添加事件偵聽器時使用 capture 模式。 |
.self | 只當事件是從偵聽器綁定的元素自己觸發時才觸發回調。 |
.{keyCode / keyAlias} | 只當事件是從特定鍵觸發時才觸發回調。 |
.native | 監聽組件根元素的原生事件。 |
.once | 只觸發一次回調。 |
.left | (2.2.0) 只當點擊鼠標左鍵時觸發。 |
.right | (2.2.0) 只當點擊鼠標右鍵時觸發。 |
.middle | (2.2.0) 只當點擊鼠標中鍵時觸發。 |
.passive | (2.3.0) 以 { passive: true } 模式添加偵聽器 |
修飾符 | 做用 |
---|---|
.prop | 被用於綁定 DOM 屬性 (property)。(差異在哪裏?) |
.camel | (2.1.0+) 將 kebab-case 特性名轉換爲 camelCase. (從 2.1.0 開始支持) |
.sync | (2.3.0+) 語法糖,會擴展成一個更新父組件綁定值的 v-on 偵聽器。 |
修飾符 | 做用 |
---|---|
.lazy | 取代 input 監聽 change 事件 |
.number | 輸入字符串轉爲數字 |
.trim | 輸入首尾空格過濾 |
對於任何複雜邏輯,你都應當使用計算屬性,而不該直接放在模板中。
計算屬性也是響應式的,可是它會基於它們的依賴進行緩存的,只有當緩存改變,它纔會從新求值;不然會直接返回緩存的結果,而沒必要再次執行函數。
應當優先使用計算屬性而不是偵聽屬性。
<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('') } } })
下面的計算屬性不會更新,由於Date.now() 不是響應式依賴。
computed: { now: function () { return Date.now() } }
<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在組件中 methods: { reversedMessage: function () { return this.message.split('').reverse().join('') } }
方法在每次調用時總會再次執行函數。
計算屬性默認只有 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] } } }
<div id="watch-example"> <p> Ask a yes/no question: <input v-model="question"> </p> <p>{{ answer }}</p> </div>
watch: { // 若是 `question` 發生改變,這個函數就會運行 question: function (newQuestion, oldQuestion) { this.answer = 'Waiting for you to stop typing...' this.getAnswer() } }
// const unWatch = app.$watch('text', (newText, oldText) => { // console.log(`${newText} : ${oldText}`) // }) // setTimeout(() => { // unWatch() // }, 2000)
當value爲真時,綁定對應的key到class
<!--內聯在模板中--> <div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"> </div> <!--綁定data或者計算屬性的的一個對象--> <div v-bind:class="classObject"></div> <!--js--> data: { classObject: { active: true, 'text-danger': false } }
<!--模板--> <div v-bind:class="[activeClass, errorClass]"></div> <!--js--> data: { activeClass: 'active', errorClass: 'text-danger' } <!--結果--> <div class="active text-danger"></div>
也可使用三元表達式。
// isActive爲真添加activeClass,errorClass始終存在 <div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
class將被添加到該組件的根元素上面。該元素上已經存在的class不會被覆蓋。
<my-component class="baz boo"></my-component>
注意:和普通的class並存,並不會覆蓋(不一樣名),最終會合成一個class。
自動偵測並添加相應瀏覽器引擎前綴。
CSS 屬性名能夠用駝峯式 (camelCase) 或短橫線分隔 (kebab-case,記得用單引號括起來) 來命名。
<!--內聯在模板中--> <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> <!--js--> data: { activeColor: 'red', fontSize: 30 } <!--綁定data或者計算屬性的的一個對象--> <div v-bind:style="styleObject"></div> <!--js--> data: { styleObject: { color: 'red', fontSize: '13px' } }
能夠將多個樣式對象應用到同一個元素上
<div v-bind:style="[baseStyles, overridingStyles]"></div>
<!--經常使用於提供多個帶前綴的值--> <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
根據表達式的值的真假條件渲染元素。
<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>
若是須要條件渲染多個元素,可使用<template>包裹。
<template v-if="ok"> <h1>Title</h1> <p>Paragraph 1</p> <p>Paragraph 2</p> </template>
Vue 會盡量高效地渲染元素,一般會複用已有元素而不是從頭開始渲染。添加一個具備惟一值的 key 屬性能夠強制其從新渲染。
根據表達式之真假值,切換元素的 display CSS 屬性。
<h1 v-show="ok">Hello!</h1>
<!--普通--> <ul id="example"> <li v-for="item in items"> {{ item.message }} </li> </ul> <!--帶索引--> <ul id="example"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </li> </ul> <!--js--> var example = new Vue({ el: '#example', data: { items: [ { message: 'Foo' }, { message: 'Bar' } ] } })
包含變異(改變原數組)和非變異(生成新數組,不改變原數組)兩組方式,都將觸發更新。
不能檢測的變更:
<!--普通--> <li v-for="value in object"> {{ value }} </li> <!--帶key--> <div v-for="(value, key) in object"> {{ key }}: {{ value }} </div> <!--帶key、索引--> <div v-for="(value, key, index) in object"> {{ index }}. {{ key }}: {{ value }} </div> <!--js--> new Vue({ data: { object: { firstName: 'John', lastName: 'Doe', age: 30 } } })
Vue 不能檢測對象屬性的添加或刪除。
var vm = new Vue({ data: { a: 1 } }) // `vm.a` 如今是響應式的 vm.b = 2 // `vm.b` 不是響應式的
var vm = new Vue({ data: { userProfile: { name: 'Anika' } } }) vm.$set(this.userProfile, 'age', 27)
this.userProfile = Object.assign({}, this.userProfile, { age: 27, favoriteColor: 'Vue Green' })
對應的刪除屬性使用vm.$delete(obj,key)
當 Vue.js 用 v-for 正在更新已渲染過的元素列表時,它默認用「就地複用」策略。
建議儘量在使用 v-for 時爲每一項提供一個惟一的 key。
循環組件的時候,key是必須的。
<div v-for="item in items" :key="item.id"> <!-- 內容 --> </div>
<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider"></li> </template> </ul>
<div id="example-3"> <button v-on:click="say('hi')">Say hi</button> <!--訪問原始的 DOM 事件--> <button v-on:click="say2('what', $event)">Say what</button> </div>
new Vue({ el: '#example-3', methods: { say: function (message) { alert(message) }, say2: function (message,event) { // 如今咱們能夠訪問原生事件對象 if (event) event.preventDefault() alert(message) } } })
修飾符能夠串聯,代碼會以串聯的順序產生。
修飾符 | 做用 |
---|---|
.stop | 調用 event.stopPropagation()。 |
.prevent | 調用 event.preventDefault()。 |
.capture | 添加事件偵聽器時使用 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 是當前元素自身時觸發處理函數 --> <!-- 即事件不是從內部元素觸發的 --> <div v-on:click.self="doThat">...</div> <!-- 點擊事件將只會觸發一次(可用於自定義組件) --> <a v-on:click.once="doThis"></a>
Vue 還對應 addEventListener 中的 passive 選項提供了 .passive 修飾符,可以提高移動端的性能,可是要避免和.prevent一塊兒使用。
<!-- 滾動事件的默認行爲 (即滾動行爲) 將會當即觸發 --> <!-- 而不會等待 `onScroll` 完成 --> <!-- 這其中包含 `event.preventDefault()` 的狀況 --> <div v-on:scroll.passive="onScroll">...</div>
在監聽鍵盤事件時,咱們常常須要檢查常見的鍵值。Vue 容許爲 v-on 在監聽鍵盤事件時添加按鍵修飾符。
<!-- 只有在 `keyCode` 是 13 時調用 `vm.submit()` --> <input v-on:keyup.13="submit"> <!-- 縮寫語法 --> <input @keyup.enter="submit">
.enter
、.tab
、.delete
(捕獲「刪除」和「退格」鍵)、.esc
、.space
、.up
、.down
、.left
、.right
// 可使用 `v-on:keyup.f1` Vue.config.keyCodes.f1 = 112
<!--可直接將 KeyboardEvent.key 暴露的任意有效按鍵名轉換爲 kebab-case 來做爲修飾符:--> <input @keyup.page-down="onPageDown">
.ctrl
、.alt
、.shift
、.meta
。
在和 keyup 事件一塊兒用時,事件觸發時修飾鍵必須處於按下狀態。換句話說,只有在按住 ctrl 的狀況下釋放其它按鍵,才能觸發 keyup.ctrl。而單單釋放 ctrl 也不會觸發事件。
<!-- Alt + C --> <input @keyup.alt.67="clear"> <!-- Ctrl + Click --> <div @click.ctrl="doSomething">Do something</div>
.exact
修飾符容許你控制由精確的系統修飾符組合觸發的事件。
<!-- 即便 Alt 或 Shift 被一同按下時也會觸發 --> <button @click.ctrl="onClick">A</button> <!-- 有且只有 Ctrl 被按下的時候才觸發 --> <button @click.ctrl.exact="onCtrlClick">A</button> <!-- 沒有任何系統修飾符被按下的時候才觸發 --> <button @click.exact="onClick">A</button>
.left
、.right
、.middle
僅響應特定的鼠標按鈕
能夠用 v-model
指令在表單 <input>
及 <textarea>
元素上建立雙向數據綁定。
v-model
僅爲v-on:input
和v-bind:value
的語法糖而已。
<input v-model="something"> <input v-bind:value="something" v-on:input="something = $event.target.value">
注意:v-model 會忽略全部表單元素的 value、checked、selected
特性的初始值而老是將 Vue 實例的數據做爲數據來源。你應該經過 JavaScript 在組件的 data 選項中聲明初始值。
<input v-model="message" placeholder="edit me"> <textarea v-model="message" placeholder="add multiple lines"></textarea> <p>Message is: {{ message }}</p>
<div id='example-3'> <input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> <label for="jack">Jack</label> <input type="checkbox" id="john" value="John" v-model="checkedNames"> <label for="john">John</label> <input type="checkbox" id="mike" value="Mike" v-model="checkedNames"> <label for="mike">Mike</label> <br> <span>Checked names: {{ checkedNames }}</span> </div>
new Vue({ el: '#example-3', data: { checkedNames: [] } }) //Checked names: [ "Jack", "John", "Mike" ]
<div id="example-4"> <input type="radio" id="one" value="One" v-model="picked"> <label for="one">One</label> <br> <input type="radio" id="two" value="Two" v-model="picked"> <label for="two">Two</label> <br> <span>Picked: {{ picked }}</span> </div>
new Vue({ el: '#example-4', data: { picked: '' } }) //Picked: Two
<div id="example-5"> <select v-model="selected"> <option disabled value="">請選擇</option> <option>A</option> <option>B</option> <option>C</option> </select> <span>Selected: {{ selected }}</span> </div>
new Vue({ el: '...', data: { selected: '' } }) //Selected: B
爲多選時則返回一個數組Selected: [ "A", "B" ]
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" >
<input type="radio" v-model="pick" v-bind:value="a">
<select v-model="selected"> <!-- 內聯對象字面量 --> <option v-bind:value="{ number: 123 }">123</option> </select>
.lazy
,默認input
事件觸發,使用此修飾則改成change事件觸發<!-- 在「change」時而非「input」時更新 --> <input v-model.lazy="msg" >
.number
將輸入的值轉換爲數值.trim
過濾掉輸入內容的首尾空白字符
組件 (Component) 是 Vue.js 最強大的功能之一。組件能夠擴展 HTML 元素,封裝可重用的代碼。組件是具備特殊功能的自定義元素。
全部的 Vue 組件同時也都是 Vue 的實例,因此可接受相同的選項對象 (除了一些根級特有的選項) 並提供相同的生命週期鉤子。
<div id="example"> <my-component></my-component> </div> //注意確保在初始化根實例以前註冊組件 // 註冊 Vue.component('my-component', { template: '<div>A custom component!</div>' })
var Child = { template: '<div>A custom component!</div>' } new Vue({ // ... components: { // <my-component> 將只在父組件模板中可用 'my-component': Child } })
webpack 的 vue cli3+
import Vue from 'vue' import upperFirst from 'lodash/upperFirst' import camelCase from 'lodash/camelCase' const requireComponent = require.context( // 其組件目錄的相對路徑 './components', // 是否查詢其子目錄 false, // 匹配基礎組件文件名的正則表達式 /Base[A-Z]\w+\.(vue|js)$/ ) requireComponent.keys().forEach(fileName => { // 獲取組件配置 const componentConfig = requireComponent(fileName) // 獲取組件的 PascalCase 命名 const componentName = upperFirst( camelCase( // 剝去文件名開頭的 `'./` 和結尾的擴展名 fileName.replace(/^\.\/(.*)\.\w+$/, '$1') ) ) // 全局註冊組件 Vue.component( componentName, // 若是這個組件選項是經過 `export default` 導出的, // 那麼就會優先使用 `.default`, // 不然回退到使用模塊的根。 componentConfig.default || componentConfig ) })
<ul>
、<ol>
、<table>
、<select>
這樣的元素裏面,爲了遵循規範,應該使用is:<table> <tr is="my-row"></tr> </table>
如下類型模板無此限制:<script type="text/x-template">
、JavaScript 內聯模板字符串、.vue
組件
能夠包含<template>
、<script>
、<style>
、<docs>
四個元素。
<template>
內只容許有一個根元素<style>
能夠有多個<docs>
說明文檔<script>
、<style>
支持src導入父組件向子組件傳遞數據。
Vue.component('child', { // 聲明 props props: ['message'], // 就像 data 同樣,prop 也能夠在模板中使用 // 一樣也能夠在 vm 實例中經過 this.message 來使用 template: '<span>{{ message }}</span>' }) <child message="hello!"></child>
<child v-bind:my-message="parentMsg"></child>
若是你想把一個對象的全部屬性做爲 prop 進行傳遞,可使用不帶任何參數的 v-bind
todo: { text: 'Learn Vue', isComplete: false } <todo-item v-bind="todo"></todo-item> //等價於 <todo-item v-bind:text="todo.text" v-bind:is-complete="todo.isComplete" ></todo-item>
<!-- 傳遞了一個字符串 "1" --> <comp some-prop="1"></comp> <!-- 傳遞真正的數值 --> <comp v-bind:some-prop="1"></comp>
爲組件的 prop 指定驗證規則,會在組件實例建立以前進行校驗。若是傳入的數據不符合要求,Vue 會發出警告。
Vue.component('example', { props: { // 基礎類型檢測 (`null` 指容許任何類型) propA: Number, // 多是多種類型 propB: [String, Number], // 必傳且是字符串 propC: { type: String, required: true }, // 數值且有默認值 propD: { type: Number, default: 100 }, // 數組/對象的默認值應當由一個工廠函數返回 propE: { type: Object, default: function () { return { message: 'hello' } } }, // 自定義驗證函數 propF: { validator: function (value) { return value > 10 } } } })
type 能夠是下面原生構造器:String
、Number
、Boolean
、Function
、Object
、Array
、Symbol
組件能夠接收任意傳入的特性,這些特性都會被添加到組件的根元素上,且會作合併處理。
子組件向父組件傳遞數據。
$on(eventName)
監聽事件$emit(eventName)
觸發事件<div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div>
Vue.component('button-counter', { template: '<button v-on:click="incrementCounter">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { incrementCounter: function () { this.counter += 1 this.$emit('increment') } }, }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } })
.sync
@update
的語法糖
<comp :foo.sync="bar"></comp> this.$emit('update:foo', newValue)
等價於
<comp :foo="bar" @update:foo="val => bar = val"></comp> this.$emit('update:foo', newValue)
v-on:input
和v-bind:value
的語法糖
<input v-model="something"> // 經過 input 事件帶出數值 this.$emit('input', Number(formattedValue))
等價於
<input v-bind:value="something" v-on:input="something = $event.target.value"> this.$emit('input', Number(formattedValue))
bus.js
var bus = new Vue() // 觸發組件 A 中的事件 bus.$emit('id-selected', 1) // 在組件 B 建立的鉤子中監聽事件 bus.$on('id-selected', function (id) { // ... })
注: 還可使用$ref、$parent、$child
進行通訊,不過不推薦。
爲了讓組件能夠組合,咱們須要一種方式來混合父組件的內容與子組件本身的模板。這個過程被稱爲內容分發。
編譯做用域: 父組件模板的內容在父組件做用域內編譯;子組件模板的內容在子組件做用域內編譯。
除非子組件模板包含至少一個 <slot>
插口,不然父組件的內容將會被丟棄。當子組件模板只有一個沒有屬性的插槽時,父組件傳入的整個內容片斷將插入到插槽所在的 DOM 位置,並替換掉插槽標籤自己。
最初在 <slot>
標籤中的任何內容都被視爲備用內容。備用內容在子組件的做用域內編譯,而且只有在宿主元素爲空,且沒有要插入的內容時才顯示備用內容。
<!--子組件--> <div> <h2>我是子組件的標題</h2> <slot> 只有在沒有要分發的內容時纔會顯示。 </slot> </div> <!--父組件--> <div> <h1>我是父組件的標題</h1> <my-component> <p>這是一些初始內容</p> <p>這是更多的初始內容</p> </my-component> </div> <!--結果--> <div> <h1>我是父組件的標題</h1> <div> <h2>我是子組件的標題</h2> <p>這是一些初始內容</p> <p>這是更多的初始內容</p> </div> </div>
<slot>
元素能夠用一個特殊的特性 name 來進一步配置如何分發內容。多個插槽能夠有不一樣的名字。具名插槽將匹配內容片斷中有對應 slot 特性的元素。
仍然能夠有一個匿名插槽,它是默認插槽,做爲找不到匹配的內容片斷的備用插槽。若是沒有默認插槽,這些找不到匹配的內容片斷將被拋棄。
<!--子組件--> <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> <!--父組件--> <app-layout> <h1 slot="header">這裏多是一個頁面標題</h1> <p>主要內容的一個段落。</p> <p>另外一個主要段落。</p> <p slot="footer">這裏有一些聯繫信息</p> </app-layout> <!--結果--> <div class="container"> <header> <h1>這裏多是一個頁面標題</h1> </header> <main> <p>主要內容的一個段落。</p> <p>另外一個主要段落。</p> </main> <footer> <p>這裏有一些聯繫信息</p> </footer> </div>
和普通的插槽對比,可以傳遞數據。
<!--子組件--> <div class="child"> <slot text="hello from child"></slot> </div> <!--父組件--> <div class="parent"> <child> <!--2.5.0+,slot-scope 能被用在任意元素或組件中而再也不侷限於 <template>--> <template slot-scope="props"> <span>hello from parent</span> <span>{{ props.text }}</span> </template> </child> </div> <!--結果--> <div class="parent"> <div class="child"> <span>hello from parent</span> <span>hello from child</span> </div> </div>
經過使用保留的 <component>
元素,並對其 is 特性進行動態綁定,你能夠在同一個掛載點動態切換多個組件:
var vm = new Vue({ el: '#example', data: { currentView: 'home' }, components: { home: { /* ... */ }, posts: { /* ... */ }, archive: { /* ... */ } } })
把切換出去的組件保留在內存中,保留其狀態或避免從新渲染
<keep-alive> <component :is="currentView"> <!-- 非活動組件將被緩存! --> </component> </keep-alive>
Vue 在插入、更新或者移除 DOM 時,提供多種不一樣方式的應用過渡效果。
適用場景:條件渲染 (使用 v-if)、條件展現 (使用 v-show)、動態組件、組件根節點
<div id="demo"> <button v-on:click="show = !show"> Toggle </button> <transition name="fade"> <p v-if="show">hello</p> </transition> </div>
new Vue({ el: '#demo', data: { show: true } })
.fade-enter-active, .fade-leave-active { transition: opacity .5s; } .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0; }
動畫在css中使用animation便可,其餘和過渡相似。
咱們能夠經過如下特性來自定義過渡類名:enter-class、enter-active-class、enter-to-class (2.1.8+)、leave-class、leave-active-class、leave-to-class (2.1.8+)
<div id="example-3"> <button @click="show = !show"> Toggle render </button> <transition name="custom-classes-transition" enter-active-class="animated tada" leave-active-class="animated bounceOutRight" > <p v-if="show">hello</p> </transition> </div>
<transition :duration="1000">...</transition> <transition :duration="{ enter: 500, leave: 800 }">...</transition>
<transition v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter" v-on:enter-cancelled="enterCancelled" v-on:before-leave="beforeLeave" v-on:leave="leave" v-on:after-leave="afterLeave" v-on:leave-cancelled="leaveCancelled" > <!-- ... --> </transition>
// ... methods: { // -------- // 進入中 // -------- beforeEnter: function (el) { // ... }, // 此回調函數是可選項的設置,done 是必須的 // 與 CSS 結合時使用 enter: function (el, done) { // ... done() }, afterEnter: function (el) { // ... }, enterCancelled: function (el) { // ... }, // -------- // 離開時 // -------- beforeLeave: function (el) { // ... }, // 此回調函數是可選項的設置,done 是必須的 // 與 CSS 結合時使用 leave: function (el, done) { // ... done() }, afterLeave: function (el) { // ... }, // leaveCancelled 只用於 v-show 中 leaveCancelled: function (el) { // ... } }
能夠經過 appear 特性設置節點在初始渲染的過渡
<!--css--> <transition appear appear-class="custom-appear-class" appear-to-class="custom-appear-to-class" (2.1.8+) appear-active-class="custom-appear-active-class" > <!-- ... --> </transition> <!--JS鉤子--> <transition appear v-on:before-appear="customBeforeAppearHook" v-on:appear="customAppearHook" v-on:after-appear="customAfterAppearHook" v-on:appear-cancelled="customAppearCancelledHook" > <!-- ... --> </transition>
當有相同標籤名的元素切換時,建議給元素設置key。
<transition name="fade" mode="out-in"> <!-- ... the buttons ... --> </transition>
多個組件的過渡使用動態組件
<!--html--> <transition name="component-fade" mode="out-in"> <component v-bind:is="view"></component> </transition> <!--js--> new Vue({ el: '#transition-components-demo', data: { view: 'v-a' }, components: { 'v-a': { template: '<div>Component A</div>' }, 'v-b': { template: '<div>Component B</div>' } } })
使用 <transition-group>
組件。
<span>
。你也能夠經過 tag 特性更換爲其餘元素。<div id="list-demo" class="demo"> <button v-on:click="add">Add</button> <button v-on:click="remove">Remove</button> <transition-group name="list" tag="p"> <span v-for="item in items" v-bind:key="item" class="list-item"> {{ item }} </span> </transition-group> </div>
<transition-group>
組件還有一個特殊之處。不只能夠進入和離開動畫,還能夠改變定位。v-move 特性,它會在元素的改變定位的過程當中應用。
<!--html--> <transition-group name="flip-list" tag="ul"> <li v-for="item in items" v-bind:key="item"> {{ item }} </li> </transition-group> <!--css--> .flip-list-move { transition: transform 1s; }
也能夠經過 move-class 屬性手動設置
<transition name="very-special-transition" mode="out-in" v-on:before-enter="beforeEnter" v-on:after-enter="afterEnter"> <slot></slot> </transition>
<transition v-bind:name="transitionName"> <!-- ... --> </transition>
混合 (mixins) 是一種分發 Vue 組件中可複用功能的很是靈活的方式。混合對象能夠包含任意組件選項。當組件使用混合對象時,全部混合對象的選項將被混入該組件自己的選項。
// 定義一個混合對象 var myMixin = { created: function () { this.hello() }, methods: { hello: function () { console.log('hello from mixin!') } } } // 定義一個使用混合對象的組件 var Component = Vue.extend({ mixins: [myMixin] })
Vue.extend()
也使用一樣的策略進行合併。除了核心功能默認內置的指令 (v-model 和 v-show),Vue 也容許註冊自定義指令。
// 註冊一個全局自定義指令 `v-focus` Vue.directive('focus', { // 當被綁定的元素插入到 DOM 中時…… inserted: function (el) { // 聚焦元素 el.focus() } }) // 註冊一個局部自定義指令 directives: { focus: { // 指令的定義 inserted: function (el) { el.focus() } } } //使用 <input v-focus>
一個指令定義對象能夠提供以下幾個鉤子函數 (均爲可選):
bind:
只調用一次,指令第一次綁定到元素時調用。在這裏能夠進行一次性的初始化設置。inserted:
被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。update:
所在組件的 VNode 更新時調用,可是可能發生在其子 VNode 更新以前。指令的值可能發生了改變,也可能沒有。可是你能夠經過比較更新先後的值來忽略沒必要要的模板更新 (詳細的鉤子函數參數見下)。componentUpdated:
指令所在組件的 VNode 及其子 VNode 所有更新後調用。unbind:
只調用一次,指令與元素解綁時調用。指令鉤子函數會被傳入如下參數:
el:
指令所綁定的元素,能夠用來直接操做 DOM 。binding:
一個對象,包含如下屬性:
name:
指令名,不包括 v- 前綴。value:
指令的綁定值,例如:v-my-directive="1 + 1" 中,綁定值爲 2。oldValue:
指令綁定的前一個值,僅在 update 和 componentUpdated 鉤子中可用。不管值是否改變均可用。expression:
字符串形式的指令表達式。例如 v-my-directive="1 + 1" 中,表達式爲 "1 + 1"。arg:
傳給指令的參數,可選。例如 v-my-directive:foo 中,參數爲 "foo"。modifiers:
一個包含修飾符的對象。例如:v-my-directive.foo.bar 中,修飾符對象爲 { foo: true, bar: true }。vnode:
Vue 編譯生成的虛擬節點。移步 VNode API 來了解更多詳情。oldVnode:
上一個虛擬節點,僅在 update 和 componentUpdated 鉤子中可用。https://cn.vuejs.org/v2/guide...
createElement
// @returns {VNode} createElement( // {String | Object | Function} // 一個 HTML 標籤字符串,組件選項對象,或者 // 解析上述任何一種的一個 async 異步函數,必要參數。 'div', // {Object} // 一個包含模板相關屬性的數據對象 // 這樣,您能夠在 template 中使用這些屬性。可選參數。 { // (詳情見下面的數據對象) }, // {String | Array} // 子節點 (VNodes),由 `createElement()` 構建而成, // 或使用字符串來生成「文本節點」。可選參數。 [ '先寫一些文字', createElement('h1', '一則頭條'), createElement(MyComponent, { props: { someProp: 'foobar' } }) ] )
數據對象:
{ // 和`v-bind:class`同樣的 API 'class': { foo: true, bar: false }, // 和`v-bind:style`同樣的 API style: { color: 'red', fontSize: '14px' }, // 正常的 HTML 特性 attrs: { id: 'foo' }, // 組件 props props: { myProp: 'bar' }, // DOM 屬性 domProps: { innerHTML: 'baz' }, // 事件監聽器基於 `on` // 因此再也不支持如 `v-on:keyup.enter` 修飾器 // 須要手動匹配 keyCode。 on: { click: this.clickHandler }, // 僅對於組件,用於監聽原生事件,而不是組件內部使用 // `vm.$emit` 觸發的事件。 nativeOn: { click: this.nativeClickHandler }, // 自定義指令。注意,你沒法對 `binding` 中的 `oldValue` // 賦值,由於 Vue 已經自動爲你進行了同步。 directives: [ { name: 'my-custom-directive', value: '2', expression: '1 + 1', arg: 'foo', modifiers: { bar: true } } ], // Scoped slots in the form of // { name: props => VNode | Array<VNode> } scopedSlots: { default: props => createElement('span', props.text) }, // 若是組件是其餘組件的子組件,需爲插槽指定名稱 slot: 'name-of-slot', // 其餘特殊頂層屬性 key: 'myKey', ref: 'myRef' }
過濾器能夠用在兩個地方:雙花括號插值和 v-bind 表達式。
<!-- 在雙花括號中 --> {{ message | capitalize }} <!-- 在 `v-bind` 中 --> <div v-bind:id="rawId | formatId"></div>
//定義局部過濾器 filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } } //定義全局過濾器 Vue.filter('capitalize', function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) })
{{ message | filterA | filterB }}
{{ message | filterA('arg1', arg2) }}
<script>
引入(本地或者cdn)npm install vue
必需要經過 Vue.use()
明確地安裝路由功能,且要經過 router 配置參數注入Vue實例,從而讓整個應用都有路由功能。
將頁面組件(components)映射到路由(routes),而後告訴 vue-router 在哪裏渲染它們
to:
屬性指定目標地址,默認渲染成帶有正確連接的 標籤, replace:
至關於router.replace()
不會留下 history 記錄append:
設置 append 屬性後,則在當前(相對)路徑前添加基路徑。例如,咱們從 /a 導航到一個相對路徑 b,若是沒有配置 append,則路徑爲 /b,若是配了,則爲 /a/btag:
屬性生成別的標籤.。另外,當目標路由成功激活時,連接元素自動設置一個表示激活的 CSS 類名。active-class:
連接激活時使用的 CSS 類名。默認值能夠經過路由的構造選項 linkActiveClass 來全局配置。將激活 class 應用在外層元素:
<router-link tag="li" to="/foo"> <a>/foo</a> </router-link>
在這種狀況下,<a>
將做爲真實的連接(它會得到正確的 href 的),而 "激活時的CSS類名" 則設置到外層的 <li>
。
路由視圖容器
<transition> <!--使用路由緩存--> <keep-alive> <router-view></router-view> </keep-alive> </transition>
若是 <router-view>
設置了名稱,則會渲染對應的路由配置中 components 下的相應組件。
<!--html--> <router-view class="view one"></router-view> <router-view class="view two" name="a"></router-view> <router-view class="view three" name="b"></router-view> <!--js--> const router = new VueRouter({ routes: [ { path: '/', components: { default: Foo, a: Bar, b: Baz } } ] })
params
//定義 routes: [ // 動態路徑參數 以冒號開頭 { path: '/user/:id', component: User } ] //調用 $route.params.id
query
//定義 routes: [ // 動態路徑參數 以冒號開頭 { path: '/user?id=6456456', component: User } ] //調用 $route.query.id
當路由參數變化時,組件的生命週期鉤子不會再被調用。
想對路由參數的變化做出響應的話,有如下兩種方式:
const User = { template: '...', watch: { '$route' (to, from) { // 對路由變化做出響應... } } }
const User = { template: '...', beforeRouteUpdate (to, from, next) { // react to route changes... // don't forget to call next() } }
同一個路徑能夠匹配多個路由時,誰先定義的,誰的優先級就最高。
所以,404類的頁面必定要放在最後,路由是按照聲明順序匹配,若是不是最後則404以後的頁面都會跳轉到404。
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ { // 當 /user/:id/profile 匹配成功, // UserProfile 會被渲染在 User 的 <router-view> 中 path: 'profile', component: UserProfile }, { // 當 /user/:id/posts 匹配成功 // UserPosts 會被渲染在 User 的 <router-view> 中 path: 'posts', component: UserPosts } ] } ] })
導航到不一樣的 URL,會向 history 棧添加一個新的記錄。
在 Vue 實例內部,調用 this.$router.push
// 字符串 router.push('home') // 對象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: 123 }}) // 帶查詢參數,變成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
和router.push功能同樣,惟一區別就是不會向 history 添加新記錄
前進或後退nN步,相似 window.history.go(n)
// 在瀏覽器記錄中前進一步,等同於 history.forward() router.go(1) // 後退一步記錄,等同於 history.back() router.go(-1)
const router = new VueRouter({ routes: [ //path { path: '/a', redirect: '/b' }, //name { path: '/a', redirect: { name: 'foo' }}, //方法 { path: '/a', redirect: to => { // 方法接收 目標路由 做爲參數 // return 重定向的 字符串路徑/路徑對象 }} ] })
/a 的別名是 /b,意味着,當用戶訪問 /b 時,URL 會保持爲 /b,可是路由匹配則爲 /a,就像用戶訪問 /a 同樣
const router = new VueRouter({ routes: [ { path: '/a', component: A, alias: '/b' } ] })
使用 props 將組件和路由解耦
const User = { props: ['id'], template: '<div>User {{ id }}</div>' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, props: true }, // 對於包含命名視圖的路由,你必須分別爲每一個命名視圖添加 `props` 選項: { path: '/user/:id', components: { default: User, sidebar: Sidebar }, props: { default: true, sidebar: false } } ] })
const router = new VueRouter({ routes: [ { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } } ] })
const router = new VueRouter({ routes: [ { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) } ] })
vue-router 默認 hash 模式。
開啓history 模式,將充分利用 history.pushState API 來完成 URL 跳轉而無須從新加載頁面,但須要後端配合。
const router = new VueRouter({ mode: 'history', routes: [...] })
vue-router 提供的導航守衛主要用來經過跳轉或取消的方式守衛導航。
//前置守衛:確保要調用 next 方法,不然鉤子就不會被 resolved。 router.beforeEach((to, from, next) => { // ... }) //後置守衛 router.afterEach((to, from) => { // ... }) //解析守衛:在導航被確認以前,同時在全部組件內守衛和異步路由組件被解析以後,解析守衛就被調用 router.beforeResolve((to, from) => { // ... })
to: Route:
即將要進入的目標 路由對象from: Route:
當前導航正要離開的路由next: Function:
必定要調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數。
next():
進行管道中的下一個鉤子。若是所有鉤子執行完了,則導航的狀態就是 confirmed (確認的)。next(false):
中斷當前的導航。若是瀏覽器的 URL 改變了(多是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。next('/')
或者 next({ path: '/' }):
跳轉到一個不一樣的地址。當前的導航被中斷,而後進行一個新的導航。你能夠向 next 傳遞任意位置對象,且容許設置諸如 replace: true、name: 'home'
之類的選項以及任何用在 router-link 的 to prop 或 router.push 中的選項。next(error):
(2.4.0+) 若是傳入 next 的參數是一個 Error 實例,則導航會被終止且該錯誤會被傳遞給 router.onError()
註冊過的回調。//與全局前置守衛的方法參數是同樣的 const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] })
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染該組件的對應路由被 confirm 前調用 // 不!能!獲取組件實例 `this` // 由於當守衛執行前,組件實例還沒被建立 }, beforeRouteUpdate (to, from, next) { // 在當前路由改變,可是該組件被複用時調用 // 舉例來講,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候, // 因爲會渲染一樣的 Foo 組件,所以組件實例會被複用。而這個鉤子就會在這個狀況下被調用。 // 能夠訪問組件實例 `this` }, beforeRouteLeave (to, from, next) { // 導航離開該組件的對應路由時調用 // 能夠訪問組件實例 `this` } }
beforeRouteEnter 守衛 不能 訪問 this,由於守衛在導航確認前被調用,所以即將登場的新組件還沒被建立。能夠經過傳一個回調給 next來訪問組件實例。
beforeRouteEnter (to, from, next) { next(vm => { // 經過 `vm` 訪問組件實例 }) }
配置meta字段記錄元信息
//定義 { path: 'bar', component: Bar, // a meta field meta: { requiresAuth: true } } //訪問 $route.matched
<transition> <router-view></router-view> </transition> <!-- 使用動態的 transition name --> <transition :name="transitionName"> <router-view></router-view> </transition>
<script>
引入(本地或者cdn)npm install vuex
必需要經過 Vue.use() 明確地安裝vuex,且要經過 store 配置參數注入Vue實例。
Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
// 在單獨構建的版本中輔助函數爲 Vuex.mapState import { mapState } from 'vuex' export default { // ... computed: mapState({ // 箭頭函數可以使代碼更簡練 count: state => state.count, // 傳字符串參數 'count' 等同於 `state => state.count` countAlias: 'count', // 爲了可以使用 `this` 獲取局部狀態,必須使用常規函數 countPlusLocalState (state) { return state.count + this.localCount } }) } -------------- //當映射的計算屬性的名稱與 state 的子節點名稱相同時,咱們也能夠給 mapState 傳一個字符串數組 computed: mapState([ // 映射 this.count 爲 store.state.count 'count' ]) -------------- computed: { localComputed () { /* ... */ }, // 使用對象展開運算符將此對象混入到外部對象中 ...mapState({ // ... }) }
若是有多處都須要從store中派生(進行二次處理)出一些狀態,那麼可使用getter(store 的計算屬性,依賴更新)
getters: { //state 做爲其第一個參數 doneTodos: state => { return state.todos.filter(todo => todo.done) }, //接受其餘 getter 做爲第二個參數 doneTodosCount: (state, getters) => { return getters.doneTodos.length } } //調用 store.getters.doneTodosCount // -> 1
import { mapGetters } from 'vuex' computed: { // 使用對象展開運算符將 getter 混入 computed 對象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) }
更改 Vuex 的 store 中的狀態的惟一方法是提交 (commit)。建議名字大寫。 mutation,可是請勿進行異步操做。
mutations: { increment (state) { // 變動狀態 state.count++ } } //調用 store.commit('increment')
載荷即commit中額外的參數。
mutations: { increment (state, n) { state.count += n } } //調用 store.commit('increment', 10) ------------- //推薦使用對象 mutations: { increment (state, payload) { state.count += payload.amount } } store.commit('increment', { amount: 10 }) //對象風格提交 store.commit({ type: 'increment', amount: 10 })
import { mapMutations } from 'vuex' export default { // ... methods: { ...mapMutations([ 'increment', // 將 `this.increment()` 映射爲 `this.$store.commit('increment')` // `mapMutations` 也支持載荷: 'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.commit('incrementBy', amount)` ]), ...mapMutations({ add: 'increment' // 將 `this.add()` 映射爲 `this.$store.commit('increment')` }) } }
Action 相似於 mutation,區別在於:
actions: { increment (context) { context.commit('increment') } } //分發 store.dispatch('increment')
Action 函數接受一個與 store 實例(不是 store 實例自己)具備相同方法和屬性的 context(context.state/context.getters/context.commit
)對象,也能夠運用參數結構。
actions: { increment ({ commit }) { commit('increment') } }
// 以載荷形式分發 store.dispatch('incrementAsync', { amount: 10 }) // 以對象形式分發 store.dispatch({ type: 'incrementAsync', amount: 10 })
import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'increment', // 將 `this.increment()` 映射爲 `this.$store.dispatch('increment')` // `mapActions` 也支持載荷: 'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.dispatch('incrementBy', amount)` ]), ...mapActions({ add: 'increment' // 將 `this.add()` 映射爲 `this.$store.dispatch('increment')` }) } }
actions: { actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation') resolve() }, 1000) }) }, //調用其餘action actionB ({ dispatch, commit }) { return dispatch('actionA').then(() => { commit('someOtherMutation') }) } } store.dispatch('actionA').then(() => { // ... })
// 假設 getData() 和 getOtherData() 返回的是 Promise actions: { async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { await dispatch('actionA') // 等待 actionA 完成 commit('gotOtherData', await getOtherData()) } }
將store分割成模塊,每一個模塊擁有本身的 state、mutation、action、getter。
actions: { incrementIfOddOnRootSum ({ state, commit, rootState }) { if ((state.count + rootState.count) % 2 === 1) { commit('increment') } } } getters: { sumWithRootCount (state, getters, rootState) { return state.count + rootState.count } }
modules: { account: { namespaced: true, // 模塊內容(module assets) state: {}, // 模塊內的狀態已是嵌套的了,使用 `namespaced` 屬性不會對其產生影響 getters: {}, actions: {}, mutations: {} } }
getters: { // 在這個模塊的 getter 中,`getters` 被局部化了 // 你可使用 getter 的第四個參數來調用 `rootGetters` someGetter (state, getters, rootState, rootGetters) {} } actions: { // 在這個模塊中, dispatch 和 commit 也被局部化了 // 他們能夠接受 `root` 屬性以訪問根 dispatch 或 commit someAction ({ dispatch, commit, getters, rootGetters }) {} }
computed: { ...mapState('some/nested/module', { a: state => state.a, b: state => state.b }) }, methods: { ...mapActions('some/nested/module', [ 'foo', 'bar' ]) }
import { createNamespacedHelpers } from 'vuex' const { mapState, mapActions } = createNamespacedHelpers('some/nested/module') export default { computed: { // 在 `some/nested/module` 中查找 ...mapState({ a: state => state.a, b: state => state.b }) }, methods: { // 在 `some/nested/module` 中查找 ...mapActions([ 'foo', 'bar' ]) } }
store.registerModule
// 註冊模塊 `myModule` store.registerModule('myModule', { // ... }) // 註冊嵌套模塊 `nested/myModule` store.registerModule(['nested', 'myModule'], { // ... })
使用store.unregisterModule(moduleName)
來動態卸載模塊
在 Vue2.0 中,代碼複用和抽象的主要形式是組件。然而,有的狀況下,你仍然須要對普通 DOM 元素進行底層操做,這時候就會用到自定義指令
建立Vue的自定義指令的這五個鉤子函數都是可選的,不必定要所有出現。而這其中bind和update兩個鉤子函數是最有用的。在實際使用的時候,咱們應該根據需求作不一樣的選擇。好比在恰當的時間經過bind鉤子函數去初始化實例,update鉤子函數去作對應的參數更新和使用unbind鉤子函數去釋放實例資源佔用等。
bind(el, binding, vnode) inserted(el, binding, vnode) update(el, binding, vnode, oldVnode) componentUpdated(el, binding, vnode, oldVnode) unbind(el, binding, vnode)
指令鉤子函數會被傳入如下參數:
el:指令所綁定的元素,能夠用來直接操做DOM binding:一個對象,這個對象包含一些屬性,稍後列出每一個屬性的含義 vnode:Vue編譯生成的虛擬節點。有關於VNode更多的資料,能夠閱讀VNode相關的API oldVnode:上一個虛擬節點,僅在update和componentUpdated兩個鉤子函數中可用
binding參數是一個對象,其包含如下一些屬性:
name:指令名,不包括v-前綴 value:指令的綁定值,如例v-hello = "1 + 1"中,綁定值爲2 oldValue:指令綁定的前一個值,僅在update和componentUpdated鉤子中可用,不管值是否改變均可用 expression:字符串形式的指令表達式。例如v-hello = "1 + 1"中,表達式爲"1 + 1" arg:傳給指令的參數,可選。例如v-hello:message中,參數爲"message" modifiers:一個包含修飾符的對象。例如v-hello.foo.bar中,修飾符對象爲{foo:true, bar:true}
除了 el 以外,其它參數都應該是隻讀的,切勿進行修改。若是須要在鉤子之間共享數據,建議經過元素的 dataset 來進行。著做權歸做者全部。
在不少時候,你可能想在 bind 和 update 時觸發相同行爲,而不關心其它的鉤子。好比這樣寫:
Vue.directive('color-swatch', function (el, binding) { el.style.backgroundColor = binding.value })
若是指令須要多個值,能夠傳入一個 JavaScript 對象字面量。記住,指令函數可以接受全部合法的 JavaScript 表達式。
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Vue.directive('demo', function (el, binding) { console.log(binding.value.color) // => "white" console.log(binding.value.text) // => "hello!" })
參考資料:
https://pablohpsilva.github.i...
https://vue-loader.vuejs.org/...