评论

高阶性能渲染-wxs

有时是否感觉到经常接口返回数据不符合而需要自己通过遍历然后修改数据,感到烦恼? 有时是否感觉到做一个拖拽时间,老是感觉到卡卡顿顿的,感到无能无力? 没事这篇文章主要讲解wxs,就是解决上面2个问题的

我们永远没有资格说放弃,因为这是属于我们的年华,应该开出耀眼的繁花。

这里主要讲解两点使用方式

  • wxs --> 数据处理使用
  • wxs --> 拖拽使用

wxs介绍

  • 1.先看看官方如何介绍的 ,如下 点我可以查看更多官方文档地址
    • WXS 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。
    • WXS 与 JavaScript 是不同的语言,有自己的语法,并不和 JavaScript 一致。
    • WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序提供的API。
    • WXS 函数不能作为组件的事件回调。
    • 由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异。
    1. 总的来说,我主要看中它快和方便 (有种在wxml写函数的感觉),并且处理函数内容后渲染不需要去调用setData,可以节省在请求数据返回后写大量的逻辑函数或者遍历方法去处理事务,所以我才拿出来讲解。

wxs数据处理使用

  • 使用我习惯现在utils文件夹里创建一个common.wxs,然后在使用的wxml引入该文件。具体使用也很简单,如下
    1. 在你定义的common.wxs文件里,写你需要处理的函数,然后使用export导出
      var getMax = function(array) {
      var max = undefined;
      for (var i = 0; i < array.length; ++i) {
        max = max === undefined ?
          array[i] :
          (max >= array[i] ? max : array[i]);
      }
      return max;
    }
    
    module.exports = {
      getMax: getMax
    };
    
    1. 在.wxml文件需要的地方引入该.wxs文件,其中<wxs>标签包含2个重要属性,modulesrc<br>
      module表示你要导出wxs的方法集合,在wxml里面可以使用该方法名去使用具体的函数<br>
      src表示你.wxs路径位置引入,代码如下
<wxs module="common" src="../../utils/common.wxs"></wxs>
<view>
  <text>{{common.getMax(arrNumber)}}</text>
</view>

上面代码里arrNumber是你页面.js文件里面定义的数据

data: {
    arrNumber: [1,2,9,2,1,5,7]
  }

就是如此简单,你已经学会了使用wxs处理数据了,接下来我们来点难的,使用wxs做一个可以随便拖动又不影响小程序性能的手势拖拽事件

wxs拖拽使用

  • 你是否还在使用setData控制元素?为什么不能频繁使用setData,点我查看详情然后通过输出手势坐标来移动元素具体位置?如果是建议你该换个方法了,推荐使用wxs,让你小程序性能上一个档次。
  • 解决思路如下:
    1. 我们先在页面的.wxml文件书写初始化的样式内容;
    2. view标签绑定手势事件,其中touchmove我使用了阻止冒泡事件绑定是为了防止在苹果机中,元素移动会带着屏幕一起移动,导致滑动手势突然中断不流畅, clickLive事件我也用了阻止冒泡事件是为了触发子元素的事件防止点击被父元素拦截而使用,代码如下:
<wxs module="comm" src="../../utils/common.wxs"></wxs>
<view class="enterLive liveMove"
    data-maxWidth="{{windowWidth}}" data-maxHeight="{{windowHeight}}"
    bind:touchstart="{{comm.liveTouchmove}}" catch:touchmove="{{comm.liveTouchmove}}" bind:touchend="{{comm.liveTouchmove}}">
    <view class="live-block" catch:tap="{{comm.clickLive}}">
        <image class="liveEnter-img"  mode="aspectFit" src="https://img0.baidu.com/it/u=401284325,23907343&fm=26&fmt=auto&gp=0.jpg" />
    </view>
</view>
  1. 我们发现上面的代码有windowWidth,windowHeight两个参数,这是在页面的.js中,是计算当前页面的宽高,用于防止滑块滑出视野范围内,导致无法滑动回来,其中下面代码getApp().globalData.systemInfo是读取全局文件app.js里面拿值的,那里我有获取系统参数设为全局保存, bindEnter事件是用于待会在.wxs里面可以触发.js文件内函数示例
data: {
  windowWidth: 375,
  windowHeight: 667,
},
ready: function() {
  let systemInfo = getApp().globalData.systemInfo;
  let width = 150 * systemInfo.windowWidth / 750;
  let height = 150 * systemInfo.windowWidth / 750;
  if (systemInfo) {
    this.setData({
      windowWidth: systemInfo.windowWidth - parseInt(width),
      windowHeight: systemInfo.windowHeight - parseInt(height)
    })
  }
},
bindEnter(e) {
    wx.showToast({
      title: '你点击到我啦~',
      icon: 'none'
    })
},
  1. 接下来我们将书写.wxs文件,处理手势输出内容,使页面的滑块可以平静的滑动;
    • 认真看的同学会发现页面的touchstart,touchmove,touchend事件我都是绑定同一个函数liveTouchmove这里是我想节约函数名称,统一使用一个函数,然后在输出的回调里面判断当前是什么手势
    • 这里的滑块滑动逻辑是:当输出是touchstart手势时,我们记住当前滑块的starLeft,starTop值及坐标starX,starY
    • 当我们判断当前是touchmove手势时,我们就用当前的x,y坐标值减去开始starX和starY坐标值,得到一个差值diffX,diffY
    • 然后我们使用这个diffX,diffY差值分别加上滑块刚开始的starLeft,starTop值,即可得到我们滑块当前移动的位置
    • 最后我们通过条件判断当前是否超出屏幕即可,我这里做多一步,就是滑块永远停留左右两边,所以要多算一次滑块停留是偏离那一边,在通过ownerInstance.selectComponent('.liveMove').setStyle可以给页面元素添加行内样式。 滑动滑动逻辑已经讲完了,就是这么简单
  • 如果你想通过.wxs函数触发.js文件内的函数,这里有提供ownerInstance.callMethod("bindEnter")方法给你触发.js里面的函数,其中ownerInstance是绑定页面函数的第二个回调参数,callMethod是官方提供的一个方法,bindEnter是.js文件里自己命名的函数方法名称,整体代码如下:更多wxs内置方法,请查看官方文档
/**
 * 滑块计算位置
 */
var starLeft = 0;
var starTop = 0;
var starX = 0;
var starY = 0;
function liveTouchmove(event, ownerInstance) {
    // console.log(JSON.stringify(event))
    // console.log(JSON.stringify(ownerInstance))
    var left = 0, top = 0;
    var diffX = 0, diffY = 0;
    if(event.type === 'touchstart') {
        starLeft = event.currentTarget.offsetLeft;
        starTop = event.currentTarget.offsetTop;
        starX = event.changedTouches[0].clientX;
        starY = event.changedTouches[0].clientY;
        left = starLeft; top = starTop;
    } else {
        diffX = event.changedTouches[0].clientX - starX;
        diffY = event.changedTouches[0].clientY - starY;
        left = starLeft + diffX;
        top = starTop + diffY;
        var maxWidth = event.currentTarget.dataset.maxwidth;
        var maxHeight = event.currentTarget.dataset.maxheight;
        if (left > maxWidth) { left = maxWidth; }
        if (top > maxHeight) { top = maxHeight; }
        if (left <= 0) { left = 0; }
        if (top <= 0) { top = 0; }
    }
    if (event.type === 'touchend') {
        if (maxWidth / 2 < left) {
            left = "calc(100% - 3% - 152rpx)";
        }
        if (maxWidth / 2 > left) {
            left = '3%';
        }
    } else {
        left = left + 'px';
    }
    var instance = ownerInstance.selectComponent('.liveMove'); // 返回组件的实例
    
    instance.setStyle({
        left: left,
        top: top +'px',
    });
}

/**
 * 点击直播入口
 * @param 
 */
function clickLive (event, ownerInstance) {
    ownerInstance.callMethod("bindEnter");
}
module.exports = {
  liveTouchmove: liveTouchmove,
  clickLive: clickLive,
};

总结

  • wxs确实可以解决我们一些性能问题,和wxml函数调用方便,但是我们也要注意几个问题
    1. 目前还不支持原生组件的事件、input和textarea组件的 bindinput 事件
    1. 1.02.1901170及以后版本的开发者工具上支持交互动画,最低版本基础库是2.4.4
    1. 目前在WXS函数里面仅支持console.log方式打日志定位问题,注意连续的重复日志会被过滤掉。
    1. wxs有自己的语法,我理解为不支持ES6及以上语法更多wxs语法可以查看官方文档
  • 以上内容,包括之前写的文章内容,最终会上传到我的gitee里面,请留意。

文章创作不易,喜欢的记得点赞

本文同步掘金号文章 喜欢的记得去点个赞哦

最后一次编辑于  2021-07-11  
点赞 9
收藏
评论

1 个评论

  • admin
    admin
    2021-07-15

    不明觉厉

    2021-07-15
    赞同
    回复 1
    • 哈罗哈皮
      哈罗哈皮
      2021-07-15
      那就先点赞为敬
      2021-07-15
      回复
登录 后发表内容