业务需求:下拉框需要满足用户可输入筛选 和 点击右侧 字符按钮 #A-Z进行用户选择
1、基础页面代码
<div>
<a-select
style="width: 100%"
placeholder="请选择客户"
allow-clear
show-search
:filter-option="false"
:not-found-content="fetching ? undefined : null"
:defaultActiveFirstOption="false"
:getPopupContainer="getPopupContainer"
@search="searhcCust"
@dropdownVisibleChange="dropdownVisibleChange"
>
//dropdownRender 插件使用,自定义右边
<div
slot="dropdownRender"
slot-scope="menu"
>
<div class="index-bar">
<div
v-for="letterItem in letter"
:key="letterItem"
@click.prevent="scrollOn(letterItem)"
class="index-letter"
@mousedown="e => e.preventDefault()" // 阻止调用默认事件
>
{{ letterItem }}
</div>
</div>
<v-nodes :vnodes="menu" /> // 注意要在components中定义
</div>
<a-select-opt-group
v-for="(group, index) in peoArray"
:key="index"
>
<span
slot="label"
class="option-letter"
:id="'peo_' + componentId + group.key"
>{{group.key}}</span>
<a-select-option
v-for="option in group.list"
:key="option.custRowId"
:value="option.custRowId"
:title="option.custName"
>
<span>{{ option.custName }}</span>
</a-select-option>
</a-select-opt-group>
</a-select>
</div>
2、script中的代码
<script>
import { debounce } from 'lodash'
export default {
props: {
componentId: { // 设置不同的id,用于同页面有多个此组件时锚点不生效
type: String,
default: ''
}
},
components: {
VNodes: {
functional: true,
render: (h, ctx) => ctx.props.vnodes,
}
},
data() {
return {
dropOpen: false,
searchValue: '',
navBarHeight: '50px', // 导航栏高度
letter: [], // 字母检索列表
peoArray: [], // 通讯录列表
custList: null,
custRowId: undefined,
fetching: false,
debounceGetCustInfoKeyList: null,
}
},
created() {
this.getCustInfoKeyList()
this.debounceGetCustInfoKeyList = debounce(this.getCustInfoKeyList, 500)
},
methods: {
dropdownVisibleChange(open) {
this.dropOpen = open
},
getPopupContainer(triggerNode) {
if (this.modalSelect) {
return triggerNode.parentNode
} else {
return document.body
}
},
changeCust(val) {
this.$emit('change', val)
},
getList(peoArray) {
let newList = []
peoArray.forEach(element => {
newList.push(...element.list)
})
return newList
},
searhcCust(val) {
this.searchValue = val
this.debounceGetCustInfoKeyList()
},
getCustInfoKeyList() {
const params = {
custName: this.searchValue,
}
this.$http.XXX(params).then(res => {
if (res.code === 200) {
this.custList = res.data
if (this.custList) {
this.setList()
} else {
this.peoArray = []
}
this.fetching = false
} else {
this.$message.warn(res.msg)
this.fetching = false
}
})
},
setList() {
let list = []
this.letter = []
for (const key in this.custList) {
this.letter.push(key)
list.push({
key,
list: this.custList[key]
})
}
setTimeout(() => {
this.peoArray = list
})
},
// 字母检索
scrollOn(item) {
let target = document.getElementById('peo_' + this.componentId + item) // 获取每个字母通讯录对象
if (target) {
const scrollDom = document.getElementsByClassName('ant-select-dropdown-menu')[0]
scrollDom.scrollTo({
behavior: 'smooth',
top: target.offsetTop - 10
})
} else {
this.$message.warn(`当前${item}元素下暂无客户`)
}
}
}
}
</script>
3、基础CSS代码
.index-bar {
position: absolute;
z-index: 99;
right: 10px;
top: 50%;
transform: translateY(-50%);
display: flex;
flex-direction: column;
align-items: center;
}
.index-letter {
margin: 0;
cursor: pointer;
color: #1677ff;
font-weight: 500;
font-size: 12px;
line-height: 20px;
}
.option-letter {
font-weight: 600;
color: rgba(0, 0, 0, 0.45);
}
4、遇到的坑是什么呢?
就是在同一个页面,渲染同一个组件时,在点击前一个组件后,后面的组件右侧按钮滚动失效。
造成这个问题的原因就是 dropdownRender 渲染不会销毁,导致scrollOn获取到的DOM是同一组数据,解决方法有两种:
// 1、在 dropdownRender 插件的地方
<div
v-if="dropOpen"
slot="dropdownRender"
slot-scope="menu"
>
// 2、scrollOn 中修改查询Dom方法
let target = document.getElementById('peo_' + this.componentId + item) // 获取每个字母通讯录对象
if (target) {
const parentDom = document.getElementById(offsetParent.id)
const scrollDom = parentDom.children[0]
scrollDom.scrollTo({
behavior: 'smooth',
top: target.offsetTop - 10
})
} else {
this.$message.warning(`当前${item}元素下暂无客户`)
}