Веб-компоненты, передавать данные в и из - PullRequest
0 голосов
/ 18 мая 2018

Насколько я понимаю, данные передаются в пользовательский элемент html через его атрибуты и отправляются путем отправки CustomEvent.

Объекты JavaScript, очевидно, могут быть отправлены в поле detail события, но что, если элементу требуется много данных, передаваемых в него.Есть ли способ предоставить ему объект в JavaScript.

Что, если элемент, например, содержит переменное число частей, которые должны быть инициализированы или изменены динамически (например, таблица с переменным числом строк)?Я могу себе представить установку и изменение атрибута, состоящего из строки JSON, которая анализируется внутри компонента, но это не похоже на элегантный способ продолжить:

<my-element tableRowProperties="[{p1:'v1', p2:'v2'}, {p1:'v1',p2:'v2'}, {p1:'v1',p2:'v2'}]"></my-element>

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

Ответы [ 2 ]

0 голосов
/ 29 мая 2019

Существует шестой способ, который действительно похож на ответ @ Intervalia выше, но использует тег <script> вместо тега <template>.

Это тот же подход, который используется при уценкеЭлемент .

class MyEl extends HTMLElement {
  connectedCallback() {
    var data;
    
    try {
      data = JSON.parse(this.children[0].innerHTML);
    }
    
    catch(ex) {
      console.error(ex);
    }

    this.innerHTML = '';
    var pre = document.createElement('pre');
    pre.textContent = JSON.stringify(data,0,2);
    this.appendChild(pre);
  }
}

// Define our web component
customElements.define('my-el', MyEl);
<my-el>
  <script type="application/json">[{"a":1},{"b":"<b>Hi!</b>"},{"c":"</template>"}]</script>
</my-el>
0 голосов
/ 18 мая 2018

Передача данных в

Если вы действительно хотите / должны передавать большие объемы данных в ваш компонент, вы можете сделать это четырьмя различными способами:

1) Использовать свойство. Это самое простое, поскольку вы просто передаете объект, передавая значение элементу следующим образом: el.data = myObj;

2) Используйте атрибут. Лично я ненавижу этоспособ сделать это таким образом, но некоторые платформы требуют передачи данных через атрибуты.Это похоже на то, как вы показываете в своем вопросе.<my-el data="[{a:1},{a:2}....]"></my-el>.Соблюдайте правила, относящиеся к экранированию значений атрибута .Если вы используете этот метод, вам нужно будет использовать JSON.parse для вашего атрибута, и это может не сработать.В HTML также может быть очень уродливо иметь огромное количество данных, отображаемых в атрибуте.

3 Передать его через дочерние элементы. Подумайте об элементе <select> с<option> дочерние элементы.Вы можете использовать любой тип элемента в качестве дочернего элемента, и они даже не должны быть настоящими элементами.В вашей функции connectedCallback ваш код просто захватывает все дочерние элементы и преобразует элементы, их атрибуты или их содержимое в данные, необходимые для вашего компонента.

4 Использование Fetch. Укажите URLдля вашего элемента, чтобы пойти получить свои собственные данные.Подумайте о <img src="imageUrl.png"/>.Если у вас уже есть данные для вашего компонента, это может показаться плохим вариантом.Но браузер предоставляет классную функцию встраивания данных, которая аналогична описанному выше варианту 2., но обрабатывается браузером автоматически.

Вот пример использования встроенных данных в изображении:

img {
  height: 32px;
  width: 32px;
}
<img src="data:image/svg+xml;charset=utf8,%3C?xml version='1.0' encoding='utf-8'?%3E%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0px' y='0px' viewBox='0 0 314.7 314.7'%3E%3Cstyle type='text/css'%3E .st0{fill:transparent;stroke:%23231F20;stroke-width:12;} .st1{fill:%23231F20;stroke:%23231F20;stroke-width:10;stroke-linejoin:round;stroke-miterlimit:10;} %3C/style%3E%3Cg%3E%3Ccircle class='st0' cx='157.3' cy='157.3' r='150.4'/%3E%3Cpolygon class='st1' points='108,76.1 248.7,157.3 108,238.6'/%3E%3C/g%3E%3C/svg%3E">

А вот пример использования встроенных данных в веб-компоненте:

function readSrc(el, url) {
    var fetchHeaders = new Headers({
      Accept: 'application/json'
    });

    var fetchOptions = {
      cache: 'default',
      headers: fetchHeaders,
      method: 'GET',
      mode: 'cors'
    };

    return fetch(url, fetchOptions).then(
      (resp) => {
        if (resp.ok) {
          return resp.json();
        }
        else {
          return {
            error: true,
            status: resp.status
          }
        }
      }
    ).catch(
      (err) => {
        console.error(err);
      }
    );
  }

  class MyEl extends HTMLElement {
    static get observedAttributes() {
      return ['src'];
    }

    attributeChangedCallback(attrName, oldVal, newVal) {
      if (oldVal !== newVal) {
        this.innerHtml = '';
        readSrc(this, newVal).then(
          data => {
            this.innerHTML = `
${JSON.stringify(data,0,2)}
            
`;});}}} // Определяем наш веб-компонент customElements.define ('my-el', MyEl);
<!--
This component would go load its own data from "data.json"
<my-el src="data.json"></my-el>
<hr/>
The next component uses embedded data but still calls fetch as if it were a URL.
-->
<my-el src="data:json,[{&quot;a&quot;:9},{&quot;a&quot;:8},{&quot;a&quot;:7}]"></my-el>

Вы можете сделать этоТо же самое с использованием XHR, но если ваш браузер поддерживает веб-компоненты, то он, вероятно, поддерживает выборку.И есть несколько хороших выборочных полифилов, если они вам действительно нужны.

Лучшее преимущество использования варианта 4 заключается в том, что вы можете получить свои данные с URL и вы можете напрямую встраивать ваши данные.Именно так работает большинство предопределенных элементов HTML, например <img>.

ОБНОВЛЕНИЕ

Я подумал о пятом способе передачи данных JSON вобъект.Это с помощью тега <template> внутри вашего компонента.Это все еще требовало от вас вызова JSON.parse, но это может очистить ваш код, потому что вам не нужно избегать JSON.

class MyEl extends HTMLElement {
  connectedCallback() {
    var data;
    
    try {
      data = JSON.parse(this.children[0].content.textContent);
    }
    
    catch(ex) {
      console.error(ex);
    }

    this.innerHTML = '';
    var pre = document.createElement('pre');
    pre.textContent = JSON.stringify(data,0,2);
    this.appendChild(pre);
  }
}

// Define our web component
customElements.define('my-el', MyEl);
<my-el>
  <template>[{"a":1},{"b":"&lt;b>Hi!&lt;/b>"},{"c":"&lt;/template>"}]</template>
</my-el>

Передача данных

Существует три способа получить данные из компонента:

1) Считать значениеиз собственности.Это идеально, поскольку свойство может быть чем угодно и обычно в формате данных, которые вы хотите.Свойство может вернуть строку, объект, число и т. Д.

2) Считать атрибут.Это требует от компонента поддерживать атрибут в актуальном состоянии и может быть неоптимальным, поскольку все атрибуты являются строками.Таким образом, ваш пользователь должен знать, нужно ли ему звонить JSON.parse по вашему значению или нет.

3) События.Это, наверное, самая важная вещь, которую нужно добавить к компоненту.События должны срабатывать при изменении состояния компонента.События должны запускаться на основе взаимодействия с пользователем и просто для предупреждения пользователя о том, что что-то произошло или что-то доступно.Традиционно вы включаете соответствующие данные в ваше мероприятие.Это уменьшает объем кода, который должен написать пользователь вашего компонента.Да, они по-прежнему могут читать свойства или атрибуты, но если ваши события включают в себя все соответствующие данные, им, вероятно, не нужно будет ничего делать.

...