【antdesign select】下拉選擇-帶選擇序號

Ugine_H發表於2020-04-17

需求:下拉框在選中時能夠在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、和禁止選擇的樣式。

而對於選中事件,需要考慮的點相對複雜些。

  1. Antdesign的原生下拉元件,在點選選中時可以控制是否清空輸入框的輸入內容(不好實現)
  2. 點選項原本為選中,再次點選時就是取消點選
  3. 選中時更新下拉框的value,否則下拉選單和下拉框的選中項會不一致
  4. 選中後是否啟用禁用

遇到的問題:

問題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('')
    }

 

相關文章