说明
在看了官方提供的《小程序开发指南》后,有所疑惑,结合网上查阅看到的以及自己的理解,简单记录一下,欢迎
交流与讨论。
首先来看一下官方指南提供的代码以及我添加的注释
<!--pages/test/test.wxml-->
<!--遍历对象数组objectArray并建立多个开关,开关文本是对象的id值-->
<switch wx:for="{{objectArray}}" wx:key="unique" > {{item.id}} </switch>
<!--建立一个按钮,绑定switch函数(该函数在test.js文件中可见),按钮文本为Switch-->
<button bindtap="switch"> Switch </button>
<!--建立一个按钮,绑定addToFront函数(同在test.js文件中可见),按钮文本为Add to the front -->
<button bindtap="addToFront"> Add to the front </button>
<!--遍历数字数组numberArray并建立多个开关,开关文本是数字的值-->
<switch wx:for="{{numberArray}}" wx:key="*this" > {{item}} </switch>
<!--建立一个按钮,绑定addNumberToFront函数(同在test.js文件中可见),按钮文本为Add Number to the front-->
<button bindtap="addNumberToFront"> Add Number to the front </button>
// pages/test/test.js
Page({
/**
* 页面的初始数据
*/
data: {
// 对象数组,期中每个对象为json格式,即键值对
// 注意此处的unique键名称 在wx:key文件中我们绑定的就是这个键的名称,这个键对应的值在数组中是唯一的(很重要),因此可以通过这个键对应的值,唯一标识数组中的每一个对象。
objectArray: [
{id: 5, unique: 'unique_5'},
{id: 4, unique: 'unique_4'},
{id: 3, unique: 'unique_3'},
{id: 2, unique: 'unique_2'},
{id: 1, unique: 'unique_1'},
{id: 0, unique: 'unique_0'},
],
// 普通的数字数组,默认可以根据index获得item
numberArray: [1, 2, 3, 4]
},
// 该函数被第一个按钮所绑定
switch: function(e) {
// 随机打乱对象数组objectArray的顺序
const length = this.data.objectArray.length
for (let i = 0; i < length; ++i) {
const x = Math.floor(Math.random() * length)
const y = Math.floor(Math.random() * length)
const temp = this.data.objectArray[x]
this.data.objectArray[x] = this.data.objectArray[y]
this.data.objectArray[y] = temp
}
// 将打乱后的对象数组重新赋值,通过setData再一次渲染界面
this.setData({
objectArray: this.data.objectArray
})
},
//被第二个按钮绑定
addToFront: function(e) {
// 在对象数组开头添加一个新的对象
const length = this.data.objectArray.length
this.data.objectArray = [{id: length, unique: 'unique_' + length}].concat(this.data.objectArray)
// 如上,将打乱后的对象数组重新赋值,通过setData再一次渲染界面
this.setData({
objectArray: this.data.objectArray
})
},
// 被第三个按钮所绑定
addNumberToFront: function(e){
// 在普通的数字前面添加一个数字
this.data.numberArray = [ this.data.numberArray.length + 1 ].concat(this.data.numberArray)
// 如上,将打乱后的对象数组重新赋值,通过setData再一次渲染界面
this.setData({
numberArray: this.data.numberArray
})
}
})
看完以上代码和注释后,看看图片进行分析
-
当我们把代码复制到对应的文件下编译后,效果如下
-
当我点击第一个Switch按钮时,上面的开关顺序会被打乱,效果如下
-
当我打开上方 2号、5号按钮后(请记住这两个按钮的位置),效果如下
-
当我再次点击Switch按钮打乱他们的顺序时,效果如下,会发现无论数字2、5跑到哪里,对应的开关就会是打开的状态。
-
这个时候我们再把代码中wx:key="unique"去掉
<!--pages/test/test.wxml-->
<!--去掉wx:key="unique"-->
<switch wx:for="{{objectArray}}"> {{item.id}} </switch>
然后按照如实步骤,重新编译,回到最初始的界面,效果如下
-
再次开启2、5号开关,效果如下
-
再次点击Switch打乱顺序后,效果如下,会发现原本开关2、5的状态并不会跟着数字的变化所改变
以上就是有无wx:key="unique"的差别
- 正如我代码注释中提到的,在有wx:key="unique"时,unique是一个对象的键名称,并且这个键名称对应的值,能够在对象数组中唯一标识出一个对象。个人比较浅显的理解:“在Switch打乱数组对象后,从代码上看,是对象与对象直接发生了数组位置上的互换,但打乱后,需要对界面进行重新的渲染,就会导致,原先属于2、5号位置的开关状态并没有随着顺序的打乱而改变,因此造成了开关状态的错位的视觉效果。本质上来说这是一个重新创建每个开关的过程,但当我们使用了了wx:key="unique"后,每一个开关就和对象数组objectArray中的对象绑定在了一起,当这个对象数组被打乱后,开关也会随着这个对象被打乱,因此开关的状态就跟随对象的位置一起变化了。”
关于使用第二个按钮进行插入开关
- 因为这个插入开关是在前面插入,本质上也是一种顺序的打乱,如果按照上面的操作,有无wx:key="unique"的的差别也和上面的效果是一样的,这里就不放图了。
关于wx:key="*this"的用法
- 这种用法演示出来的效果同上,即卡关状态会不会随着数字的变化而变化。那为什么要有这种形式呢?
- 我的理解是,当你数组中的item是一个数字或者是字符串时,并不存在什么键名称用于wx:key的绑定,因此,采用*this表示这个item本身,这样就可以唯一识别数组中的每一个item了,从而达到以上的效果。