前端入门之(vuex源码解析三)
上兩節前端入門之(vuex源碼解析二)我們把vuex的源碼大概的擼了一遍,還剩下(插件、getters跟module),我們繼續哈~
插件童鞋們可以去看看vuex在各個瀏覽器的狀態顯示插件,小伙伴可以直接看官網然后集成哈,我這邊網連github太慢了,就不帶著一起安裝了,附上vue-devtools插件地址:
https://github.com/vuejs/vue-devtools
我們簡單看一下插件怎么運行的哈,看Store的構造函數中有這么幾行代碼:
// apply pluginsplugins.forEach(function (plugin) { return plugin(this$1); });if (Vue.config.devtools) {devtoolPlugin(this);}可以看到,很簡單,就是循環遍歷所有插件,然后執行插件方法 把store對象傳遞進去:
plugin(this$1);我們可以看到底下有一個自帶的插件:
if (Vue.config.devtools) {devtoolPlugin(this);} function devtoolPlugin (store) {if (!devtoolHook) { return }store._devtoolHook = devtoolHook;devtoolHook.emit('vuex:init', store);devtoolHook.on('vuex:travel-to-state', function (targetState) {store.replaceState(targetState);});store.subscribe(function (mutation, state) {devtoolHook.emit('vuex:mutation', mutation, state);}); }可以看到,devtoolPlugin其實就是注冊了一個鉤子函數,讓vuex的state發送變換的時候,監聽state的變換,最后回調devtoolHook的emit方法,那么devtoolHook又是什么呢?對的! 就是針對各個瀏覽器做的vuex插件,也就是文章開始我跟大家說的vue瀏覽器調試插件.
插件會根據state的變換,然后用可視化的形式列出state的各個層級:
小伙伴感興趣可以直接去玩玩哈~~
好啦,說完插件,我們說一下getters,getters也算是vuex里面的一個大模塊,那么getters是干嘛的呢? 可以把getters看作是vue里面的computed:
var vm = new Vue({computed: {// 計算屬性的 getterreversedMessage: function () {// `this` 指向 vm 實例return this.message.split('').reverse().join('')}} })至于什么是computed,小伙伴不懂的可以去看官網哈
https://cn.vuejs.org/v2/guide/computed.html
對的!! 因為在vuex的內部,getters其實就是computed的另外一種表現形式,底層就是通過vue的computed實現的,我們可以看源碼:
function resetStoreVM (store, state, hot) {var oldVm = store._vm;// bind store public gettersstore.getters = {};var wrappedGetters = store._wrappedGetters;var computed = {};forEachValue(wrappedGetters, function (fn, key) {// use computed to leverage its lazy-caching mechanismcomputed[key] = function () { return fn(store); };Object.defineProperty(store.getters, key, {get: function () { return store._vm[key]; },enumerable: true // for local getters});});// use a Vue instance to store the state tree// suppress warnings just in case the user has added// some funky global mixinsvar silent = Vue.config.silent;Vue.config.silent = true;store._vm = new Vue({data: {$$state: state},computed: computed});....這里的computed就是我們在store定義的getters~~這樣說有點抽象哈,我們結合demo一起看看用法
我們的store:
/*** @author YASIN* @version [React-Native Ocj V01, 2018/7/22]* @date 17/2/23* @description index*/ import Vue from 'vue'; import Vuex from 'vuex'; import moduleA from './a'; // window.Vue=Vue Vue.use(Vuex) let state = {count: 0 }; const actions = {increase({commit}) {commit('increase');},decrease({commit}) {commit('decrease');} }; const mutations = {increase(state) {state.count++;},decrease(state) {state.count--;} }; export default new Vuex.Store({state,actions,mutations,modules: {a: moduleA},getters: {doneTodos: state => {return state.count}} });可以看到我們給了一個:
getters: {doneTodos: state => {return state.count}}然后直接返回了count,因為我前面說了,getters其實就是computed計算屬性,所以當state.count發生變換的時候,我們的doneTodos的值應該也會改變,我們試試哈.
首先在我們的組件中獲取getters中的doneTodos:
computed: {count() {return this.$store.state.count},doneTodos(){return this.$store.getters.doneTodos},...mapState('a',{aCount: 'count'})},然后渲染出doneTodos:
<div class="hello">{{doneTodos}}<div class="opt-container">demo全部代碼:
<template><div class="hello">{{doneTodos}}<div class="opt-container"><div class="opt opt-increase" @click="increase">+</div><span class="opt">{{count}}</span><div class="opt opt-decrease" @click="decrease">-</div></div><div class="opt-container"><div class="opt opt-increase" @click="increaseA">+</div><span class="opt">{{aCount}}</span><div class="opt opt-decrease" @click="increaseA">-</div></div></div> </template><script>import {mapState,mapActions} from 'vuex'export default {name: 'HelloWorld',computed: {count() {return this.$store.state.count},doneTodos(){return this.$store.getters.doneTodos},...mapState('a',{aCount: 'count'})},methods: {increase() {this.$store.dispatch({type:'increase'}).then(()=>{alert('執行了一次加法');});},decrease() {this.$store.dispatch({type:'decrease'});},...mapActions('a',{increaseA: {type:'increase'}}), // increaseA(){ // this.$store.dispatch({type:'a/increase'}); // }, // decreaseA() { // this.$store.dispatch({type:'a/decrease'}); // },},mounted(){this.$store.subscribeAction((action,state)=>{alert('你正在操作action,type為:'+action.type);})}} </script><!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped>.opt-container {font-size: 0px;}.opt {display: inline-block;text-align: center;height: 40px;width: 40px;border-radius: 20px;background-color: #efefef;line-height: 40px;user-select: none;font-size: 20px;margin: 0 10px;vertical-align: middle;} </style>然后運行項目:
可以看到,當我們點擊+的時候,除了中間的count加了外,上面的doneTodos也跟著變換了,所以了解computed的童鞋應該知道,當寫在計算屬性方法里面的數據發生變化的時候,computed的值就會變化.
好啦!! 最后還剩下一個module模塊化, 當我們項目中有很多模塊的時候,我們為了區分每個模塊的功能,讓rootstore不那么臃腫,于是出來了一個叫模塊的東西,我們怎么用呢?
我們只需要在我們的store里面添加modules即可:
moduleA:
/*** @author YASIN* @version [React-Native Ocj V01, 2018/7/31]* @date 17/2/23* @description index*/ let state = {count: 10 }; const actions = {increase({commit}) {commit('increase');},decrease({commit}) {commit('decrease');} }; const mutations = {increase(state) {state.count++;},decrease(state) {state.count--;} }; export default {namespaced: true,state,actions,mutations, }怎么用呢? 我們獲取a模塊里面的count,叫aCount:
computed: {count() {return this.$store.state.count},doneTodos(){return this.$store.getters.doneTodos},...mapState('a',{aCount: 'count'})},我直接使用了命名空間,看起來有點怪哈,命名空間小伙伴自己去看官網哈,代碼很簡單,我就不一行一行去解析了https://vuex.vuejs.org/zh/guide/modules.html
<div class="opt-container"><div class="opt opt-increase" @click="increaseA">+</div><span class="opt">{{aCount}}</span><div class="opt opt-decrease" @click="increaseA">-</div></div>a模塊的action怎么調用呢?
...mapActions('a',{increaseA: {type:'increase'},decreaseA: {type:'decrease'}}),當然也是加了命名空間的~~~
效果我就不展示了,我們簡單看一下源碼實現~~
首先是Store的構造函數中:
this._modules = new ModuleCollection(options);options是我們傳進去的參數,包含了modules,ModuleCollection是什么呢?
var ModuleCollection = function ModuleCollection (rawRootModule) {// register root module (Vuex.Store options)this.register([], rawRootModule, false); };繼續走:
ModuleCollection.prototype.register = function register (path, rawModule, runtime) {var this$1 = this;if ( runtime === void 0 ) runtime = true;if (process.env.NODE_ENV !== 'production') {assertRawModule(path, rawModule);}var newModule = new Module(rawModule, runtime);if (path.length === 0) {this.root = newModule;} else {var parent = this.get(path.slice(0, -1));parent.addChild(path[path.length - 1], newModule);}// register nested modulesif (rawModule.modules) {forEachValue(rawModule.modules, function (rawChildModule, key) {this$1.register(path.concat(key), rawChildModule, runtime);});} };可以看到,最后遞歸調用
this$1.register(path.concat(key), rawChildModule, runtime);那么當我們傳入的Store為:
export default new Vuex.Store({state,actions,mutations,modules: {a: moduleA},getters: {doneTodos: state => {return state.count}} });這樣的時候,我們的 this._modules = new ModuleCollection(options);最后的層級就是:
root(Module){child: a(Module)}好啦!! vuex算是告一段落了,接下來就是研究一下vue-router了,加油!!! 歡迎入群,一起學習~~
總結
以上是生活随笔為你收集整理的前端入门之(vuex源码解析三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++操作word接口
- 下一篇: C# 进制转换(二进制、十六进制、十进制