波比-vue.js状态管理及ssr
1.中心化和去中心化中心化:一些需要共享的状态,抽离出来放到一个统一的地方进行管理去中心化:就是各个组件的本地状态,各个组件管理各个组件中的状态2.实现状态管理的思路首先要有一个全局的对象要对外暴露出api,也就是修改状态的方法与底层框架视图结合起来,状态更新了 -> 视图要更新3.实现代码Step1 - store 注册/*** store.js - store 注册*/let Vue//
·
1.中心化和去中心化
- 中心化:一些需要共享的状态,抽离出来放到一个统一的地方进行管理
- 去中心化:就是各个组件的本地状态,各个组件管理各个组件中的状态
2.实现状态管理的思路
- 首先要有一个全局的对象
- 要对外暴露出api,也就是修改状态的方法
- 与底层框架视图结合起来,状态更新了 -> 视图要更新
3.实现代码
- Step1 - store 注册
/**
* store.js - store 注册
*/
let Vue
// vue 插件必须要这个 install 函数
export function install(_Vue) {
// 拿到 Vue 的构造器,存起来
Vue = _Vue
// 通过 mixin 注入到每一个vue实例 👉 https://cn.vuejs.org/v2/guide/mixins.html
Vue.mixin({ beforeCreate: vuexInit })
function vuexInit () {
const options = this.$options
// 这样就可以通过 this.$store 访问到 Vuex 实例,拿到 store 了
if (options.store) {
this.$store = typeof options.store === 'function'
? options.store()
: options.store
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store
}
}
}
- Step2 - 响应式
/**
* store.js - 利用 VUE 实现响应式
*/
// this.$store.state
export class Store {
constructor(options = {}) {
resetStoreVM(this, options.state)
}
get state () {
return this._vm._data.$$state
}
}
function resetStoreVM(store, state) {
// 因为 vue 实例的 data 是响应式的,正好利用这一点,就可以实现 state 的响应式
store._vm = new Vue({
data: {
$$state: state
}
})
}
- Step3 - 衍生数据
/**
* store.js - 衍生数据(getters)
*/
export class Store {
constructor(options = {}) {
const state = options.state
resetStoreVM(this, state)
// 我们用 getters 来收集衍生数据 computed\
this.getters = {}
// 简单处理一下,衍生不就是计算一下嘛,传人 state
_.forEach(this.getters, (name, getterFn) => {
Object.defineProperty(this.getters, name, {
get: () => getterFn(this.state)
})
})
}
get state () {
return this._vm._data.$$state
}
}
function resetStoreVM(store, state) {
store._vm = new Vue({
data: {
$$state: state
}
})
}
- Step4 - Actions/Mutations
/**
* store.js - Actions/Mutations 行为改变数据
*/
export class Store {
constructor(options = {}) {
const state = options.state
resetStoreVM(this, state)
this.getters = {}
_.forEach(options.getters, (name, getterFn) => {
Object.defineProperty(this.getters, name, {
get: () => getterFn(this.state)
})
})
// 定义的行为,分别对应异步和同步行为处理
this.actions = {}
this.mutations = {}
_.forEach(options.mutations, (name, mutation) => {
this.mutations[name] = payload => {
// 最终执行的就是 this._vm_data.$$state.xxx = xxx 这种操作
mutation(this.state, payload)
}
})
_.forEach(options.actions, (name, action) => {
this.actions[name] = payload => {
// action 专注于处理异步,这里传入 this,这样就可以在异步里面通过 commit 触发 mutation 同步数据变化了
action(this, payload)
}
})
}
// 触发 mutation 的方式固定是 commit
commit(type, payload) {
this.mutations[type](payload)
}
// 触发 action 的方式固定是 dispatch
dispatch(type, payload) {
this.actions[type](payload)
}
get state () {
return this._vm._data.$$state
}
}
function resetStoreVM(store, state) {
store._vm = new Vue({
data: {
$$state: state
}
})
}
- Step5 - 分形,拆分出多个 Module
// module 可以对状态模型进行分层,每个 module 又含有自己的 state、getters、actions 等
// 定义一个 module 基类
class Module {
constructor(rawModule) {
this.state = rawModule || {}
this._rawModule = rawModule
this._children = {}
}
getChild (key) {
return this._children[key]
}
addChild (key, module) {
this._children[key] = module
}
}
// module-collection.js 把 module 收集起来
class ModuleCollection {
constructor(options = {}) {
this.register([], options)
}
register(path, rawModule) {
const newModule = new Module(rawModule)
if (path.length === 0 ) {
// 如果是根模块 将这个模块挂在到根实例上
this.root = newModule
}
else {
const parent = path.slice(0, -1).reduce((module, key) => {
return module.getChild(key)
}, this.root)
parent.addChild(path[path.length - 1], newModule)
}
// 如果有 modules,开始递归注册一波
if (rawModule.modules) {
_.forEach(rawModule.modules, (key, rawChildModule) => {
this.register(path.concat(key), rawChildModule)
})
}
}
}
// store.js 中
export class Store {
constructor(options = {}) {
// 其余代码...
// 所有的 modules 注册进来
this._modules = new ModuleCollection(options)
// 但是这些 modules 中的 actions, mutations, getters 都没有注册,所以我们原来的方法要重新写一下
// 递归的去注册一下就行了,这里抽离一个方法出来实现
installModule(this, this.state, [], this._modules.root);
}
}
function installModule(store, state, path, root) {
// getters
const getters = root._rawModule.getters
if (getters) {
_.forEach(getters, (name, getterFn) => {
Object.defineProperty(store.getters, name, {
get: () => getterFn(root.state)
})
})
}
// mutations
const mutations = root._rawModule.mutations
if (mutations) {
_.forEach(mutations, (name, mutation) => {
let _mutations = store.mutations[name] || (store.mutations[name] = [])
_mutations.push(payload => {
mutation(root.state, payload)
})
store.mutations[name] = _mutations
})
}
// actions
const actions = root._rawModule.actions
if (actions) {
_.forEach(actions, (name, action) => {
let _actions = store.actions[name] || (store.actions[name] = [])
_actions.push(payload => {
action(store, payload)
})
store.actions[name] = _actions
})
}
// 递归
_.forEach(root._children, (name, childModule) => {
installModule(this, this.state, path.concat(name), childModule)
})
}
4.vuex和redux区别
- 响应式(vuex通过vue实例)
- 范式(vuex比较好的范式,redux没有范式,由用户定义,比较粗狂)
- vuex分形
5.CSR和SSR
- CSR其实就是浏览器端渲染,其特点就是会在浏览器端的运行时去动态的渲染、更新 DOM 节点,特别是 SPA 应用来说,其模版 HTML 只有一个 DIV,然后是运行时(React,Vue,Svelte 等)动态的往里插入内容,这样的话各种 BaiduSpider 拿不到啥有效信息,自然 SEO 就不好了,项目一旦复杂起来, bundle 可能超乎寻常的大…这也是一个开销
- SSR则是服务端渲染,在服务端完成了渲染过程,将渲染完成的 HTML 字符串或者流返回给浏览器,就少了脚本解析、运行这一环节,理论上 FP 表现的更佳,SEO 同样。但对服务端的开销很大
更多推荐
已为社区贡献1条内容
所有评论(0)