Как сделать поле ввода тегов\меток на чистом js
Нужно сделать поле ввода тегов на чистом js без библиотек как в данном примере https://ruseller.com/lessons.php?id=992&rub=32 При вводе запятой или нажатии клавиши Enter весь введённый текст должен превратиться в тег. После можно продолжить вводить следующий тег и т.д. По клику на тег, он должен удалиться из текстового поля. Поле для тегов должно создаваться программно следующим образом::help:
let tagField = createTagsField(); document.body.append(tagField.element); |
Цитата:
Цитата:
Также можно перемещаться между тегами при помощи стрелок и теги удаляются, как обычный текст, при помощи клавиш BackSpace и Delete. <body><script> class TagsField extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); this.shadowRoot.innerHTML = ` <style> span { background-color: #4CAF50; color: white; text-shadow: 0 1px rgba(0, 0, 0, 0.5); box-shadow: 0 0.1em 0.1em rgba(0, 0, 0, 0.2); border-radius: 1em; padding: 0.45em 0.8em; margin: 0.1em; display: inline-block; } label { border: 1px solid #ccc; border-radius: .5em; padding: .5em; display: inline-flex; font: bolder 100% sans-serif; flex-wrap: wrap; position: relative; } label::before { content: "Input tags"; position: absolute; pointer-events: none; line-height: 0; top: 0; text-shadow: 2px 0 white, -2px 0 white; } input { all: unset; min-width: 5em; width: 0; padding: 0.45em 0.8em; margin: 0.1em; } </style> <label> <input> </label> `; this.input = this.shadowRoot.querySelector("input"); this.label = this.shadowRoot.querySelector("label"); this.input.value = "\u200b\u200b"; this.inputHandler = this.inputHandler.bind(this); this.contextMenuHandler = this.contextMenuHandler.bind(this); "input focus keydown keyup touchstart touchmove click".split(" ").forEach(type => { this.input.addEventListener(type, this.inputHandler); }); this.label.addEventListener("contextmenu", this.contextMenuHandler); } inputHandler(event) { if(event.type !== "focus" && event.type !== "click") { if( this.input.selectionStart === 0 && this.input.selectionEnd === 0 ) { if(this.input.previousElementSibling) { if(this.input.value.length === 1 || !this.input.value.startsWith("\u200b")) this.label.removeChild(this.input.previousElementSibling); else this.label.insertBefore( this.input.previousElementSibling, this.input.nextElementSibling ); } } if( this.input.selectionStart === this.input.value.length && this.input.selectionEnd === this.input.value.length ) { if(this.input.nextElementSibling) { if(this.input.value.length === 1 || !this.input.value.endsWith("\u200b")) this.label.removeChild(this.input.nextElementSibling); else this.label.insertBefore( this.input.nextElementSibling, this.input ); } } } var rawTags = this.input.value.slice(1, -1); if(event.type === "keyup" && event.key === "Enter") { rawTags += ","; } const tags = rawTags.split(","); const editableTag = tags.pop(); tags.filter(tag => tag).map(this.constructor.createTag).forEach(tag => { this.label.insertBefore(tag, this.input); }); this.input.value = `\u200b${editableTag}\u200b`; this.input.style.width = "0"; this.input.style.width = this.input.scrollWidth + "px"; this.input.selectionStart = Math.max(1, Math.min(this.input.selectionStart, this.input.value.length - 1)); this.input.selectionEnd = Math.max(1, Math.min(this.input.selectionEnd, this.input.value.length - 1)); } contextMenuHandler(event) { if(event.target.nodeName === "SPAN") { if(confirm("Remove tag?")) { event.preventDefault(); this.label.removeChild(event.target); } } } static createTag(tag) { const element = document.createElement("span"); element.textContent = tag; return element; } get tags() { return Array.from(this.label.querySelectorAll("span")).map(element => element.textContent); } } customElements.define("tags-field", TagsField); // Поле для тегов создаётся программно следующим образом: let tagField = document.createElement("tags-field"); document.body.append(tagField); </script> |
Malleys,
:thanks: |
Часовой пояс GMT +3, время: 01:26. |