navigation

[Deep 01] Execution context [Deep 02] Prototype chain [Deep 03] Inheritance [Deep 04] Event loop [Deep 05] Curri Bias function [Deep 06] Function memory [Deep 07] Implicit conversions and operators [Deep 07] Browser caching mechanism (HTTP caching mechanism) [Deep 08] Front-end security [Deep 09] Deep copy [Deep 10] Debounce Throttle [Deep 10] Front-end routing [Deep 12] Front-end modularization [Deep 13] Observer mode Publish subscribe mode Bidirectional data binding [Deep 14] Canvas [Deep 15] webSocket Webpack HTTP and HTTPS CSS- Interview Handwriting Promise

[react] Hooks

[Deployment 01] Nginx [Deployment 02] Docker deployVue project [Deployment 03] gitlab-CI

[source code – Webpack01 – precompiler] AST abstract syntax tree [source code – Webpack02 – Precompiler] Tapable [source code – Webpack03] hand written webpack-compiler simple compilation process [source code] Redux React-redux01 [source] Axios [source] vuex [source -vue01] Data reactive and initialize render [source -vue02] Computed responsive – Initialize, access, Update Procedure [source -vue04] Watch Listening properties – Initialize and update [source -vue04] vue. set and vm.$set [source -vue05] vue.extend

Vue. NextTick and VM.$nextTick

Front knowledge

Some words

The Mutation was raw and assert was stored in internal state. Store internal state) duplicate: repeat, assignment, a copy of the localized: local unity: unified (unifyObjectStyle unified object type) Valid: effectiveCopy the code

How does Vue write a plug-in

  • Plug-ins are usually used to add (global functionality) to vue

    • Global methods, global resources, global mixin, vUE instance methods, etc
    • namelyThe Vue constructor static methods and properties.Ue. Prototype Instance methods and properties.mixin.directive
  • If you use plug-ins

    • In the form of components:
        1. Vue.use(plugin, [options])
        1. New Vue(Component options)
    • Import through script
      • Such asVue - the router plug-in
        • Window.vue. Use (VueRouter) window.vue
  • Note:

    • Each plug-in should expose a install method, and the first parameter of the install method must be the Vue constructor, and the second parameter must be an optional parameter object
      • Because the first argument to the install method is the Vue constructor, you can get directives, mixins, and so on on Vue
    • As you’ll see later, if the install method is not exposed, then the plug-in itself must be a function, and that function will be treated as the install method
  • code

Const firstPlugin = {install(Vue, options) {console.log(options,'options'FirstGlobalMethod vue.firstGlobalMethod =function () {
            console.log('Plug-ins - global methods - that is, static methods of the Vue constructor'} // Add global resource global directive Vue. Directive ()'first-directive', {
            bind(el, binding, vnode, oldVnode) {
                console.log('is called only once, when the directive is first bound to the element. You can do a one-time initialization here. ')
                console.log(el, The 'el 'directive binds elements that can be used to manipulate the DOM directly.)
                console.log(binding, 'binding')
                console.log(vnode, 'Virtual nodes generated by Vue compilation')
                console.log(oldVnode, 'Last virtual node, available only in Update and componentUpdated hooks')},inserted() {
                console.log('Called when the bound element is inserted into the parent node (only the parent node is guaranteed to exist, but not necessarily already inserted into the document)')}}) // Globally mixed injection component option vue.mixin ({created:function () {
                console.log('Plug-in - Global mix - Mix the Created () life cycle in all components')}}) // Instance methods // It is normal to mount properties and methods on vue.prototype beginning with $vue.prototype.$firstPluginMethod = function () {
            console.log('Plug-in - Instance methods - methods mounted on vue instance prototype objects, remember that the properties and methods start with $')}}}export default firstPlugin
Copy the code
To register a plug-in: import Vue from'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
import firstFlugin from './plugin/first-plugin'

Vue.config.productionTip = false

Vue.prototype.$axios= axios Vue. Use (firstFlugin) / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- registered plug-in new Vue ({the router, store, render: h => h(App) }).$mount('#app')

Copy the code

Vue.use()

  • Vue.use( plugin )
  • Parameter: object or function
  • Function:
    • Install the Vue plug-in
    • Plug-ins are objects: provide the install method
    • The plug-in is a function: it acts as the install method itself
    • The install method: takes Vue as an argument and executes automatically when vue.use () is called
  • Note:
    • Vue.use() needs to be called before new Vue()
    • When the install method is called multiple times by the same plug-in, the plug-in will only be installed once
  • Vue. Use () the source code
    • We have mainly done the following
      1. If the plug-in is registered
        • Return this directly (returns this primarily to enable chained calls)
      2. Not registered
        • Determine whether the plug-in is an object or a function
          • Object: Calls the install method
          • Function: Call this function directly with the plug-in as the install method
        • Add the plugin to the plugin array, and the next time you check if the registration is out of date, it will be registered
        • Returns a convenient chained call to this
      • Conclusion:
        • Vue.use() mostly calls the install method of the plug-in
// vue.use () source code // File path: core/global-api/use.js import {toArray} from'.. /util/index'

export function initUse(Vue: GlobalAPI) {
  Vue.use = function(plugin: Function | Object) {/ / Vue. Use mount the use method on the Vue constructor const installedPlugins = (enclosing _installedPlugins | | (this._installedPlugins = [])) // installedPlugins // Assign values directly if ui._installedplugins exist There are no arrays assigned emptyif(installedplugins.indexof (plugin) > -1) {// If the plugin exists in installedplugins.indexof (plugin) > -1) {// If the plugin exists in installedPlugins, return thisreturnthis } const args = toArray(arguments, Args. unshift(this) // Add Vue to the front of the array // Because args will be used as an argument for the plug-in install method, The install method specifies that the first argument must be the Vue constructorif (typeof plugin.install === 'function') {// If the plugin is an object, bind this to the plugin's install method, pass in arguments to plugin.install.apply(plugin, args)}else if (typeof plugin === 'function') {// Plugin.apply (null, args)} installedplugins.push (plugin) // If the plugin does not exist in installedPlugins, first assign an empty array to it. After executing ISNtall, add the plug-in to installedPlugins to indicate that it existsreturn this
    // returnThis is for the sake of chain calls, this refers to the Vue}} / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- / / toArray (list, start) / / such as: List = [1,2,3,4export functiontoArray(list: any, start? : number): Array<any> { start = start || 0let i = list.length - start
  const ret: Array<any> = new Array(i)
  while(I --) {ret[I] = list[I + start] //while(3) / / then minus 1 namely I = 2 / / ret [2] [3] = list / / ret [1] [2] = list / / ret [0] = list [1] / / ret = [4] 2}return ret
}

Copy the code

Vuex source

(1) How to install and use vuEX

  • The installation
    • npm install vuex -S
  • use
In main.js ---- import Vuex from'vuex'Vue. Use (Vuex) / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- will call Vuex install method on const store = new Vuex. Store ({/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- new Store(options) state: {}, mutations: {}, actions: {}, getters: {}, modules: {}}) const app = new Vue ({the router, store, / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- into the store render: h = > h (app)}).$mount('#app')

Copy the code

(2) Vue.use(Vuex)

  • Vue.use(Vuex) calls the vuex.install method in Vuex
    • Vuex.installMethod will callapplyMixin(Vue)
      • applyMixin(Vue)
        • The main thing is to inject the store real example into each component
        • Specifically, mixins are mixed in the component’s beforeCreate lifecyclevuexInitMethod to inject a Store instance into each component
          • Mixins need to be noted:
              1. The hook functions of the same name will be merged into an array and therefore both will be called
              1. Hooks that blend in with an object are called before the component’s own hooks
  • Conclusion:
    • Vue.use(Vuex) => Vuex.install() => applyMixin(Vue) => Vue.mixin({ beforeCreate: vuexInit })
    • The end result with vue.use (Vuex) is to inject a Store instance into each component, sharing the same Store instance
    • So: Strore instances can be accessed in each component via this.$store
The install method in Vuex is ----let Vue // bind on install
export function install (_Vue) {
  if (Vue && _Vue === Vue) {
    if (__DEV__) { 
      console.error(
        '[vuex] already installed. Vue.use(Vuex) should be called only once.')}return// applyMixin(applyMixin) {// applyMixin(applyMixin) {// applyMixin(applyMixin) {// applyMixin(applyMixin) {// applyMixin(applyMixin)}Copy the code
applyMixin(Vue)
---
 
export default function (Vue) {
  const version = Number(Vue.version.split('. ') [0])if(version >= 2) {vue.mixin ({beforeCreate: vuexInit}) {beforeCreate: vuexInit}}else{// Version 1 is for compatibility, not considered}function vuexInit () {
    const options = this.$options// This represents each component and has beforeCreate hook // Store injectionif (options.store) {
      // this.$optionsConst vue = new vue ({store: store}) const vue = new vue ({store: store})$store = typeof options.store === 'function'? Options.store () : options.store // change to$storeAttribute // 1. Store is a function, directly call the function, return value assignment // 2. Store is an object, directly assign value}else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$storeBeforeCreate = beforeCreate = beforeCreate = beforeCreate = beforeCreate = beforeCreate = beforeCreate$storeBoth use the parent component$store// 2. So: causes all components$storeAre used by the root component$store, the root component only uses its own$store3. Finally: all components use the root component$store}}}Copy the code

(3) Store class constructor

this._modules = new ModuleCollection(options)

  • ModuleCollection class
    • The main role
        1. Assign this. Root to the root module
        1. If there is a modules property in the module, add the mapping to the parent module’s _children property object
    • Instance attributes
      • root
        • That is, a new Module instance
    • The prototype property
      • GetNamespace: Recursively concatenated path if the Module’s Namespaced property exists
    • Call this.register([], rawRootModule, false) in constructor
    • this.register([], rawRootModule, false)
      • The main function is:
      • new Module(rawModule, runtime)
        • Instance attributes
          • Mount Runtime, _children, _rawModule, and state on the instance
          • _children: The default is an empty object
            • Used to store submodules
          • _rawModule: is the incoming module
            • Either the root Module, which is passed Vuex options
            • Or modules in modules
          • state
            • Is a function to call that function to return the state object
            • Is a direct assignment to an object
        • The prototype property
          • GetChild, addChild, Namespaced, Update, forEachGetter…
          • GetChild: Returns a module in the _children object
          • AddChild: Adds mogg Module to the _children object
          • Namespaced: Whether the module has a Namespaced property, which is a Boolean
          • ForEachGetter: Loops through the getters object, passing value and key to the argument function
      • parent.addChild(path[path.length – 1], newModule)
        • Adds a child module mapping to the _children object in the parent Module
      • Note the array.prototype.reduce method
        • [].reduce((a,b) => {... }, params)When an empty array executes reduce, the second argument params is returned regardless of any logic performed by the first argument function
        • There are plenty of empty arrays in the source code to perform reduce logic, such as registering modules and registering Namespce
      • The array.prototype.slice method needs some attention
        • [].slice(0, -1)An empty array is returned

installModule(this, state, [], this._modules.root)

  • The main role

    1. Map module concatenated (path) and (moudle) as key-values to the (store._modulesNamespacemap) object
    2. state
      • Merge state in modules of all modules into state in rootModule
      • key => moduleName
      • value => moduleState
      • Note that all changes to state need to be wrapped in (store._withCOMMIT)
    3. local
      • Construct the module.context object, assign the value to the local object, and pass the local object as parameters to registerMutation, registerAction, registerGetter
      • Local objects have properties such as Dispatch, commit, getters, state, and so on
    4. mutations
      • All of the modules (the functions in mutations) are added to the store (this._mutations) object
        • Key:
          • A function name in namespace + mutations of the module
          • Such ascart/incrementItemQuantityModule name + name of the mutation function
        • value
          • An array
          • A member is a wrapper function for a specific mutation function,wrappedMutationHandler (payload)
      • Note:

        • mutations hander

          • parameter
            • The first argument is state
              • This state is the state of the current local module, not the total state
            • The second parameter payload

        • commit

          • store.commit
          • The only way to modify the state in a store isstore.commit(mutations hander)
          • store.commit('increment', 10)
          • store.commit('increment', {amount: 10})
          • store.commit({type: 'increment',amount: 10})
    5. actions
      • Add all module (actions) functions to the store (this._actions) object
      • key:
        • action.root ? key : namespace + key
        • The key above represents the name of the action function in the Actions
        • The namespace above represents the moudle name +/
        • Such as:cart/addProductToCartModule name + Action function name
      • value:
        • An array
        • A member is a wrapper around a concrete action function,wrappedActionHandler(payload)
      • Note:

        • The action function

          • parameter
            • The first parameter
              • Is a context object. Context and Store instances have the same methods and properties
              • The context object hasdispatch commit getters state rootGetters rootStateThese properties
            • Second parameter
              • payload

        • dispatch

          • store.dispatch
          • The action function is triggered by store.dispatch
          • store.dispatch('increment')
          • store.dispatch('incrementAsync', {amount: 10})
          • store.dispatch({type: 'incrementAsync', amount: 10})
    6. getters
      • Map the getters in all modules to the (store._wrappedgetters) object
        • Key: namespace + keyModule name /getter function
        • Value: a function, wrappedGetter (store)

      • The getter function

        • parameter
          • The first argument: the local state object
          • Second argument: local getters object
          • The third parameter: root state
          • Fourth argument: root getters
          • (state, getters, rootState, rootGetters) => {... }
          • Note that the arguments to the getter function are ordered, while the action function is the first argument pair that has no order
    7. Loop through the (_children) object in the moudle, executing the (installModule) method in turn
  • store._modules.getNamespace(path)

    • Main function: Concatenate module path, and then assign value to namespace
  • store._withCommit(fn)

    • Wrap the mutation function passed in
      • Set this._research to true when the mutation function executes
      • Set this._research to false after the mutation function executes
      • This ensures that state can only be changed by mutation. If you don’t set this._research to true, this proves that it wasn’t changed by mutation
  • Vue.set(parentState, moduleName, module.state)

    • Merge the module state in moudles to the parent state
  • makeLocalContext(store, namespace, path)

    • Generates a local object with properties such as Dispatch, commit, getters, state, etc
  • module.forEachMutation(fn)

    • Iterate over the mutations object in the current Module, passing value and key to fn(mutation, key)
    • Add a namespace and key
    • Call registerMutation(store, namespacedType, mutation, local)
  • registerMutation(store, namespacedType, mutation, local)

    • Mutations [type]) array push (mutation wrapper)
      1. store._mutations[type]
        • typeNamespace /getter function nameLike thiscart/incrementItemQuantity
        • valuewrappedMutationHandler (payload)A function like this
      2. A wrapper function is to add a shell to the mutation function, pass in payload, and call the mutation Handle from inside
      3. Note:
        • Store._mutations is an object
        • Each store._mutations[type] is an array
  • module.forEachAction(fn)

    • andmodule.forEachMutation(fn)similar
    • Loop through the actions object in the current Module
      • Use (action.root) to get the different types
      • Assign the value handle to whether (action.handle) exists
      • callregisterAction(store, type, handler, local)function
  • registerAction(store, type, handler, local)

    • Push one into the (store._actions[type]) array (wrappedActionHandler)
  • wrappedActionHandler(payload)

    • The handler function is called internally (action or action.handler)
    • If the handler function returns a value that is not a promise, it converts the return value to a PROMISE object with the value resolve, and then returns a promise object in the fulfilled state
    • handler()
      • Bind this to store
      • Parameters:
        • The first argument is an object with the following properties
          • dispatch
          • commit
          • getters
          • state
          • rootGetters
          • rootState
        • The second parameter is payload
  • module.forEachGetter(fn)

    • Loop through all getters in the Module getters
    • Pass value and key to FN (value, key)
  • registerGetter(store, namespacedType, getter, local)

    • Add attribute methods to (store._wrappedgetters)
      • key => namespace + key
      • value => wrappedGetter
    • wrappedGetter
      • The wrapper function for the getter,(store) => getter(localState, localGetters, rootState, rootGetters)
      • Parameters: local state getters, root state getter

commit (_type, _payload, _options)

  • We have mainly done the following:
    1. If the first parameter is an object, modify the parameter
      • Store.com MIT (‘increment’, {amount: 10})
      • Store.com MIT ({type: ‘increment’,amount: 10})
      • Transform the second into the first
    2. Searching for the mutaation, that is, finding the mutation corresponding to this._mutations through key [mutation]
      • No error found
      • Find the mutation wrapper in the loop array that calls the true mutation Handler function
    3. Shallow copy this._subscribers and then iterate over the array, calling subscribe => to change state and need to respond to views, etc
  • subscribe
    • subscribe(handler: Function): Function
      • store.subscribe((mutation, state) => {... })
      • Subscribe to store mutation
      • The handler is called after each mutation completes, taking the mutation and the state after the mutation as parameters
      • To stop the subscription, call the function returned by this method to stop the subscription

dispatch (_type, _payload)

  • We have mainly done the following
    1. Transformation parameters
    2. Execute in this._actionSubscribersbeforeThe hook’s action listens to the function
      • Before means that the subscription handler should be called before an action is distributed
    3. Execute the action function
      • This._actions[type] If the array length is greater than 1, wrap promise.all and ensure that the result is all promise resolve
      • This._actions [type] The array length is less than or equal to 1
    4. When all promises are resolved, and all asynchrons have returned results, execution is performed in _actionSubscribersafterThe hook’s action listens to the function
      • After means that the subscription handler should be called after an action has been distributed
    5. Resolve the final result and return the PROMISE object
  • subscribeAction
    • subscribeAction(handler: Function): Function
      • store.subscribeAction((action, state) => {... })
      • Subscribe to the Store action
      • The handler is called on each action dispatch and receives the action description and the state of the current store as parameters
      • Note:
        • As of 3.1.0, the subscribeAction can also specify whether the subscription handler should be called before or after an action is distributed (the default behavior is before)
        • You can specifystore.subscribeAction({before: (action, state) => {},after: (action, state) => {}})

The source code

(1) this._modules = new ModuleCollection(options)

  • The main role
    • Assign this. Root to the root module
    • If there is a modules property in the module, add the mapping to the parent module’s _children property object
// File directory SRC /module/module-collection.jsexport default class ModuleCollection {
  constructor (rawRootModule) {
    // register root module (Vuex.Store options)
    this.register([], rawRootModule, false)
  }
}

---

register (path, rawModule, runtime = true) {
    if(__DEV__) {assertRawModule(path, rawModule) // dev environment, which asserts that each key of each property object passed in options is of the type of value it should be, if not, Const newModule = newModule (rawModule, rawModule) const newModule = newModule (rawModule, Runtime) / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- analysis / 1 / create a module instance / / module / / instance attribute runtime, _children, _rawModule, state // prototype getChild, addChild, namespaced, update,forEachGetter ... Etc.if(path.length === 0) {this.root = newModule // if the array length is 0, assign the newModule instance to the root attribute}else{// Problem: when path.length! == 0 // And then we'll check if there's a modules attribute, and when there is a modules attribute, we'll call register again, The length is not zero const parent = this. Get (path. Slice (0, 1)) / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 2 / analysis/parent: Obtain parent module parent-addChild (path[path.length-1], NewModule) / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- analysis of 3 / / to the parent module. _children object to add the key and the value, that is, the father modlue child module}if(rawModule.modules) {// Iterate through modules if there are modules objects in the moduleforEachValue(rawModule.modules, (rawChildModule, Key) = > {/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- analysis 4 this. Register (path. The concat (key), rawChildModule, // Path.concat (key) => Similar to [module1],[module2], note that concat does not change path // rawChildModule => Module1 Module2})}}Copy the code
  • Analysis of the 1
// File directory SRC /module/module.jsexportdefault class Module { constructor (rawModule, {this. Runtime = runtime // Store some children item this._children = object.create (null) // _children Object // // key => name of the moudle // value => Module object, There may be state, mutations, the actions, getters / / Store the origin module objectwhichPassed by programmer this._rawModule = rawModule // Const rawState = rawModule.state // Store the origin module's state this.state = (typeof rawState === 'function'? rawState() : RawState) | | {} / / state / / function: call, stated / / object returned from an object: } addChild (key, module) {this._children[key] = module} getChild (key) {return this._children[key]}}Copy the code
  • Analysis of 2
Get (path) {// When path is an empty array, [].Reducer ((a,b) => a.GoChild (key), this.root) returns rootreturn path.reduce((module, key) => {
      return module.getChild(key)
    }, this.root)
  }
Copy the code
  • Analysis of 3
addChild (key, Module) {this._children[key] = module // Add a mapping to the _children attribute object of the module instance // key => moudle name // value => Module object}Copy the code
  • Analysis of 4
export function forEachValue (obj, fn) {object.keys (obj).foreach (key => fn(obj[key], key)) // select * from obj as the second argument // select * from obj as the first argument}Copy the code

(2) Store class constructor

The store-class constructor is SRC /stroe.js --export class Store {
  constructor (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 # 731
    if(! Vue && typeof window ! = ='undefined'&& window.vue) {install(window.vue) // Install (window.vue) if Vue does not exist and window.vue does exist;}if(__DEV__) { assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`) assert(typeof Promise ! = ='undefined', `vuex requires a Promise polyfill inthis browser.`) assert(this instanceof Store, 'store must be called with the new operator.') // Assert // vue.use (Vuex) must be called before new vuex.store () // Whether promise exists, } const {plugins = [], // deconstruct the assigned plugins and strict, and assign the default value strict =false
    } = options

    // store internal state
    this._committing = false"// _research // This flag bit, default isfalse// This case is wrapped in _withCommit (), and this. _research = ()true, which is set tofalse// The mutation function is used to determine whether the state is changed. This._actions = object.create (null) // _actions // Store all moudle actions // { // cart/checkout: [ƒ], f = wrappedActionHandler (payload) // cart/checkout: [ƒ], // products/getAllProducts: [], //} this._actionSubscribers = [] // _actionSubscribers // _mutations = object.create (null) // _mutations // Mutations // mutations // { / / cart/incrementItemQuantity: [ƒ], refers to the wrappedMutationHandler/f/cart/pushProductToCart: [ƒ], / / cart /setCartItems: [ƒ], / / cart /setCheckoutStatus: [ƒ], / / products/decrementProductInventory: [ƒ], / / products /setProducts: [ƒ],
      // }
  
    this._wrappedGetters = Object.create(null)
    // _wrappedGetters
      // 存放所有module中的getter
      // {
      //   cart/cartProducts: ƒ wrappedGetter(store)
      //   cart/cartTotalPrice: ƒ wrappedGetter(store)
      // }
      // 注意:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        // 1. this._wrappedGetters 在resetStoreVM(this, state)会用到 
        // 2. 注意区分 ( store.getters ) 和 ( store._wrappedGetters)

    this._modules = new ModuleCollection(options)
    // _modules
      // ModuleCollection 类主要就是收集所有的moudle
      // {
      //   root: {
      //     runtime: false, // state: {}, // note that state is not yet combined // _children: {// put the module from moudules into the _children attribute of the parent module // cart: Module, // products: Module, // }, // _rawModule: Root module //} //} this._modulesNamespacemap = object.create (null) // _modulesNamespaceMap // Mapping Object between namespace and Mdule // { // cart/: Module // products/: Module //} this._subscribers = [] // _subscribers // mutation // this._actionSubscribers = [] Action listener function this._watcherVM = new Vue() this._makelocalgetTerscache = Object.create(null) //bind commit and dispatch to self
    const store = this
    const { dispatch, commit } = this
    this.dispatch = function boundDispatch (type, payload) {
      return dispatch.call(store, type// Bind the dispatch function this to the store instance} this.mit =function boundCommit (type, payload, options) {
      return commit.call(store, type} // Strict mode this. Strict = strict // Strict mode // Default is flase // In strict mode, State can only be modified by mutation // Shutdown is recommended in production environments because strict mode deeply monitors the state tree to detect noncompliant state changes, Const state = this._modules. Root. State // root state // init root module sub-modules // and collects all module getters inside this._wrappedGetters installModule(this, state, [], This. _modules. Root) / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the following will analyze / / initialize the store vm,which is responsible forthe reactivity // (also registers _wrappedGetters as computed properties) resetStoreVM(this, State) / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the following will analyze / / apply plugins plugins. The forEach (plugin = > Plugin (this)) // Loop through the plugin, passing stroe const useDevtools = options.devtools! == undefined ? options.devtools : Vue.config.devtools does not exist: Devtools exists in options passed to new vuex.stroe (options) Vue.config.devtoolsif (useDevtools) {
      devtoolPlugin(this)
    }
  }
}
Copy the code

(3) installModule(this, state, [], this._modules.root)

functioninstallModule (store, rootState, path, module, hot) { const isRoot = ! Path. length // When the length of the path array is 0, GetNamespace (path) // getNamespace => module name + // / => or' '

  // register in namespace map
  if(module.namespaced) {// module.namespaced // Each module can have a Namespaced property, Is a Boolean value / / said local module name/website/namespace (https://vuex.vuejs.org/zh/guide/modules.html)if (store._modulesNamespaceMap[namespace] && __DEV__) {
      console.error(`[vuex] duplicate namespace ${namespace} for the namespaced module ${path.join('/')}} store._modulesNamespacemap [namespace] = module // _modulesNamespaceMap // Establish the mapping between module and namespace // key  : namespace // vlaue: module // { // cart/: Module // products/: Module // } } //set state
  if(! isRoot && ! Hot) {// not the root module and hot is flase, Const parentState = getNestedState(rootState, path.slice(0, 0, 0)) Const moduleName = path[path.length-1] store._withcommit (() => {if (__DEV__) {
        if (moduleName in parentState) {
          console.warn(
            `[vuex] state field "${moduleName}" was overridden by a module with the same name at "${path.join('.')}"')}} vue.set (parentState, moduleName, module.state) // Merge all modules into rootState})} constlocal= module.context = makeLocalContext(store, namespace, path) // Declare module.context and assign a value //local
    // dispatch
    // commit
    // getters
    // state

  module.forEachMutation((mutation, key) => {
    const namespacedType = namespace + key
    registerMutation(store, namespacedType, mutation, local) / / all the modules in a mutations in each of the mutation function is added to the _mutations object / / _mutations object following the format of the / / {/ / cart/incrementItemQuantity: [ƒ], f denotes wrappedMutationHandler // cart/pushProductToCart: [ƒ], // cart/setCartItems: [ƒ], / / cart /setCheckoutStatus: [ƒ], / / products /setProducts: [f],
    // }
  })

  module.forEachAction((action, key) => {
    const type = action.root ? key : namespace + key
    const handler = action.handler || action
    registerAction(store, type, handler, local) // Add the action function from each of the actions of all modules to the _actions object // The _actions object looks like this // {// cart/addProductToCart: [logon], f = wrappedActionHandler (payload) // cart/checkout: [logon] // products/getAllProducts: [] // } }) module.forEachGetter((getter, key) => { const namespacedType = namespace + key registerGetter(store, namespacedType, getter,local// add all getters from modul to _wrappedGetters // store getters for all modules // {// cart/cartProducts: ƒ wrappedGetter (store) / / cart/cartTotalPrice: ƒ wrappedGetter(store) //}}) module.forEachChild((child, key) => {installModule(store, rootState, path.concat(key), // Loop through the module._children object and execute the installModule method on each loop})}Copy the code

(4) resetStoreVM(this, this.state, hot)

functionresetStoreVM (store, state, Hot) {// resetStoreVM // parameter // store // state // hot const oldVm = store._vm // oldVm cache old store._vm //bindStore public getters store.getters = {} // Add getters property object to the store instance, the initial value is an empty object // Note: // 1. Distinguish store._wrappedgetters from store.getters // resetlocalgetters cache store._makeLocalGettersCache = Object.create(null) const wrappedGetters = store._wrappedGetters // WrappedGetters // Cache store._wrappedGetters const computed = {} // Declares computed variablesforEachValue(wrappedGetters, (fn, key) => {// Loop wrappedGetters, passing value and key as argumentsforComputed [key] = partial(fn, store) //. Partial is such a function //function partial (fn, arg) {
      //   return function () {
      //     returnFn (arg) //} //} // 2. Computed [key] = () => fn(store) // fn is the specific getter function object.defineProperty (store.getters, key, { get: () => store._vm[key], enumerable:true// enumerable}) // 1. Add a key attribute to the store.getters object // 2. Stroe.getters [key] = store._vm[key] // Use a Vue instance to store the state tree // suppress warnings justin caseThe user has added // some funky global mixins const silent = vue.config.silent // Cache Vue.config.silent Vue.config.silent =trueStore._vm = new Vue({data: {$). = new Vue({data: {$$state: state // 11. Assign the passed state value to $in data$stateAttribute}, computed // 22. Assign the computed variable to the computed attribute in Vue(computed[key] = () => fn(store))}) // store._vm = new Vue(...) State and () => fn(store) have a responsive vue.config. silent = silent // Turn off the cancel warning //enable strict mode for new vm
  if (store.strict) {
    enableStrictMode(store) StrictMode(store) is enabled to ensure that store can be changed only by mutation}if (oldVm) {
    if (hot) {
      // dispatch changes in all subscribed watchers
      // to force getter re-evaluation for hot reloading.
      store._withCommit(() => {
        oldVm._data.$$state= null // Dereferencing})} vue.nexttick (() => oldVm.$destroy// const oldVm = store._vm // store._vm = new vue ()}}Copy the code

(5) commit

commit (_type, _payload, _options) {
    // check object-style commit
    const {
      typePayload, options} = unifyObjectStyle(_type, _payload, _options) // Construct parameters required for commit // 1.store.com MIT ('increment', 10)
    // 2. store.commit('increment', {amount: 10}) 
    // 3. store.commit({type: 'increment',amount: 10}) const mutation = {type, payload }

    const entry = this._mutations[type] // entry Finds the array of the mutation functions to be submitted. It is an arrayif(! Entry) {// The mutation was not foundif (__DEV__) {
        console.error(`[vuex] unknown mutation type: ${type}`)}return} this._withCOMMIT (() => {// this._withCOMMIT guarantees that state is legal (this._research is modifying)true
      entry.forEach(functionCommitIterator (handler) {handler(payload) // Pass parameters to execute the mutation Handle function})}) this._intimation.slice () // Shallow copy  to prevent iterator invalidationifSubscriber synchronously calls unsubscribe. ForEach (sub => sub(mutation, this.state)) // Shallow-copy this._subscribers Call the subscribe function inside // that changes the state after the need to respond to the view, etcif (
      __DEV__ &&
      options && options.silent
    ) {
      console.warn(
        `[vuex] mutation type: ${type}. Silent option has been removed. ` +
        'Use the filter functionality in the vue-devtools')}}Copy the code

(6) dispatch

dispatch (_type, _payload) {
    // check object-style dispatch
    const {
      typePayload} = unifyObjectStyle(_type, _payload) // Construct the parameter type required for commit // 1.store.dispatch ('increment')
    // 2. store.dispatch('incrementAsync', {amount: 10})
    // 3. store.dispatch({type: 'incrementAsync'Amount: 10}) const action = {type, payload }
    const entry = this._actions[type]
    if(! Entry) {// The action was not foundif (__DEV__) {
        console.error(`[vuex] unknown action type: ${type}`)}return
    }

    try {
      this._actionSubscribers
        .slice() // shallow copy to prevent iterator invalidation ifsubscriber synchronously calls unsubscribe .filter(sub => sub.before) .forEach(sub => sub.before(action, This.state)) // before the hook action listener // before means that the subscription handler should be called before an action is distributed} catch (e) {if (__DEV__) {
        console.warn(`[vuex] error inbefore action subscribers: `) console.error(e) } } const result = entry.length > 1 ? Promise.all(entry.map(handler => handler(payload))) : Entry [0](payload) // Length is greater than 1, promise.all() guarantees that result all resolve // length is less than or equal to 1, call directlyreturnnew Promise((resolve, reject) => { result.then(res => { try { this._actionSubscribers .filter(sub => sub.after) .forEach(sub => Sub.after (action, this.state))} catch (e) {sub.after(action, this.state))}if (__DEV__) {
            console.warn(`[vuex] error inafter action subscribers: ') console.error(e)}} resolve(res) error => { try { this._actionSubscribers .filter(sub => sub.error) .forEach(sub => sub.error(action, this.state, error)) } catch (e) {if (__DEV__) {
            console.warn(`[vuex] error in error action subscribers: `)
            console.error(e)
          }
        }
        reject(error)
      })
    })
  }
Copy the code

(7) mapstate

  • First of all, how is mapState used
Example computed: {... mapState('some/nested/module', {a: state => state.a, b: state => state.b})} MapState ([// map this.count to store.state.count'count'
])
Copy the code
  • The source code
    • Construct state as a computed object return
    • Passes (local state and getters as arguments) to the passed parameter objects according to the namespace.
exportConst mapState = normalizeNamespace((namespace, States) => {// normalizeNamespace F (namespace, states) // Change to the following parameter form //... mapState('some/nested/module', {
      //   a: state => state.a,
      //   b: state => state.b
      // })
  const res = {}
  if(__DEV__ && ! IsValidMap (States)) {// If the dev environment and states are not an object or an array // error is reported //function isValidMap (map) {
    //   return Array.isArray(map) || isObject(map)
    // }
    console.error('[vuex] mapState: mapper parameter must be either an Array or an Object') } normalizeMap(states).forEach(({ key, val }) => { // 1. If states are arrays, return an array where each member is an object ({key: key, val: key}) // 2. If states are objects, return an array with each member as an object ({key:key, val: map[key]}) res[key] =function mappedState () {
      let state = this.$store.state
      let getters = this.$store.getters
      if (namespace) {
        const module = getModuleByNamespace(this.$store.'mapState'// module // Find the corresponding module in the (store._modulesNamespacemap) object.if(! module) {return} state = module.context.state = module.context.state = module.context.state}return typeof val === 'function'? val.call(this, state, getters) : Val.call (this, state, getters) {// val is not a function, return state[val]} // mark vuex gettersfor devtools
    res[key].vuex = true
  })
  returnRes // Finally returns the res object // The res object is computed for the component})Copy the code
------

function normalizeNamespace (fn) {
  return (namespace, map) => {
    if(typeof namespace ! = ='string') {// If namespace is not a string // if only one parameter was passed // then namespace=' ', assign the first non-string parameter to the second parameter map = namespace Namespace =' '
    } else if(namespace.charAt(namespace.length - 1) ! = ='/') {
      namespace += '/'// If there is no /, add}returnFn (namespace, map) // return fn after the transformation argument}}Copy the code
------

function getModuleByNamespace (store, helper, namespace) {
  // 1. getModuleByNamespace(this.$store.'mapState'Const module = store._modulesNamespacemap [namespace] // Find the module corresponding to the namespaceif(__DEV__ && ! module) { console.error(`[vuex] module namespace not foundin ${helper}() :${namespace}`)}returnModule // Return module}Copy the code
------

function normalizeMap (map) {
  if(! isValidMap(map)) {return[] // Not an array or object, return an array by default}returnArray.isArray(map) ? map.map(key => ({ key, val: key })) : Object.keys(map).map(key => ({ key, val: map[key] })) // 1. If it is an array, return an array where each member is an object ({key: key, val: key}) // 2. If it is an object, return an array with each member as an object ({key:key, val: map[key]})}Copy the code

Note points in use

MapState – (with and without namespace)

mapGetters

mapMutations

mapActions

  • In the UI components
<template>
  <div class="vuex">
    <div>
      <div style="font-size: 30px"> <div> send an action => store.dispatch({type: 'actionName', payload: ' '})</div> <div>commit a mutation => store.dispatch({type: 'actionName', payload: ' '})</div>
     
      <div>------</div>
      <button @click="changeCount"> Click to modify vuexModule count+1 </button> <div>{{modulestate. count}}</div> <div>------</div> <div><button @click="getName"</button>< div>< div>< button@click ="getName2"> Select * from name where name = name; </button></div> <div>{{modulestate. name}}</div> </div> </div> </template> <script> import {mapState,  mapGetters, mapMutations, mapActions } from"vuex";

export default {
  name: "vuex".data() {
    return{}; }, computed: { ... MapState ({rootState: state = > {/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- named rootStatereturnstate; / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the state here is rootMoudule state}}),... mapState("vuexModule"{/ / -- -- -- -- -- -- -- -- -- -- -- -- the namespace moduleState: state = > {/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- named moduleStatereturnstate; / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the state here is moudles vuexModule state}}),... mapGetters("vuexModule"{// ---------- The second argument is the object, that is, you can change the name of the getter changeGetterName:"square"
    }),
    ...mapGetters("vuexModule"['square']), // The second argument is an array}, methods: {... mapMutations('vuexModule', { 
      addCountChangeName: 'AddCount'// ------- object mode, you can change the name of the mutation}),... mapActions('vuexModule'['getData'.'getData2']), // mapActions
    changeCount() {this.addcountChangename (1) // the ----------- parameter will be the payload of the mutation(state, payload)},getName() {this. GetData () / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- don't preach to action function, deal with asynchronous},getName2() {enclosing getData2 ({/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- send ginseng to action function, deal with asynchronous url:"/home",
        method: "get"})}},mounted() {
    console.log(
      this.rootState.vuexModule.count,
      "State-access coount for mapState without namespace"
    );
    console.log(
      this.moduleState.count,
      "State-access count obtained by mapState with namespace"
    );
    console.log(this.changeGetterName, 'mapGetters second argument is object ');
    console.log(this.square, 'mapGetters second argument is an array '); }}; </script>Copy the code
  • store/vuexModule
import {getName} from '.. /.. /api/home'

const vuex = {
  namespaced: true.state() {
    return {
      count: 2,
      name: 'init name'
    }
  },
  getters: {
    square(state, getters, rootState, rootGetters) {
      console.log(state, 'state')
      console.log(getters, 'getters')
      console.log(rootState, 'rootState')
      console.log(rootGetters, 'rootGetters')
      return(state.count * rootState.rootCount) } }, mutations: { AddCount(state, payload) { state.count = state.count + payload }, getNameData(state, payload) { state.name = payload } }, actions: {async getData(context) {// dispatch const {commit} = context const res = await getName({url:"/home",
        method: "get"
      });
      if (res && res.data && res.data.name) {
        console.log(res.data.name, '2222')
        commit('getNameData'Res.data.name)}}, async getData2(context, payload) {// dispatch parameters to action function // Action (context, payload) // First parameter: Context and Store have the same API // second argument: Payload is to dispatch an action as an argument const {commit} = context const res = await getName(payload); // const res = await getName({ // url:"/home",
      //   method: "get"
      // });
      if (res && res.data && res.data.name) {
        console.log(res.data.name, '2222')
        commit('getNameData', res.data.name)
      }
    },
  }
};

export default vuex
Copy the code

data

Vuex official website documentation vuex.vuejs.org/zh/

Sichuan God more comprehensive juejin.cn/post/684490… 2.3.1 version Vuex, detailed process: juejin.cn/post/684490… Yck juejin. Cn/post / 684490…