組件樹html
DOM訪問前端
數據訪問vue
DOM方法的使用git
// vue 的 渲染過程是異步的<template> <div id="app"> <p>{{text}}</p> </div></template><script>export default { data() { return { text: 0 }; } mounted(){ setInterval(()=> { this.text +=1; this.text +=1; this.text +=1; this.text +=1; this.text +=1; },1000) }}</script>
能夠看到text值的變化是0 5 10 15 … 而並無出現 0 1 2 3 … 這樣連續的變化github
event方法的使用vue-router
1.監聽vuex
// 第一種寫法watch: { text(new, old) { console.log(`${new}:${old}`); }}// 第二種寫法const unWatch = this.$watch('text',(new,old)=> console.log(`${new}:${old}`);})// 2秒後銷燬 unWatchsetTimeout(()=> { unWatch();},2000)// 兩種寫法的結果同樣,只是第二種須要在組件銷燬手動銷燬$watch
2.觸發數組
3.刪除瀏覽器
4.其餘緩存
<template> <div id="app"> <p>{{obj.a}}</p> </div></template><script>export default { data() { return { obj:{} }; } mounted(){ let i = 0; setInterval(()=> { i++; // 第一種 this.obj.a = i ; // obj.a沒有定義,vue是沒法監聽到這個屬性的變化,因此頁面的值也不會變化,這時能夠用$forceUpdate進行強制渲染,固然不推薦這種用法 this.$forceUpdate(); // 第二種 this.$set(this.obj,'a',i); },1000) }}</script>
Vue 生命週期
vue 官方生命週期
render (h) { throw new TypeError('render error') // console.log('render function invoked') // render 在beforeMount 和 mounted之間執行 // return h('div', {}, this.text) // 虛擬DOM},renderError (h, err) { return h('div', {}, err.stack)},errorCaptured () {// 會向上冒泡,而且正式環境可使用}
若是要修改data裏面的值,最先只能放到create生命週期中
Vue 數據綁定
<template> <div id="app"> <p>{{isActive?'active':'notActive'}}</p> <p>{{arr.join(' ')}}</p> <p>{{Date.now()}}</p> <p v-html="html"></p> <div :class="{ active: isActive }" :style="[styles, styles2]" ></div> <div :class="[isActive? 'active':'']"></div> <ul> <li v-for="(item,index) in arr" :key="index">{{item}}</li> </ul> // 單個checkbox <input type="checkbox" v-model="a"> {{a}} <br/> // 多個checkbox 愛好:<input type="checkbox" v-model="b" value="游泳"> 游泳 <input type="checkbox" v-model="b" value="游泳"> 登山 <input type="checkbox" v-model="b" value="游泳"> 睡覺 性別:<input type="radio" v-model="c" value="男"> 男 <input type="radio" v-model="c" value="女"> 女 // 只綁定一次 <p v-once="a"></p> </div></template><script>export default { data() { return { isActive: false, arr: [1, 2, 3], html: '<span>123</span>', styles: { color: 'red', appearance: 'none' }, styles2: { color: 'black' }, a: false, b:[], // 能夠拿到checkbox 的 value c:'' // 性別 }; }}</script>
v-model 的修飾符
來自官網的例子:
1. .number
若是想自動將用戶的輸入值轉爲數值類型,能夠給 v-model 添加 number 修飾符:
<input v-model.number="age" type="number">
這一般頗有用,由於即便在 type=」number」 時,HTML 輸入元素的值也總會返回字符串。
2. .trim
若是要自動過濾用戶輸入的首尾空白字符,能夠給 v-model 添加 trim 修飾符:
<input v-model.trim="msg">
3. .lazy
在默認狀況下, v-model 在每次 input 事件觸發後將輸入框的值與數據進行同步 。你能夠添加 lazy 修飾符,從而轉變爲使用 change 事件進行同步(當輸入框失去焦點):
<!-- 在「change」時而非「input」時更新 --><input v-model.lazy="msg" >
數組和對象的注意事項
數組
因爲 JavaScript 的限制,Vue 不能檢測如下變更的數組:
var vm = new Vue({ data: { items: ['a', 'b', 'c'] }})vm.items[1] = 'x' // 不是響應性的vm.items.length = 2 // 不是響應性的
爲了解決第一類問題,如下兩種方式均可以實現和 vm.items[indexOfItem] = newValue 相同的效果,同時也將觸發狀態更新:
// Vue.setVue.set(vm.items, indexOfItem, newValue)// Array.prototype.splicevm.items.splice(indexOfItem, 1, newValue)
你也可使用 vm.$set 實例方法,該方法是全局方法 Vue.set 的一個別名:
vm.$set(vm.items, indexOfItem, newValue)
爲了解決第二類問題,你可使用 splice:
vm.items.splice(newLength)
對象
Vue 不能檢測對象屬性的添加或刪除:
var vm = new Vue({ data: { a: 1 }})// `vm.a` 如今是響應式的vm.b = 2// `vm.b` 不是響應式的
對於已經建立的實例,Vue 不能動態添加根級別的響應式屬性。可是,可使用 Vue.set(object, key, value) 方法向嵌套對象添加響應式屬性。例如,對於:
var vm = new Vue({ data: { userProfile: { name: 'Anika' } }})
你能夠添加一個新的 age 屬性到嵌套的 userProfile 對象:
Vue.set(vm.userProfile, 'age', 27)
你還可使用 vm.$set 實例方法,它只是全局 Vue.set 的別名:
vm.$set(vm.userProfile, 'age', 27)
有時你可能須要爲已有對象賦予多個新屬性,好比使用 Object.assign() 或 _.extend() 。在這種狀況下,你應該用兩個對象的屬性建立一個新的對象。因此,若是你想添加新的響應式屬性,不要像這樣:
Object.assign(vm.userProfile, { age: 27, favoriteColor: 'Vue Green'})
你應該這樣作:
vm.userProfile = Object.assign({}, vm.userProfile, { age: 27, favoriteColor: 'Vue Green'})
computed 計算屬性
計算屬性的使用
<template> <div id="app"> <p>{{name}}</p> </div></template><script>export default { data() { return { firstName: 'Fin', lastName: 'Get', }; }, computed: { name() { return `${this.firstName}${this.lastName}` } }}</script>
雙向綁定的計算屬性與Vuex
// vuex state是沒法直接修改的,官方給出了 v-model 的解決方案<input v-model="message">computed: { message: { get () { return this.$store.state.obj.message }, set (value) { this.$store.commit('updateMessage', value) } }}
若是在方法或者生命週期中使用了計算屬性,則必須設置一個set
watch 監聽器
watch 簡單使用
<div id="demo">{{ fullName }}</div>var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { // watch 方法最初綁定的時候,它是不會執行的,只有變化了纔會執行 firstName: function (val) { this.fullName = val + ' ' + this.lastName }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } }})watch: { // 聲明一個handler,這樣在初始化時就會執行一次 handler firstName: { handler(val) { this.fullName = val + ' ' + this.lastName }, immediate: true }}
監聽對象屬性的變化
<div id="demo">{{ obj.a }}</div><input v-model="obj.a" />var vm = new Vue({ el: '#demo', data: { obj: { a: '123' } }, watch: { obj: { handler() { console.log('obj.a changed'); }, immediate: true, deep: true // 若是不加這一句,在輸入框中輸入值,並不會打印 obj.a changed } }})// 這樣寫就能監聽到屬性值的變化watch: { 'obj.a': { handler() { console.log('obj.a changed'); } }}
Vue 組件
Vue 組件中的data爲何必須是函數
官網解釋
在Vue組件中data必須是函數,可是在 new Vue() 中data能夠是一個對象
Vue.component('MyComponent', { template: '<div>this is a component</div>', data() { return {} // 返回一個惟一的對象,不要和其餘組件共用一個對象進行返回 },})
上面定義了一個 MyComponent 組件,在這裏咱們能夠把這個組件當作一個構造函數。在其餘頁面引入,並註冊組件時,其實是對這個構造函數的一個引用。當在模板中正真使用組件時相似於實例化了一個組件對象。
// 模擬一下let MyComponent = function() { // 定義一個構造函數}MyComponent.prototype.data = { name: 'component', age: 0}// 實例化組件對象let componentA = new MyComponent();let componentB = new MyComponent();componentA.data.name === componentB.data.name; // truecomponentA.data.age = 4;componentB.data.name;
能夠看出,兩個實例組件對象的data是如出一轍的,一個改變也會致使另外一個改變,這在實際開發中是不符合組件式思想的。
// 模擬一下let MyComponent = function() { // 定義一個構造函數}// 這樣就好了 寫成函數,函數有本身的做用域,不會相互影響MyComponent.prototype.data = function() { return { name: 'component', age: 0 }}
用 Vue.use() 定義全局組件
// 定義一個 button 組件// button.vue<template> <div class="button"> 按鈕 </div></template><script></script>// button.jsimport ButtonComponent from './button.vue';const Button={ install:function (Vue) { Vue.component('Button',ButtonComponent) }}export default Button;// main.jsimport Button from './component/button.js';Vue.use(Button);
完成上面的步驟就能夠在全局使用button組件了,其實最重要的 Vue.component('Button',ButtonComponent) , Vue.use(Button) 會執行install方法,也能夠直接在 main.js 使用 Vue.component() 註冊全局組件。
props
<template> <div class="button"> 按鈕 </div></template><script>export default { props: ['msg'], // 沒有任何限制 // 輸入限制 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 ['success', 'warning', 'danger'].indexOf(value) !== -1 } } }}</script>
子組件是不能直接修改props的。
Vue組件之間的通訊問題能夠看這裏…
Vue 組件 extend
使用 Vue.extend 就是構造了一個Vue構造函數的「子類」。它的參數是一個 包含組件選項的對象 ,其中 data 選項必須是函數。
import Vue from 'vue'// 一個包含組件選項的對象const compoent = { props: { active: Boolean, propOne: String }, template: ` <div> <input type="text" v-model="text"> <span v-show="active">see me if active</span> </div> `, data () { return { text: 0 } }, mounted () { // 這個mounted先打印 console.log('comp mounted'); }}// 建立一個「子類」const CompVue = Vue.extend(compoent);// 實例化一個「子類」new CompVue({ el: '#root', propsData: { // 這裏若是用props,組件內是拿不到值的 propOne: 'xxx' }, data: { text: '123' }, mounted () { console.log('instance mounted'); }})const component2 = { extends: component, // 繼承於 component data(){ return { text: 1 } }, mounted () { this.$parent.text = '111111111'; // 能夠改變父組件的值 console.log('comp2 mounted') }}new Vue({ name: 'Root', el: '#root', mounted () { console.log(this.$parent.$options.name) }, components: { Comp: componet2 }, data: { text: 23333 }, template: ` <div> <span>{{text}}</span> <comp></comp> </div> `})
Vue 組件高級屬性
Vue 組件插槽
一般咱們會向一個組件中傳入一些自定義的內容,這個時候就能夠用到插槽。插槽內能夠包含任何模板代碼,包括HTML或者是一個組件。
// 定義一個帶插槽的組件const component = { name: 'comp', template: ` <div> <slot></slot> </div> `}new CompVue({ el: '#root', components:{ Comp }, template: ` <div> <comp> <p>這裏的內容顯示在插槽內</p> </comp> </div> `}
具名插槽
官網連接: https://cn.vuejs.org/v2/guide/components-slots.html
<div class="container"> <header> <!-- 咱們但願把頁頭放這裏 --> <slot name="header"></slot> </header> <main> <!-- 咱們但願把主要內容放這裏 --> <slot name="main"></slot> </main> <footer> <!-- 咱們但願把頁腳放這裏 --> <slot name="footer"></slot> </footer></div>
具名插槽的使用:
第一種:在一個父組件的 <template> 元素上使用 slot 特性
<base-layout> <template slot="header"> <h1>Here might be a page title</h1> </template> <template slot="main"> <p>A paragraph for the main content.</p> <p>And another one.</p> </template> <template slot="footer"> <p>Here's some contact info</p> </template></base-layout>
第二種:直接在普通元素上使用
<base-layout> <h1 slot="header">Here might be a page title</h1> <div slot="main"> <p>A paragraph for the main content.</p> <p>And another one.</p> </div> <p slot="footer">Here's some contact info</p></base-layout>
插槽的默認內容
在插槽中能夠設置一個默認內容,若是用戶沒有設置新的內容,則會顯示默認內容
<button> <slot>提交</slot></button>
做用域插槽
2.1.0+ 新增 在 2.5.0+, slot-scope 再也不限制在 <template> 元素上使用,而能夠用在插槽內的任何元素或組件上。
const component = { name: 'comp', template: ` <div> <slot value="456" name="finget"></slot> </div> `}new CompVue({ el: '#root', components:{ Comp }, template: ` <div> <comp> <p slot-scope="props">{{props.value}} {{props.name}}</p> // 456 finget </comp> </div> `}
provide/inject 跨級組件交互
2.2.0 新增
這對選項須要一塊兒使用,以容許一個祖先組件向其全部子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效。
// 父級組件提供 'foo'var Provider = { provide: { foo: 'bar' }, // ...}// 子組件注入 'foo'var Child = { inject: ['foo'], created () { console.log(this.foo) // => "bar" } // ...}
若是是注入一個父級組件內部的值,provide須要做爲一個函數,相似於data
const component = { name: 'comp', inject: ["value"] template: ` <div>子組件 {{value}}</div> `}new CompVue({ el: '#root', data() { return { value: '123' } } components:{ Comp }, provide() { // 這裏若是隻是一個對象的話是沒法拿到this.value的 return { value: this.value } }, template: ` <div> <comp></comp> <input type="text" v-model="value"> </div> `}
若是要監聽父級組件的屬性值的變化,從而自動更新子組件的值,須要手動實現監聽
const component = { name: 'comp', inject: ["data"] template: ` <div>子組件 {{data.value}}</div> `}...provide() { const data = {} // 這是vue雙向綁定的基礎 Object.defineProperty(data,"value",{ get: () => this.value, enumerable: true }) return { data }},...
Vue 的render
Vue模板的解析: https://finget.github.io/2018/05/31/mvvm-vue/
Vue-router
router構建選項
重定向:
{ path: '/', redirect: '/app'}
History 模式:
const router = new VueRouter({ mode: 'history', routes: [...]})
vue-router 默認 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,因而當 URL 改變時,頁面不會從新加載。
不過這種模式要玩好,還須要後臺配置支持。由於咱們的應用是個單頁客戶端應用,若是後臺沒有正確的配置,當用戶在瀏覽器直接訪問 http://oursite.com/user/id 就會返回 404,這就很差看了。
給個警告頁:
const router = new VueRouter({ mode: 'history', routes: [ { path: '*', component: NotFoundComponent } ]})
base
const router = new VueRouter({ mode: 'history', base: '/base/', routes: [ { path: '/hello', component: hello } ]})
當訪問 localhost:8080/hello 會變成 localhost:8080/base/hello ,全部的路由路徑都會加上 /base ,固然手動刪除 /base 仍是能夠打開頁面
linkActiveClass 和 linkExactActiveClass
<router-link to="/app">app</router-link><router-link to="/login">login</router-link>
router-link 在頁面中會渲染成 a 標籤,點擊以後會添加兩個類名: router-link-exact-active 和 router-link-active
const router = new VueRouter({ linkActiveClass: 'active-link', linkExactActiveClass: 'exact-active-link'})
這至關因而從新命名了兩個類名。
二者的不一樣點:
<router-link to="/login">login</router-link><router-link to="/login/exact">login exact</router-link>
上面這兩個路由有一部分 /login 是相同的,在點擊了 login exact 路由調轉到 /login/exact 後:
/login 上還保留了 router-link-active 類名
scrollBehavior
使用前端路由,當切換到新路由時,想要頁面滾到頂部,或者是保持原先的滾動位置,就像從新加載頁面那樣。
注意: 這個功能只在支持 history.pushState 的瀏覽器中可用。
const router = new VueRouter({ scrollBehavior(to, form, savedPosition){ if (savedPosition) { return savedPosition } else { return { x: 0, y: 0 } } }, routes: [...]})
scrollBehavior 方法接收 to 和 from 路由對象。第三個參數 savedPosition 當且僅當 popstate 導航 (經過瀏覽器的 前進/後退 按鈕觸發) 時纔可用。
parseQuery 和 stringifyQuery
提供自定義查詢字符串的解析/反解析函數。覆蓋默認行爲。
const router = new VueRouter({ parseQuery (query) { console.log(query) }, stringifyQuery (obj) { console.log(obj) }})
fallback
當瀏覽器不支持 history.pushState 控制路由是否應該回退到 hash 模式。默認值爲 true。
在 IE9 中,設置爲 false 會使得每一個 router-link 導航都觸發整頁刷新。它可用於工做在 IE9 下的服務端渲染應用,由於一個 hash 模式的 URL 並不支持服務端渲染。
const router = new VueRouter({ fallback: true})
路由元信息
官網例子:
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, children: [ { path: 'bar', component: Bar, // a meta field meta: { requiresAuth: true } } ] } ]})
那麼如何訪問這個 meta 字段呢?
首先,咱們稱呼 routes 配置中的每一個路由對象爲 路由記錄。路由記錄能夠是嵌套的,所以,當一個路由匹配成功後,他可能匹配多個路由記錄
例如,根據上面的路由配置, /foo/bar 這個 URL 將會匹配父路由記錄以及子路由記錄。
一個路由匹配到的全部路由記錄會暴露爲 $route 對象 (還有在導航守衛中的路由對象) 的 $route.matched 數組。所以,咱們須要遍歷 $route.matched 來檢查路由記錄中的 meta 字段。
下面例子展現在全局導航守衛中檢查元字段:
router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { // this route requires auth, check if logged in // if not, redirect to login page. if (!auth.loggedIn()) { next({ path: '/login', query: { redirect: to.fullPath } }) } else { next() } } else { next() // 確保必定要調用 next() }})
命名視圖
在一個路由下展現多個視圖組件,用的並很少
// 在這個頁面中要分別展現三個視圖<router-view></router-view> // 默認的<router-view name="a"></router-view> // 視圖a<router-view name="b"></router-view> // 視圖bconst router = new VueRouter({ routes: [ { path: '/', components: { // 加s default: Foo, // 對應默認router-view a: Bar, // name = "a" b: Baz // name = "b" } } ]})
導航守衛
路由改變時,按順序觸發的鉤子函數
全局守衛
const router = new VueRouter({ ... })router.beforeEach((to, from, next) => { console.log('before each invoked'); next();})router.beforeResolve((to, from, next) => { console.log('before resolve invoked'); next();})
每一個守衛方法接收三個參數:
確保要調用 next 方法,不然鉤子就不會被 resolved 。
路由對象
一個路由對象 (route object) 表示當前激活的路由的狀態信息,包含了當前 URL 解析獲得的信息,還有 URL 匹配到的路由記錄 (route records)。
路由對象是不可變 (immutable) 的,每次成功的導航後都會產生一個新的對象。
路由對象屬性:
const router = new VueRouter({ routes: [ // 下面的對象就是路由記錄 { path: '/foo', component: Foo, children: [ // 這也是個路由記錄 { path: 'bar', component: Bar } ] } ]})
當 URL 爲 /foo/bar, $route.matched 將會是一個包含從上到下的全部對象 (副本)。
全局後置鉤子
router.afterEach((to, from) => { console.log('after each invoked');})
路由獨享的守衛
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` 訪問組件實例 })}
完整的導航解析流程
異步路由
在路由文件中,直接import全部組件勢必形成頁面首次渲染時間變長,異步路由,當進入對應的路由才加載對應的頁面。
const router = new VueRouter({ routes: [ { path: '/foo', component: () => import('../view/...'), } ]})
這種寫法須要安裝 syntax-dynamic-import ,並在 .babelrc 進行配置
// .babelrc{ "plugins": ["syntax-dynamic-import"]}
Vux
如下內容來自 官網:https://vuex.vuejs.org/zh/
簡單使用vuex
// store.jsimport Vuex from 'vuex'import Vue from 'vue'Vue.use(Vuex)const store = new Vuex.Store({ state: { count: 0 }, mutations: { updateCount(state, num) { state.count = num } }})export default store// main.jsimport Vue from 'vue'import App from './App'import store from './store/store.js'Vue.config.productionTip = false/* eslint-disable no-new */new Vue({ el: '#app', store, // 掛載 components: { App }, template: '<App/>'})// 任意組件mounted(){ console.log(this.$store) let i = 1 setInterval(() => { this.$store.commit('updateCount', i++) })},computed: { count() { return this.$store.state.count }}
核心概念
State
Vuex 使用單一狀態樹——是的,用一個對象就包含了所有的應用層級狀態。至此它便做爲一個「惟一數據源 (SSOT)」而存在。這也意味着,每一個應用將僅僅包含一個 store 實例。單一狀態樹讓咱們可以直接地定位任一特定的狀態片斷,在調試的過程當中也能輕易地取得整個當前應用狀態的快照。
大白話: state就至關因而個全局對象,經過 Vue.use(Vuex) 全局註冊了vuex以後,在任意組件中能夠用 this.$store.state 拿到該對象
Vuex的狀態存儲是響應式的,從store實例中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態。
computed: { count() { return this.$store.state.count }}
當 state 中的 count 變化時,自動會更新 computed ,從而改變相關 DOM
mapState 輔助函數
當一個組件須要獲取多個狀態時候,將這些狀態都聲明爲計算屬性會有些重複和冗餘。爲了解決這個問題,咱們可使用 mapState 輔助函數幫助咱們生成計算屬性,讓你少按幾回鍵:
// 在單獨構建的版本中輔助函數爲 Vuex.mapStateimport { 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: { ...mapState(['count'])}// 換一個變量名computed: { ...mapState({ count1 : 'count', count2 : state => state.count })}
Getter
Getter就是vuex種state的computed,經過state派生出新的state,並且它會被緩存起來,只有依賴的state發生變化纔會從新計算
export default { fullName(state) { // 默認接收state做爲第一個參數 return `${state.firstName}${state.lastName}` }}
mapGetters 輔助函數
getter的使用和state相似,能夠把它當作state來用。
import { mapGetters } from 'vuex'export default { // ... computed: { // 使用對象展開運算符將 getter 混入 computed 對象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) }}
若是想給getter換個名字,方法和state同樣,不重複
Mutation
Mutation必須是同步的
更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。Vuex 中的 mutation 很是相似於事件:每一個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是咱們實際進行狀態更改的地方,而且它會接受 state 做爲第一個參數:
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 變動狀態 state.count++ } }})
你不能直接調用一個 mutation handler。這個選項更像是事件註冊:「當觸發一個類型爲 increment 的 mutation 時,調用此函數。」要喚醒一個 mutation handler,你須要以相應的 type 調用 store.commit 方法:
store.commit('increment')
提交載荷(傳參)
你能夠向 store.commit 傳入額外的參數,即 mutation 的 載荷(payload):
// ...mutations: { increment (state, n) { state.count += n }}store.commit('increment', 10)
在大多數狀況下,載荷應該是一個 對象 ,這樣能夠包含多個字段而且記錄的 mutation 會更易讀:
// ...mutations: { increment (state, payload) { state.count += payload.amount }}store.commit('increment', { amount: 10})
對象風格的提交方式
提交 mutation 的另外一種方式是直接使用包含 type 屬性的對象:
store.commit({ type: 'increment', amount: 10})
當使用對象風格的提交方式,整個對象都做爲載荷傳給 mutation 函數,所以 handler 保持不變:
mutations: { increment (state, payload) { state.count += payload.amount }}
使用常量替代 Mutation 事件類型
使用常量替代 mutation 事件類型在各類 Flux 實現中是很常見的模式。這樣可使 linter之類的工具發揮做用,同時把這些常量放在單獨的文件中可讓你的代碼合做者對整個 app 包含的 mutation 一目瞭然:
// mutation-types.jsexport const SOME_MUTATION = 'SOME_MUTATION'// store.jsimport Vuex from 'vuex'import { SOME_MUTATION } from './mutation-types'const store = new Vuex.Store({ state: { ... }, mutations: { // 咱們可使用 ES2015 風格的計算屬性命名功能來使用一個常量做爲函數名 [SOME_MUTATION] (state) { // mutate state } }})
在組件中提交 Mutation
你能夠在組件中使用 this.$store.commit('xxx') 提交 mutation ,或者使用 mapMutations 輔助函數將組件中的 methods 映射爲 store.commit 調用(須要在根節點注入 store)。
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
Action 能夠包含異步操做
Action跟Mutation相似,Action是調用 commit 方法,提交 mutation 的。
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } }})
Action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象,所以你能夠調用 context.commit 提交一個 mutation ,或者經過 context.state 和 context.getters 來獲取 state 和 getters 。
實踐中,咱們會常常用到 ES2015 的 參數解構 來簡化代碼(特別是咱們須要調用 commit 不少次的時候):
actions: {// {commit} = context 解構出來 increment ({ commit }) { commit('increment') }}
實際代碼:
在組件中分發 Action
你在組件中使用 this.$store.dispatch('xxx') 分發 action ,或者使用 mapActions 輔助函數將組件的 methods 映射爲 store.dispatch 調用(須要先在根節點注入 store):
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')` }) }}
嚴格模式
開啓嚴格模式,僅需在建立 store 的時候傳入 strict: true:
const store = new Vuex.Store({ // ... strict: true})
在嚴格模式下,不管什麼時候發生了狀態變動且不是由 mutation 函數引發的,將會拋出錯誤。這能保證全部的狀態變動都能被調試工具跟蹤到。
開發環境與發佈環境
不要在發佈環境下啓用嚴格模式!嚴格模式會深度監測狀態樹來檢測不合規的狀態變動——請確保在發佈環境下關閉嚴格模式,以免性能損失。
相似於插件,咱們可讓構建工具來處理這種狀況:
const store = new Vuex.Store({ // ... strict: process.env.NODE_ENV !== 'production'})
原文連接:https://finget.github.io/2018/06/28/vue-family/?utm_source=tuicool&utm_medium=referral 若有侵權請聯繫刪除,謝謝