Создание настраиваемого поля ввода с веб-компонентами, добавляемыми через шаблон и настраиваемыми перед добавлением в DOM

Я пытаюсь создать собственное текстовое поле через веб-компоненты

'use strict';

class TextBox extends HTMLElement {

  constructor() {
    super();

    var shadow = this.attachShadow({ mode: 'open' });

    let textbox = document.createElement("input");
    shadow.appendChild(textbox);
    textbox.addEventListener("change", this.validate);


    textbox.value ="Init";

  }

   validate(event) {

    console.log("input can be validated");
  }

  get value() {
    console.log("get");
    let textbox = this.shadowRoot.querySelector("input");
    return textbox.value;

  }

  set value(newValue) {
    console.log("set");
    let textbox = this.shadowRoot.querySelector("input");
    textbox.value = newValue;
  }

}
customElements.define('test-textbox',TextBox);

Позже я хотел бы встроить пользовательский ввод в шаблон и изменить его значения перед добавлением:

 let control= document.getElementById("control");
 let clone = control.content.cloneNode(true);
 clone.children[0].value = "tb value has been changed before adding";
 document.getElementById("app").appendChild(clone);

Но если сделать это в моем коде, значение ввода остается на "Init", но значение моего пользовательского элемента управления будет иметь свойство "Значение tb было изменено перед добавлением".

Было бы лучше расширить с HTMLInput? Заданная процедура также срабатывает только один раз.

0 ответов

Значение - это атрибут ввода, а не свойство. Чтобы установить атрибут элемента HTML, вы должны использовать textbox.setAttribute('value', myNewValue)

Вам не нужно расширять HTMLInput. Вот как бы я это сделал. Я добавил передал все свойства, прикрепленные к <text-box /> к его внутреннему элементу ввода, но это не является необходимым, если вы не пытаетесь имитировать элемент ввода более близко.

Я надеюсь, что расширение определенных элементов, таких как HTMLInput, не будет проблемой в ближайшее время, но я склонен избегать их, потому что в настоящее время есть некоторые проблемы с ними.

const css = `
  <style>
    :host([hidden]) { display: none; }
    :host {
      display: block;
    }
    input {
      background-color: #f5f5f5;
      border: 1px solid transparent;
      border-radius: 4px;
      padding: 1em;
      font-size: 16px;
      width: 400px;
    }
    input:focus {
      background-color: #fff;
      border: 1px solid #dadce0;
      outline: 0;
    }
  </style>
`

const html = `<input type='text' value='Init' />`

class TextBox extends HTMLElement {
  static get observedAttributes () {
    return ['value']
  }

  constructor () {
    super()

    this.attachShadow({mode: 'open'})
    this.shadowRoot.appendChild(template.content.cloneNode(true))

    // Cache the value of the inputNode
    this.inputNode = this.shadowRoot.querySelector('input')

    this.inputNode.value = 'Something else'

    // Add all properties on text-box to input
    for (let i = 0; i < this.attributes.length; i++) {
      this.inputNode.setAttribute(
        this.attributes[i].nodeName,
        this.attributes[i].nodeValue
      )
    }
  }

  validate (event) {
    console.log('input can be validated')
  }

  get value () {
    return this.inputNode.value
  }

  set value (newValue) {
    this.inputNode.value = newValue
  }

  connectedCallback () {
    this.inputNode.addEventListener('change', this.validate)
  }

  disconnectedCallback () {
    this.inputNode.removeEventListener('change', this.validate)
  }

  attributeChangedCallback (name, oldValue, newValue) {
    if (name === 'value') {
      this.inputNode.value = newValue
    }
  }
}

const template = document.createElement('template')
template.innerHTML = `${css}${html}`

window.customElements.define('text-box', TextBox)
Другие вопросы по тегам