Recently, there was a small program project that needed iteration, but the iteration tasks were few and time was abundant. This widget was first developed in ’18 using the WePY 1.7.2 framework, which was updated to version 2.0 last year. The updated WePY, in the words of WePY’s official documentation, makes it easier and more efficient to develop small program projects by optimizing details, introducing promises, Async Functions, etc. Based on these backgrounds, my friends and I hit it off and decided to upgrade the framework of our project to experience what WePY2 can bring to us.

Based on the structure and coding mode of the current project, this paper will consider what needs to be changed, how to change and what needs to be paid attention to after upgrading WePY2. It will be written by comparing the writing methods of the two versions. I’m not going to get too serious about the implementation or principle differences between WePY2 and WePY1. Let me list the changes one by one.

This article records the places and potholes that my friends and I need to change during the upgrade of the framework, using version 2.1.0 of WEPY. If the potholes recorded in this article have been repaired after the upgrade, please ignore the problems mentioned in this article. In addition, the 2.x version mentioned below refers to wepy_v2.1.0.

Initialize a WePY2 demo

Since there are other local projects using wepy_v1.7.2, WePY2 CLI tools cannot be installed in the global environment, only in the current project. The official recommendation is to initialize a 2.0.x project directly with 1.7.x CLI:

Zzodr wepy init standard# 2.0 xCopy the code

It is possible to initialize a wepy2 project template locally, but @wepy/core is 2.0.0-alpha.16, update it to the latest version 2.1.0, and also update the dependencies used by the whole old project and the new template.

{
    "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": "Hundreds"."@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." "}}Copy the code

The next step is to delete the code in the template and move the structure and code of the project over.

2. Wpy file code structure adjustment

The WePy single-file component is mainly composed of four parts:

<template></template> <script> export default class Home extends wepy.page { config = { navigationBarTitleText: </script> <style></style>Copy the code

2. X writing:

<template></template> <script></script> <config> {navigationBarTitleText: 'home'} </config> </style> </style>Copy the code

3. Adjust the registration mode of program/page/component

Instead of using inheritance, the registration method will call the corresponding instance method directly. 1.7.2 writing:

export default class APP extends wepy.app {}  // Registration procedure
export default class HOME extends wepy.page {}  // Register page
export default class LIST extends wepy.component {}  // Register the component
Copy the code

2. X writing:

wepy.app({})  // Registration procedure
wepy.page({})  // Register page
wepy.component({})  // Register the component
Copy the code

4. Code structure changes from class structure to object structure

As registration changes, the natural code structure has to be adjusted. 1.7.2 writing:

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

2. X writing:

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

Just using the page as an example, wepy.app() and wepy.component() should also be adjusted accordingly.

5. Custom methods and component event handlers need to be moved to Methods

There are several types of pages or component functions registered in WePY 1.7.2:

  • Lifecycle functions, for exampleonLoad,onShowAnd so on;
  • wxmlThe event handler, that is, thewxmlThis type of function needs to be defined inmethods, such as:bindtap,bindchangeAnd so on;
  • Intercomponent event handler functions that respond to messages between components$broadcast,$emit,$invokeThe passed event function, which needs to be defined ineventsIn the object;
  • Custom functions, that is, functions that are called directly by other functions, need to be defined in andmethodsSame level of position.

In WePY 2, you need to put both component handlers and custom functions into methods. $emit(‘updateList ‘); this.$emit(‘updateList ‘); this.$emit(‘updateList ‘)

1.7.2 writing:

<template> <view> <view bindtap="tapBox"></view> </view> </template> <script> export default class HOME extends Wepy.page {data = {} onLoad() {} // Life cycle function onShow() {} // life cycle function events = {updateList () => {} // intercomponent event handler function} methods TapBox () {// WXML event handler this.getmsg ()}} getMsg() {// custom function} </script>Copy the code

2. X writing:

<template> <view> <view @tap="tapBox"></view> </view> </template> <script> wepy.page({ data: {}, {}, onLoad () function onShow / / life cycle () {}, / / life cycle function the methods: {tapBox() {// WXML event handler this.getmsg ()}, updateList() {}, // custom function},}) </script>Copy the code

6. Component introduction changes

In 2.x, component imports are no longer imported through import, but are defined directly in the configuration

of the page. 1.7.2 writing:

<template>
    <view>
        <child></child>
    </view>
</template>
<script>
import Child from './components/child.wpy';
export default class HOME extends wepy.page {
    components = {
        child: Child
    }
}
</script>
Copy the code

2. X writing:

<template>
    <view>
        <child></child>
    </view>
</template>
<script>
wepy.page({})
</script>
<config>
{
    usingComponents: {
        'child': './components/child.wpy',
    }
}
</config>
Copy the code

In addition, 2.x no longer supports defining global components in app.wpy, whereas 1.7.2 did.

7. Life cycle function adjustment

In 2.x, the lifecycle function is basically the same as it was in 1.7.2, except that onLoad in the component is changed to Ready, and nothing else is changed.

level 1.7.2 2.x
app onLaunch onLaunch
app onShow onShow
page onLoad onLoad
page onShow onShow
page onReady onReady
component created
component attached
component onLoad ready

2. Execution sequence of X life cycle:

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

Page onHide is executed when the current page opens a new page via wx.navigateTo, but not if the current page is clicked back to the previous page or wx.redirectTo.

8. Request interceptors (pits) are no longer supported

In 1.7.2, we can configure interceptors in the wepy.app constructor to intercept requests, add more request parameters after the interception, and unified error handling after the request response, which is quite useful. However, this function is not seen in 2.x at least in the documentation. Although a use-Intercept package is provided in the source code, I still get errors after several attempts, so I plan to discard the interceptor and directly add parameters and handle errors in the request. Request.js here is a sample of the code:

import wepy from "@wepy/core";
import { HOST } from "./constants";
export default function(url, data, handler = toast, header = {}) {
    // The header parameter is added
    header["Content-Type"] = "application/json";
    header["cType"] = "WECHAT";
    
    return wepy.wx.request({  // Wepy.wx. Request is promisify configured in app.wpy
        method: "POST".data: data || {},
        header,
        url: `${HOST}${url}`,
    }).then(data= > {
        // Put the request success handling code here
        return Promise.reject(data)
    }).catch(err= > {
        // Put the error handling code here
        return Promise.reject(err);
    });
}
Copy the code

Wepy.wx. request requires configuration of promisify in app.wpy as use-promisify

9. The value of the tag attribute must be enclosed in double quotes

In 1.7.2, single and double quotes are not mandatory, but in 2.x, they must be double quotes or the compilation will fail. 1.7.2 writing:

<template>
    <view>
        <view class="title" bindtap='change'></view>
    </view>
</template>
Copy the code

2. X writing:

<template>
    <view>
       <view class="title" bindtap="change"></view>
    </view>
</template>
Copy the code

Call the native event with the parameter $wx

The applet native event passes an event parameter. WePY’s event dispatcher, on the other hand, has a $event parameter for handling events. The $event parameter wraps the event in an effort to align the Web Event standard properties ininvasively. $event.$wx === event. Therefore, the event parameters obtained in WePY in response to events refer to $event. To retrieve the native event parameters, use $event.$wx. 1.7.2 writing:

<template>
    <view><input bindinput="setInput" value="{{name}}" /></view>
</template>
<script>
export default class HOME extends wepy.page {
    data = {
        name: '',
    }
    methods = {
        setInput(e) {
            this.name = e.detail.value
        }
    }
}
</script>
Copy the code

$wx =”setInput” @input=”setInput($wx)”;

11. Template syntax modification

2. X template syntax inherits the basic WXML template syntax and supports most Vue template syntax. For tags: 2.x supports most HTML tags, which are converted to standard WXML template syntax when compiled. However, one tag

is no longer supported in 1.7.2 and needs to be replaced with

and lofted with V-for.

Here are some common template syntax for comparison between the two versions: 1.7.2 Writing

<template> <view> <! <view id="{{id}}"></view> <! <view>{{name}}</view> <! - event - > < view bindtap = "change ({{index}})" > < / view > <! --> <view class="change {{hasData? 'has-data' : '' }}"></view> <! - style binding - > < view style = "{{' color: '+ color +'; ' + 'font-size:' + fontSize + '; ' }}"></view> <! - condition judgment - > < view wx: if = "{{flag1}}" > < / view > < view wx: elif = "{{flag2}}" > < / view > < view wx: else > < / view > <! <view hidden="{{! isShow }}"></view> <! -- List rendering, default: Item, index --> <view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName"></view> </view> </template>Copy the code

2. X writing:

<template> <view> <! <view :id="id"></view> <! <view>{{name}}</view> <! - event - > < view @ tap = "change (index)" > < / view > <! - class binding - > < the view class = "change" : class = "{' has - data: hasData}" > < / view > <! - style binding - > < view: style = "{' color: color, 'the font - size: fontSize}" > < / view > <! - condition judgment - > < view v - if = "flag1" > < / view > < view v - else - if = "flag2" > < / view > < view v - else > < / view > <! <view v-show="isShow"></view> <! <view v-for="(item, index) in array" :key="index"></view> </view> </template>Copy the code

Github Issues: V -for loop list: github Issues: V -for loop list: V -for loop list: V -for loop list

<view v-for="item in array">
    <view>{{ index }}</view>
    <view @tap="tapItem(index)"></view>
</view>
Copy the code

For the above code,

{{index}}
displays the index index normally, but tapItem passes undefined. So we need to display the declaration index v-for=”(item, index) in array”.

12. Form bidirectional binding adjustment

2. In X, v-model is directly used for form binding, without the need to define a function to assign to it. 1.7.2 writing:

<template>
    <input value="{{ name }}" bindtap="setInput" />
</template>
<script>
export default class HOME extends wepy.page {
    data = {
        name: '',
    }
    methods = {
        bindtap(e) {
            this.name = e.detail.value
        }
    }
}
Copy the code

2. X writing:

<template>
    <input v-model="name" />
</template>
<script>
wepy.page({
    data: {
        name: ' ',}})Copy the code

13. Adjust the method of obtaining global data attributes

We sometimes need to define the globalData attribute globalData in app.wpy:

export default class APP extends wepy.app {
    globalData = {
        isBack: false}}Copy the code

In 2.x, the definition method is the same, but the fetch method is changed:

/ / 1.7.2 access the console. The log (this. $parent. GlobalData. IsBack) / / 2 x access the console. The log (this. $app. $options. GlobalData. IsBack)Copy the code

Global styles do not apply to components

2. The implementation of components in x retains many of the features of native applets, such as this one, which is explicitly stated in the component style: Besides inheritance pattern, app. WXSS in style, the style of the components in the page of custom components is invalid (unless you change the component style isolation option), while it is possible by changing component style isolation option enables the components can be global style effect, but sometimes also can bring disadvantages, such as in front of the label attribute class plus ~, It is possible to make components get global styles, but there is a problem with this: the class style defined in the component is invalidated 😭. This kind of update really makes writing styles difficult, so to make writing styles as easy as possible, I’ll just define the component styles in the component, not globally.

15. Component communication no longer supports $broadcast

A parent component can send data to a child component by setting a static or dynamic prop property or by broadcasting $broadcast so that all child components receive the parent component’s message. A child component can send data to a parent component by setting custom events at the parent level and communicating via $emit in the child component. In 2.x, the parent is no longer allowed to broadcast the event to the child component. Instead, the parent can directly manipulate the child component function by adding the ref attribute to the child component, as shown in this.

<template>
    <child ref="child"></child>
</template>
<script>
wepy.page({
    onLoad() {
        this.$refs.child.getList()
    }
})
</script>
Copy the code

Child. Wpy:

<script>
wepy.component({
    methods: {
        getList() {}
    }
})
</script>
Copy the code

Component Prop no longer supports bidirectional binding

In 1.7.2, you can pass parameters to child components by setting a prop. If you add.sync to the prop, the parameters passed to child components will be automatically updated when the parent component parameters are updated. If you add twoWay to the prop of child components: True then the child component data can be bound to the parent component. To achieve bidirectional binding of component data. The functionality is still useful, but unfortunately in 2.x it is no longer supported to bind data from child components to parent components via twoWay: True. Parent to child is possible, but sync is no longer required. The child component needs to update the parent component’s data via a custom event and then updates the parent component’s data via $emit. 1.7.2 Written: Parent page:

<template>
    <child :title.sync="title"></child>
</tempalte>
Copy the code

Child components:

export default class CHILD extends wepy.component {
    props = {
        title: {
            type: String,
            default: '',
            twoWay: true
        }
    }
}
Copy the code

2. X written: Parent page

<template> <child :title="title" @changeTitle="changeTitle"></child> </tempalte> <script> export default class HOME Extends wepy.page {data = {title: ' ',} events = {changeTitle(val) {this.title = val}} </script>Copy the code

Child components:

Wepy. Page ({props: {title: {type: String, default: '',}}, onLoad(){this.$emit('changeTitle', 'changed title ')}})Copy the code

17, Component slot code inserted after hierarchy disorder (pit)

This issue has been mentioned in Github Issues and has been flagged as a bug by the author. Source code: parent.wpy parent page:

<template>
    <view>parent</view>
    <child>
        <view>child view</view>
    </child>
</template>
Copy the code

Child.wpy child component:

<template>
    <view>  
        <view>child</view>
        <slot></slot>
    </view>
</template>
Copy the code

The expected compiled (correct) template is:

<template>
    <view>parent</view>
    <view>
        <view>child</view>
        <view>child view</view>
    </view>
</template>
Copy the code

The actual 2.x compiled template inserts the corresponding content at the level of the child component and root element:

<template>
    <view>parent</view>
    <view>
        <view>child</view>
    </view>
    <view>child view</view>
</template>
Copy the code

For old projects where slot was used, I had to rewrite the code to get around this hole.

18. Adjust the introduction of resources

This section describes how to adjust the importing mode of resources, including importing components and importing images. Let’s start with component introduction:

<config>
{
  usingComponents: {
    'load-more': '/components/loadMore'.// Absolute path
    'btn': '.. /btn'.// Relative path
    'list': '~@/components/list'.// Use wepy.config.js to configure the alias @ to point to SRC, which is actually an absolute path
    'van-icon': 'module:van-icon'.// Module import
  }
}
</config>
Copy the code

For image import, there are two ways: one is static, the program knows which images need to be loaded at compile time, and the other is dynamic, the program only knows which images need to be loaded at run time. For the first method, a relative path, an absolute path, or @ can be introduced into the image:

<template> <view> <image src=".. /bg.png"></image> <image src="/images/icon.png"></image> <image src="@/images/nodata.png"></image> </view> </template>Copy the code

/ SRC /images/static, then wepy.config.js static: / SRC /images/static [‘/ SRC /images/static’] will copy all files in this path to the output directory at compile time, so that the dynamic images can be referenced accurately. Wepy. Config. Js configuration:

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

Page:

<template> <view> <image :src="'.. /images/static/' + fileType + '.png'"></image> <image :src="imgSrc"></image> </view> </template> <script> wepy.page({ data: { imgSrc: '', }, onLoad() { this.imgSrc = '/images/static/icon.png' } }) </script>Copy the code

Special handling of static images: Put them in a separate directory and configure static in wepy.config.js

19. The introduction of.wxss files in SCSS will terminate the compilation process

The following code is a SCSS style page that introduces WXSS files, which will eventually cause the compilation process to terminate.

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

Solutions:

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

20, Special characters in SCSS style will cause compilation error (pit)

The special characters here are also normal requirements, such as the introduction of a font icon, which might have the style content: ‘\6499’, and then cause a compilation error because of the backslash. The solution is to put this special character style in WXSS, and then import another style. The compiler will compile the SCSS style, but WXSS will copy directly to the input directory, not compile, so it can bypass the hole.

<style lang="scss" type="text/scss">
    @import "./btn.scss";
</style>
<style lang="wxss" type="text/wxss">
    .icon-success::after {
        content: '\e8921';
        color: green;
    }
</style>
Copy the code

21. Data binding mechanism adjustment

1.7.2 Data binding with dirty check, using $apply() to update data and re-render the page. In 2.x, Vue Observer was used to implement data binding, leaving $apply() out, but there was a problem. When an array item was updated, the array was updated, but it did not trigger the page to be re-rendered, even if splice was used. However, you can simply copy a reference type and reassign it to trigger the page to be rerendered.

wepy.page({
    data: {
        list: [{
            name: 'aaa'.hasBorder: true}, {name: 'bbb'.hasBorder: false,}},methods: {
        handleClick() {
            this.list[1].hasBorder = true  // The page will not be re-rendered
            this.list.splice(1.1, {  // The page will not be re-rendered
                name: 'bbb'.hasBorder: true,})this.list = [...this.list]  // Shallow copy, so that the reference address of this.list changes, so that the page is re-rendered}}})Copy the code