Как получить доступ к основателю вложенных веб-компонентов? - PullRequest
0 голосов
/ 18 марта 2019

Я реализую шаблон Orchestrator для своих веб-компонентов, например:

<body>
  <my-controller>
    <div>
      <my-list>
        <span>
          <my-item></my-item>
        </span>
      </my-list>
    </div>
  </my-controller>
</body>

Все созданные мной пользовательские элементы используют Shadow DOM, используя const root = super.attachShadow({mode: "open"}); root.appendChild(...);.

Из моей внутренней сети.компоненты, к которым я хочу подключиться my-controller компонент в connectedCallback():

public connectedCallback(): void
    {
        if (this.isConnected)
        {
            for (let node = this.parentElement; node; node = node.parentElement)
                if (node instanceof ContainerBase)
                {
                    this._service = (<ContainerBase>node).GetService(this);
                    break;
                }

            if (this._service) this.Reset();
            else throw new ReferenceError(`${this.nodeName.toLowerCase()}: Couldn't find host element while connecting to document.`);
        }
    }

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

Итак, если connectedCallback() вызывается на <my-list>, я могу достичь <my-controller>, но если connectedCallback() вызывается на <my-item>, я достигаю <span>.Я даже не могу достичь <my-list>, когда начинаю поиск с <my-item>.

Даже когда я хожу по дереву DOM после вызова connectedCallback(), я не могу выйти за пределы <span>, когда яначать с <my-item>.

Это намеренно?

Почему может Я получаю доступ к внешнему веб-компоненту из первого вложенного, а я не могу добраться до первого вложенного веб-компонента со второго вложенного?

Как мне полностью перейти на дерево DOM с любого вложенного уровня?

Ответы [ 3 ]

2 голосов
/ 20 марта 2019

Когда вы определяете содержимое пользовательского элемента в Shadow DOM, вы создаете отдельное дерево DOM.Shadow DOM - это DocumentFragment без корневого элемента.

Как следствие, вы не можете достичь его (интуитивного) предка, просто пройдя DOM вверх по свойству parentElement.

Чтобы достичьВ качестве основного элемента Shadow DOM вместо используется getRootNode() в сочетании с host.

Из <my-item> s connectedCallback() метод:

connectedCallback() {
   var parent = this.getRootNode().host
   console.log( parent.localNode ) // my-list
}

Если вы хотите получить предка, вы можете попробовать эту рекурсивную функцию .

1 голос
/ 18 марта 2019

Обычно считается недопустимым, чтобы внутренний / дочерний элемент имел доступ к данным из внешнего / родительского элемента.

Безопаснее и меньше использовать пользовательские события из внутренних компонентов, которыезахватывается внешними компонентами.

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

Вы можете сделать что-то вроде этого:

Детский элемент

connectedCallback() {
  this.dispatch(new CustomEvent('request-service'));
}

set service(val) {
  this._service = val;
}

get service() {
  return this._service;
}

Служебный элемент:

constructor() {
  super();
  this.addEventListener('request-service',
    evt => {
      evt.target.service = this.GetService(evt.target);
    }
  );
}
0 голосов
/ 20 марта 2019

ShadowRoot не является элементом, а ShadowRoot 'parentNode не является его хост-элементом.Вы должны заботиться о них.

function shadowIncludingParentElement(node) {
  if (node.parentElement)
    return node.parentElement;
  if (!node.parentNode)
    return null;
  if (node.parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE)
    return node.parentNode.host;
  return null;
}

...
for (let node = this.parentElement; node;
    node = shadowIncludingParentElement(node)) {
  ...
}
...