Создание новых экземпляров пользовательских элементов HTML - PullRequest
0 голосов
/ 29 октября 2018

Я пытаюсь понять новые пользовательские элементы HTML.

Моя цель, учитывая некоторый массив данных, создать n экземпляров пользовательского элемента.Например, учитывая список из 10 пользователей, создайте 10 пользовательских html-объектов.

Хорошо, поэтому я определяю пользовательский элемент в html

HTML

<template-user>
   <div class="user-name"></div>
</template-user>

Затем я создаю свой контроллер

JS

class UserTemplate extends HTMLElement {
   constructor(){
      super();
      this.username = this.querySelectorAll('[class="user-name"]')[0];
   }
   setName(name){
      this.username.innerHtml = name;
   }
}
customElements.define('template-user', UserTemplate);

Страница загружается нормально, но теперь я не понимаю, как использовать повторно этот элемент.Если бы я занимался обычными вещами старой школы, у меня был бы цикл, откачивающий некоторые строки HTML и устанавливающий что-то innerHTML.Но сейчас я бы предпочел сделать что-то вроде

for(let i = 0; i < users.length; i++){
   let userTemplate = new UserTemplate();
   userTemplate.setName(user.name);
   // append to user list, etc..
}

Когда я пытаюсь это сделать, кажется, что это почти работает.Но он не может найти username, то есть this.querySelectorAll вернет ноль.Это только когда я пытаюсь создать новый экземпляр этого элемента.Как тогда я должен создавать новые объекты DOM пользовательских элементов?

Ответы [ 4 ]

0 голосов
/ 30 апреля 2019

вы можете создавать свои компоненты и назначать свойства прямо в JS

let templateUser = document.createElement('template-user');
templateUser.userName= 'Your name here';
document.body.appendChild(templateUser);

или что-то подобное, основанное на ваших потребностях. У Google есть несколько документов здесь , примерно на 2/3 ниже описано, как «создать экземпляр в JavaScript». Что может быть довольно мощным, особенно в цикле for, как в вашем примере

0 голосов
/ 29 октября 2018

Убедитесь, что вы понимаете требования и ограничения конструкторов для веб-компонентов:


https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-conformance

4.13.2 Требования к конструкторам пользовательских элементов

При разработке пользовательских конструкторов элементов авторы обязаны соблюдать следующие требования соответствия:

  • Безпараметрический вызов super () должен быть первым оператором в теле конструктора, чтобы установить правильную цепочку прототипов и это значение перед выполнением любого следующего кода.
  • Оператор return не должен появляться где-либо внутри тела конструктора, кроме случаев, когда это простое раннее возвращение (возврат или возврат этого).
  • Конструктор не должен использовать методы document.write () или document.open ().
  • Атрибуты и дочерние элементы не должны проверяться, так как в случае отсутствия обновления ни один из них не будет присутствовать, а использование обновлений делает элемент менее пригодным для использования.
  • Элемент не должен иметь никаких атрибутов или дочерних элементов, поскольку это нарушает ожидания потребителей, которые используют методы createElement или createElementNS.
  • В общем, работа должна быть максимально отложена до connectedCallback, особенно работа, включающая выборку ресурсов или рендеринг. Однако обратите внимание, что connectedCallback можно вызывать более одного раза, поэтому любая работа по инициализации, которая действительно является одноразовой, потребует защиты, чтобы предотвратить ее выполнение дважды.
  • В общем случае конструктор должен использоваться для установки начального состояния и значений по умолчанию, а также для настройки прослушивателей событий и, возможно, теневого корня.

Некоторые из этих требований проверяются во время создания элемента, прямо или косвенно, и их несоблюдение приведет к созданию пользовательского элемента, который не может быть реализован парсером или API DOM. Это верно даже в том случае, если работа выполняется внутри инициируемой конструктором микрозадачи, поскольку контрольная точка для микрозадачи может появиться сразу после построения.


Вы можете внести изменения, подобные этим:

class TemplateUser extends HTMLElement {
  static get observedAttributes() {
    return ['user-name'];
  }

  constructor(){
    super();
    this.attachShadow({mode:'open'});
    this.shadowRoot.innerHTML = '<div></div>';
  }
   
  attributeChangedCallback(attrName, oldVal, newVal) {
    if (oldVal !== newVal) {
      this.shadowRoot.firstChild.innerHTML = newVal;
    }
  }
 
  get userName() {
    return this.getAttribute('user-name');
  }
  
  set userName(name) {
    this.setAttribute('user-name', name);
  }
}

customElements.define('template-user', TemplateUser);


setTimeout( function () {
  var el = document.querySelector('[user-name="Mummy"]');
  el.userName = "Creature from the Black Lagoon";
}, 2000);
<template-user user-name="Frank N Stein"></template-user>
<template-user user-name="Dracula"></template-user>
<template-user user-name="Mummy"></template-user>

При этом используется shadowDOM для хранения <div>, затем вы устанавливаете значение с помощью атрибута user-name или свойства userName.

0 голосов
/ 29 октября 2018

Когда вы создаете пользовательский элемент через Javascript с помощью new, вы можете установить некоторые переменные, которые будут передаваться в качестве параметров в методе constrcutor():

for (let user of users) {
   document.body.appendChild( new UserTemplate(user.name) )
}

Вы можете получить его и сохранить в переменной объекта или использовать в качестве переменной в строке литерала шаблона в Shadow DOM.

class UserTemplate extends HTMLElement {
    constructor(username){
        super()
        //this.username = username
        this.attachShadow({ mode:'open' })
            .innerHTML = `<div class="user-name"> ${username} </div>` 
    }
}
customElements.define('template-user', UserTemplate);
0 голосов
/ 29 октября 2018

Но он не может найти имя пользователя, т.е. this.querySelectorAll вернет ноль.

Когда вы создаете новый экземпляр, у нового элемента нет дочерних элементов, поэтому querySelectorAll вернет пустоеNodeList.Если вы запросите DOM и выберете template-user, который был определен в вашей разметке, то свойство username будет ссылаться на ваш элемент div.

Если вы хотите, чтобы динамически сгенерированный элемент template-userпо умолчанию у вас есть дочерний элемент <div class="user-name"></div>, вы должны создать и добавить элемент в свой конструктор.

Также для выбора первого соответствующего элемента вы можете использовать .querySelector(...) вместо .querySelectorAll(...)[0].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...