前端入门之(vuex源码解析一)
前言: 這兩天聽到最多的就是“假疫苗“事件了,唉唉~~ 真的是為了利益可以不管不顧一切啊,這可能也是當(dāng)今社會(huì)的一個(gè)現(xiàn)象,悲哀!! 說是有臺(tái)風(fēng)啥的,在家一個(gè)人默默地待了兩天,一個(gè)人的時(shí)候總喜歡胡思亂想,甚至?xí)ㄉ弦徽斓臅r(shí)間思考完整個(gè)人生,有時(shí)候真希望自己能夠活得天真或者自私點(diǎn),這樣就不會(huì)有太多煩惱了.
bb了一會(huì)進(jìn)入今天的主題哈,入坑前端也有一段時(shí)間了,從android的(data-binding、eventbus、rxjava)、rn的redux、然后vue的vuex,以前也就是用用,沒太大感覺,每個(gè)框架都是大同小異,最終的目的也就是是全局狀態(tài)的管理,redux跟android的data-binding啥的小伙伴有時(shí)間自己去研究哈,正好最近一直在接觸vue,所以就從vuex開刀了~~
先附上vuex的官網(wǎng)地址和github地址:
https://vuex.vuejs.org/zh/installation.html
https://github.com/vuejs/vuex
至于vuex是什么?然后vuex的基本用法?我就不說了哈,官網(wǎng)比我說的好~~ 哈哈哈
我們用vue-cli創(chuàng)建一個(gè)簡(jiǎn)單的vue工程:
vue init webpack VuexDemo然后安裝vuex
yarn add vuex最后修改工程的HelloWorld.vue,然后添加按鈕+-:
<template><div class="hello"><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> </template><script>export default {name: 'HelloWorld',data() {return {count: 0}},methods: {increase() {this.count++;},decrease() {this.count--;}}} </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;} </style>最后運(yùn)行工程:
哈哈~走到這一步,想必只要接觸過vue的童鞋都沒問題,好啦~~ 我們現(xiàn)在就把我們的count變量抽取到vuex里面去.小伙伴跟著我一起往下走哈~~
首先我們創(chuàng)建一個(gè)store文件夾,然后返回store對(duì)象:
/*** @author YASIN* @version [React-Native Ocj V01, 2018/7/22]* @date 17/2/23* @description index*/ import Vue from 'vue'; import Vuex from 'vuex';Vue.use(Vuex); let state = {count: 0 }; const actions = {increase({commit}) {commit('increase');},decrease({commit}) {commit('decrease');} }; const mutations = {increase(state) {this.state.count++;},decrease(state) {this.state.count--;} }; export default new Vuex.Store({state,actions,mutations });然后修改我們的main.js文件,把store引入到vue組件中:
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import store from './store'Vue.config.productionTip = false/* eslint-disable no-new */ new Vue({el: '#app',router,store,components: {App},template: '<App/>' })最后我們?cè)谖覀兊慕M件中把count跟store中的count綁定,然后添加increase跟decrease方法:
<template><div class="hello"><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> </template><script>export default {name: 'HelloWorld',computed: {count() {return this.$store.state.count}},methods: {increase() {this.$store.dispatch('increase');},decrease() {this.$store.dispatch('decrease');}}} </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>好啦!! 一個(gè)簡(jiǎn)單的vuexdemo就是是完成了,效果我就不演示了,跟我們一開始截屏是一樣的,所以現(xiàn)在不管是在項(xiàng)目哪個(gè)地方,我們只需要執(zhí)行
this.$store.dispatch('decrease'); this.$store.dispatch('increase');都能改變demo頁(yè)面中的count值.
好啦~ 我們先看看我們的store文件:
Vue.use(Vuex); let state = {count: 0 }; const actions = {... }; const mutations = {... }; export default new Vuex.Store({state,actions,mutations });可以看到我們?cè)诖a一開始執(zhí)行了:
Vue.use(Vuex);官網(wǎng)也說了:
// 如果在模塊化構(gòu)建系統(tǒng)中,請(qǐng)確保在開頭調(diào)用了 Vue.use(Vuex)我們都知道,當(dāng)執(zhí)行Vue.use(xx)方法后,Vue會(huì)執(zhí)行xx的install方法,并會(huì)傳遞當(dāng)前vue對(duì)象給第一個(gè)參數(shù),所以:
我們看看vuex源碼中干了什么,我們找到vuex源碼的install方法:
繼續(xù)往下~
var applyMixin = function (Vue) {var version = Number(Vue.version.split('.')[0]);if (version >= 2) {Vue.mixin({ beforeCreate: vuexInit });} else {// override init and inject vuex init procedure// for 1.x backwards compatibility.var _init = Vue.prototype._init;Vue.prototype._init = function (options) {if ( options === void 0 ) options = {};options.init = options.init? [vuexInit].concat(options.init): vuexInit;_init.call(this, options);};}我們用的vue版本是Vue.version = ‘2.5.16’;所以繼續(xù)往下
Vue.mixin({ beforeCreate: vuexInit });所以當(dāng)用的了Vue.use(vuex),當(dāng)我們組件加載的時(shí)候,就會(huì)觸發(fā)組件的beforeCreate生命周期方法,然后就會(huì)走vuexInit方法:
function vuexInit () {//獲取當(dāng)前組件的vue對(duì)象var options = this.$options;// store injectionif (options.store) {//如果當(dāng)前vue對(duì)象是否包含store對(duì)象,則把當(dāng)前store對(duì)象賦給this.$store屬性this.$store = typeof options.store === 'function'? options.store(): options.store;} else if (options.parent && options.parent.$store) {//如果父組件包含了store對(duì)象,那么就把父控件的store對(duì)象給當(dāng)前vue組件this.$store = options.parent.$store;}}看到了這是不是有點(diǎn)明白了,就是為了讓全局用一個(gè)store對(duì)象,然后通過組件的$store拿到當(dāng)前store對(duì)象,所以Vue.use(vuex)還是很重要的.
好啦~~ 看完了Vue.use(vuex)后,我們找到vuex的Store對(duì)象,首先找到Store的構(gòu)造方法:
var Store = function Store (options) {var this$1 = this;if ( options === void 0 ) options = {};// Auto install if it is not done yet and `window` has `Vue`.// To allow users to avoid auto-installation in some cases,// this code should be placed here. See #731if (!Vue && typeof window !== 'undefined' && window.Vue) {install(window.Vue);}{assert(Vue, "must call Vue.use(Vuex) before creating a store instance.");assert(typeof Promise !== 'undefined', "vuex requires a Promise polyfill in this browser.");assert(this instanceof Store, "Store must be called with the new operator.");}var plugins = options.plugins; if ( plugins === void 0 ) plugins = [];var strict = options.strict; if ( strict === void 0 ) strict = false;var state = options.state; if ( state === void 0 ) state = {};if (typeof state === 'function') {state = state() || {};}// store internal statethis._committing = false;this._actions = Object.create(null);this._actionSubscribers = [];this._mutations = Object.create(null);this._wrappedGetters = Object.create(null);this._modules = new ModuleCollection(options);this._modulesNamespaceMap = Object.create(null);this._subscribers = [];this._watcherVM = new Vue();// bind commit and dispatch to selfvar store = this;var ref = this;var dispatch = ref.dispatch;var commit = ref.commit;this.dispatch = function boundDispatch (type, payload) {return dispatch.call(store, type, payload)};this.commit = function boundCommit (type, payload, options) {return commit.call(store, type, payload, options)};// strict modethis.strict = strict;// init root module.// this also recursively registers all sub-modules// and collects all module getters inside this._wrappedGettersinstallModule(this, state, [], this._modules.root);// initialize the store vm, which is responsible for the reactivity// (also registers _wrappedGetters as computed properties)resetStoreVM(this, state);// apply pluginsplugins.forEach(function (plugin) { return plugin(this$1); });if (Vue.config.devtools) {devtoolPlugin(this);} };代碼不是很多,我們首先看到:
if (!Vue && typeof window !== 'undefined' && window.Vue) {install(window.Vue);}也就是當(dāng)我們沒有使用Vue.use的時(shí)候,如果window對(duì)象中有Vue對(duì)象,也會(huì)執(zhí)行跟Vue.use一樣的操作:
我們先簡(jiǎn)單的說一下vuex的原理哈,主要看構(gòu)造函數(shù)的這一行代碼:
// initialize the store vm, which is responsible for the reactivity// (also registers _wrappedGetters as computed properties)resetStoreVM(this, state);字面上可以看出,就是注冊(cè)一個(gè)store的vm對(duì)象,那么vm對(duì)象到底是什么呢?我們繼續(xù)往下:
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});Vue.config.silent = silent;// enable strict mode for new vmif (store.strict) {enableStrictMode(store);}if (oldVm) {if (hot) {// dispatch changes in all subscribed watchers// to force getter re-evaluation for hot reloading.store._withCommit(function () {oldVm._data.$$state = null;});}Vue.nextTick(function () { return oldVm.$destroy(); });} }先忽略其它代碼,我們看到這么一段:
store._vm = new Vue({data: {$$state: state},computed: computed});好吧,小伙伴是不是明白了,其實(shí)就是創(chuàng)建了Vue對(duì)象,然后把我們創(chuàng)建在store的state對(duì)象給了data的$$state屬性,在vue中我們知道,data對(duì)象是響應(yīng)式的,所以當(dāng)我們發(fā)出一個(gè)action后,然后走到mutations,改變state的值,從而改變組件中綁定的值變換.
有點(diǎn)晚了,今天就先到這了,之后我會(huì)從vuex的dispatch—>mutations—>state的過程,帶著源碼一步一步走,最后再把a(bǔ)ctions的鉤子函數(shù)等等把vuex的源碼全部走一遍.
好啦~~ 大牛勿噴,下節(jié)見啦!!!!
總結(jié)
以上是生活随笔為你收集整理的前端入门之(vuex源码解析一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 8的新特性—终极版
- 下一篇: html5倒计时秒杀怎么做,vue 设