likes
comments
collection
share

岁寒之松柏:什么!WXS也可以响应事件?

作者站长头像
站长
· 阅读数 13

WXS介绍

WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。需要特别说明的是WXS是运行在小程序的渲染线程(也就是webview中)的脚本文件,语法和JS很像,但是也有些许不同。

WXS语法简介

因为WXS整体和JS(ES5)实在太过相像,就说一下有什么不同吧(踩过的坑::>_<::)

  • WXS中不支持new Date()如果想要获取Date对象要使用getDate()函数函数
  • WXS中不支持new RegExp()如果想要获取RegExp对象要使用getRegExp()函数
  • 类型判断仅支持利用构造器进行类型判断typeof进行部分数据判断
// 构造器判断类型
var number = 10;
console.log( "Number" === number.constructor );

var string = "str";
console.log( "String" === string.constructor );

var boolean = true;
console.log( "Boolean" === boolean.constructor );

var object = {};
console.log( "Object" === object.constructor );

var func = function(){};
console.log( "Function" === func.constructor );

var array = [];
console.log( "Array" === array.constructor );

var date = getDate();
console.log( "Date" === date.constructor );

var regexp = getRegExp();
console.log( "RegExp" === regexp.constructor );

// typeof 区分部分数据类型

var number = 10;
var boolean = true;
var object = {};
var func = function(){};
var array = [];
var date = getDate();
var regexp = getRegExp();

console.log( 'number' === typeof number );
console.log( 'boolean' === typeof boolean );
console.log( 'object' === typeof object );
console.log( 'function' === typeof func );
console.log( 'object' === typeof array );
console.log( 'object' === typeof date );
console.log( 'object' === typeof regexp );

console.log( 'undefined' === typeof undefined );
console.log( 'object' === typeof null );

AppService响应事件的问题

一般情况下,小程序响应事件是指在Wxml中绑定事件然后通过JS文件中的函数响应的,也就是webview(渲染层)的事件是要传到AppService线程中处理,这个过程是跨线程的,很显然有很多情况下,Appservice需要频繁响应webview中事件,并且修改data值,就需要进行大量的跨线程通信,性能自然就会降低。比如如下例子,一个跟随view 跟随另一个view水平移动并且x大于250时进行特殊的业务处理:

岁寒之松柏:什么!WXS也可以响应事件? 使用movable-view组件实现该例子代码如下

<!--wxml文件-->
<movable-area  class="move-area" >

  <movable-view class="move-view" x="{{0}}" y="{{0}}" direction="horizontal" bindchange="handleChange">
    1
  </movable-view>
    <!--需要设置direction属性 否则无法移动-->
  <movable-view class="move-view" animation="{{false}}" x="{{x}}" y="{{y}}" direction="all"  >
    2
  </movable-view>
</movable-area>
//js文件
Page({
  /**
   * 页面的初始数据
   */
  data: {
    x: 0,
    y: 100,
  },
  handleChange(e) {
    if (e.detail.x > 250) {
      wx.showToast({
        title: "业务逻辑",
        icon: "none",
      });
      return;
    }
    this.setData({
      x: e.detail.x,
    });
  },
});

该实现方式的底层调用逻辑

岁寒之松柏:什么!WXS也可以响应事件?

可以看到这个过程会进行大量的setData,而执行setData渲染是会阻塞其他脚本执行。进一步思考一下其实很容易发现问题所在,在对view2设置坐标这个过程中绝大多数的change事件对业务层都是无效,业务层只需要在x大于250时响应事件即可,再就是滑动这个动作本身就是渲染层的事件,把他放到业务层处理本身就是有问题,正确的方式应该是当在渲染层中独自实现view2的跟随滑动,当滑动x大于250时再抛出事件来给到业务层处理。正确的逻辑应该是如下图

岁寒之松柏:什么!WXS也可以响应事件?

要实现如上图所示的逻辑我们就要用到WXS来响应事件。

WXS响应事件

简单使用

先看效果 可以看出来是完全同步的

岁寒之松柏:什么!WXS也可以响应事件?

使用wxs实现代码如下

 <!-- wxml 不需要设置moveable-area -->
<view class="container">
    <!-- 使用双大括号调用wxs函数 -->
    <view
    class="move-view-1" 
    prop={{prop}} 
    prop:change="{{tool.propObserver}}" 
    catchtouchstart="{{tool.handleTouchstart}}" 
    catchtouchmove="{{tool.handleMove}}">
      1
    </view>
    <view class="move-view-2">
      2
    </view>
</view>
<wxs module="tool">
    // WXS 代码
    var moveView2
    module.exports = {
        handleTouchstart:function(event, ownerInstance) {
          // `ownerInstance` 表示的是触发事件的组件所在的组件的 实例,
          //如果触发事件的组件是在页面内的,`ownerInstance` 表示的是页面实例。
          moveView2 = ownerInstance.selectComponent('.move-view-2')
        },
        handleMove: function(event, ownerInstance) {
           
            var x = event.touches[0].pageX
            // 设置move-view-1位置
            //`event.instance` 来表示触发事件的组件的实例
            event.instance.setStyle({
              left: x + "px"
            })
            if(x>250){
              // 第二个参数可以向AppService传值
              ownerInstance.callMethod("handleEvent",{isMore250:true})
              return
            }
            // 如过在组件中 可以通过triggerEvent 触发组件事件 
            // if(x>250){
            //   ownerInstance.triggerEvent("handleEvent",{isMore250:true})
            //   return
            // }
             // 设置move-view-2位置
            moveView2.setStyle({
              left: x + "px"
            })
        },
        // 当业务层的数据变化可以回调此函数
        propObserver: function(newValue, oldValue, ownerInstance, instance) {
             console.log('prop observer', newValue, oldValue)
        }
}
</wxs>
Page({
  /**
   * 页面的初始数据
   */
  data: {
    x: 0,
    y: 100,
  },
  handleEvent(e) {
    wx.showToast({
      title: "业务逻辑",
      icon: "none",
    });
  },
});

代码的简单实现逻辑

  1. 在wxml声明两个view 其中一个view使用双大括号使用wxs响应事件
  2. 在wxs的分别获取到两个view的实例 通过setStyle方法设置view的位置
  3. 当x大于250是通过callMethod调用页面的handleEvent方法
  4. 在js的handleEvent方法中实现业务逻辑

WXS 常用API

岁寒之松柏:什么!WXS也可以响应事件?

引用

WXS响应事件

WXS语法参考