2.x 中对组件的实现方式保留了很多原生小程序的特性,比如这一条,组件样式 中明确说明:除继承样式外, app.wxss 中的样式、组件所在页面的的样式对自定义组件无效(除非更改组件样式隔离选项),虽然可以通过更改组件样式隔离选项使得组件可以被全局样式作用到,但有时候也会带来弊端,比如在标签的属性 class 前面加上 ~,可以使组件获取全局样式,但是这样一来也带来一个问题,就是定义在组件里的该 class 样式会失效😭。这样的升级真的让写样式很难受,所以为了让样式写得尽量方便简单,我还是老老实实的把组件的样式就定义在组件里,不从全局拿样式了。
最近有个小程序项目需要迭代,但是迭代任务不多,时间比较充裕。而这个小程序最早是在18年的时候开发的,用的开发框架是
WePY
的1.7.2
版本,去年也就是19
年的时候WePY
框架进行了升级,到了2.0
版本。升级之后的WePY
,用WePY
官方文档的话来说:通过优化细节,引入Promise
、Async Functions
等让开发小程序项目变得更加简单,高效。基于这些背景,我和小伙伴一拍即合,决定对我们的项目进行框架升级,体验下到底WePY2
能给我们带来什么。本文将以项目改动为出发点,基于当前这个项目的结构和编码方式来考虑到底升级
WePY2
后,哪里需要改,怎么改以及有哪些需要注意的地方,通过对比2
个版本的写法差异这个思路来写,不会去太较真WePY2
相对于WePY1
实现或原理上的区别。下面我将一条一条的列出来需要改动的点。1、 初始化一个WePY2的demo
由于本地还有其他项目用的是
WePY_v1.7.2
,所以我们不能把WePY2
的CLI
工具安装在全局环境中,只能安装在当前项目中。官方推荐是直接用1.7.x
的CLI
去初始化2.0.x
的项目:这样就能够在本地初始化一个
wepy2
的项目模板,但是@wepy/core
是2.0.0-alpha.16
版本的,将它更新到最新的2.1.0
版本,这里也一起更新下整个旧项目和新模板所用到的依赖,下面直接贴出来:接下来操作主要是删除模板里的代码,然后把项目的结构和代码搬过去。
2、 wpy文件代码结构调整
WePy
单文件组件主要由<script>
、<template>
、<style>
、<config>
四部分组成(也包括小程序<wxs>
标签)。所以需要把WePY 1.7.2
中定义在<script>
中的config
配置需要独立到外层的<config>
中。1.7.2
写法:2.x
写法:3、 程序/页面/组件注册方式调整
注册方式将不再使用继承的方式,而是改成直接调用对应的实例方法。
1.7.2
写法:2.x
写法:4、代码结构由类结构变成对象结构
由于注册方式的改变,那么自然的代码结构也要有所调整。
1.7.2
写法:2.x
写法:上面仅仅只是以页面做为例子,
wepy.app()
和wepy.component()
也要对应调整。5、自定义方法和组件事件处理函数需要移到 methods 里
在
WePY 1.7.2
中注册的页面或者组件函数有这么几种类型:onLoad
、onShow
等;wxml
事件处理函数,即在wxml
中绑定的事件,这类函数需要定义在methods
,比如:bindtap
、bindchange
等;$broadcast
、$emit
、$invoke
所传递的事件函数,这类函数需要定义在events
对象里;methods
同级的位置。而在
WePY 2
中需要将组件处理函数和自定义函数都放到methods
里。下面假设HOME
页面有一个子组件child
,且子组件里会执行这句this.$emit('updateList)
,基于这个背景看下2
个版本下的写法差异:1.7.2
写法:2.x
写法:6、组件引入方式变更
在
2.x
版本中组件引入不再通过import
进行导入,而是直接定义在页面的配置<config>
中。1.7.2
写法:2.x
写法:另外,
2.x
中已经再不支持在app.wpy
里定义全局组件,而1.7.2
中是可以的。7、生命周期函数调整
在
2.x
中生命周期函数基本和原生保持一致,和1.7.2
相比,只是需要把组件中的onLoad
改成了ready
即可,其他无需变动。2.x
生命周期执行顺序:app onLaunch
->app onShow
->component created
->component attached
->page onLoad
->page onShow
->component ready
->page onReady
->page onUnload
->component detached
8、不再支持请求拦截器(坑)
在
1.7.2
中可以在wepy.app
的构造函数里通过配置拦截器可以对请求进行拦截,请求被拦截后可以加上更多的请求参数以及请求响应后可以进行统一的错误处理,功能还是挺好用的。但是在2.x
中这个功能至少从文档上是没看到,虽然源码里提供了一个 use-intercept拦截器的包,但是经过我几番尝试之后还是报错,所以就打算弃用拦截器了,直接在请求里进行参数增加和错误处理。request.js
这里贴一份大概的代码:其中
wepy.wx.request
这种写法需要在app.wpy
里配置promisify
,可以参考这里 use-promisify9、标签属性的值必须被双引号包裹
在
1.7.2
中对单引号和双引号没有强制要求,但是在2.x
中必须是双引号,不然编译会报错。1.7.2
写法:2.x
写法:10、调用原生事件需要传入参数$wx
小程序原生事件会传递一个 event 参数。而
WePY
的事件分发器在处理事件时会有一个$event
参数。$event
参数是对event
进行了一层包装,目地是为了无侵入地对齐Web Event
标准属性。而其中$event.$wx === event
。 因此,WePY
中响应事件获得的事件参数均是指$event
。如果想拿到原生事件参数,请使用$event.$wx
。1.7.2
写法:2.x
写法,只需要将bindinput="setInput"
改成@input="setInput($wx)"
即可。11、模板语法修改
2.x
的模板语法继承了WXML
的基本模板语法,并支持大部分Vue
模板语法。 对于标签:2.x
支持绝大部分的HTML
标签,经过编译后会转成标准的WXML
模板语法。但是对于1.7.2
中的有一个标签<repeat>
不再支持,需要将其替换成<view>
并且用v-for
进行循环渲染。下面是一些常用的模板语法对于
2
个版本之间写法的对比:1.7.2
写法2.x
写法:对于
v-for
循环列表的时候这里有一个(坑)不得不提一下,github issues直接看下面的代码:对于上面的代码,
<view>{{ index }}</view>
可以正常显示索引值index
,但是tapItem
传的参数却是undefined
,这所以我们需要显示的声明索引v-for="(item, index) in array"
即可。12、表单双向绑定调整
2.x
中直接用v-model
进行表单绑定,而不需要再定义一个函数对其进行赋值操作。1.7.2
写法:2.x
写法:13、全局数据属性获取方式调整
我们有时候需要在
app.wpy
里定义全局数据属性globalData
:在
2.x
中定义方式没变,但是获取方式有所调整:14、全局样式对组件无效
2.x
中对组件的实现方式保留了很多原生小程序的特性,比如这一条,组件样式 中明确说明:除继承样式外,app.wxss
中的样式、组件所在页面的的样式对自定义组件无效(除非更改组件样式隔离选项),虽然可以通过更改组件样式隔离选项使得组件可以被全局样式作用到,但有时候也会带来弊端,比如在标签的属性class
前面加上~
,可以使组件获取全局样式,但是这样一来也带来一个问题,就是定义在组件里的该class
样式会失效😭。这样的升级真的让写样式很难受,所以为了让样式写得尽量方便简单,我还是老老实实的把组件的样式就定义在组件里,不从全局拿样式了。15、组件通信不再支持$broadcast
父组件给子组件传递数据可以通过设置静态或者动态的
prop
属性或者通过广播$broadcast
来让所有子组件都收到父组件的信息,而子组件给父组件通信可以通过在父级自定义事件,在子组件中通过$emit
来通信。但是在2.x
中不再支持父级给子组件进行事件广播了,而是可以通过给子组件加上ref
属性后,通过this.$refs
来直接操作子组件函数来达成通信的目的,如下代码:parent.wpy
:child.wpy
:16、组件prop不再支持双向绑定
在
1.7.2
中可以通过可以通过设置prop
给子组件传参,如果设置的时候加上.sync
那么当父组件参数更新的时候,传递给子组件的也会自动更新,而如果在子组件的prop
里加上twoWay: true
则子组件数据可以绑定到父组件。从而实现组件数据的双向绑定。功能还是挺好用的,但遗憾的是在2.x
中已经不再支持通过twoWay: true
的方式从子组件绑定数据到父组件,父到子是可以的,但是不再需要设置sync
。那子组件需要更新父组件的数据,只能通过自定义事件,然后在子组件通过$emit
进行更新数据了。1.7.2
写法: 父页面:子组件:
2.x
写法: 父页面:子组件:
17、组件插槽slot代码插入后层级错乱问题(坑)
这个问题已经提到 github issues 中,且已经被作者标记为
bug
。 原始代码:parent.wpy
父页面:child.wpy
子组件:期望的编译后(正确)的
template
是:而实际
2.x
编译后的template
是会将对应的内容插入到子组件与根元素并列那级:针对老项目里用到
slot
的地方,我只能改写代码来避开这个坑了。18、资源引入调整
资源引入方式调整主要是介绍组件引入和图片引入两种。首先来看组件引入:
对于图片引入,存在两种方式:一种是静态的,程序在编译的时候就知道需要把哪些图片加载出来,另一种是动态的,只有在程序执行的时候才知道要加载哪些图片。对于第一种方式,通过相对路径、绝对路径或者
@
都可以引入到图片:对于第二种方式,需要将动态的图片放置在某个固定的位置,比如
/src/images/static
,然后再wepy.config.js
里配置static: ['/src/images/static']
这样在编译的时候就会把这个路径下的文件都拷贝到输出后的目录,从而能够准确引用这些动态图片。wepy.config.js
配置:页面:
静态图片特殊处理:单独放到一个目录里,然后再WePY.config.js里配置static
19、scss里如果引入.wxss文件会直接终止编译进程
下面的代码是一个页面的
scss
样式里,引入了wxss
文件,最终会导致编译进程终止。解决办法:
20、scss样式里存在特殊字符会导致编译报错(坑)
这里的特殊字符其实也是正常的需求,比如引入了字体图标,那可能会有这种样式
content: '\6499'
, 然后因为有反斜杠会直接导致报错编译错误。解决思路是把这种带有特殊字符的样式放到wxss
里,然后通过另外一个style
引入进来,编译器进行编译的时候会对scss
样式进行编译处理,但是对于wxss
会直接拷贝到输入目录,而不进行编译处理,所以能绕过这个坑。21、数据绑定机制调整
1.7.2
中用脏检查进行数据绑定,通过$apply()
方法使得数据能够及时更新,页面重新渲染。在2.x
中使用了Vue Observer
实现数据绑定,告别$apply()
,但是遇到一个问题,某个数组项的某个属性更新后,数组虽然是更新了,但是不能够触发页面进行重新渲染,即使使用splice
也不行。不过可以通过浅拷贝一个引用类型,重新赋值,从而触发页面重新渲染。