vue 美团框架_Vuex框架原理与源码分析

Vuex是一个专为Vue服务,用于管理页面数据状态、提供统一数据操作的生态系统。它集中于MVC模式中的Model层,规定所有的数据操作必须通过 action - mutation - state change 的流程来进行,再结合Vue的数据视图双向绑定特性来实现页面的展示更新。统一的页面状态管理以及操作处理,可以让复杂的组件交互变得简单清晰,同时可在调试模式下进行时光机般的倒退前进操作,查看数据改变过程,使code debug更加方便。

最近在开发的项目中用到了Vuex来管理整体页面状态,遇到了很多问题。决定研究下源码,在答疑解惑之外,能深入学习其实现原理。

先将问题抛出来,使学习和研究更有针对性:

1. 使用Vuex只需执行 Vue.use(Vuex),并在Vue的配置中传入一个store对象的示例,store是如何实现注入的?

2. state内部是如何实现支持模块配置和模块嵌套的?

3. 在执行dispatch触发action(commit同理)的时候,只需传入(type, payload),action执行函数中第一个参数store从哪里获取的?

4. 如何区分state是外部直接修改,还是通过mutation方法修改的?

5. 调试时的“时空穿梭”功能是如何实现的?注:本文对有Vuex有实际使用经验的同学帮助更大,能更清晰理解Vuex的工作流程和原理,使用起来更得心应手。初次接触的同学,可以先参考Vuex官方文档进行基础概念的学习。

一、框架核心流程

进行源码分析之前,先了解一下官方文档中提供的核心思想图,它也代表着整个Vuex框架的运行流程。

如图示,Vuex为Vue Components建立起了一个完整的生态圈,包括开发中的API调用一环。围绕这个生态圈,简要介绍一下各模块在核心流程中的主要功能:Vue Components:Vue组件。HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。

dispatch:操作行为触发方法,是唯一能执行action的方法。

actions:操作行为处理模块。负责处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。

commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。

mutations:状态改变操作方法。是Vuex修改state的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。

state:页面状态管理容器对象。集中存储Vue components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。

getters:state对象读取方法。图中没有单独列出该模块,应该被包含在了render中,Vue Components通过该方法读取全局state对象。Vue组件接收交互行为,调用dispatch方法触发action相关处理,若页面状态需要改变,则调用commit方法提交mutation修改state,通过getters获取到state新值,重新渲染Vue Components,界面随之更新。

二、目录结构介绍

打开Vuex项目,看下源码目录结构。

Vuex提供了非常强大的状态管理功能,源码代码量却不多,目录结构划分也很清晰。先大体介绍下各个目录文件的功能:

* module:提供module对象与module对象树的创建功能;

* plugins:提供开发辅助插件,如“时光穿梭”功能,state修改的日志记录功能等;

* helpers.js:提供action、mutations以及getters的查找API;

* index.js:是源码主入口文件,提供store的各module构建安装;

* mixin.js:提供了store在Vue实例上的装载注入;

* util.js:提供了工具方法如find、deepCopy、forEachValue以及assert等方法。

三、初始化装载与注入

了解大概的目录及对应功能后,下面开始进行源码分析。index.js中包含了所有的核心代码,从该文件入手进行分析。

3.1 装载实例

先看个简单的例子:/**

* store.js文件

* 创建store对象,配置state、action、mutation以及getter

*

**/

import Vue from 'vue'

import Vuex from 'vuex'

// install Vuex框架

Vue.use(Vuex)

// 创建并导出store对象。为了方便,不配置任何参数

export default new Vuex.Store()

store.js文件中,加载Vuex框架,创建并导出一个空配置的store对象实例。/**

* vue-index.js文件

*

*

**/

import Vue from 'vue'

import App from './../pages/app.vue'

import store from './store.js'

new Vue({

el: '#root',

router,

store,

render: h => h(App)

})

然后在index.js中,正常初始化一个页面根级别的Vue组件,传入这个自定义的store对象。

如问题1所述,以上实例除了Vue的初始化代码,只是多了一个store对象的传入。一起看下源码中的实现方式。

3.2 装载分析

index.js文件代码执行开头,定义局部 Vue 变量,用于判断是否已经装载和减少全局作用域查找。let Vue

然后判断若处于浏览器环境下且加载过Vue,则执行install方法。// auto install in dist mode

if (typeof window !== 'undefined' && window.Vue) {

install(window.Vue)

}

install方法将Vuex装载到Vue对象上,Vue.use(Vuex) 也是通过它执行,先看下Vue.use方法实现:function (plugin: Function | Object) {

/* istanbul ignore if */

if (plugin.installed) {

return

}

// additional parameters

const args = toArray(arguments, 1)

args.unshift(this)

if (typeof plugin.install === 'function') {

// 实际执行插件的install方法

plugin.install.apply(plugin, args)

} else {

plugin.apply(null, args)

}

plugin.installed = true

return this

}

若是首次加载,将局部Vue变量赋值为全局的Vue对象,并执行applyMixin方法,install实现如下:function install (_Vue) {

if (Vue) {

console.error(

'[vuex] already installed. Vue.use(Vuex) should be called only once.'

)

return

}

Vue = _Vue

applyMixin(Vue)

}

来看下applyMixin方法内部代码。如果是2.x.x以上版本,可以使用 hook 的形式进行注入,或使用封装并替换Vue对象原型的_init方法,实现注入。export default function (Vue) {

const version = Number(Vue.version.split('.')[0])

if (version >= 2) {

const usesInit = Vue.config._lifecycleHooks.indexOf('init') > -1

Vue.mixin(usesInit ?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值