Element分析(組件篇)——FilterPanel

filter-panel是專門針對篩選器寫的一個組件,最外面是一個el-zoom-in-toptransition,然后內(nèi)部根據(jù)是否可以多選分為兩個部分,多選部分用 checkbox 來實現(xiàn),單選部分直接用 list 來實現(xiàn)。

<transition name="el-zoom-in-top">
  <div class="el-table-filter" v-if="multiple" v-show="showPopper">
    ...
  </div>
  
  <div class="el-table-filter" v-else v-show="showPopper">
    ...
  </div>
</transition>

其中 multiple 是根據(jù)列的 filterMultiple 來設置的。

因為要實現(xiàn) popper 的效果,因此 mixin 中加入了 Popper 這一 mixin,其初始化在 mounted 這一生命周期中:

mounted() {
  // 自身掛載元素作為 popper
  this.popperElm = this.$el;
  // 對應的表頭的單元格作為 reference
  this.referenceElm = this.cell;
  // 表主題滾動的時候,重新計算 popper
  this.table.bodyWrapper.addEventListener('scroll', () => {
    this.updatePopper();
  });

  // 處理 popper 的開關(guān)
  this.$watch('showPopper', (value) => {
    if (this.column) this.column.filterOpened = value;
    if (value) {
      Dropdown.open(this);
    } else {
      Dropdown.close(this);
    }
  });
}

其中 Dropdown 是抽象出來為了處理開關(guān) popper 的。

import Vue from 'vue';
// 存儲打開的 dropdown
var dropdowns = [];

/**
 * 處理點擊事件,如果不是點擊在 dropdown 就關(guān)閉
 * @param event 點擊事件
 * @return
 */
!Vue.prototype.$isServer && document.addEventListener('click', function(event) {
  // 對每一個打開的 dropdown 進行判斷
  dropdowns.forEach(function(dropdown) {
    // 觸發(fā)事件的元素
    var target = event.target;
    // 如果不存在對應的 dropdown,或者沒有掛載元素,直接返回
    if (!dropdown || !dropdown.$el) return;
    // 如果點擊在 dropdown,或者它的內(nèi)部也直接返回
    if (target === dropdown.$el || dropdown.$el.contains(target)) {
      return;
    }
    // 其他情況就調(diào)用相應的 handleOutsideClick 函數(shù)
    dropdown.handleOutsideClick && dropdown.handleOutsideClick(event);
  });
});

export default {
  // 打開,push 進數(shù)組
  open(instance) {
    if (instance) {
      dropdowns.push(instance);
    }
  },

  // 關(guān)閉,從數(shù)組中移出
  close(instance) {
    var index = dropdowns.indexOf(instance);
    if (index !== -1) {
      dropdowns.splice(instance, 1);
    }
  }
};

多選

多選部分的實現(xiàn),就是一個 checkbox-group,實現(xiàn)較為簡單,重點講解一下,各種數(shù)據(jù)是如何獲得的。

<div class="el-table-filter" v-if="multiple" v-show="showPopper">
  <!-- 多選部分 -->
  <div class="el-table-filter__content">
    <el-checkbox-group class="el-table-filter__checkbox-group" v-model="filteredValue">
      <el-checkbox
        v-for="filter in filters"
        :label="filter.value">{{ filter.text }}</el-checkbox>
    </el-checkbox-group>
  </div>
  <!-- 操作 -->
  <div class="el-table-filter__bottom">
    <button @click="handleConfirm"
      :class="{ 'is-disabled': filteredValue.length === 0 }"
      :disabled="filteredValue.length === 0">{{ t('el.table.confirmFilter') }}</button>
    <button @click="handleReset">{{ t('el.table.resetFilter') }}</button>
  </div>
</div>

篩選條件

首先是 filteredValue ,這是一個計算元素,用來表示篩選條件,包含 getset,都是操縱的對應列的對應數(shù)據(jù)。

computed: {
  filteredValue: {
    get() {
      if (this.column) {
        return this.column.filteredValue || [];
      }
      return [];
    },
    set(value) {
      if (this.column) {
        this.column.filteredValue = value;
      }
    }
  },
}

filters 也是對應列上的一個屬性,是對應的篩選器的相關(guān)信息。

computed: {
  filters() {
    return this.column && this.column.filters;
  },
}

操作按鈕

操作的兩個按鈕的設置也很簡單,內(nèi)部數(shù)據(jù)用了 i18n 來實現(xiàn)多語言,首先分析一下確認按鈕。

<button
  @click="handleConfirm"
  :class="{ 'is-disabled': filteredValue.length === 0 }"
  :disabled="filteredValue.length === 0">
  {{ t('el.table.confirmFilter') }}
</button>

首先是監(jiān)聽 click 事件,并綁定 handleConfirm 函數(shù)。

methods: {
  handleConfirm() {
    // 根據(jù)選擇的篩選條件來篩選
    this.confirmFilter(this.filteredValue);
    // 隱藏
    this.handleOutsideClick();
  },
  
  // 直接改變 showPopper,然后 watch 會處理關(guān)閉這個 popper
  handleOutsideClick() {
    this.showPopper = false;
  },
  
  // 根據(jù)篩選條件來篩選
  confirmFilter(filteredValue) {
    this.table.store.commit('filterChange', {
      column: this.column,
      values: filteredValue
    });
  }
}

然后是重置按鈕,只是簡單的監(jiān)聽 click 事件,來觸發(fā) handleReset

<button @click="handleReset">{{ t('el.table.resetFilter') }}</button>
methods: {
  handleReset() {
    // 清空篩選條件
    this.filteredValue = [];
    // 重新獲取篩選數(shù)據(jù)
    this.confirmFilter(this.filteredValue);
    // 關(guān)閉
    this.handleOutsideClick();
  },
}

單選

單選是通過 li 來實現(xiàn)。

<div class="el-table-filter" v-else v-show="showPopper">
  <ul class="el-table-filter__list">
    <!-- 沒有選擇任何一個篩選條件 -->
    <li class="el-table-filter__list-item"
        :class="{ 'is-active': !filterValue }"
        @click="handleSelect(null)">{{ t('el.table.clearFilter') }}</li>
    
    <!-- 列表渲染每個篩選條件 -->
    <li class="el-table-filter__list-item"
        v-for="filter in filters"
        :label="filter.value"
        :class="{ 'is-active': isActive(filter) }"
        @click="handleSelect(filter.value)" >{{ filter.text }}</li>
  </ul>
</div>

其中 handleSelect 是用來處理選擇了哪個篩選條件的,它復用了多選的相關(guān)操作,通過 filterValue 這一計算屬性來影響 filterdValue。

computed: {
  filterValue: {
    // 篩選條件的第一個
    get() {
      return (this.column.filteredValue || [])[0];
    },
    
    // 設置篩選條件
    set(value) {
      if (this.filteredValue) {
        if ((typeof value !== 'undefined') && (value !== null)) {
          this.filteredValue.splice(0, 1, value);
        } else {
          this.filteredValue.splice(0, 1);
        }
      }
    }
  },
},

methods: {
  // 參數(shù)是篩選條件
  handleSelect(filterValue) {
    this.filterValue = filterValue;

    if ((typeof filterValue !== 'undefined') && (filterValue !== null)) {
      this.confirmFilter(this.filteredValue);
    } else {
      this.confirmFilter([]);
    }

    this.handleOutsideClick();
  },
  
  // 判斷是否是所選的篩選條件
  isActive(filter) {
    return filter.value === this.filterValue;
  },
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容