业务需求:下拉框需要满足用户可输入筛选 和 点击右侧 字符按钮 #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}元素下暂无客户`) }