微信小程序mpvue框架总结

原理架构

JSBridge

做为native 与 JS 之间相互通讯的桥梁
JS部分(bridge): 在JS环境中注入 bridge 的实现代码,包含了协议的拼装/发送/参数池/回调池等一些基础功能。
Native部分(SDK): 在客户端中 bridge 的功能映射代码,实现了URL拦截与解析/环境信息的注入/通用功能映射等功能。css

逻辑层与视图层

一、逻辑层负责计算逻辑处理
二、视图层负责页面展现
数据变动驱动视图更新;视图交互触发事件,事件响应函数修改数据再次触发视图更新(用户交互,触发逻辑计算,最后由视图更新展现)html

原理

vue - data -> 小程序
vue <- 事件响应 - 小程序vue

一、生命周期关联:在小程序上触发数据更新,由vue处理,vue处理完后同步到小程序
为实现数据同步,mpvue 修改了 Vue.js runtime 实现,在 Vue.js 的生命周期中增长了更新小程序数据的逻辑。
二、事件代理机制:用户交互触发的数据更新经过事件代理机制完成,在小程序触发的事件代理到vue的method上
在小程序组件节点上触发事件后,找到虚拟 DOM 上对应的节点,触发对应的事件;另外一方面,Vue.js 事件响应若是触发了数据更新,其生命周期函数更新将自动触发,在此函数上同步更新小程序数据,数据同步也就实现了node

Vue代码
一、将小程序页面编写为 Vue.js 实现
二、以 Vue.js 开发规范实现父子组件关联git

小程序代码
一、以小程序开发规范编写视图层模板
二、配置生命周期函数,关联数据更新调用
三、将 Vue.js 数据映射为小程序数据模型github

并在此基础上,附加以下机制
一、Vue.js 实例与小程序 Page 实例创建关联
二、小程序和 Vue.js 生命周期创建映射关系,能在小程序生命周期中触发 Vue.js 生命周期
三、小程序事件创建代理机制,在事件代理函数中触发与之对应的 Vue.js 组件事件响应vue-cli

Vue.js 视图层渲染由 render 方法完成,同时在内存中维护着一份虚拟 DOM,mpvue 无需使用 Vue.js 完成视图层渲染,经过改造 render 方法,禁止视图层渲染;在 Vue runtime 时,添加平台 mpvuenpm

事件代理机制

一、在 mpvue 生成的 wxml 文件中,全部的事件都被 handleProxy 的函数接管,在 handleProxy 进行处理后再去调用咱们写的真正的事件处理函数。这个方法在initMp时,做为小程序Page构造函数的一个选项,从而能够在wxml中被正确调用
二、handleProxy将小程序的event对象传给handleProxyWithVue函数进行进一步处理
三、handleProxyWithVue 的做用json

  1. 从根实例开始,根据comkey找出事件处理函数所在的mpvue实例(getVm)
  2. 经过遍历找到的vm的vnode,结合eventid找到小程序事件对应的真实的事件处理函数(getHandle)
  3. 将小程序的event对象包装为mpvue的event对象(getWebEventByMP),并添加了preventDefault和stopPropagation方法
  4. 将包装后的event对象传给真实的处理函数进行调用。

(生成的wxml中绑定事件的节点都有data-comkey和data-eventid属性,在一个事件触发时,它们是被用来寻找事件对应的vm实例和对应的事件处理函数的)小程序

生命周期

微信小程序:

一、App对象,主要有onLaunch, onShow和onHide
二、Page对象,主要有onLoad, onShow, onReady, onHide和onUnload

Vue的生命周期主要体如今8个钩子:

beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestroy, destroyed

vue & mpvue 生命周期

mpvue 生命周期图

mpvue 生命周期

vuw & mpvue 生命周期对比图

vuw & mpvue 生命周期对比图

过程

app启动:
app-beforeCreate -> app-created -> app-onlaunch -> app-beforeMount -> app-mounted -> app-onShow

进入页面,更新操做:
page beforeCreate -> page created -> page onLoad -> page onShow -> page onReady -> page beforeMount -> component beforeCreate -> component created -> component onLoad -> component onReady -> component beforeMount -> component mounted -> page mounted

返回(隐藏),没有触发destroy:
page onUnload -> component onUnload

测试

page A、B(page tab)、C、D(page tab) (c 是 A 的子组件)
A -> B -> A (按钮跳转)
A -> B (点击左上角返回键)

一、App启动
app-beforeCreate.....
app-created...
app-onlaunch...
app-beforeMount.....
app-mounted.....
app-onShow....
A-beforeCreate.....
A-created....
B-beforeCreate.....
B-created.....
D-beforeCreate.....
D-created.....

二、进入 page A
A-onLoad....
A-onShow....
A-onReady.....
A-beforeMount.....
C-beforeCreate.....
C-created.....
C-onLoad....
C-onReady.....
C-beforeMount.....
C-mounted.....
A-mounted.....

三、离开page A
A-onUnload....
C-onUnload....

四、进入page B
B-onLoad....
B-onShow....
B-onReady.....
B-beforeMount.....
B-mounted.....
B-beforeUpdate..... // 更新
B-updated.....

五、离开page B
B-onHide.....

六、从新进入page A(switchTab)
A-onLoad....
C-onLoad....
A-onShow....
C-onShow....
A-onReady.....
C-onReady.....
A-beforeMount.....
A-beforeUpdate.....
A-mounted.....
C-beforeUpdate.....
C-updated.....

七、经过返回键返回 page B
A-onUnload....
C-onUnload....
B-onShow....

建立项目

# 安装 vue-cli
$ npm install --global vue-cli
# 根据模板项目建立本地项目,目前为内网地址
$ vue init mpvue/mpvue-quickstart my-project
# 安装依赖和启动自动构建
$ cd my-project
$ npm install
# 如今支持微信wx、头条tt、支付宝my、百度swan,运行该命令生成dist文件夹,即小程序
$ npm run dev

目录结构

├── build                  编译配置
├── config                 编译配置
├── dist                   小程序运行代码目录(该目录由编译生成)
├── `node_modules`           
├── src                    开发目录
|   ├── components         组件目录
|   |   ├── a.vue      组件a
|   |   └── b.vue      组件b
|   ├── pages              页面目录
|   |   ├── index          index页面(默认会在src/main.js主入口生成pages配置,路径为pages/index/main)
            ├── index.vue  由其入口文件编译main.js后,生成index/main.js、index/main.wxml和index/main.wxss文件
            ├── main.js     页面默认入口文件(config属性会编译为页面配置文件index/main.json)
|   |   └── other           other页面(默认会在src/main.js主入口生成pages配置,路径为pages/other/main)
            ├── index.vue  由其入口文件编译main.js后,生成other/main.js、other/main.wxml和other/main.wxss文件
            ├── main.js    页面默认入口文件(config属性会编译为页面配置文件other/main.json)
|   └── main.js            小程序配置项(全局数据、样式、声明钩子等;经build后,会在dist目录下生成app.js、app.json和app.wxss文件)
└── static                 静态文件,会直接被复制到dist/下
└── package.json           项目的package配置
└── project.config.json    小程序开发工具的配置

项目demo

本身写的demo,在以前原生微信小程序的基础上,使用 mpvue 重构了电影模块:
mpvue-play

注意

如下是一些本身在写demo时,踩过的坑或是一些须要注意的点(尤为对习惯了vue的童学),具体也可参见mpvue文档
一、onShow 代替 mounted:从一个页面返回到前一页面时,mounted不会再次被调用,由于页面没有被销毁,于是不须要从新挂载
onLoad 代替 created: 启动项目时,全部页面的beforeCreatecreated都已调用,而且进入页面时,不会再调用beforeCreatecreated
虽然建议尽可能不要使用小程序中的生命周期的钩子函数

二、小程序不支持路由,所以,路由跳转使用小程序的页面导航api代替
this.$router.push --> wx.navigateTo() //进入子页面
this.$router.replace --> wx.reLaunch()//打开新页面

三、微信小程序的页面的 query 参数是经过 onLoad 获取的,mpvue 对此进行了优化,直接经过 this.$root.$mp.query 获取相应的参数数据

四、小程序里全部的 BOM/DOM 都不能用,所以v-html、v-text不能用

五、图片 src="{{}}" => :src="",才能生效

六、不支持部分复杂的 JavaScript 渲染表达式,mpvue会把 template 中的 {{}} 双花括号的部分,直接编码到 wxml 文件中,因为微信小程序的能力限制(数据绑定),因此没法支持复杂的 JavaScript 表达式。建议使用computed
目前可使用的有 + - * % ?: ! == === > < [] .,剩下的还待完善。

七、不支持filter过滤器,由于小程序wxml不支持

八、列表渲染须要注意一点,嵌套列表渲染,必须指定不一样的索引 :key=""

九、不支持在 template 内使用 methods 中的函数,即<div>{{handleFn()}}</div>

十、获取当前页面地址
this.$route.fullPath --> getCurrentPages()[0].route

十一、不支持本地图片用做背景图,可使用网络图片、或者base64,或者使用img、image标签

十二、上拉加载/下拉刷新,选用小程序的全局api; scroll-view中没法使用

1三、不支持css媒体查询,css样式避免标签选择器,不易于维护,尽可能使用类选择器

1四、CSS样式导入,使用 @import url("")

1五、暂不支持在组件上使用 Class 与 Style 绑定

参考:
mpvue文档
用Vue.js开发微信小程序:开源框架mpvue解析
mpvue小程序开发 - 生命周期梳理
美团小程序框架--mpvue入坑指南
mpVue的使用小技巧之跳转与传参
小程序开发框架WePY与mpvue
px2rpx-loader使用和源码分析