今天,就想和各位說說微信小程式中的【臂膀】——
wx-key
。
毫無疑問,wx-key在微信小程式中可謂是“大出風頭”,這一點尤其在for循環中展現出來。但wx-key的作用,你真的了解嗎?
事實上,作為“唯一辨別”,微信小程式也極力提倡在一些元件中使用
我們先來寫一個簡單的list清單:
//wxml
<block wx:for="{{arr}}">
<view>{{item}}</view>
</block>
//js-data
data:{
arr:['wxml','js','wxss','json']
},
現在,我們給它加上索引:
//wxml
<block wx:for="{{arr}}">
<view>{{index}}-{{item}}</view>
</block>
微信小程式for循環預設每一項是一個“item”,預設每一項的索引為“index”。
當然,也可以通過
wx:for-item
重新設定(每一項的名稱)。
上面是wx-for循環的使用,
為了更好的展示wx:key的作用,我們給每一項前面加個【複選框】,并增加一個button按鈕用來對list進行“随機排序”:
//wxml
<block wx:for="{{arr}}" wx:for-item="data">
<view><checkbox />{{data}}</view>
</block>
<button bindtap="sort">随機排序</button>
//js-随機排序代碼(本文所有“随機排序”皆用此代碼)
sort(){
const len=this.data.arr.length
for(let i in this.data.arr){
let x=Math.floor(Math.random()*len)
let y=Math.floor(Math.random()*len)
let temp=this.data.arr[x]
this.data.arr[x]=this.data.arr[y]
this.data.arr[y]=temp
}
this.setData({
arr:this.data.arr
})
},
重點來了,現在我随機勾選兩項,然後按下button按鈕:
我們會“驚恐”的發現:不管怎樣,選中的都是“第二項”和“第四項”;但顯然,我們希望選中的隻是最開始“第二項”和“第四項”對應的資料!
其實,這無疑是“資料優先”的一個特點:從始至終我們都在操控資料,而無關結構
當然,這也是wx:key的作用之一:
正式篇:wx:key的解析
可能有的初學者會發現,有的地方完全“沒必要”加上wx:key,而有的地方卻必須要用?
這是【資料項是否發生變化】的差別。
所謂key —— 鑰匙。正如“一把鑰匙對應一把鎖”。當一個資料項需要保證(持)他自己的【特征】,或者說【狀态】時,才需要為其添加“key屬性”。
我們改寫一下上面的代碼:
//wxml
<block wx:for="{{arr}}" wx:for-item="data" wx:key="{{index}}">
<view><checkbox />{{data}}</view>
</block>
<button bindtap="sort">随機排序</button>
前面說過,微信中for循環預設每一項“下标”用index顯示。
然後我們會發現:毫無作用。
是key壞了麼?
還是不應該加index?
但是不是說為每一項加一個“唯一辨別”就行麼,難道下标不是?
其實還真不行:“前面說了,for循環索引是index” —— 壞就壞在這句話上:索引本來就是“不變的”啊。
這麼說吧:比如這裡的arr數組,索引永遠是0、1、2、3,哪怕元素改變了,下标卻并不“被攜帶”。
這有點像什麼呢?
“索引是數組為元素(位置)定下的索引,而不是元素的索引”
遇見這種情況我們就需要用到另一個關鍵字 ——
*this
,用于小程式的for循環中,作為“指針”指向每一項自身:
//wxml
<block wx:for="{{arr}}" wx:for-item="data" wx:key="*this">
<view><checkbox />{{data}}</view>
</block>
<button bindtap="sort">随機排序</button>
現在就可以了!
由此可見:key屬性必須是“關乎資料項自身的”、“獨一無二的”。
我們不妨來看另一種情況,把資料變“複雜”一些:
//js-data
data:{
arr:[{
id:1,
name:'wxml'
},{
id:2,
name:'js'
},{
id:3,
name:'wxss'
},{
id:4,
name:'json'
}]
},
好吧,現在又回到“解放前”。
不過有了上面的經驗,我們知道:這是key不到位的緣故;
但現在資料項變成了一個一個的對象了,還能和以前一樣嗎?
//wxml
<block wx:for="{{arr}}" wx:for-item="data" wx:key="{{id}}">
<view><checkbox />{{data}}</view>
</block>
<button bindtap="sort">随機排序</button>