MVVM
sequenceDiagram
View-)viewmodel: 用户操作view层
viewmodel--)View: viewmodel与model相互影响
viewmodel-)model: 改变了数据结构
model--)viewmodel: 更新数据,可以驱动viewmodel
VUEX使用
使用一个独立之外的实例来保存和获取我们需要的变量。那么这个状态机应该具有以下的特性:
- 全局化 => 全局挂载
- 全局唯一性 => 单例形态
- 状态流转链 => 异步转同步
mutation 内应该避免处理业务,只更改state的值
1.全局引入
//index.js
import store from './store'
new Vue({
store,
render: h => h(App)
}).$mount('#app')
2.生成实例
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
actions:{
changeUserInfoAct({commit},userInfo){
commit('SET_USERINFO',userInfo)
},
changeElseAct({commit,dispatch},userInfo){
//调用其他action
dispatch('changeUserInfoAct', userInfo)
//如果调用其他模块的action,需要添加 root
//dispatch('changeUserInfoAct', userInfo , {root:true})
}
},
mutations:{
SET_USERINFO(state,{userInfo}){
state.userInfo = userInfo
}
},
state:{
userInfo:{
name:'',
age:18
}
}
})
export default store
3.模块化
import user from './modules/user'
import common from './modules/common'
...
// index.js
const store = new Vuex.Store({
modules: {
user, // 使用模块化
common,
}
})
// user.js
const user = {
state:{
},
mutation:{
},
action:{
}
}
export defalut user
4. getter
const getters = {
age: state => state.user.userInfo.age >= 18 ? "成年" : "未成年",
}
export default getters
5.使用store
获取数据
import { mapStates , mapGetters } from "vuex";
//...
computed:{
...mapStates(['userInfor'])
...mapGetters(["age"]),
//或者另外一种写法
...mapStates({
userInfor : state => state.userInfo
})
}
赋值
this.$store.dispatch('changeUserInfoAct',{
name:"-",
age:23
})
VUEX分析
vuex 本质是一个 vue实例
vuex主体结构:
if (__DEV__) {
//__DEV__ 就是process.env.NODE_ENV ,就是运行时候的一个状态
// 浏览器不支持 promise
assert(typeof Promise !== 'undefined', `vuex requires a Promise polyfill in this browser.`)
//store必须实例化调用,
assert(this instanceof Store, `store must be called with the new operator.`)
}
- process.env.NODE_ENV 有两个值
development和production,当取值development时,__DEV__才为true,其余为false assert是自己定义的异常处理方法
export function assert (condition, msg) {
if (!condition) throw new Error(`[vuex] ${msg}`)
}
为什么要自己定义告警?
自己定义告警可以控制是否阻断后续操作,可以做告警级别控制
// store internal state
/*
* 所有变量的初始化
*/
this._committing = false //内部state
this._actions = Object.create(null)
this._actionSubscribers = [] //存放action订阅
this._mutations = Object.create(null)
this._wrappedGetters = Object.create(null)
this._modules = new ModuleCollection(options) //模块收集器 - 树形结构
this._modulesNamespaceMap = Object.create(null) //命名空间对应关系
//订阅列表
this._subscribers = []
//本地getters - 还没更新前的数据
this._makeLocalGettersCache = Object.create(null)
// bind commit and dispatch to self
const store = this //单例模式核心写法,确保this绑定到了实例上
const { dispatch, commit } = this
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)
}
//进入严格模式,使用mutation以外的方法进行修改state的值都会抛出异常
this.strict = strict
const state = this._modules.root.stat
挂载命名空间 并注册state、mutation、action 并递归注册子module
export function installModule (store, rootState, path, module, hot) {
const isRoot = !path.length
const namespace = store._modules.getNamespace(path)
// 挂载命名空间
if (module.namespaced) {
//判断重名,异常
if (store._modulesNamespaceMap[namespace] && __DEV__) {
console.error(`[vuex] duplicate namespace ${namespace} for the namespaced module ${path.join('/')}`)
}
store._modulesNamespaceMap[namespace] = module
}
// set state
//赋值
if (!isRoot && !hot) {
const parentState = getNestedState(rootState, path.slice(0, -1))
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('.')}"`
)
}
}
parentState[moduleName] = module.state
})
}
const local = module.context = makeLocalContext(store, namespace, path)
module.forEachMutation((mutation, key) => {
const namespacedType = namespace + key
registerMutation(store, namespacedType, mutation, local)
})
module.forEachAction((action, key) => {
const type = action.root ? key : namespace + key
const handler = action.handler || action
registerAction(store, type, handler, local)
})
module.forEachGetter((getter, key) => {
const namespacedType = namespace + key
registerGetter(store, namespacedType, getter, local)
})
module.forEachChild((child, key) => {
installModule(store, rootState, path.concat(key), child, hot)
})
}
中心思想是利用单例,将数据存储在全局的store中,并利用vue的颗粒度响应记住来进行状态更新,进行高效处理。