需求:下拉框在選中時能夠在check-icon後面顯示當前選中項的排序,以及當超過最大可選數時不允許繼續選中。
在Antdesign組件裏好像沒有控制可選數的option,這點真的讓人很奇怪誒~還得自己在onchange裏寫邏輯來控制。
一開始我能想到的簡單思路是:
1.通過在屬性options裏面塞個icon,自定義選項的展示
2.通過操作渲染好的下拉列表裏的dom元素
實踐後發現上述的都不太可行,最後只能採用了自定義下拉框內容(dropdownRender屬性)來實現。
放一下代碼template
<template #dropdownRender="{list}">
<v-nodes :vnodes="list" />
<a-list :locale="{emptyText: notFoundContent}" @mousedown.prevent>
<li
v-for="item in filteredDataSource"
:key="item.id"
:value="item.id"
class="sort-select-list-item"
:class="{'disabled':item.disabled,'selected':item.selected}"
@click="handleClickItem(item)"
@mouseenter="handleMouseEnterItem(item)"
@mouseleave="handleMouseLeaveItem(item)"
>
{{ item.name }}
<a-icon v-if="item.selected" class=" check-icon check-icon-selected" type="check" />
<a-icon v-else v-show="item.hovered && !item.disabled" class=" check-icon check-icon-hovered" type="check" />
<span v-if="item.selected" :class="{'check-order-circle': item.selected}" class="check-icon-selected">
<span class=" check-order ">{{ item.order }}</span>
</span>
<span v-else v-show="item.hovered && !item.disabled" class="check-order-circle-hovered check-icon-hovered">
<span class=" check-order ">{{ item.order }}</span>
</span>
</li>
</a-list>
</template>
可以看到,實際上就是自定義下拉框用了個list組件,並且通過狀態屬性disabled、selected、hovered來控制這些選項的樣式。
這樣子改寫了antdesign的下拉列表展示後,就得重新寫一遍樣式和交互,才能保持和原有樣式一致。
現在說一下思路:
調用這個組件
傳入屬性:dataSource
獲取到dataSource後,不會直接用來渲染模板。需要處理成新的dataSource,給它添加些基礎狀態屬性。
// 新的dataSource(接收prop,添加相關屬性後的dataSource,主要用於數據處理)
get newDataSource() {
const data: any = this.dataSource.map((item: any) => {
return {
...item,
selected: false,
disabled: false,
hovered: false,
order: 1
}
})
this.filteredDataSource = data
return data
}
這裏還有個filteredDataSource變量,在上一張圖可以看到,實際模板最後渲染的list數據是來自filteredDataSource的。
這個就是爲了允許這個下拉框可以有搜索功能。
結合Antdesign的原生下拉組件中的search事件來實現
// 搜索匹配相應的信息
handleSearch(value: any) {
if (value) {
this.filteredDataSource = this.newDataSource.filter((item: any) => {
if (item.name.includes(value))
return true
})
} else {
this.filteredDataSource = this.newDataSource
}
}
之後就是針對鼠標事件(點擊、移入、移除)來修改對應的狀態屬性值,從而實現選中、hovered、和禁止選擇的樣式。
而對於選中事件,需要考慮的點相對複雜些。
- Antdesign的原生下拉組件,在點擊選中時可以控制是否清空輸入框的輸入內容(不好實現)
- 點擊項原本爲選中,再次點擊時就是取消點擊
- 選中時更新下拉框的value,否則下拉列表和下拉框的選中項會不一致
- 選中後是否啓用禁用
遇到的問題:
問題1.當鼠標點擊下拉框,下拉列表出現,然後快速hover到列表項時會出現下拉列表抖動的問題,這我就很奇怪了,發現在這個過程中下拉列表漸現漸隱的動畫執行了兩遍。
之所以會被執行兩次,我猜測了下:應該是在這個hover過程中,我對下拉列表的hover列表項的狀態屬性修改了,對應的列表項時會有選中樣式以及序號icon,就導致下拉列表重新渲染,與此同時動畫執行了一半。又被重新執行了。
一開始是思考:
1.看看在hover事件時延時賦值,但這就導致整體功能看起來有卡頓延時。
2.在下拉框剛點擊的幾秒內不允許hover,但這樣代碼上,每個列表項就需要判斷什麼時候是下拉框點擊的幾秒內。不太知道怎麼來判斷
最後嘗試性打印了antdesign的下拉框元素,神奇的發現有個控制動畫的屬性,於是思考能否將這個值置爲空,成功解決了這個問題。
問題2.當下拉框允許搜索且鍵入了搜索關鍵字後,下拉列表項被過濾展示後,點擊選中任一下拉項後,搜索框的內容沒有被清空。
在antdesign下拉組件中是有這個屬性的設置,可以用於是否自動清空搜索框的。
// 如果允許清空,清空輸入框輸入的內容(todo)
if (this.autoClearSearchValue) {
(this.$refs.sortSelect as any).$children[0].$children[0].setInputValue('')
}