sjs Event Handling
Background
In Mini Programs, there can be some performance issues when frequently interacting with users. For example, if a page contains two elements, A and B, and the user performs a touchmove gesture on A, requiring B to follow the movement of A. The response process for a single touchmove event is as follows:
- The touchmove event is sent from the view layer (Webview) to the logic layer (App Service).
- The logic layer (App Service) processes the touchmove event and changes the position of B using setData.
The response to a touchmove event involves two rounds of communication between the logic and rendering layers, as well as one rendering operation. Communication consumes a significant amount of time. Additionally, the rendering performed by setData can block other script execution, resulting in delays in the overall user interaction animation.
Implementation Approach
The basic idea of this approach is to reduce the number of communications and make events respond in the view layer (Webview). Mini Programs are divided into view layers (Webview) and logic layers (App Service). This layered structure is designed for management purposes, where developer code can only run in the logic layer (App Service). However, this approach requires developer code to run in the view layer (Webview), as shown in the following diagram:
The sjs
function is used to respond to Mini Program events. Currently, it can only respond to events from built-in components and does not support events from custom components. The sjs
function can handle pure logical operations and can also access and set component classes and styles using the pre-packaged ComponentDescriptor
instance. For interactive animations, setting styles and classes is sufficient. Here's an example of an sjs
function:
var sjsFunction = function (event, ownerInstance) {
var instance = ownerInstance.selectComponent(".classSelector"); // Returns the component instance
instance.setStyle({
"font-size": "14px",
});
instance.getDataset();
instance.setClass(className);
// ...
return false; // Does not propagate upward, equivalent to calling stopPropagation and preventDefault simultaneously
};
The event
parameter is an extension of the Mini Program event object with an additional event.instance
to indicate the ComponentDescriptor
instance of the component that triggered the event. The ownerInstance
parameter represents the ComponentDescriptor
instance of the component where the event was triggered. If the component triggering the event is on a page, ownerInstance
represents the page instance.
Here's the definition of ComponentDescriptor
:
Method | Parameters | Description |
---|---|---|
selectComponent | selector object | Returns a ComponentDescriptor instance of the component. |
setStyle | Object/string | Sets the component's style. Styles set here have higher priority than those defined in the component's DLT. Cannot set styles for the top-level page. |
addClass/removeClass/hasClass | string | Sets the component's class. Classes set here have higher priority than those defined in the component's DLT. Cannot set classes for the top-level page. |
getDataSet | None | Returns the dataset object of the current component/page. |
callMethod | (funcName: string, args: object) | Calls functions defined in the logic layer (App Service) for the current component/page. funcName represents the function name, and args represents the function's parameters. |
requestAnimationFrame | Function | Same as the native requestAnimationFrame. Used to set animations. |
getComputedStyle | Array.<string> | Parameters are consistent with SelectorQuery's computedStyle. |
setTimeout | (Function, Number) | Same as the native setTimeout. Used to create timers. |
clearTimeout | Number | Same as the native clearTimeout. Used to clear timers. |
getBoundingClientRect | None | Returns a value consistent with SelectorQuery's boundingClientRect. |
sjs
runs in the view layer (Webview), where the available events are limited. Therefore, there needs to be a mechanism to communicate with developer code in the logic layer (App Service). The callMethod
method mentioned above allows sjs
to call developer code in the logic layer (App Service).
How to Use
- Define an event with
dlt
<import-sjs module="test" src="./test.sjs"></import-sjs>
<view bind:touchmove="{{test.touchmove}}" class="movable"></view>
Note: The sjs
function must be enclosed in {{}}
.
- In the
test.sjs
file, define and export event handling functions and functions triggered by property changes:
export default {
touchmove: function (event, instance) {
var touch = event.touches[0] || event.changedTouches[0];
var pageX = touch.pageX;
var pageY = touch.pageY;
var left = pageX - startX + lastLeft;
var top = pageY - startY + lastTop;
startX = pageX;
startY = pageY;
lastLeft = left;
lastTop = top;
ins.selectComponent(".movable").setStyle({
left: left + "px",
top: top + "px",
});
},
};