Почему пользовательские элементы не поддерживают атрибуты как объект?

Я пытаюсь передать атрибут данных в настраиваемый элемент как объект, но при получении внутри метода connectedCallback получаю значение «[объект объекта]» в строковой форме.

Так может ли кто-нибудь помочь мне выяснить, что нужно делать, чтобы получить атрибуты как объект внутри custom-element (веб-компонента).

образец кода

<script>
class myElements extends HTMLElement {
    createdCallback() {
        this.innerHTML = `<h1>Hello</h1>`;
    }
    attachedCallback() {
        console.log(this.getAttribute('data'));
    }
}

 document.registerElement('my-element', myElements);
</script>

тег настраиваемого элемента

<script>
    var object = { key1: 111, key2: 222, key3: function(){return "hi"}, key4:[1,2,3]};

   function changeHandler() {
    page('/default', function() {
        // some logic to decide which route to redirect to
        if (admin) {
            page.redirect('/admin');
        } else {
            page.redirect('/guest');
        }
    });
}

</script>

<my-element data="object" onchange="changeHandler"></my-element>

Примечание: предположим, что <my-element> - это раскрывающийся список, который дает пользователю возможность выбрать какое-либо значение.

Решение: по-прежнему нет собственного решения в спецификациях настраиваемых элементов (v0 и v1).

Поскольку пользовательские элементы не поддерживают привязку данных, для этого нам нужен слой шугаринга (например, Polymer или SkateJS), как указано @tony в комментарии.


person coder    schedule 19.12.2016    source источник
comment
Отсутствуют кавычки при значении атрибута data-*. Какова цель сохранения функции в атрибуте элемента html?   -  person guest271314    schedule 19.12.2016
comment
Похоже, вы пытаетесь смешать синтаксис React с настраиваемыми элементами. Это не сработает.   -  person Bergi    schedule 19.12.2016
comment
@Bergi Нет, я просто хочу реализовать функциональность / функцию React, также я отредактировал свой вопрос, чтобы минимизировать путаницу   -  person coder    schedule 19.12.2016
comment
Вы можете попробовать что-то вроде этого: stackoverflow.com/questions/11697863/   -  person sidesquare    schedule 19.12.2016
comment
@ guest271314, основная цель - передать функции в атрибуте как обработчик callBack, например. ‹Данные моего элемента = объект onchange = changeHandler› ‹/my-element›   -  person coder    schedule 19.12.2016
comment
@coder основная цель - передать функции в атрибуте как обработчике callBack Какая у вас проблема? Вы можете определить object как глобальную переменную и использовать скобки для ссылки на object.   -  person guest271314    schedule 19.12.2016
comment
Ну object и changeHandler - это просто строки в значениях этих атрибутов, они не имеют отношения к вашему JS-коду. Пожалуйста, покажите нам точный код, который вы использовали для получения [object object].   -  person Bergi    schedule 19.12.2016
comment
@ guest271314 Проблема в том, что у меня есть раскрывающийся список (как настраиваемый элемент), поэтому требуется, чтобы когда пользователь выбирал любое значение из раскрывающегося списка, я хочу изменить маршрут страницы, а также я хочу, чтобы это действие было вне жизненного цикла компонента ( раскрывающийся список), чтобы отделить логику приложения от логики компонента (раскрывающегося списка). например, функция changeHandler () {/ * изменить маршрут * / page (./ nextPage); }   -  person coder    schedule 19.12.2016
comment
@coder См. исходный вопрос Почему пользовательские элементы не поддерживают атрибуты как объект? Я пытаюсь передать атрибут данных в настраиваемый элемент как объект, но при получении внутри метода connectedCallback получаю значение [объект объекта] в строковой форме.? Можете ли вы создать stacksnippets или jsfiddle для воспроизведения [object object]?   -  person guest271314    schedule 19.12.2016
comment
@ guest271314, согласен, но основная проблема в том, как передавать объекты / функции в качестве атрибута. Хорошо, я очень скоро отправлю фактический фрагмент кода.   -  person coder    schedule 19.12.2016
comment
@coder См. stackoverflow.com/help/mcve, stackoverflow.com/help/how-to-ask   -  person guest271314    schedule 19.12.2016
comment
@coder Как отмечали другие, значения атрибутов могут быть только строками. То, что вы ищете, - это эффективная привязка данных, которую сами Custom Elements не поддерживают из коробки. Для этого вам понадобится слой шугаринга (например, Polymer или SkateJS).   -  person tony19    schedule 19.12.2016
comment
@ tony19 Спасибо, чтобы подтвердить, что это недостающая функция в custom-element, мне также интересно, почему в спецификации custom-element отсутствуют эти важные функции. Вчера я также прочитал спецификацию custom-element v1, но у нее тоже такая же проблема.   -  person coder    schedule 19.12.2016


Ответы (2)


Попробуйте преобразовать объект в строку JSON,

var object = { key1: 111, key2: 222};
JSON.stringify(object);

Затем, когда вы хотите получить значение, проанализируйте его до объекта

JSON.parse(this.getAttribute('data'));
person Himanshu Tanwar    schedule 19.12.2016
comment
Спасибо @Himanshu за ваш комментарий и извините за реализацию формата объекта .... но как насчет этих типов объектов var object = {key1: 111, key2: 222, key3: function () {return hi}, key4: [1, 2,3]}; - person coder; 19.12.2016
comment
Предлагаемый подход (преобразование в строку и синтаксический анализ) не работает для объекта, имеющего функции в качестве значения внутри. - person coder; 19.12.2016

Пользовательские элементы не изменяют стандартное поведение атрибута HTML-элемента, которое всегда имеет тип string.

Из-за этого вы должны либо:

  1. Отправьте change событие из вашего настраиваемого элемента, которое вызовет обработчик onchange.

  2. Зарегистрируйте обратный вызов объекта / функции с помощью метода настраиваемого элемента.

  3. Измените атрибут состояния, который будет наблюдаться (с Mutation Observer) его контейнером.

Если вы все равно хотите использовать атрибут, вы всегда можете использовать eval().


Пример решения 1 с вызовом changeHandler():

//define custom element
class DropDown extends HTMLElement 
{
  connectedCallback ()
  {
    var span = this.querySelector( 'span' )

    //define ul list
    var ul = this.querySelector( 'ul' )

    ul.onclick = ev => {
      if ( this.value != ev.target.textContent )
      {
        this.value = ev.target.textContent
        this.setAttribute( 'value', this.value )
        span.textContent = this.value 
        this.dispatchEvent( new CustomEvent( 'change' ) )
      }
    }

    //show or hide
    this.onclick = ev => ul.classList.toggle( 'show' )
    
  }

}
customElements.define( 'drop-down', DropDown )
drop-down  {
  position: relative ;
  cursor: pointer ;
  display: inline-block ;
}
drop-down > span {
  border: 1px solid #aae ;
  padding: 2px 5px ;
}
drop-down > ul {
  position: absolute ;
  top: 4px ; left: 5px ;
  list-style: none ;
  outline: 1px solid #aae ;
  padding: 0 ;
  display: inline-block ;
  opacity: 0 ;
  transition: all 0.3s ease-out ;
  background: white ;
  visibility: hidden ;
  z-index: 10 ;
}
drop-down > ul.show {
  opacity: 1 ;
  visibility: visible ;
}
drop-down > ul > li {
  padding: 2px 5px ;
}
drop-down > ul > li:hover {
  background: lightgoldenrodyellow ;
}
<drop-down onchange="changeHandler()">
  <span>select value</span>
  <ul>
    <li>Chrome</li>
    <li>Firefox</li>
    <li>Opera</li>
    <li>Safari</li>
  </ul>
</drop-down>

<script>
  function changeHandler ()
  {
    console.log( 'changeHandler()', event.target.value )
  }
</script>

person Supersharp    schedule 19.12.2016