Respond to Events with WXS

Start from base library version 2.4.4. Please remaining backward compatible.

Background

Frequent user interactions can cause stutters of a Mini Program. For example, A and B are two elements on the page. When the user makes a touchmove gesture on A, B is required to follow A to move. movable-view is a typical example. The response process for a touchmove event is as follows.

a. A touchmove event is thrown from the view layer (Webview) to the logical layer (App Service);

b. The touchmove event is handled at the logic layer (App Service), and then the position of B is changed through setData.

A response to touchmove involves two rounds of communication between the logic layer and rendering layer, as well as a rendering. The time-consumed communication and setData rendering that blocks the execution of other scripts cause delays of the interactive animations.

Implementation of Solution

The solution is about reducing the number of communication rounds to respond to the event at the view layer (Webview). The framework of a Mini Program is divided into view layer (Webview) and logic layer (App Service) for better control. Developer's code can only run at the logic layer (Webview), but the solution requires that the code run at the view layer (App Service) instead, as shown below:

WXS function can only be used to respond to the events of built-in components of a Mini Program and does not support custom component events. In addition to purely logic operations, WXS function can also access and set the class and style of a component through the encapsulated ComponentDescriptor instance. Setting style and class is sufficient for interactive animations. The following is an example of WXS function:

var wxsFunction = function(event, ownerInstance) {
    var instance = ownerInstance.selectComponent('.classSelector') // Returns the instance of the component
    instance.setStyle({
        "font-size": "14px" // rpx is supported
    })
    instance.getDataset()
    instance.setClass(className)
    // ...
    return false // The event does not bubble (is not propagated to the parent node), which means both stopPropagation and preventDefault are called.
}

For the input parameter event, the event.instance parameter is added to the event objects of Mini Program to indicate the ComponentDescriptor instance of the component triggering the event. ownerInstance represents the ComponentDescriptor instance of the component where the component triggering the event resides. If the component triggering the event is inside the page, ownerInstance indicates a page instance.

The definition of ComponentDescriptor is as follows:

Method Parameter Description
selectComponent "selector" object Returns ComponentDescriptor instance of the component
selectAllComponents "selector" object array Returns the array of ComponentDescriptor instances of the component
setStyle Object/string Sets the component style (rpx is supported). The style set has priority over that defined in the component wxml. It does not support setting the style of the topmost page.
addClass/removeClass/ hasClass string Sets the component class. The class set has priority over that defined in the component wxml. It does not support setting the class of the topmost page.
getDataset None Returns the dataset object of the current component/page
callMethod (funcName:string, args:object) Calls the function defined by the current component/page at the logic layer (App Service). funcName indicates the function name and args the function's parameters.
requestAnimationFrame Function Sets animation, same as the native requestAnimationFrame.
getState None Returns an object. It is used when a local variable needs to be stored for subsequent use.
triggerEvent (eventName, detail) Same as triggerEvent of component

WXS runs at the view layer (Webview), where fewer events can be handled. Therefore, a mechanism is needed to communicate with the developer's code at the logic layer (App Service). The callMethod is a method in WXS that calls the developer's code at logic layer (App Service), and WxsPropObserver is the mechanism by which the developer's code at logic layer (App Service) calls the WXS logic.

Usage

  • Define events using WXML
<wxs module="test" src="./test.wxs"></wxs>
<view change:prop="{{test.propObserver}}" prop="{{propValue}}" bindtouchmove="{{test.touchmove}}" class="movable"></view>

The change:prop above (a property prefixed by change:) triggers the WXS function when the prop value is set, and its value must be enclosed with {{}}. Similar to the "observer" in Component-defined properties, setData({propValue: newValue}) will trigger the WXS function once being called.

Note: The WXS function must be enclosed with {{}} and is triggered once the prop value is set, rather than just when the value is changed. Therefore, the WxsPropObserver function is called when the page is initialized.

  • The event handler and the functions triggered when properties are changed are defined in and exported from the WXS file test.wxs:
module.exports = {
    touchmove: function(event, instance) {
        console.log('log event', JSON.stringify(event))
    },
    propObserver: function(newValue, oldValue, ownerInstance, instance) {
        console.log('prop observer', newValue, oldValue)
    }
}

For more examples, see Preview with Developer Tool.

Tips

  1. Events of native components and the bindinput event of input and textarea components are not supported.
  2. Weixin DevTools 1.02.1901170 or above supports interactive animations. The minimum version of base library is 2.4.4.
  3. Only console.log is supported for log location in the WXS function. Note that consecutive duplicate logs will be filtered out.