1. 程式人生 > 實用技巧 >vue 自定義下拉選擇table元件

vue 自定義下拉選擇table元件

element ui的select元件對大量資料的渲染效能差,自己用table+input跟著搗鼓一下。。參考select原始碼但駕馭不住。(目前就抄了css)

呸,自己實現,能用就行。(菜是原罪)

效果:

程式碼:

<template>
  <div :id="createdId">
    <div class="input-select el-input__inner" v-if="showSelect">
      <div class="tags">
        <el-tag v-for="(item, index) in multipleSelectionTags" closable @close="handleCloseTag(item)" size="small"
          type
="info" effect="plain">{{item.deviceName}}</el-tag> <input type="text" ref="selectInput" :value="value" :placeholder="placeholderForTag" @focus="onfocus" @input="changeValue($event.target.value)"> <i class="el-icon-arrow-down select-down" :class="visible&&'rotate180'"></i> </div> </div> <el-input v-else
:value="value" @input="changeValue" @focus="onfocus" @blur="onblur" clearable :placeholder="placeholder" ref="inputValue"></el-input> <div class="el-picker-panel" :style="pStyle" v-show="visible" ref="elcombogrid"> <div class="table-container"> <el-table v-loading="listLoading" :data="list" @row-click="rowClick" stripe size="mini" element
-loading-text="Loading" ref="comboGridTable" fit border highlight-current-row @selection-change="handleSelectionChange" @select="handleSingelSelectionChange"> <el-table-column type="selection" v-if="showSelect" width="55" align="center" /> <el-table-column v-if="showIndex" label="序號" type="index" align="center" width="50"></el-table-column> <el-table-column v-for="item in columns" :type="item.type" :key="item.key" :label="item.label" :prop="item.key" :align="item.align" :width="item.width" :header-align="item.headerAlign"> <template slot-scope="scope"> <span>{{ scope.row[item.key] }}</span> </template> </el-table-column> </el-table> <el-pagination v-show="pagination" small :total="total" :page-size="5" layout="prev, pager, next, total" @current-change="changePage" /> </div> </div> </div> </template> <script> import request from '@/utils/request'; export default { name: "el-combo-grid", props: { placeholder: { type: String }, value: { type: String }, requestConfig: { default: () => { return { url: '', method: 'get' } } }, columns: { type: Array }, panelStyle: { type: String }, keywordKey: { type: String }, showIndex: { type: Boolean }, pagination: { type: Boolean, default: true }, otherParmas: { default: () => { } }, showSelect: { default: false } }, data() { return { visible: false, pStyle: 'width:500px', list: [], total: 0, listLoading: true, listQuery: { pageNum: 1, pageSize: 5, deviceName: null }, keyword: '', createdId: '0', multipleSelection: [], multipleSelectionTags: [], placeholderForTag: '' } }, mounted() { this.createdId = String(new Date().getTime()) // 給個隨機id 判斷是否clickoutside this.placeholderForTag = this.placeholder }, methods: { changePage(cur) { this.listQuery.pageNum = cur this.getList() }, changeValue(val) { this.$emit('input', val)//向上級傳送資料 this.keyword = val this.listQuery.pageNum = 1 this.getList() }, onfocus(el) { this.pStyle = this.panelStyle + ';position:absolute;z-index:999999;' this.visible = true this.keyword = el.target.value document.removeEventListener('click', this.clickOutFn) document.addEventListener('click', this.clickOutFn) this.getList() }, onblur(el) { }, getList() { for (let key in this.otherParmas) { this.listQuery[key] = this.otherParmas[key] } if (this.pagination) { this.listQuery[this.keywordKey] = this.keyword } else { if (this.keyword) { this.listQuery[this.keywordKey] = this.keyword } else { this.listLoading = false return //如果不分頁,無keyword不查詢資料(避免大資料量) } } this.listLoading = true this.multipleSelection.length = 0 this.queryTableData(this.listQuery).then(response => { this.list = response.data.rows this.total = response.data.total this.listLoading = false this.$nextTick(() => { // multipleSelectionTags 引用問題,無法與table資料全等。。。 let ids = this.multipleSelectionTags.map(item => item.id) this.list.length && this.list.forEach((item, index) => { if (ids.includes(item.id)) { this.$refs.comboGridTable.toggleRowSelection(item) } }) }) }) }, queryTableData(params) { const reqObj = { url: this.requestConfig.url, method: this.requestConfig.method } let p = this.requestConfig.method === 'get' ? 'params' : 'data' reqObj[p] = params return request(reqObj) }, rowClick: function (row, column, event) { if (this.showSelect) { this.$refs.comboGridTable.toggleRowSelection(row); this.$emit('input', '') } else { this.visible = false this.$emit('row-select-event', row, column, event) this.$emit('input', row[this.keywordKey]) document.removeEventListener('click', this.clickOutFn) } }, clickOutFn(e) { if (e.path.some(item => item.id === this.createdId)) return this.visible = false document.removeEventListener('click', this.clickOutFn) }, /** * 根據選擇與上次的選擇進行對比,處理tags * todo 聚焦狀態。。。觸發太多,暫不處理 */ handleSelectionChange(val) { if (this.multipleSelection.length === 0 && val.length === 0) return if (val.length > this.multipleSelection.length) { for (let item of val) { if (!this.multipleSelection.some(mitem => mitem.id === item.id)) { let ids = this.multipleSelectionTags.map(item => item.id) !ids.includes(item.id) && (this.multipleSelectionTags = this.multipleSelectionTags.concat(item)) } } } else { for (let item of this.multipleSelection) { if (!val.some(mitem => mitem.id === item.id)) { let index = this.multipleSelectionTags.findIndex(mitem => mitem.id === item.id) index > -1 && this.multipleSelectionTags.splice(index, 1) } } } this.multipleSelection = val this.placeholderForTag = this.multipleSelectionTags.length ? '' : this.placeholder this.$emit('getSelect', this.multipleSelectionTags) // this.$refs.selectInput.focus() todo.. }, /** * 處理單個複選框選擇 */ handleSingelSelectionChange() { this.$emit('input', '') }, handleCloseTag(item) { this.multipleSelectionTags.splice(this.multipleSelectionTags.findIndex(mitem => mitem.id === item.id), 1) this.$refs.comboGridTable.toggleRowSelection(item) } } } </script> <style lang="scss" scoped> .input-select { display: inline-block; position: relative; width: 100%; height: auto; min-width: 240px; -webkit-appearance: none; background-color: #fff; background-image: none; border-radius: 4px; border: 1px solid #dcdfe6; box-sizing: border-box; color: #606266; font-size: inherit; outline: none; padding: 0 15px; transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); .select-down { position: absolute; top: 50%; right: 10px; transform: translateY(-50%); transition: all 0.5s; &.rotate180 { transform: translateY(-50%) rotate(180deg); } } .tags { min-height: 36px; flex-wrap: wrap; line-height: normal; white-space: normal; z-index: 1; display: inline-flex; align-items: center; flex-wrap: wrap; /deep/ .el-tag { margin-right: 3px; margin-bottom: 1px; } input { flex: 1; border: none; outline: none; padding: 0; color: #666; font-size: 14px; appearance: none; height: 28px; background-color: transparent; &::-webkit-input-placeholder { color: #c0c4cc; } &::-moz-placeholder { /* Mozilla Firefox 19+ */ color: #c0c4cc; } &:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ color: #c0c4cc; } &:-ms-input-placeholder { /* Internet Explorer 10-11 */ color: #c0c4cc; } } } } </style>

呼叫:

<inputTable  v-model="form.deviceName"
                          v-if="open" // 用v if 處理各種疑難雜症
                          placeholder="請選擇"
                          :requestConfig="{url: '/api/as/my/list', method: 'get'}"
                          :pagination="true" // 是否分頁
                          :columns="myColumns" //
                          :showIndex="true" // 顯示序號
                          keywordKey="name" // 請求的keyword
                          :panelStyle="'width:550px'" // 樣式
                          :otherParams="{deviceBind: 1}" // 其他請求引數
                          :showSelect="true" // 是否多選
                          @getSelect="getRowsSelect" // 返回的多選
                         @row-select-event="getRowSelect" // 單行點選事件
                        />

myColumns:[{label:'asdasd', key: 'Name'},{label:'6666', key: 'code'}]

getRowSelect(row, column, event) {
     // dosomething
 },
getRowsSelect(arr) {
              this.form.ids= arr.map(item=>item.id)
            },
                    

參考地:https://blog.csdn.net/raozhangqiang/article/details/108715580