element select下拉选项剔除已添加的选项

本文详细介绍了在Vue.js项目中如何实现动态下拉菜单,特别是处理已选择选项不再显示的问题。首先,通过遍历列表并比较已添加的ID来更新下拉选项。然后,修复了一个bug,即当选择一个选项后,该选项从下拉列表中消失。最后,通过监听点击事件并在选择时将当前选项重新添加到列表中,实现了既能剔除已选选项又保持当前选项可见的功能。

项目中遇到个需求:
货权主体为下拉单选,点击“新增”可以添加多个货权主体,如下图:
在这里插入图片描述
要求每次新增一行后,下拉选项需要剔除列表中已添加过的选项,如下图:
在这里插入图片描述

1.初步代码实现:

思路:
循环货权主体列表,将已添加选项的 id(value) 组成一个数组,去跟下拉选项的初始数据作对比,筛选出未添加的选项生成新的下拉选项数组,赋值给 select 绑定的变量即可。这些逻辑可以写成一个公用方法。

然后在每次操作列表时(如下拉框change、点击新增、删除)都调用这个方法。比如@change 调用一下 existOps 方法,调用的具体代码下面就省略啦。。。

<el-select 
	filterable
	clearable
	v-model="scope.row.ownerCompanyId"
    placeholder="请选择货权主体">
    <el-option
      v-for="item in ownerCompanyOpts"
      :key="item.value"
      :label="item.label"
      :value="item.value"
      @change="ownerCompanyChange($event, scope.row)">
     </el-option>
</el-select>
export default {
  data() {
  	ownerCompanyOpts: [], // 货权主体下拉列表渲染数据
    ownerCompanyInitData: [], // 货权主体下拉列表初始数据
    existIds: [], // 货权主体下拉已添加选项的id
    form: {
	    "items": [
	      {
	        "ownerCompanyId": "",
	        "ownerContact": "",
	        "ownerEmail": "",
	      }
	    ]
    }
  },
  created() {
    this.getCompanyOpts()
  },
  methods: {
  	// 获取货权主体下拉列表数据
    getCompanyId(){
      api.getZhutiList({}).then(res => {
        this.ownerCompanyOpts = res.list.map(item => {
          return {
            label: item.companyName,
            value: item.id
          }
        })
        this.ownerCompanyInitData = this.ownerCompanyOpts
      })
    },
  	// 下拉是否已添加
	existOps() {
		// 清空重置
		this.existIds = []
		// 货权主体下拉已选的id
		this.form.items.forEach(item => {
			if(!this.existIds.includes(item.ownerCompanyId)) {
				this.existIds.push(item.ownerCompanyId)
			}
		})
		// 货权主体下拉可选的数组
		let companyArr = []
		this.ownerCompanyInitData.forEach(item => {
			if(this.existIds.includes(item.value)) {
				companyArr.push(item)
			}
		})
		this.ownerCompanyOpts = companyArr
	}
  }
}

缺陷

写完上面的代码,确实可以剔除已有的选项了。但是测试立马就给我提了 bug,那是什么问题呢??
在这里插入图片描述
每次操作完,当前选项就变成了 value 值,本来是应该展示 label 的呀,怎么肥事???
测试一番发现,当前选项的下拉选项列表里是剔除了当前这一项的,于是,它就找不到对应的 label 值了,所以只会显示 value

那么,我又想到了一个方法:那就让每个选项的下拉选项列表都为完整的初始数据,用个 show 字段控制它们的显示、隐藏就好啦。

2.修复上一步的 bug

模板里新增 v-show=“item.show”

<el-select 
	filterable
	clearable
	v-model="scope.row.ownerCompanyId"
    placeholder="请选择货权主体">
    <el-option
      v-for="item in ownerCompanyOpts"
      :key="item.value"
      :label="item.label"
      :value="item.value"
      v-show="item.show"
      @change="ownerCompanyChange($event, scope.row)">
     </el-option>
</el-select>

注释“新增”的部分就是做了改动的代码:

methods: {
  	// 获取货权主体下拉列表数据
    getCompanyId(){
      api.getZhutiList({}).then(res => {
        this.ownerCompanyOpts = res.list.map(item => {
          return {
            label: item.companyName,
            value: item.id,
            show: true // 新增
          }
        })
        this.ownerCompanyInitData = this.ownerCompanyOpts
      })
    },
  	// 下拉是否已添加
	existOps() {
		// 清空重置
		this.existIds = []
		// 新增
		this.ownerCompanyInitData.forEach(item => {
	        item.show = true
	     })
		// 货权主体下拉已选的id
		this.form.items.forEach(item => {
			if(!this.existIds.includes(item.ownerCompanyId)) {
				this.existIds.push(item.ownerCompanyId)
			}
		})
		// 货权主体下拉可选的数组
		let companyArr = []
		this.ownerCompanyInitData.forEach(item => {
			if(this.existIds.includes(item.value)) {
				// 新增
				item.show = false
			}
			// 新增
			companyArr.push(item)
		})
		this.ownerCompanyOpts = companyArr
	}
  }
缺陷

功能实现了呀!每个选项的下拉都剔除了已添加的选项了呀!!那还有啥缺陷??
在这里插入图片描述
测试大哥就说了,虽然是剔除了已添加的选项,但是把当前选项自个儿也剔除了,看着怪怪的。它自己个儿应该也在下拉列表里面的。。。那就再优化一下吧!

3.优化

思路:
那就不能在监听 change 事件时调用 existOps 方法了,因为 change 事件得改变选项了才会触发。所以得用 click 事件,每次点击 select 时就触发。

之前的代码只需要加一步,点击 select 时,在调用 existOps 将已有选项剔除后,再将当前选项加回到下拉选项中,即将对应的 show 置为 true。

模板中新增 @click.native=“ownerCompanyClick(scope.row)” :

<el-select 
	filterable
	clearable
	v-model="scope.row.ownerCompanyId"
    placeholder="请选择货权主体"
    @click.native="ownerCompanyClick(scope.row)">
    <el-option
      v-for="item in ownerCompanyOpts"
      :key="item.value"
      :label="item.label"
      :value="item.value"
      v-show="item.show">
     </el-option>
</el-select>

methods 中增加 ownerCompanyClick 方法即可:

ownerCompanyClick(row) {
  this.existOps() // 先调用之前的方法
  // 将当前选项加入到选项列表
  this.ownerCompanyOpts.forEach(item => {
    if(item.value == row.ownerCompanyId) {
      item.show = true
    }
  })
},

在这里插入图片描述
在这里插入图片描述
可以看到,当前选项的选项下拉列表中就包含自己了!!完美!!

<template> <aui-dialog-box :visible="visible" :title="title" width="500px" append-to-body draggable :close-on-click-modal="false" @close="onClose" > <aui-form ref="form" label-position="top" validate-position="bottom" :model="formData" :rules="formRules" :append-to-body="false" > <aui-form-item :label="mainOptionsLabel" prop="selectMainKey"> <aui-checkbox-group v-if="isMultiMain" v-model="formData.selectMainKey" :options="mainOptions"> </aui-checkbox-group> <aui-radio-group v-else v-model="formData.selectMainKey" :options="mainOptions"> </aui-radio-group> </aui-form-item> <div v-for="rule in ruleList" :key="rule.id"> <!-- <aui-form-item :prop="rule.id" :required="rule.fieldIsRequired === 'yes'"> --> <!-- <span>{{ rule.id }}</span> --> <aui-form-item :prop="rule.id"> <template #label> <div class="flex-wrap"> {{ rule[nameKey] }} <aui-tooltip v-if="rule[commentKey]" effect="light" placement="top" popper-class="commentTippoper"> <template #content> {{ rule[commentKey] }} </template> <IconHelpCircle class="iconHelp" /> </aui-tooltip> </div> </template> <!-- <span>{{ ruleValueList[rule.id] }}</span> --> <aui-select :ref="handleRef(rule)" v-model="ruleValueList[rule.id]" v-show-all-checked-tag="getShowAllCheckedTagBindingValue(rule, selectOptionLabels, ruleValueList)" :multiple="isMultiple(rule)" :query-debounce="300" :collapse-tags="isMultiple(rule)" :remote-method="searchText => remoteMethod(rule, searchText)" :remote-config="{ autoSearch: true, clearData: true, showIcon: true }" remote filterable clearable reserve-keyword :loading="loadingList[rule.id]" loading-text="Loading..." @change="selected => onSelectChange(rule, selected)" @clear="onClearSelection(rule)" is-drop-inherit-width > <template #dropdown> <li v-if="isMultiple(rule) && hasOptions(rule)" class="aui-select-dropdown__item all-checked-option" data-tag="aui-select-dropdown-item" :class="[{ selected: isAllChecked(rule) }]" @mouseenter="onAllCheckedOptionMouseOver" > <aui-checkbox :indeterminate="isIndeterminate(rule)" :checked="isAllChecked(rule)" @change="allChecked => onAllCheckedChange(rule, allChecked)" > {{ $t('semantic.material.MySelect.label.allChecked') }} </aui-checkbox> </li> </template> <template v-for="item in selectOptionLabels[rule.id]"> <aui-option v-if="item" :key="item.value || item" :label="item.label || item" :value="item.value || item" /> </template> </aui-select> </aui-form-item> </div> </aui-form> <template #footer> <aui-button @click="onCancel"> {{ $t('semantic.material.common.button.cancel') }} </aui-button> <aui-button type="primary" @click="onConfirm"> {{ $t('semantic.material.common.button.confirm') }} </aui-button> </template> </aui-dialog-box> </template> <script lang="ts"> import { defineComponent } from '@vue/composition-api'; import { DialogBox, Radio, Form, FormItem, Select, Option, Button, CheckboxGroup, RadioGroup, Tooltip, Checkbox, } from '@aurora/vue'; import { IconHelpCircle } from '@aurora/vue-icon'; import { getQueryParams, getFieldDataFromContent, showSelectLabel } from '../../query-select/QueryDataHelper'; import { queryDetailData } from '../../../service/detailDataService'; import { isEmptyStringArray, isLocaleZh } from '../../../utils/PageContextUtils'; import * as Export from '../common/export'; import { createDirective as createShowAllCheckedTagDirective } from '../../../directives/show-all-checked-tag'; type FormState = { selectMainKey: string[] | string; }; let promise: Promise<FormState> | null; let resolve: ((v: FormState) => void) | null; let reject: ((err: Error) => void) | null; export default defineComponent({ components: { AuiDialogBox: DialogBox, AuiForm: Form, AuiFormItem: FormItem, AuiRadio: Radio, AuiOption: Option, AuiSelect: Select, AuiButton: Button, AuiCheckboxGroup: CheckboxGroup, AuiRadioGroup: RadioGroup, AuiTooltip: Tooltip, AuiCheckbox: Checkbox, IconHelpCircle: IconHelpCircle(), }, directives: { showAllCheckedTag: createShowAllCheckedTagDirective(), }, setup() {}, data() { return { formData: { selectMainKey: [], }, mainOptions: [], configData: [], visible: false, ruleList: [], ruleValueList: {}, loadingList: {}, selectOptionLabels: {}, searchValue: '', remoteSearched: {}, isMultiMain: false, mainOptionsLabel: '', cascadeRuleMap: new Map(), title: '', defaultAllChecked: {}, }; }, computed: { nameKey() { return isLocaleZh() ? 'nameCn' : 'nameEn'; }, commentKey() { return isLocaleZh() ? 'commentCn' : 'commentEn'; }, configDataMapById() { return new Map(this.configData.map(item => [item.id, item])); }, formRules() { const rules: any = {}; // 为 selectMainKey 添加必填规则 rules['selectMainKey'] = [ { required: true, trigger: 'change', }, ]; // 动态生成其他规则 this.ruleList.forEach(rule => { if (rule.fieldIsRequired === 'yes') { rules[rule.id] = [ { required: true, trigger: 'change', }, ]; } }); console.log(rules, '添加必填规则'); return rules; }, }, watch: { 'formData.selectMainKey': { handler(newVal) { this.changeRuleList(newVal); }, }, }, methods: { /** 全选项的切换中状态回调 */ onAllCheckedChange(rule, allChecked: string[]) { const options = this.selectOptionLabels[rule.id]; const oldChecked = this.ruleValueList[rule.id]; let newChecked; if (allChecked) { // 追加 newChecked = [...new Set([...oldChecked, ...options])]; } else { // 剔除列表中中的项 newChecked = oldChecked.filter(checked => !options.includes(checked)); } this.$set(this.ruleValueList, rule.id, newChecked); this.updateDefaultAllCheckedOnSelect(rule, allChecked); // 触发级联查询 下级字段 if (this.cascadeRuleMap.get(rule.id)?.length) { // 下级字段 this.setSelectChangeCascaded(rule); } }, /** 移除兄弟节点的 hover 样式 */ onAllCheckedOptionMouseOver(e) { [...e.target.parentNode.children].forEach(ele => { if (ele !== e.target) { ele.classList.remove('hover'); } }); }, /** 是否有下拉选项 */ hasOptions(rule) { return this.selectOptionLabels?.[rule.id]?.length > 0; }, isDefaultAllCheckedRule(rule) { return this.defaultAllChecked[rule.id] === true; }, /** 是否有中项 */ hasSelected(rule) { const value = this.ruleValueList?.[rule.id]; if (typeof value === 'number' && !isNaN(value)) { return true; } return value?.length > 0; }, /** * 远程搜索扩展的半逻辑。 */ isIndeterminate(rule) { if (!this.hasSelected(rule) || !this.hasOptions(rule)) { return false; } // 只要某个选项中(即中列表未包含所有选项),就是半 return !this.isSelectedContainsAllOptions(rule); }, isAllChecked(rule) { if (!this.hasSelected(rule) || !this.hasOptions(rule)) { return false; } // 中列表未包含所有选项就是全 return this.isSelectedContainsAllOptions(rule); }, /** 更新全标记 */ updateDefaultAllChecked(rule: typeof this.ruleList[number], allChecked) { this.$set(this.defaultAllChecked, rule.id, allChecked); }, isRemoteSearchedRule(rule) { return this.remoteSearched[rule.id] === true; }, isSelectedContainsAllOptions(rule, checkedList = this.ruleValueList[rule.id]) { const allSelect = this.selectOptionLabels[rule.id]?.every(ruleId => checkedList?.includes(ruleId)); // 模糊搜索后,列表项会发生变化,如果所有列表项被中,全部也要中 // 避免在存在重复value的场景时,全后,无法直接取消用于重复value项的勾 const lengthValid = this.selectOptionLabels[rule.id]?.length <= checkedList.length; return allSelect && lengthValid; }, updateDefaultAllCheckedOnSelect(rule, allCheckedOrCheckList) { if (!this.isMultiple(rule)) { return; } const forAllCheck = typeof allCheckedOrCheckList === 'boolean'; let ret = false; // 只要触发了远程搜索,就不会打上 全 标记 if (this.isRemoteSearchedRule(rule)) { ret = false; } else if (forAllCheck) { // 如果是全选项触发的中,全标记的值与 全选项的状态一致 ret = allCheckedOrCheckList; } else { // 如果是非全选项触发的中,则判断所有选项都被中,即 中列表包含所有选项 // 为什么要用 判断中列表是否包含了所有列表,是因为有需求: // 模糊搜索后,列表项会发生变化,如果所有列表项被中,全部也要中 ret = this.isSelectedContainsAllOptions(rule, allCheckedOrCheckList); } this.updateDefaultAllChecked(rule, ret); }, isAllCheckedTagShow(rule) { return this.isMultiple(rule) && !this.isRemoteSearchedRule(rule) && this.isDefaultAllCheckedRule(rule); }, getShowAllCheckedTagBindingValue(rule, selectOptionLabels, ruleValueList) { return { isAllChecked: this.isAllCheckedTagShow(rule), options: selectOptionLabels[rule.id], checked: ruleValueList[rule.id], label: this.$t('semantic.material.MySelect.label.allChecked'), updateAllCheckedStatus: allChecked => { this.updateDefaultAllChecked(rule, allChecked); }, check: options => { this.$set(this.ruleValueList, rule.id, options); }, showLog: false, }; }, setPromise() { return (promise = new Promise((rawResolve, rawReject) => { resolve = rawResolve; reject = rawReject; })); }, clearPromise() { promise = null; resolve = null; reject = null; }, changeRuleList(newVal) { const checked = newVal ? [newVal].flat() : []; // 使用 this.$set 确保 ruleList 的更新是响应式的 this.$set(this, 'ruleList', checked.flatMap(id => { return this.configDataMapById.get(id).customOptions ?? []; })); }, isMultiple(rule) { return rule.functionalOperator?.includes('IN'); }, // 因为select是循环渲染出来的,所以绑定的ref也是动态的 handleRef(rule) { if (this.isMultiple(rule)) { return `multiSelect${rule.id}`; } else { return `select${rule.id}`; } }, remoteMethod(rule, selectValue) { this.processData(rule, selectValue, false); const select = this.$refs[this.handleRef(rule)][0]; select.state.cachedOptions.forEach(item => { item.state.visible = !selectValue || showSelectLabel(rule, selectValue, item.label); }); }, normalizeQueryParams(rule, selectValue) { const { modelId, tableId, tableName } = rule; let params = getQueryParams(modelId, tableId, tableName, rule, selectValue); params.resultFilter.having = ''; // 分组筛器,这里传空 return this.normalizeCascadeRuleQueryParams(rule, params); }, normalizeProcessDataFetcher(rule, selectValue, useCache = false) { if (rule.cascadeRuleList.length) { const params = this.normalizeQueryParams(rule, selectValue); return queryDetailData({ ...params, useCache }); } else { return this.getData(rule, selectValue, useCache); } }, setFieldValue(rule, content) { const obj = getFieldDataFromContent(rule, content); this.$set(this.selectOptionLabels, rule.id, obj.valueFieldData); }, getParamsOptions(rule) { const list = rule.field.valueList.map(item => ({ value: item.value, label: item[this.nameKey] })); this.$set(this.selectOptionLabels, rule.id, list); }, // 数据处理 async processData(rule, selectValue, useCache = false) { this.searchValue = selectValue; if (rule.tableId === 'params') { this.getParamsOptions(rule); return; } this.$set(this.loadingList, rule.id, true); return this.normalizeProcessDataFetcher(rule, selectValue, useCache) .then( data => { if (selectValue === this.searchValue) { this.setFieldValue(rule, data); this.$set(this.remoteSearched, rule.id, Boolean(selectValue)); } }, e => { this.$set(this.remoteSearched, rule.id, false); return Promise.reject(e); }, ) .finally(() => { this.$set(this.loadingList, rule.id, false); }); }, getData(rule, searchText, useCache) { const { modelId, tableId, tableName } = rule; const params = getQueryParams(modelId, tableId, tableName, rule, searchText); return queryDetailData({ ...params, useCache }); }, normalizeCondition(rule, ruleValue) { const field = { ...rule.field }; return { functionalOperator: rule.functionalOperator, field: { id: field.id, }, args: { type: field.customDataType || field.dataType, values: [...ruleValue].flat(), }, tableId: rule.tableId, }; }, /** 已拼查询条件中的 conditions */ conditionsOfParams(params) { try { return JSON.parse(params.resultFilter.where)?.conditions ?? []; } catch (e) { return []; } }, /** 拼级联条件 */ normalizeCascadeRuleQueryParams(rule, params) { if (!rule.cascadeRuleList.length) { return params; } const cascadeRuleList = rule.cascadeRuleList; // 条件操作符,带入已拼的搜索关键字及其他 const conditions = this.conditionsOfParams(params); // 多个上级 this.ruleList.forEach(item => { if (cascadeRuleList.includes(item.id)) { // 上级已值 const value = this.ruleValueList[item.id]; if (!isEmptyStringArray(value)) { conditions.push(this.normalizeCondition(item, value)); } } }); // 如果父级有部分是非全的,conditions 一定是非空数组 if (conditions.length) { params.resultFilter.where = JSON.stringify({ logicalOperator: 'and', // 只有一层默认传and conditions, }); } return params; }, /** 非全选项切换中状态回调 */ onSelectChange(rule, checkedList) { this.$set(this.ruleValueList, rule.id, checkedList); console.log(this.ruleValueList, rule.id, this.ruleValueList[rule.id],'中的值'); this.updateDefaultAllCheckedOnSelect(rule, checkedList); // 触发级联查询 if (this.cascadeRuleMap.get(rule.id)?.length) { // 下级字段 this.setSelectChangeCascaded(rule); } }, // 级联字段清空 setSelectChangeCascaded(rule) { this.ruleList.forEach(item => { if (this.cascadeRuleMap.get(rule.id)?.includes(item.id)) { // 清空已 this.$set(this.ruleValueList, item.id, ''); // 清空下拉框值 this.$set(this.selectOptionLabels, item.id, []); // 查询下拉框值 this.processData(item, '', false); } }); }, /** 清除中项时执行的回调 */ onClearSelection(rule) { this.remoteMethod(rule, ''); }, initDefaultAllChecked() { this.ruleListData?.forEach(rule => { this.defaultAllChecked[rule.id] = false; }); }, getChildRuleId(rule, ruleList) { const childRuleId = ruleList.filter(item => item.cascadeRuleList.includes(rule.id)).map(item => item.id); childRuleId.length && this.cascadeRuleMap.set(rule.id, childRuleId); }, async show(buttonConfig) { this.title = buttonConfig[this.nameKey]; const serviceConfig = buttonConfig.service; this.cascadeRuleMap.clear(); this.initDefaultAllChecked(); this.configData = serviceConfig.list.map(item => ({ ...item, customOptions: item.customOptions?.map(rule => { this.getChildRuleId(rule, item.customOptions || []); return { ...rule, parentId: item.id, }; }) || [], })); this.isMultiMain = serviceConfig.isMultiple ?? false; this.mainOptionsLabel = serviceConfig[this.nameKey]; this.mainOptions = this.configData.map(item => ({ text: item?.servicePath?.[this.nameKey], label: item.id })); if (this.isMultiMain) { this.formData.selectMainKey = []; } else { this.formData.selectMainKey = ''; } this.ruleValueList = {}; this.selectOptionLabels = {}; this.visible = true; await this.$nextTick(); this.$refs.form?.clearValidate?.(); // 返回 promise,将 show 方法设计成异步方法,点确定的时候,兑现 return this.setPromise(); }, reset() { this.remoteSearched = {}; this.defaultAllChecked = {}; this.ruleValueList = {}; this.selectOptionLabels = {}; }, hide(success = true) { if (reject) { this.visible = false; this.reset(); if (!success) { reject(new Error(Export.ErrorMsg.CANCEL)); } this.clearPromise(); } }, // 获取所有的中值 getOptions(id) { const selectRule = this.ruleList.filter(item => item.parentId === id); const options: unknown[] = []; selectRule.forEach(rule => { let selectValues = []; if ((this.isMultiple(rule) && this.ruleValueList[rule.id].length) || this.ruleValueList[rule.id]) { selectValues.push(this.ruleValueList[rule.id]); } selectValues = selectValues.flat(); if (selectValues.length) { options.push({ key: rule.exportType, value: selectValues, }); } }); return options; }, // 数据拼装 handleParams() { const selectServiceList = this.configData.filter(item => { if (this.isMultiMain) { return this.formData.selectMainKey.includes(item.id); } return this.formData.selectMainKey === item.id; }); const params = selectServiceList.map(item => ({ config: item, options: this.getOptions(item.id), })); return params; }, async onConfirm() { await this.$refs.form?.validate?.(); // resolve 一定不能是 null 或 undefined, // 如果是 null 或 undefined,一定是 setPromise 的调用时机不对 // 需要纠正 setPromise 调用时机,而不是对 resolve 进行空值判断 resolve!(this.handleParams()); this.hide(); }, onClose() { this.hide(false); }, onCancel() { this.hide(false); }, }, }); </script> <style lang="less" scoped> .iconHelp { margin-left: 5px; font-size: 1em; fill: #666; &:hover { fill: #0067d1ed; } } .flex-wrap { display: flex; align-items: center; display: inline-block } </style> aui-form 标签上 :model 绑定要用来验证的数据对象,:rules 绑定用来验证表单的规则。 aui-form-item的 prop 属性值需要和 rules 中校验字段对应,prop 属性值和表单组件绑定的变量名一定要相同。 由于<aui-form-item :prop="rule.id"> 和v-model="ruleValueList[rule.id]"对不上,所以导致校验有问题,该怎么修复
最新发布
12-05
### 实现方法 为了在 Element UI 的 `el-select` 组件中自定义选项框并加入添加按钮,可以通过修改 CSS 和利用 Vue.js 的特性来完成这一需求。具体来说,可以在 `el-select` 下添加一个禁用的 `el-option` 并设置其 value 为 undefined 来作为占位符,再通过覆盖默认样式使该位置显示成所需的按钮形式[^3]。 #### 自定义样式的实现方式如下: 1. **HTML 结构** 需要在原有的 `<el-select>` 中引入一个新的 `<el-option>` 或者其他 HTML 元素用于表示按钮,并确保此元素不会影响到实际的择逻辑。对于这个特定的需求,创建一个不可中的条目是一个不错的方法。 2. **CSS 覆盖** 使用自定义类名或更具体的 CSS 择器来调整新添加按钮的位置、大小以及外观等属性,使其看起来像一个真正的按钮而不是普通的列表项。这里给出一段简单的例子展示如何改变最后一个选项(即我们用来模拟按钮的那个)的样式: ```css /* 修改最后一条记录(假定是我们的'添加'按钮) */ .custom-add-button { cursor: pointer; text-align: center; padding: 0 !important; font-size: 12px; color: #409EFF; background-color: transparent; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } /* 移除默认高亮效果 */ .custom-add-button:hover, .custom-add-button:focus { background-color: rgba(64, 158, 255, 0.1); } /* 添加图标或其他装饰性内容 */ .custom-add-button::before{ content:"+ 新增"; } ``` 3. **JavaScript 处理点击事件** 当用户点击了这个特殊的 "按钮" 后,应该执行相应的业务逻辑,比如打开对话框让用户输入新的数据等等。这通常涉及到监听 click 事件并将它绑定到某个函数上。 ```javascript methods:{ handleAddOption(){ alert('This is a custom add button'); // Your logic here... } }, mounted() { const addButton = this.$refs.addBtn.$el; addButton.addEventListener('click',this.handleAddOption); } ``` 4. **Vue 模板部分** 将上述所有的配置组合起来形成完整的模板结构。注意这里的 key 属性是为了防止与其他正常工作的 option 发生冲突而特意指定的一个唯一标识;disabled 设置为 true 表示这条记录不允许被真正意义上的 “择”。 ```html <!-- Select Component --> <el-select v-model="selectedValue"> <el-option v-for="(item,index) in options" :key="index" :label="item.label" :value="item.value"></el-option> <!-- Custom Add Button --> <el-option ref="addBtn" class="custom-add-button" disabled :value="undefined">+</el-option> </el-select> ``` 以上就是关于如何在 Element UI 的 select 组件内嵌入一个具有特殊功能的按钮的大致思路和技术细节说明。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值