本文由 llunnn 首发于 IMWeb 社区网站 imweb.io。点击阅读原文查看 IMWeb 社区更多精彩文章。
最近在开发小程序,尝试性地使用了一下mpvue框架。
mpvue是一个使用Vue.js开发小程序的前端框架。框架基于Vue.js核心,mpvue修改了Vue.js的runtime和compiler实现,使其可以运行在小程序环境中,从而为小程序开发引入了整套Vue.js开发体验。
mpvue同时维护了Vue和小程序的两套机制,因此需要对两套机制进行关联。这里主要对mpvue的生命周期来进行一些梳理。
微信小程序生命周期
首先我们需要了解,微信小程序的生命周期:
App对象,主要有onLaunch, onShow和onHide。
Page对象,主要有onLoad, onShow, onReady, onHide和onUnload。
Vue到mpvue
mpvue的出现使得我们可以用书写Vue实例的方式去声明这两种对象,并使得Vue实例兼容小程序的生命周期。
Vue的生命周期主要体现在8个钩子:beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestroy, destroyed。
来对比一下Vue和mpvue的生命周期,看一下mpvue做出了什么改变:
对比来看,mpvue主要是对created和beforeMount之间的过程做了改变。
在Vue中,这个阶段主要作用是将template编译为render函数:
而在mpvue中,对于App或Page组件(这里的Is App or Page component应该要解释为“是否为App或Page组件”),为他们初始化小程序的生命周期,并注册App对象或Page对象:
这里可以看出来,mpvue中,Vue和小程序生命周期钩子触发的基本顺序是beforeCreate -> created -> onLaunch/onLoad -> onShow -> onReady -> beforeMount -> mounted -> ...
实践验证
这里有一个入口页面,包含一个通过wx.navigateTo跳转到newPage的按钮。
newPage中包含一个card组件,和一个通过wx.navigateBack跳转回入口页面的按钮。
在App, newPage和card的各个生命周期钩子输出信息,来观察它们的触发情况和顺序。
在App被创建,跳转到newPage前
我们可以观察到,app对象首先被创建,触发onLaunch和onShow。
在这之后,newPage被create。需要注意的是,此时我们还没有跳转到newPage,也就是说在mpvue中,无论页面是否被访问到,其Vue实例的beforeCreate和created都在app创建后就被触发。
第一次跳转到newPage并返回入口页面
由于newPage页面的beforeCreate和created已经提前被触发过了,在调用了wx.NavigateTo跳转到newPage时,先触发小程序的生命周期,再触发beforeMount,这时候开始创建子组件card的实例,按照beforeCreate -> created -> onLoad -> onReady -> beforeMount -> mounted 的顺序触发生命周期钩子。(这里组件的onShow为什么没有触发..需要再深入探究一下)
在wx.navigateBack时,小程序的生命周期钩子onUnload被触发。但需要注意的是:Vue的生命周期钩子beforeDestroy和destroyed并没有被触发,也就是说小程序中newPage的page对象被卸载了,但newPage和card的Vue实例并没有被销毁。
第二次跳转到newPage并返回入口页面
newPage和card都已经被create且没有destroy,在再次wx.navigateTo时将直接从onLoad -> onShow -> onReady开始触发,newPage的mount和update过程也会出发,而component之后update过程被触发了。这里可以发现,在onLoad之后还经过了几个阶段,才开始触发Vue实例的生命周期钩子,而上一次保存在内存中的数据并没有被destroy,因此在重新加载的过程中,Vue实例还保存着上一次加载页面时的数据。
开发时遇到的问题
遇到的问题主要是由create过程在页面加载前就被统一触发引起的。 在使用Vue时,经常在created钩子中获得新的data。因为此时对data的数据观测已经被建立,但是页面内容尚未被挂载,Vue实例可以观测到data的变化并在视图显示出来之前改变其内容。
如果在mpvue中,我们想获取页面路由query中的数据,或是想在页面创建时请求接口,我们可能会这样考虑:
在created中获取数据?在mpvue中,created只被触发一次,且在页面创建前被触发,也就是说query中的数据是无法获得的,再次访问页面时如果数据发生了变化,created中的逻辑也并不会再次执行。
推迟到beforeMount?从功能上说,在beforeMount获取数据是没有问题的。但由于页面unload时没有触发destroy,在再次加载页面时,Vue实例仍然保存着前一次获得的数据,而页面的onLoad、onShow均在beforeMount之前被触发,实践时会发现,页面在数据更新之前就会被显示出来,旧的数据会在页面中“一闪而过”。
在onLoad中获取数据?实践证明这的确是一种最稳妥的方法,数据能被正确地设置,页面也不会“闪”。 但是官方文档有这样一句话: 除特殊情况外,不建议使用小程序的生命周期钩子。
这里大概是为了代码的移植性做考虑吧,不知道这里算不算特殊情况呢。
使用computed?为了避免使用小程序的生命周期钩子,还可以考虑使用computed的来获取query中的内容,而query需要在页面onLoad之后才存在,这里需要注意做一些判断。
总结
从Vue过度到mpvue还是非常平滑的,特别是在有过小程序开发经验的情况下。但是由于小程序本身和浏览器的差异,使得开发过程中会遇到一些难以理解的问题,将生命周期做一下梳理对更顺利地进行开发是有一些好处的。
但是,从这里也可以看到,对于开发小程序来说,mpvue实际上额外地维护了一套Vue的机制,并对小程序的事件、数据进行代理、同步,实际上这个过程可能会造成一些性能上的损耗。再加上mpvue目前还是存在一些缺陷,而小程序也支持了数据绑定、组件化开发,个人认为若是追求高质量的开发还是直接使用原生小程序更优吧~
关注我们
IMWeb 团队隶属腾讯公司,是国内最专业的前端团队之一。
我们专注前端领域多年,负责过 QQ 资料、QQ 注册、QQ 群等亿级业务。目前聚焦于在线教育领域,精心打磨 腾讯课堂 及 企鹅辅导 两大产品。
社区官网:
http://imweb.io/
加入我们:
https://hr.tencent.com/position_detail.php?id=26701
扫码关注 IMWeb前端社区 公众号,获取最新前端好文
微博、掘金、Github、知乎可搜索 IMWeb 或 IMWeb团队 关注我们。