小程序onload_小程序升级WePY2踩坑记

56f9a58d163eb09011f228472986a4e8.png

点击上方蓝字关注我们

最近有个小程序项目需要迭代,但是迭代任务不多,时间比较充裕。而这个小程序最早是在18年的时候开发的,用的开发框架是 WePY1.7.2 版本,去年也就是 19 年的时候 WePY 框架进行了升级,到了 2.0 版本。升级之后的 WePY,用 WePY 官方文档的话来说:通过优化细节,引入 PromiseAsync Functions 等让开发小程序项目变得更加简单,高效。基于这些背景,我和小伙伴一拍即合,决定对我们的项目进行框架升级,体验下到底 WePY2 能给我们带来什么。

本文将以项目改动为出发点,基于当前这个项目的结构和编码方式来考虑到底升级 WePY2 后,哪里需要改,怎么改以及有哪些需要注意的地方,通过对比 2 个版本的写法差异这个思路来写,不会去太较真 WePY2 相对于 WePY1 实现或原理上的区别。下面我将一条一条的列出来需要改动的点。

本篇文章记录的是我和小伙伴这次升级框架遇到的需要改动的地方和坑,所使用的是 wepy2.1.0 版本,后续如果版本升级后,本篇记录到的坑如果已经被修复了,请自行忽略本文所述的问题。另外下文中所说到的 2.x 版本都是指 wepy_v2.1.0

1、初始化一个 WePY2 的 demo

由于本地还有其他项目用的是 WePY_v1.7.2,所以我们不能把 WePY2CLI 工具安装在全局环境中,只能安装在当前项目中。官方推荐是直接用 1.7.xCLI 去初始化 2.0.x 的项目:

wepy init standard#2.0.x zzodr

这样就能够在本地初始化一个 wepy2 的项目模板,但是 @wepy/core2.0.0-alpha.16 版本的,将它更新到最新的 2.1.0 版本,这里也一起更新下整个旧项目和新模板所用到的依赖,下面直接贴出来:

{
    "dependencies": {
    "@wepy/core": "^v2.1.0",
    "@wepy/use-intercept": "^2.1.0",
    "@wepy/use-promisify": "^2.1.0",
    "@wepy/x": "^2.0.2",
    "miniprogram-slide-view": "0.0.3"
  },
  "devDependencies": {
    "@babel/core": "^7.1.0",
    "@babel/preset-env": "^7.1.0",
    "@wepy/babel-plugin-import-regenerator": "0.0.2",
    "@wepy/cli": "^2.1.0",
    "@wepy/compiler-babel": "^2.0.1",
    "@wepy/compiler-sass": "^2.1.0",
    "@wepy/plugin-define": "^2.1.0",
    "babel-eslint": "^7.2.1",
    "cross-env": "^5.1.3",
    "eslint": "^3.18.0",
    "eslint-config-standard": "^7.1.0",
    "eslint-friendly-formatter": "^2.0.7",
    "eslint-plugin-html": "^2.0.1",
    "eslint-plugin-promise": "^3.5.0",
    "eslint-plugin-standard": "^2.0.1",
    "wepy-eslint": "^1.5.3"
  }
}

接下来操作主要是删除模板里的代码,然后把项目的结构和代码搬过去。

2、wpy 文件代码结构调整

WePy 单文件组件主要由 四部分组成(也包括小程序 标签)。所以需要把 WePY 1.7.2 中定义在 中的 config 配置需要独立到外层的 中。1.7.2 写法:




2.x 写法:




{
    navigationBarTitleText: '首页'
}

3、 程序/页面/组件注册方式调整

注册方式将不再使用继承的方式,而是改成直接调用对应的实例方法。1.7.2 写法:

export default class APP extends wepy.app {}  // 注册程序
export default class HOME extends wepy.page {}  // 注册页面
export default class LIST extends wepy.component {}  // 注册组件

2.x 写法:

wepy.app({})  // 注册程序
wepy.page({})  // 注册页面
wepy.component({})  // 注册组件

4、代码结构由类结构变成对象结构

由于注册方式的改变,那么自然的代码结构也要有所调整。1.7.2 写法:

export default class HOME extends wepy.page {
    data = {}
    methods = {}
    onLoad() {}
    onShow() {}
}

2.x 写法:

wepy.page({
    data: {},
    methods: {},
    onLoad() {},
    onShow() {},
})

上面仅仅只是以页面做为例子,wepy.app()wepy.component() 也要对应调整。

5、自定义方法和组件事件处理函数需要移到 methods 里

WePY 1.7.2 中注册的页面或者组件函数有这么几种类型:

  • 生命周期函数,比如 onLoadonShow 等;
  • wxml 事件处理函数,即在 wxml 中绑定的事件,这类函数需要定义在 methods,比如:bindtapbindchange 等;
  • 组件间事件处理函数,响应组件之间通过 $broadcast$emit$invoke 所传递的事件函数,这类函数需要定义在 events 对象里;
  • 自定义函数,即用于被其他函数直接调用的函数,需要定义在和 methods 同级的位置。

而在 WePY 2 中需要将组件处理函数和自定义函数都放到 methods 里。下面假设 HOME 页面有一个子组件 child,且子组件里会执行这句 this.$emit('updateList),基于这个背景看下 2 个版本下的写法差异:

1.7.2 写法:

"tapBox">

2.x 写法:

"tapBox">

6、组件引入方式变更

2.x 版本中组件引入不再通过 import 进行导入,而是直接定义在页面的配置 中。1.7.2 写法:



2.x 写法:




{
    usingComponents: {'child': './components/child.wpy',
    }
}

另外,2.x 中已经再不支持在 app.wpy 里定义全局组件,而 1.7.2 中是可以的。

7、生命周期函数调整

2.x 中生命周期函数基本和原生保持一致,和 1.7.2 相比,只是需要把组件中的 onLoad 改成了 ready 即可,其他无需变动。

级别1.7.22.x
apponLaunchonLaunch
apponShowonShow
pageonLoadonLoad
pageonShowonShow
pageonReadyonReady
component-created
component-attached
componentonLoadready

2.x 生命周期执行顺序:

app onLaunch -> app onShow -> component created -> component attached -> page onLoad -> page onShow -> component ready -> page onReady -> page onUnload -> component detached

page onHide 在当前页面通过 wx.navigateTo 打开新页面的时候会执行,而如果是在当前页面点击返回上一个页面或者 wx.redirectTo 并不会执行。

8、不再支持请求拦截器(坑)

1.7.2 中可以在 wepy.app 的构造函数里通过配置拦截器可以对请求进行拦截,请求被拦截后可以加上更多的请求参数以及请求响应后可以进行统一的错误处理,功能还是挺好用的。但是在 2.x 中这个功能至少从文档上是没看到,虽然源码里提供了一个 use-intercept拦截器的包,但是经过我几番尝试之后还是报错,所以就打算弃用拦截器了,直接在请求里进行参数增加和错误处理。request.js 这里贴一份大概的代码:

import wepy from "@wepy/core";
import { HOST } from "./constants";
export default function(url, data, handler = toast, header = {}) {
    // 头参数添加
    header["Content-Type"] = "application/json";
    header["cType"] = "WECHAT";
    
    return wepy.wx.request({  // 这里 wepy.wx.request 这种写法,需要在app.wpy里配置promisify,
        method: "POST",
        data: data || {},
        header,
        url: `${HOST}${url}`,
    }).then(data => {
        // 请求成功处理代码放这儿
        return Promise.reject(data)
    }).catch(err => {
        // 错误处理代码放这儿
        return Promise.reject(err);
    });
}

其中 wepy.wx.request 这种写法需要在 app.wpy 里配置 promisify,可以参考这里 use-promisify

9、标签属性的值必须被双引号包裹

1.7.2 中对单引号和双引号没有强制要求,但是在 2.x 中必须是双引号,不然编译会报错。1.7.2 写法:

"title" bindtap='change'>

2.x 写法:

"title" bindtap="change">

10、调用原生事件需要传入参数$wx

小程序原生事件会传递一个 event 参数。而 WePY 的事件分发器在处理事件时会有一个 $event 参数。$event 参数是对 event 进行了一层包装,目地是为了无侵入地对齐 Web Event 标准属性。而其中 $event.$wx === event。因此,WePY 中响应事件获得的事件参数均是指 $event。如果想拿到原生事件参数,请使用 $event.$wx1.7.2 写法:



2.x 写法,只需要将 bindinput="setInput" 改成 @input="setInput($wx)" 即可。

11、模板语法修改

2.x 的模板语法继承了 WXML 的基本模板语法,并支持大部分 Vue 模板语法。对于标签:2.x 支持绝大部分的 HTML 标签,经过编译后会转成标准的 WXML 模板语法。但是对于 1.7.2 中的有一个标签 不再支持,需要将其替换成 并且用 v-for 进行循环渲染。

下面是一些常用的模板语法对于 2 个版本之间写法的对比:1.7.2 写法

"{{ id }}">{{ name }}"change({{ index }})">"change {{hasData ? 'has-data' : '' }}">"{{ 'color:' + color + ';' + 'font-size:' + fontSize + ';' }}">if="{{ flag1 }}">elif="{{ flag2 }}">else>"{{ !isShow }}">for="{{ array }}" wx:for-index="idx" wx:for-item="itemName">

2.x 写法:

"id">{{ name }}"change( index )">"change" :class="{ 'has-data': hasData }">"{'color': color, 'font-size': fontSize }">"flag1">"flag2">"isShow">"(item, index) in array" :key="index">

对于 v-for 循环列表的时候这里有一个(坑)不得不提一下,github issues直接看下面的代码:

"item in array">{{ index }}"tapItem(index)">

对于上面的代码,{{ index }} 可以正常显示索引值 index,但是 tapItem 传的参数却是 undefined,这所以我们需要显示的声明索引 v-for="(item, index) in array" 即可。

12、表单双向绑定调整

2.x 中直接用 v-model 进行表单绑定,而不需要再定义一个函数对其进行赋值操作。1.7.2 写法:

"{{ name }}" bindtap="setInput" />

child.wpy


子组件:

wepy.page({
    props: {
        title: {
            type: String,
            default: '',
        }
    },
    onLoad(){
        this.$emit('changeTitle', '改变之后的标题')
    }
}) 

17、组件插槽slot代码插入后层级错乱问题(坑)

这个问题已经提到 github issues 中,且已经被作者标记为 bug。原始代码:parent.wpy 父页面:

parentchild view

child.wpy 子组件:

  child

期望的编译后(正确)的 template 是:

parentchildchild view

而实际 2.x 编译后的 template 是会将对应的内容插入到子组件与根元素并列那级:

parentchildchild view

针对老项目里用到 slot 的地方,我只能改写代码来避开这个坑了。

18、资源引入调整

资源引入方式调整主要是介绍组件引入和图片引入两种。首先来看组件引入:


{usingComponents: {'load-more': '/components/loadMore',  // 绝对路径 'btn': '../btn',  // 相对路径'list': '~@/components/list',  // 通过wepy.config.js配置别名@指向src,实际上也是绝对路径'van-icon': 'module:van-icon',  // 模块引入
  }
}
</config>

对于图片引入,存在两种方式:一种是静态的,程序在编译的时候就知道需要把哪些图片加载出来,另一种是动态的,只有在程序执行的时候才知道要加载哪些图片。对于第一种方式,通过相对路径、绝对路径或者 @ 都可以引入到图片:

"../bg.png">"/images/icon.png">"@/images/nodata.png">

对于第二种方式,需要将动态的图片放置在某个固定的位置,比如 /src/images/static,然后再 wepy.config.js 里配置 static: ['/src/images/static'] 这样在编译的时候就会把这个路径下的文件都拷贝到输出后的目录,从而能够准确引用这些动态图片。wepy.config.js 配置:

module.exports = {
    static: ['src/images/static'],
}

页面:

"'../images/static/' + fileType + '.png'">"imgSrc">

静态图片特殊处理:单独放到一个目录里,然后再WePY.config.js里配置static

19、scss里如果引入.wxss文件会直接终止编译进程

下面的代码是一个页面的 scss 样式里,引入了 wxss 文件,最终会导致编译进程终止。

<style lang="scss" type="text/scss">
    @import "./btn.scss";
    @import "./styles/common.wxss";
style>

解决办法:



20、scss样式里存在特殊字符会导致编译报错(坑)

这里的特殊字符其实也是正常的需求,比如引入了字体图标,那可能会有这种样式 content: '\6499', 然后因为有反斜杠会直接导致报错编译错误。解决思路是把这种带有特殊字符的样式放到 wxss 里,然后通过另外一个 style 引入进来,编译器进行编译的时候会对 scss 样式进行编译处理,但是对于 wxss 会直接拷贝到输入目录,而不进行编译处理,所以能绕过这个坑。



21、数据绑定机制调整

1.7.2 中用脏检查进行数据绑定,通过 $apply() 方法使得数据能够及时更新,页面重新渲染。在 2.x 中使用了 Vue Observer 实现数据绑定,告别 $apply(),但是遇到一个问题,某个数组项的某个属性更新后,数组虽然是更新了,但是不能够触发页面进行重新渲染,即使使用 splice 也不行。不过可以通过浅拷贝一个引用类型,重新赋值,从而触发页面重新渲染。

wepy.page({
    data: {
        list: [{
            name: 'aaa',
            hasBorder: true,
        }, {
            name: 'bbb',
            hasBorder: false,
        }]
    },
    methods: {
        handleClick() {
            this.list[1].hasBorder = true  // 不会重新渲染页面
            this.list.splice(1, 1, {  // 也不会重新渲染页面
                name: 'bbb',
                hasBorder: true,
            })
            this.list = [...this.list]  // 浅拷贝,使得this.list的引用地址变化了,使得页面重新渲染
        }
    }
})

END

fef07eeb918a89e8990c17c1b7fa7665.gif

关注我

又是快乐的一天呀

f6a6ae03c47b5b7ee11981c30299316c.png我就知道你在看!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值