1、效果
注意: 新增并选中、这里需要后端的支持,新增接口请求成功后端返回新增数据。
2、在main.js中加入自定义指令
// select下拉刷新
Vue.directive('loadmore', {
inserted(el, binding, vnode) {
const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
if (SELECTWRAP_DOM) {
SELECTWRAP_DOM.addEventListener('scroll', function() {
const condition = this.scrollHeight - this.scrollTop <= this.clientHeight
const type = binding.value.type
// const fn = binding.value.fn
if (condition) {
binding.value.fn(type)
}
})
}
}
})
3、防抖
// 防抖
debounce: (fn, interval) => {
var timer
var gapTime = interval || 1500 // 间隔时间,如果interval不传,则默认1000ms
return function() {
clearTimeout(timer)
var context = this
var args = arguments // 保存此处的arguments,因为setTimeout是全局的,arguments不是防抖函数需要的。
timer = setTimeout(function() {
fn.apply(context, args)
}, gapTime)
}
},
4、组件代码
<template>
<div class="SelectAddLabel">
<el-select
ref="select"
v-model="childValue"
v-loadmore="{fn:loadMore ,type:'remoteMethod'}"
style="width: 300px;"
multiple
clearable
placeholder="请选择"
@change="change"
>
<div v-loading="loading">
<el-input
v-model="params.search"
class="select-input"
prefix-icon="el-icon-search"
/>
<el-option
v-if="noData"
value=""
label="空空如也"
/>
<el-option
v-for="item in option"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<div style="display: flex; justify-content: space-between;position: sticky; bottom: 0px ; background-color: aliceblue;">
<el-popover
v-model="popoverVisible"
placement="top"
width="160"
>
<el-input v-model="addForm.label_name" autocomplete="off" clearable />
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="popoverClose">取消</el-button>
<el-button type="primary" size="mini" @click="popoverConfirm">确定</el-button>
</div>
<el-button slot="reference" type="text" style="margin-left: 40px;">新增</el-button>
</el-popover>
<el-button type="text" style="margin-right: 40px;" @click="editShow = true ; getTableLabelData()">编辑</el-button>
</div>
</div>
</el-select>
<!-- 编辑来源 -->
<el-dialog title="编辑标签" width="500px" :visible.sync="editShow" append-to-body>
<el-table :loading="tableLoading" :data="tableData" height="50vh">
<el-table-column property="label_name" label="标签名" />
<el-table-column label="操作">
<template slot-scope="{ row }">
<el-button type="text" style="color: red" @click.stop="del(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page.sync="tableParams.page"
:page-size="tableParams.limit"
layout="total, prev, pager, next"
:total="tableCount"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-dialog>
<!-- 编辑来源 -->
</div>
</template>
<script>
import fn from '@/utils/fn' //内有防抖节流方法
import Label from '@/api/label' // 获取数据接口
export default {
model: { // 定义model
// 父组件v-model绑定的值传递给props中的fatherValue
prop: 'fatherValue',
// 通过emit触发childValueChange将内部值传递给父组件v-model绑定的值
event: 'childValueChange'
},
props: {
type: {
type: Number,
default: null
},
fatherValue: { // 接受父组件传递的值
type: Array,
default: () => []
},
fatherOption: {
type: Array,
default: () => []
}
},
data() {
return {
noData: false,
loading: false,
popoverVisible: false,
childValue: this.fatherValue,
option: [],
editShow: false,
addShow: false,
addForm: {
label_name: ''
},
params: {
search: '',
page: 1,
limit: 10
},
tableParams: {
search: '',
page: 1,
limit: 10
},
tableData: [],
tableLoading: false,
tableCount: 0
}
},
watch: {
fatherValue(val) { // 这一步重新赋值 是因为props里面的fatherValue改变了 但是data里面的childValue不会改变 从而视图不会更新
this.childValue = val
},
tableParams: {
deep: true,
handler() {
this.getTableLabelData()
}
},
fatherOption: {
immediate: true,
deep: true,
handler(val) {
if (val && val.length > 0) {
val.forEach(item => {
this.judgeAdd(item)
})
}
}
},
'params.search': {
handler() {
this.loading = true
this.params.page = 1
this.getLabelData()
}
}
},
created() {
this.getLabelData()
},
methods: {
// 判断是否能插入
judgeAdd(obj) {
if (!obj || Object.keys(obj).length === 0) {
return
}
const have = this.option.some(item => item.value === obj.value)
if (!have) {
this.option.push(obj)
}
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`)
},
handleCurrentChange(val) {
this.tableParams.page = val
},
// 获取table数据
getTableLabelData() {
this.tableLoading = true
Label.getLabelData(this.tableParams).then(res => {
this.tableData = res.data
this.tableCount = res.count
this.tableLoading = false
})
},
// 滚动触底
loadMore(type) {
if (!this.loading && !this.noData) {
this.params.page++
}
this.loading = true
this.getLabelData('add')
},
// 删除
del(val) {
Label.deleteLabelData({ id: val }).then(res => {
this.getLabelData()
})
},
change() {
// 通过$emit触发childValueChange(model内定义)事件,将内部值传递给给父组件
this.$emit('childValueChange', this.childValue)
},
// popover确定
popoverConfirm() {
if (!this.addForm.label_name) {
this.$message({
type: 'error',
message: '不能为空'
})
return
}
Label.saveLabelData({ ...this.addForm, label_type: this.type }).then(res => {
const obj = {
value: res.data.id,
label: res.data.label_name
}
this.option.push(obj)
this.childValue.push(res.data.id)
this.change()
this.params.page = 1
this.getLabelData()
this.popoverClose()
})
},
// popover取消
popoverClose() {
this.popoverVisible = false
this.addForm.label_name = ''
},
// 获取标签
getLabelData: fn.debounce(async function(type) {
this.loading = true
await Label.getLabelData({ ...this.params, label_type: 4 }).then(res => {
const getArrData = res.data.map(item => ({ value: item.id, label: item.label_name }))
if (type === 'add') {
getArrData.forEach(item => {
this.judgeAdd(item)
})
// this.option.push(...getArrData)
} else {
this.option = getArrData
}
if (!getArrData || getArrData.length === 0) {
this.noData = true
} else {
this.noData = false
}
}).catch((res) => {
this.$message.error(res.message || '获取下拉选项失败')
}).finally(() => {
this.loading = false
})
}, 1000)
}
}
</script>
<style lang="scss" scoped>
.select-input{
padding: 0 12px;
box-sizing: border-box;
margin-bottom: 12px;
position: sticky;
top: 0px;
z-index: 9999;
::v-deep .el-input__inner {
border: none;
border-bottom: 1px solid #EBEBEB;
border-radius: 0;
}
}
.SelectAddLabel{
::v-deep .el-dialog{
.el-dialog__body{
.el-form-item{
.el-form-item__label{
width:11em !important;
}
.el-form-item__content{
margin-left:12em !important;
}
}
}
}
}
</style>
5、全局引入组件
import SelectAddLabel from './SelectAddLabel'
export default {
install(Vue) {
Vue.component('SelectAddLabel', SelectAddLabel)
}
}
6、template
<SelectAddLabel v-model="addContactForm.label_id" :father-option="labelOption" :type="4" />
7、data
data(){
return{
addContactForm:{
label_id: []
},
labelOption:[] //用于数据返现
}
}
8、methods
// 需要获取数据用于返显
editContact(row) {
this.labelOption = row.customer_contact_to_label.map(item => {
return {
value: item.id,
label: item.label_name
}
})
this.dialogFormVisible = true
},