The main function of the control is to display multiple tags in a single line, and to move tags in components by using left and right keys.
Code directly:
<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>
The following is the processing logic, mainly the implementation of navLeft and navRight methods (typescript):
The main idea is to change left and control the displacement of tag in 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'); } }
In order not to allow select controls to switch multiple lines, you need to override the relevant css:
.tag-input { width: 645px; overflow-x:hidden; .el-select__tags { flex-wrap: nowrap; justify-content: flex-end; transition: left .5s; } }
There are still several problems in the above way of implementation:
1) The left and right keys affect the position of the input cursor in select
2) When the drop-down box is displayed, deleting the tag will cause the position deviation of the drop-down box.
3) To slide the tag to the beginning, deleting the tag from the beginning will create a blank because the left value has not been adjusted.
It can provide solutions:
1) The mobile tag can be controlled without the left and right keys, and replaced with other keys.
2) When deleting, hide the drop-down box manually and display it when entering the search.
3) When deleting, adjust the left value
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'); } } }
Look at the picture below.