基于Element UI的Select控件实现多选框中单行显示&左右移动

12 篇文章 2 订阅
11 篇文章 0 订阅

控件主要功能,可以单行显示多选的tag,并且可以利用左右键移动tag在组件中的位置

直接上代码:

<el-select
			v-model="tags"
			ref="tagsSelect"
			multiple
			filterable
			remote
			clearable
			popper-class="tag-input-options"
			:remote-method="searchTags"
			:loading="isSearching"
			class="tag-input"
			@keyup.native.left="navLeft"
			@keyup.native.right="navRight">
			<el-option
				v-for="item in tagOptions"
				:key="item.id"
				:label="item.full_path.map(f => f.name).join('  >  ')"
				:value="item.id">
				<span class="tag-option" v-html="highlightTagOption(item.name)"></span>
			</el-option>
  		</el-select>

下面是处理逻辑,主要是navLeft以及navRight方法的实现(typescript):

主要思路就是改变left,控制tag在select中的位移

const TAGS_SELECTOR = '.tag-input .el-select__tags';
const TAG_SELECTOR = '.tag-input .el-select__tags .el-tag';

private navLeft() {

		let $hitTagDoms = $(TAG_SELECTOR + '.is-hit');
		if (!$hitTagDoms.length) {
			$(TAG_SELECTOR).last().addClass('is-hit');
			return;
		} else if ($hitTagDoms.is($(TAG_SELECTOR).first())) {
			$(TAG_SELECTOR).removeClass('is-hit');
			$(TAG_SELECTOR).last().addClass('is-hit');
			$(TAGS_SELECTOR).css('left', '11px');
			return;
		}

		let $lastTagDom = $hitTagDoms.hasClass('is-hit') ? $hitTagDoms.prev() : $hitTagDoms;
		$(TAG_SELECTOR).removeClass('is-hit');
		$lastTagDom.addClass('is-hit');

		let firstTagRect = $(TAG_SELECTOR).get(0).getBoundingClientRect() as DOMRect;
		let containerTagRect = $('.tag-input').get(0).getBoundingClientRect() as DOMRect;
		
		let left = Number.parseFloat($(TAGS_SELECTOR).css('left'));
		left = Number.isNaN(left) ? 0 : left;
		let totalLeft = left + ($lastTagDom.innerWidth() as number);

		if (totalLeft >= containerTagRect.x - firstTagRect.x + 11) { // 11 is padding left of tags
			totalLeft = left + containerTagRect.x - firstTagRect.x + 11;
		}
		
		$(TAGS_SELECTOR).css('left', totalLeft + 'px');
	}
private navRight() {

		let $lastHitTagDoms = $(TAG_SELECTOR + '.is-hit');
		if (!$lastHitTagDoms.length || $lastHitTagDoms.is($(TAG_SELECTOR).last())) { return; }

		$(TAG_SELECTOR).removeClass('is-hit');
		let $hitTagDoms = $lastHitTagDoms.next();
		$hitTagDoms.addClass('is-hit');

		let hitTagRect = $hitTagDoms.get(0).getBoundingClientRect() as DOMRect;
		let containerTagRect = $('.tag-input').get(0).getBoundingClientRect() as DOMRect;

		if (hitTagRect.right + 56 > containerTagRect.right) { // 56 is width of search button
			let left = Number.parseFloat($(TAGS_SELECTOR).css('left'));
			left = Number.isNaN(left) ? 0 : left;
			let totalLeft = left - ($hitTagDoms.innerWidth() as number);
			if ($hitTagDoms.is($(TAG_SELECTOR).last())) { // assure input showing
				totalLeft = 0;
			}
			$(TAGS_SELECTOR).css('left', totalLeft + 'px');
		}
	}

为了不让select控件多选换行,需要覆盖一下相关的css:

.tag-input {
		width: 645px;
		overflow-x:hidden;

		.el-select__tags {
			flex-wrap: nowrap;
			justify-content: flex-end;
			transition: left .5s;
        }
}

上面这样实现方式还有几个问题:

1)左右键会影响select中的input光标位置

2)在下拉框显示的时候,删除tag,会造成下拉框的位置偏移

3)把tag滑到最开始的时候,从前往后删除tag,会造成空白,因为没有调整left值

可以提供解决的思路:

1)可以不用left,right键控制移动tag,换成其他键

2)在删除的时候,手工隐藏下拉框,在输入搜索的时候在显示出来

3)在删除的时候,调整left值

private renderingTag() {
		let $firstTagDom = $(TAG_SELECTOR + ':first-child');
		if ($firstTagDom.length) {
			let firstTagRect = $firstTagDom.get(0).getBoundingClientRect() as DOMRect;
			let containerTagRect = $('.tag-input').get(0).getBoundingClientRect() as DOMRect;

			if (firstTagRect.left > containerTagRect.left + 11) { // 11 is margin left
				let left = Number.parseFloat($(TAGS_SELECTOR).css('left'));
				left = Number.isNaN(left) ? 0 : left;
				left -= (firstTagRect.left - containerTagRect.left - 11);
				$(TAGS_SELECTOR).css('left', left + 'px');
			}
		}
	}

 

下面看下效果图:

可以使用 Element UISelect 控件结合远程搜索功能来实现。下面是一个简单的示例代码: ```vue <template> <div> <el-select v-model="selectedValue" remote filterable remote-method="remoteSearch" :loading="loading" :remote-method="remoteSearch" :loading-text="'Searching...'" :no-match-text="'No matching results'" :value-key="'value'" > <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" ></el-option> </el-select> </div> </template> <script> export default { data() { return { selectedValue: '', loading: false, options: [] }; }, methods: { remoteSearch(query) { this.loading = true; // 发起远程请求,根据 query 获取匹配的数据 // 假设远程请求返回的数据格式为 [{ value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }] setTimeout(() => { // 模拟异步请求 this.loading = false; this.options = [ { value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' } ]; }, 1000); } } }; </script> ``` 上述代码,我们使用了 `remote` 属性来开启远程搜索的功能,通过 `remote-method` 属性指定了远程搜索的方法名 `remoteSearch`。在 `remoteSearch` 方法,你可以发起异步请求,根据用户输入的 `query` 参数获取匹配的数据,并将结果赋值给 `options` 数组。同时,我们使用了 `loading` 属性来展示加载状态。 这样,当用户在 Select 控件输入内容时,会触发 `remoteSearch` 方法进行远程搜索,并根据搜索结果动态更新下拉选项。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值