基於Element UI的Select控件實現多選框中單行顯示&左右移動

控件主要功能,可以單行顯示多選的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');
			}
		}
	}

 

下面看下效果圖:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章