Vuex principle analysis
The design concept of VUEX is centralized state management and predictable state changes
The plug-in
To use vuex, you first need vue. use(vuex), that is, to install the vuex plug-in.
-
How to implement a plug-in?
Simply expose the install() method.
-
What are the main functions of this plug-in?
Mount $store, since vue.use () is executed first, new Vue() instance has not been created yet, so mixins are used to mix the lazy mount.
function install(_Vue) {
Vue. Use () can receive Vue instances
Vue = _Vue
Vue.mixin({
beforeCreate() {
// Because of mixin, the hook is called when each component instance is created
// The root instance has this option
if (this.$options.store) {
// Mount the vue prototype so that other components can call $store
Vue.prototype.$store = this.$options.store
}
}
})
}
Copy the code
State Reactive state management
- How many ways to implement data responsiveness?
Object.defineProperty()
Vue.util.defineReactive()
Vue.observable()
new Vue({data(){}})
This is the fourth one
new Vue({
data: {
$$state = $$state = $$state = $$state
$$state:options.state
}
})
Copy the code
The state assembly
// Read-only state, which can obtain data
get state() {
return this._vm._data.$$state
}
set state(v) {
console.error('please use replaceState to reset state');
}
Copy the code
implementationcommit()
dispatch()
methods
Pass in the method name and parameters, go mutations and actions to match
// Save mutaions and Actions options
this._mutations = options.mutations;
this._actions = options.actions;
commit(type, payload) {
const entry = this._mutations[type]
if(! entry) {console.error('unkown mutation type');
}
/ / to the state
entry(this.state, payload)
}
dispatch(type, payload) {
const entry = this._actions[type]
if(! entry) {console.error('unkown action type');
}
//{commit} context object is the current instance this
entry(this, payload)
}
Copy the code
Bind this to
this.commit = this.commit.bind(this)
this.dispatch = this.dispatch.bind(this)
Copy the code
Implement getters
Vuex’s getters realize real-time data monitoring through computed property of VUE
this._wrappedGetters = options.getters
// The outside world accesses getters via $store.getters. XXX
this.getters = {};
Define computed data
const computed = {};
// Get the current this
const store =this;
Object.keys(this._wrappedGetters).forEach(key= > {
// This refers to change, use the above defined this
const fn = store._wrappedGetters[key]
// Computed is a parameterless function, and getters is a parameterless function, so higher-order functions are included
computed[key] = function(){
return fn(store.state)
}
})
// Specify getters as read-only
Object.defineProperty(store.getters,key,{
get: () = > store._vm[key]
})
this._vm = new Vue({
data: {
$$state: options.state // GoEast is not a proxy and can not be accessed directly
},
computed
})
Copy the code
Vue – principle of the router
In a single-page program, the URL changes and the corresponding view content is not refreshed
Implement the plug-in to mount $router
// Argument 1 is passed in when vue. use is called
VueRouter.install = function(_Vue) {
Vue = _Vue;
// 1. Mount $router
//Vue. Use () takes precedence. New Vue() has not been executed yet, so $router mount is delayed
// Global mixin purpose: delay the following logic until the router is created and appended to the option
Vue.mixin({
//new Vue() the first hook function to execute
beforeCreate() {
// Because of mixin, the hook is called when each component instance is created
// The root instance has this option
if (this.$options.router) {
// Mount the vue prototype so that other components can call $router
Vue.prototype.$router = this.$options.router; }}});Copy the code
The PAGE does not refresh when the URL changes
hash
The #/user/1 hash mode carries a ‘#’, does not refresh the browser, and listens for URL changes by listening for hashchange
this.current = window.localtion.hash.slice(1) | |"/";
// Listen for hash changes
window.addEventListener("hashchange".() = > {
console.log(this.current);
this.current = window.location.hash.slice(1);
});
Copy the code
history
/user/1 history Normal URL format By listening for POPState, listen for URL changes
Data responsive, URL changing content is re-rendered
Vue.util. DefineReactive Defines reactive data
// Define the response-matched array, which stores the nested components matched by the current route
Vue.util.defineReactive(this.'matched'[]);// Routing table routes
this.match();
match(routes){
/ / the routing table
let routes = routes || this.$options.routes;
// Recursively traverses the routing table
for(route of routes){
if(route.path === '/' && this.current === '/') {// Add routing information
this.matched.push(route);
return;
}
// /about/info
if(route.path ! = ='/' && this.current.indexOf(route.path) ! = -1) {/ / include/about
this.matched.push(route);
// There are nested subroutes, recursively calling match
if(route.children.length > 0) {this.match(route.children)
}
return; }}}}Copy the code
Implement two global components router-link and router-view
To realize the router – the link
Vue.component("router-link", {
props: {
to: {
type: String.required: true,}},render(h) {
// <a href="to">xxx</a>
// return <a href={'#'+this.to}>{this.$slots.default}</a>
return h(
"a",
{
attrs: {
href: "#" + this.to,
},
},
this.$slots.default ); }});Copy the code
Implement the router – the view
Determine the depth of router-view to realize route nesting. Render nested components via matched array
Vue.component("router-view", {
render(h) {
// Mark the current router-view depth
this.$vnode.data.routerView = true;
// Depth identifier
let depth = 0;
// Look up the routerView
let parent = this.$parent;
while(parent){
const vnodeData = parent.$vnode && parent.$vnode.data;
if(vnodeData.routerView){
// Parent is a router-view
depth++;
}
parent = parent.$parent;
}
// Get the component of the current route
let component = null;
// Matched is responsive so it dynamically renders the route
const route = this.$router.matched[depth];
if (route) {
component = route.component
}
console.log(this.$router.matched, component);
returnh(component); }}); };Copy the code