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" :key="index" closable @close="handleCloseTag(item)" size="small"
type="info" effect="plain">{{item[keywordKey] || ''}}</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 },
otherParams: { default: () => { } },
showSelect: { default: false }
},
data() {
return {
visible: false,
pStyle: 'width:500px',
list: [],
total: 0,
listLoading: true,
listQuery: {
pageNum: 1,
pageSize: 5
},
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.otherParams) {
this.listQuery[key] = this.otherParams[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

