問題描述
在瀏覽器端開發(fā)時(shí)锅睛,經(jīng)常會(huì)有這種情況:?jiǎn)螕裟硞€(gè)元素煌茴,讓其高亮顯示,例如下圖
這個(gè)用 js 很容易實(shí)現(xiàn)双妨, 因?yàn)閱螕羰录|發(fā)時(shí)淮阐,函數(shù)傳入的 event 事件包含 target 對(duì)象,里面會(huì)有觸發(fā)事件的 DOM 元素刁品,我們只需要操作這個(gè) DOM 元素泣特,為其添加 class 名就好了。
而在微信小程序開發(fā)時(shí)挑随,由于其類似于 vue 不建議直接操作 DOM (兩者都有API可以做到)状您,事件觸發(fā)的時(shí)候同樣會(huì)有默認(rèn)參數(shù)傳入, 但是無法直接取到 DOM 節(jié)點(diǎn)本身兜挨,而是包含掛載的一些數(shù)據(jù)膏孟,和點(diǎn)擊部位的坐標(biāo)信息等,具體參閱官方文檔《事件·小程序》 拌汇,this
也總是指向 Page 柒桑,所以我們就需要通過數(shù)據(jù)間接操縱 DOM來實(shí)現(xiàn)。
例如我遇到的問題是担猛,我想做一個(gè)月歷幕垦,當(dāng)你選中某一天的時(shí)候,那一天高亮顯示傅联。
參考解決方案
由于自己在做這一塊時(shí)遇到了很多這方面的困惑先改,所以我在網(wǎng)上看了一些解決方案,下面列舉一種在 CSDN 上看到的方案:
- wxml
<view class="list-wrapper">
<view class="list-top">
<view data-num="1" class="list-menu list-menu1 {{_num==1?'cur':''}}" bindtap="menuClick">頭條</view>
<view data-num="2" class="list-menu list-menu2 {{_num==2?'cur':''}}" bindtap="menuClick">活動(dòng)</view>
<view data-num="3" class="list-menu list-menu3 {{_num==3?'cur':''}}" bindtap="menuClick">公告</view>
</view>
</view>
- js
menuClick:function(e){
this.setData({
_num:e.target.dataset.num
})
},
這個(gè)方法綁定了一個(gè)動(dòng)態(tài)的 class 名蒸走,用一個(gè)變量 _num
可以做到切換 class 的作用仇奶,當(dāng)點(diǎn)擊元素時(shí),js 獲取到節(jié)點(diǎn)上 data-num
上的值比驻,這里將值賦給變量 _num
该溯,相應(yīng)的由于是數(shù)據(jù)驅(qū)動(dòng),節(jié)點(diǎn)上的 class 名經(jīng)過計(jì)算變化為 cur
别惦,其他的同理狈茉。
原始解決方案
在沒有搞清這個(gè)方法前,我制作月歷是使用的條件渲染掸掸。具體做法是氯庆,每個(gè)日期節(jié)點(diǎn)準(zhǔn)備兩個(gè) DOM 元素蹭秋,一個(gè)帶有 class="selected"
,一個(gè)沒有堤撵, 經(jīng)過列表渲染之后每個(gè)單位實(shí)際上存在兩個(gè)邏輯上的元素仁讨,這個(gè)時(shí)候通過點(diǎn)擊改變 Page
中 data
里面的 selectedDate
和 selectedDate
,進(jìn)一步控制 wx:if
的條件來實(shí)現(xiàn)元素的渲染與否实昨。
<!-- 列表渲染 -->
<view wx:for="{{unit.dates}}" wx:key="item.date">
<view wx:if="{{item.date == selectedDate && item.month == selectedMonth}}" class="selected" data-year="{{item.year}}" data-month="{{item.month}}" data-date="{{item.date}}">{{item.date}}</view>
<view wx:else data-year="{{item.year}}" data-month="{{item.month}}" data-date="{{item.date}}">{{item.date}}</view>
</view>
點(diǎn)擊事件發(fā)生時(shí)洞豁,獲取節(jié)點(diǎn)中的 data-month
和 data-date
值, 并賦給 selectedDate
和 selectedDate
由于每個(gè)月都有某些日期荒给, 所以加個(gè)月份限制丈挟,這里我設(shè)置了只做從這個(gè)月到未來6個(gè)月的月歷,所以不需要加年份限制锐墙。
深知這個(gè)方案問題很大礁哄,是這一類的MVVM框架因的條件渲染切換消耗較大,微信小程序開發(fā)文檔中介紹了 wx:if 相關(guān):
wx:if
vshidden
因?yàn)?wx:if
之中的模板也可能包含數(shù)據(jù)綁定溪北,所有當(dāng)wx:if
的條件值切換時(shí)桐绒,框架有一個(gè)局部渲染的過程,因?yàn)樗鼤?huì)確保條件塊在切換時(shí)銷毀或重新渲染之拨。
同時(shí)wx:if
也是惰性的茉继,如果在初始渲染條件為false
,框架什么也不做蚀乔,在條件第一次變成真的時(shí)候才開始局部渲染烁竭。
相比之下,hidden
就簡(jiǎn)單的多吉挣,組件始終會(huì)被渲染派撕,只是簡(jiǎn)單的控制顯示與隱藏。
一般來說睬魂,wx:if
有更高的切換消耗而 hidden 有更高的初始渲染消耗终吼。因此,如果需要頻繁切換的情景下氯哮,用 hidden 更好际跪,如果在運(yùn)行時(shí)條件不大可能改變則wx:if
較好。
當(dāng)用戶點(diǎn)擊某個(gè)日期的時(shí)候會(huì)重新渲染整個(gè) DOM 喉钢,所以這個(gè)方案并不好姆打。
改進(jìn)方案
<view class="day {{item.date > 0 ? '' : 'hidden'}}" wx:for="{{unit.dates}}" wx:key="item.date">
<view wx:if="{{item.date > 0}}">
<view class="{{item.date == selectedDate && item.month == selectedMonth ? 'selected' : ''}}" data-year="{{item.year}}" data-month="{{item.month}}" data-date="{{item.date}}">{{item.date}}</view>
</view>
</view>
搞懂前面的邏輯,再來看這個(gè)方案就會(huì)很明白了肠虽。