avatar

目录
微信小程序计算属性的实现

一、相关技术背景

小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。小程序并非凭空冒出来的一个概念。当微信中的 WebView 逐渐成为移动 Web 的一个重要入口时,微信就有相关的 JS API 了,通过暴露微信的接口使得 Web 开发者能够拥有更多的能力。
小程序的主要开发语言是 JavaScript、WXSS样式、WXMl模板,小程序的开发同普通的网页开发相比有很大的相似性。网页编程采用的是 HTML + CSS + JS 这样的组合,其中 HTML 是用来描述当前这个页面的结构,CSS 用来描述页面的样子,JS 通常是用来处理这个页面和用户的交互。同样道理,在小程序中也有同样的角色,其中 WXML 充当的就是类似 HTML 的角色,WXSS充当的就是类似 CSS的角色。其次,微信小程序中还有JSON配置文件,SON 是一种数据格式,并不是编程语言,在小程序中,JSON扮演的静态配置的角色。它能通过配置改变项目和各个页面的表现。

二、WXML模版语法缺陷

原生的WXML模板语法能实现将JavaScript中的逻辑状态绑定到WXML模板中,当状态改变时,模板中会自动更新数据,将最新状态展示给用户。但是,在WXML模板语法中,插入变量的双括号内只能进行简单的运算:三元运算、算术运算、逻辑判断等。

html
1
2
3
<view hidden="{{flag ? true : false}}"> Hidden </view>
<view> {{a + b}} + {{c}} + d </view>
<view wx:if="{{length > 5}}"> </view>

某个状态需要经过稍复杂的计算处理再展示,那原生的WXML模板语法就实现不了。比如下面这个常见需求:一个用户可以搜索的列表;
html
1
2
3
4
5
6
7
<!-- WXML代码 -->
<view class="test-component">
<input placeholder="请搜索" bindinput="search" />
<view class="list">
<view class="list-item" wx:for="{{list}}" wx:key="{{item}}">{{item}}</view>
</view>
</view>

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// JavaScript代码
Component({
/**
* Component initial data
* searchValue 搜索值
* list 列表数据
*/
data: {
searchValue: '',
list: ['apple', 'banana', 'orange', 'pear'],
},

// Component methods
methods: {
// 搜索
search: function (event) {
this.setData({ searchValue: event.detail.value });
},
}
})

此时,列表只是展示了所有数据。如果要加入搜索框的搜索功能,则需要在WXML模板中加入列表筛选逻辑:
html
1
<view class="list-item" wx:for="{{list.map(item => item.indexOf(searchValue) >= 0)}}" wx:key="{{item}}">{{item}}</view>

但是,WXML模板只支持简单运算,并不支持map, indexOf语法,微信小程序开发者工具会报错:bad attr。

三、computed函数的实现

  1. 流程图
    1.png
  2. 代码实现
    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    // 暂时存储
    let computedHandle = null;

    function computed(context, computedFuncs) {
    // 代理对象,监听取值和赋值
    const handlerObj = {};
    context.data = new Proxy(context.data, {
    get: function(obj, prop) {
    if (computedHandle) {
    if (!handlerObj[prop]) {
    handlerObj[prop] = [];
    }
    handlerObj[prop].push(computedHandle)
    }
    return obj[prop];
    },
    set: function(obj, prop, value) {
    if (obj[prop] === value) return;

    if (handlerObj[prop].length > 0) {
    // 用 setTimeout 延时更新
    setTimeout(() => {
    handlerObj[prop].forEach(handle => handle())
    }, 0);
    }
    obj[prop] = value;
    }
    });

    // 添加各个计算属性所依赖的原始data中的状态
    const computedObj = {};
    Object.keys(computedFuncs).forEach(prop => {
    computedHandle = function() {
    context.setData({
    [prop]: computedFuncs[prop].call(context)
    })
    };
    computedObj[prop] = computedFuncs[prop].call(context);
    computedHandle = null;
    }, {})
    context.setData(computedObj)
    }

    export default computed;

四、computed工具函数的使用

以上面的可搜索列表为例:

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 1. 引入computed函数
import computed from '../utils/computed.js';

Component({
/**
* Component initial data
* searchValue 搜索值
* list 列表数据
*/
data: {
searchValue: '',
list: ['apple', 'banana', 'orange', 'pear'],
},

// 声明周期函数
lifetimes: {
/**
* showList 经过用户搜索值筛选过的列表数据
*/
attached: function () {
// 2. 执行computed函数,传入页面对象和计算属性,就可以直接在WXML模版中使用相关计算属性的变量
computed(this, {
showList: this.list.map(item => item.indexOf(this.searchValue) >= 0)
});
}
},

// Component methods
methods: {
// 搜索
search: function (event) {
this.setData({ searchValue: event.detail.value });
},
},
})

文章作者: 盛顺炎
文章链接: https://www.shengshunyan.xyz/2019/11/20/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7%E7%9A%84%E5%AE%9E%E7%8E%B0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 果实的技术分享
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论