Using element UI to add tag widget

Make a groove first:
input can get focus and select automatically, but it can't adapt text width;
Contentable can adapt the text width but can't call focus() and select()!
It's really frustrating to meet the need to select the sample text and change it when adding a new tag...

Start of text:

Environment: Vue cli, element UI

In this way, the adaptive mode is more beautiful:
First, analyze the automatic full selection of contentable:

let range = document.createRange(); 
range.selectNodeContents(newtag);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);

range is the area that we need to select when we create it, and selection is the area that has been selected on the screen. range can be added to the screen through the addRange method, and the effect we see is to automatically select it.
According to the document, selectNodeContents is to select a parent element that does not include all the child elements of the element itself, but when deleting the internal text, you can actually delete the parent element itself together.. The temporary solution is to wrap another layer of div in the outer layer, so that it is convenient for hover to locate the small fork deletion key in the upper right corner.

First, write an interface, use the elementui to make him look better, and then use the icon inside the fork:

<template>
	<div>
		<template v-for="(item,index) in tags"> 
			<div contenteditable="plaintext-only" class='el-button primary el-button--mini is-plain newtag' @blur="checkTag(index)"
			 @mouseenter="showCloseBtn(index)" @mouseleave="hideCloseBtn(index)">
				<div class="newtag-content" :ref='`newTag${index}`'>
					{{ item }}
				</div>
				<i class="close-i el-icon-circle-close" :ref="`closeI${index}`" @click="removeTag(index)"></i>
			</div>
		</template>
		<i class="el-icon-circle-plus-outline" @click="addTag()"></i>
	</div>
</template>

Methods to bind:
checkTag: if there is no content in the new tag, click the blank space and the tag disappears;
showCloseBtn: the mouse moves into the tag fork;
hideCloseBtn: the mouse moves out of the tag fork and disappears;
removeTag: click the fork in the upper right corner of the tag to delete the tag;
addTag: click the plus icon to add a tag, and select all the text automatically.

In addition, add a ref related to the loop index to each tag and icon for easy access to elements.

Implementation method, supplement css:

<script>
	export default {
		data() {
			return {
				tags:['Chuanjianguo','Aoguanhai'], //Increase or decrease tag s directly by manipulating array data
			}
		},
		methods:{
			addTag() {
				this.recForm.tags.push('new label');
				this.$nextTick(()=>{
					let len = this.recForm.tags.length;
					let newtag = this.$refs[`newTag${len-1}`][0]; //Get the new label, the last one in the array
					let range = document.createRange();
					range.selectNodeContents(newtag);
					window.getSelection().removeAllRanges();
					window.getSelection().addRange(range); //Auto select all
				});
			},
			showCloseBtn(index){
				this.$refs[`closeI${index}`][0].style.display = 'block'; //Show fork
			},
			hideCloseBtn(index){
				this.$refs[`closeI${index}`][0].style.display = 'none';  //Fork disappears
			},
			checkTag(index){ //Judge whether the tag has content
				let text = this.$refs[`newTag${index}`][0].innerText.trim();
				if(text.length==0){
					this.recForm.tags.pop();
				}else{
					this.recForm.tags[index] = text;
				}
			},
			removeTag(index){  //Delete fork
				this.recForm.tags.splice(index,1);
			},
		}
	}
</script>
<style scoped>
.close-i{
		position: absolute;
		top:-8px;
		right: -9px;
		display: none;
		cursor: pointer;
		font-size: 18px;
		background-color: white;
		border-radius: 10px;
	}
	.newtag{
		position: relative;
		cursor: text;
		overflow: visible;
		display: inline-block;
		padding: 0;	//Move the original padding 7px 15px to the inner layer, so that the mouse click position will be larger,
	}
	.newtag-content{
		margin: 7px 15px; 
	}
</style>

Final rendering:

Tags: Vue

Posted on Wed, 10 Jun 2020 02:19:18 -0400 by EagleAmerican