在線地址: cl8023.com github
未完...
父組件經過 props 向子組件通訊,在父組件內可經過 this.$children 來讀取子組件中的值。props 是單向綁定,不可在子組件中賦值。
在 src/components 目錄下建立文件夾 common 用於存放公共組件,並在 common 下建立單文件組件 LeftNavItem.vue(子組件)css
<template> <div> {{ childMes }} </div> </template> <script> export default { name: 'LeftNav', props: ['childMes'], } </script> <style lang="scss"> </style>
在 src/components/page/Blog.vue(父組件) 裏引入組件 LeftNavItem.vuevue
<template> <div> <div class="child-area"> <Leftnav :childMes="message"></Leftnav> <button @click="getChild">getChild</button> </div> </div> </template> <script> import Leftnav from '../common/LeftNavItem' export default { name: 'blog', data() { return { message: 'father message', } }, components: { Leftnav }, methods: { getChild() { console.log(this.$children[0].childMes); } } } </script> <style scoped> .father-area { background-color: aqua; padding: 10px; } .child-area { background-color: bisque; padding: 10px; } </style>
這裏父組件是 Blog.vue,子組件是 LeftNavItem.vue,父組件中調用子組件ios
<Leftnav :childMes="message"></Leftnav>
其中 :childMes 中的 childMes 是要傳遞到子組件中的變量,即對應 LeftNavItem.vue 中 props 屬性中的值,能夠傳遞多個變量git
props: ['childMes', 'childMes2', 'childMes3'],
這樣在父組件中更改 message 的值,子組件便會獲得相應的更新。es6
父組件向子組件傳遞事件方法,子組件經過 $emit 觸發事件,回調給父組件。使用$parent能夠訪問父組件的數據
在 LeftNavItem.vue 中增長代碼github
<template> <div> {{ childMes }} <button @click="toParent">toParent</button> </div> </template> <script> export default { name: 'LeftNav', props: ['childMes'], methods: { toParent() { this.$emit('mesFunc', 'from children'); console.log(this.$parent); } } } </script> <style lang="scss"> </style>
Blog.vue 增長代碼vuex
<template> <div> <div class="father-area"> {{ fatherMes }} </div> <div class="child-area"> <Leftnav :childMes="message" @mesFunc="func"></Leftnav> <button @click="getChild">getChild</button> </div> </div> </template> <script> import Leftnav from '../common/LeftNavItem' export default { name: 'blog', data() { return { message: 'father message', fatherMes: 'Hello World' } }, components: { Leftnav }, methods: { getChild() { console.log(this.$children[0].childMes); }, func(data) { console.log(data); this.fatherMes = data; } } } </script> <style scoped> .father-area { background-color: aqua; padding: 10px; } .child-area { background-color: bisque; padding: 10px; } </style>
父組件 Blog.vue 中經過element-ui
<Leftnav :childMes="message" @mesFunc="func"></Leftnav>
將事件方法 mesFunc 傳遞到子組件axios
子組件 LeftNavItem.vue 中經過 $emit 能夠觸發事件,並傳遞數據數組
this.$emit('mesFunc', 'from children') // 第一個參數:父組件傳遞過來的事件 // 第二個參數:要傳遞到父組件的數據
Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
以上是官方介紹,通俗點將有點相似全局變量,來管理各類狀態。
Vuex 中 Store 的模版化定義以下:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { }, actions: { }, mutations: { }, getters: { }, modules: { } }) export default store
在 scr 下新建文件夾 store,並在 store 裏新建文件 index.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); const state = { currentArticle: {id: '1', title: '學習筆記', tag: 'vue'}, // 當前文章狀態, 名字, 標籤 count: 1 } // 使用常量替代 Mutation 事件類型 const types = { CURRENT_ARTICLE: 'CURRENT_ARTICLE', COUNT: 'COUNT' } const actions = { currentArticle({commit}, obj) { commit(types.CURRENT_ARTICLE, obj); }, countIncrement({commit}, n) { commit(types.COUNT, n); } } const mutations = { [types.CURRENT_ARTICLE](state, obj) { obj.id == undefined ? false : state.currentArticle.id = obj.id; obj.title == undefined ? false : state.currentArticle.title = obj.title; obj.tag == undefined ? false : state.currentArticle.tag = obj.tag; obj.catalog == undefined ? false : state.currentArticle.catalog = obj.catalog; }, [types.COUNT](state, n = 1) { state.count += n; } } export default new Vuex.Store({ state, actions, mutations, })
往下以前先了解下 ES6 的新語法 ES6教程
對象的解構賦值,變量必須與屬性同名,才能取到正確的值
let { foo, bar } = { foo: "aaa", bar: "bbb" }; foo // "aaa" bar // "bbb" const actions = { currentArticle({commit}, obj) { commit(types.CURRENT_ARTICLE, obj); }, } // 等同於 const actions = { currentArticle(context, obj) { context.commit(types.CURRENT_ARTICLE, obj); }, } // 傳入 currentArticle 的第一個參數是一個與 store 實例具備相同方法和屬性的 context 對象,能夠調用 context.commit 提交一個 mutation,或者經過 context.state 和 context.getters 來獲取 state 和 getters,這裏只要用到 context.commit 這個方法,因此能夠 {commit} = context 即 commit = context.commit
ES6 容許在對象之中,直接寫變量。這時,屬性名爲變量名, 屬性值爲變量的值
const foo = 'bar'; const baz = {foo}; baz // {foo: "bar"} // 等同於 const baz = {foo: foo}; export default new Vuex.Store({ state, actions, mutations, }) // 等同於 export default new Vuex.Store({ state: state, actions: actions, mutations: mutations })
對象方法屬性能夠簡寫
const o = { method() { return "Hello!"; } }; // 等同於 const o = { method: function() { return "Hello!"; } };
ES6 容許字面量定義對象時,用方法二(表達式)做爲對象的屬性名,即把表達式放在方括號內
let propKey = 'foo'; let obj = { [propKey]: true, ['a' + 'bc']: 123;
因此
const mutations = { [types.CURRENT_ARTICLE](state, obj) { }, } // 等同於 const mutations = { ['CURRENT_ARTICLE'](state, obj) { }, } // 等同於 const mutations = { CURRENT_ARTICLE: function(state, obj) { }, }
言歸正傳,咱們定義一個 state 狀態屬性 currentArticle 對象,用來記錄當前文章的 id,title,tags,catalog,仍是使用 Blog.vue 和 LeftNavItem.vue 來測試
// Blog.vue <template> <div> <div class="father-area"> id: <input type="text" v-model="currentArticle.id"> title: <input type="text" v-model="currentArticle.title"> tag: <input type="text" v-model="currentArticle.tag"> count: <input type="text" v-model="count"> </div> <div class="child-area"> <Leftnav></Leftnav> </div> </div> </template> <script> import Leftnav from '../common/LeftNavItem' import store from '../../store/demo' export default { name: 'blog', data() { return { message: 'father message' } }, components: { Leftnav }, methods: { }, computed: { currentArticle() { return store.state.currentArticle }, count() { return store.state.count } } } </script> <style scoped> .father-area { background-color: aqua; padding: 10px; } .child-area { background-color: bisque; padding: 10px; } </style>
咱們能夠在每一個組件內引入 store
import store from '../../store/index'
而後經過計算屬性(命名符合規則便可)來獲取狀態值,能夠看到,要得到多個狀態時,將這些狀態都聲明爲計算屬性會有些重複和冗餘,內置 mapState 輔助函數能夠幫助咱們生產計算屬性。要想使用輔助函數,須要先將 store 實例註冊到 vue 實例中,這樣 store 實例會注入到跟組件下的全部組件,且子組件能經過 this.$store 訪問到。
你們 src/main.js 引入 store 實例,並在 vue 根實例中註冊 store 選項
import Vue from 'vue' import App from './App' import router from './router' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' import axios from 'axios' import store from './store/index.js' Vue.config.productionTip = false Vue.use(ElementUI) Vue.prototype.$http = axios /* eslint-disable no-new */ new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })
改寫 src/components/page/Blog.vue 使用 mapState 輔助函數生產狀態屬性
<template> <div> <div class="father-area"> id: <input type="text" v-model="currentArticle.id"> title: <input type="text" v-model="currentArticle.title"> tag: <input type="text" v-model="currentArticle.tag"> count: <input type="text" v-model="count"> </div> <div class="child-area"> <Leftnav></Leftnav> </div> </div> </template> <script> import Leftnav from '../common/LeftNavItem' import { mapState } from 'vuex'; export default { name: 'blog', data() { return { message: 'father message' } }, components: { Leftnav }, methods: { }, computed: mapState(['currentArticle', 'count']) } </script> <style scoped> .father-area { background-color: aqua; padding: 10px; } .child-area { background-color: bisque; padding: 10px; } </yle>
mapState 除了能夠傳入數組外,還可傳入對象
// 1. 直接只用函數返回狀態住 computed: mapState({ currentArticle: state => state.currentArticle, count: state => state.count }) // 2. 使用別名對應狀態屬性,對象中的值 value 對應等同於 state => state.value // key 值是狀態值的別名,value 是 state 中的狀態值,不能簡寫成 {currentArticle, count},必須有對應的狀態屬性 computed: mapState({ currentArticle: 'currentArticle', count: 'count' }) // 3. 由於 computed 中也可能會有其餘計算屬性,不僅有 mapState,要將它與其餘計算屬性混合使用,就要用到對象的擴展運算符(...),用於取出參數對象的全部可遍歷屬性,拷貝到當前對象之中,例如: let z = { a: 3, b: 4}; let n = { ...z }; // 等同於 n = Object.assign({}, z) n // ( a: 3, b: 4 ) // mapState 函數返回的是一個對象,因此混合其餘計算屬性: computed: { otherComputed() { }, ...mapState(['currentArticle', 'count']) // 也可傳入對象 }
Action 提交的是 mutation,而不是直接修改狀態
Action 經過 store.dispatch 方法觸發
在 Blog.vue 中增長一個按鈕和一個方法來增長 count 的值
<template> <div> <div class="father-area"> id: <input type="text" v-model="currentArticle.id"> title: <input type="text" v-model="currentArticle.title"> tag: <input type="text" v-model="currentArticle.tag"> count: <input type="text" v-model="count"> <button @click="countAdd">+</button> </div> <div class="child-area"> <Leftnav></Leftnav> </div> </div> </template> <script> import Leftnav from '../common/LeftNavItem' import { mapState } from 'vuex'; export default { name: 'blog', data() { return { message: 'father message' } }, components: { Leftnav }, methods: { countAdd() { this.$store.dispatch('countIncrement'); } }, computed: mapState(['currentArticle', 'count']) } </script> <style scoped> .father-area { background-color: aqua; padding: 10px; } .child-area { background-color: bisque; padding: 10px; } </style>
點擊 + 號後調用方法 countAdd 觸發 countIncrement 的 Action,接着觸發類型爲 COUNT 的 mutation,完成狀態的修改。根據 action 中 countIncrement 方法的定義,能夠傳入第二個參數,this.$store.dispatch('countIncrement', 3)。
Action 也有輔助函數 mapAction 將組件的 methods 映射爲 store.dispatch(須要如今根結點注入 store)
<template> <div> <div class="father-area"> id: <input type="text" v-model="currentArticle.id"> title: <input type="text" v-model="currentArticle.title"> tag: <input type="text" v-model="currentArticle.tag"> count: <input type="text" v-model="count"> <button @click="countAdd">+</button> </div> <div class="child-area"> <Leftnav></Leftnav> </div> </div> </template> <script> import Leftnav from '../common/LeftNavItem' import { mapState, mapActions } from 'vuex'; export default { name: 'blog', data() { return { message: 'father message' } }, components: { Leftnav }, methods: { countAdd() { this.countIncrement(2); }, ...mapActions(['countIncrement']) // 將 this.countIncrement 映射爲 this.$store.dispatch('countIncrement) }, computed: mapState(['currentArticle', 'count']) } </script> <style scoped> .father-area { background-color: aqua; padding: 10px; } .child-area { background-color: bisque; padding: 10px; } </style>
和 mapStata 相似,mapActions 也能夠傳入對象,使用別名來代替 countIncrement
methods: { countAdd() { this.add(2); }, ...mapActions({ add: 'countIncrement' }) }
我我的以爲 vuex 中的 state、actions 比較難理解,因此筆記就記下這兩塊,其餘官方文檔應該能夠看明白,和這兩個用法也都比較相似。
對於大型項目,通常把 vuex 相關代碼分割到模塊中
在 src/store 下新建文件
// index.js import Vue from 'vue' import Vuex from 'vuex' import actions from './action' import mutations from './mutation' Vue.use(Vuex); const state = { currentArticle: {id: '1', title: '學習筆記', tag: 'vue'}, count: 1 } export default new Vuex.Store({ state, actions, mutations, }) // actions.js import * as types from './mutation_type' export default { currentArticle({commit}, obj) { commit(types.CURRENT_ARTICLE, obj); }, countIncrement({commit}, n) { commit(types.COUNT, n); } } // mutation_type.js export const CURRENT_ARTICLE = 'CURRENT_ARTICLE' export const COUNT = 'COUNT' // mutation.js import * as types from './mutation_type' export default { [types.CURRENT_ARTICLE](state, obj) { obj.id == undefined ? false : state.currentArticle.id = obj.id; obj.title == undefined ? false : state.currentArticle.title = obj.title; obj.tag == undefined ? false : state.currentArticle.tag = obj.tag; obj.catalog == undefined ? false : state.currentArticle.catalog = obj.catalog; }, [types.COUNT](state, n = 1) { state.count += n; } }
而後在 main.js 中註冊 Store 實例便可
// main.js import Vue from 'vue' import App from './App' import router from './router' import store from './store/index.js' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })