Как общаться между веб-компонентами (нативный интерфейс)? - PullRequest
2 голосов
/ 05 марта 2019

Я пытаюсь использовать нативные веб-компоненты для одного из моих проектов пользовательского интерфейса и для этого проекта, я не использую никаких фреймворков или библиотек, таких как Polymer и т. Д. Я хотел бы знать, есть ли лучший способ или другой способвзаимодействовать между двумя веб-компонентами, как мы делаем в angularjs / angular (как концепция шины сообщений).

В настоящее время в веб-компонентах пользовательского интерфейса я использую dispatchevent для публикации данных и полученияданные, я использую addeventlistener .Например, есть 2 веб-компонента, ChatForm и ChatHistory.

// chatform webcomponent on submit text, publish chattext data 
this.dispatchEvent(new CustomEvent('chatText', {detail: chattext}));

// chathistory webcomponent, receive chattext data and append it to chat list
this.chatFormEle.addEventListener('chatText', (v) => {console.log(v.detail);});

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

Ответы [ 3 ]

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

Если вы рассматриваете веб-компоненты как встроенные компоненты, такие как <div> и <audio>, тогда вы можете ответить на свой вопрос.Компоненты не взаимодействуют друг с другом.

Как только вы начинаете разрешать компонентам общаться друг с другом напрямую, у вас нет компонентов, у вас есть система, которая связана вместе, и вы не можете использовать Компонент А безКомпонент B. Это слишком тесно связаны между собой.

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

Сказав, что есть два исключения из этого правила со встроенными компонентами:

  1. Тег <label>: он использует атрибут for для получения идентификатора другого компонента и, если он установлен и действителен, то передает фокус на другой компонент при нажатии на <label>

  2. Тег <form>: ищет элементы формы, которые являются дочерними для сбора данных, необходимых для публикации формы.

Но биные из них до сих пор не привязаны ни к чему.<label> сообщается получателю события focus и передает его только в том случае, если идентификатор установлен и действителен, или первому элементу формы как дочерний.И элементу <form> не важно, какие дочерние элементы существуют или сколько он просто проходит через всех своих потомков, находя элементы, которые являются элементами формы, и захватывает их свойство value.

Но, как правило, выследует избегать разговора одного компонента-брата с другим.Методы перекрестной связи в приведенных выше двух примерах, вероятно, являются единственными исключениями.

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

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

Как правило, я никогда не позволяю элементам братьев и сестер разговаривать друг с другом, и единственным способом, которым они могут общаться со своимиродители переживают события .Родители могут напрямую общаться со своими детьми с помощью атрибутов, свойств и функций.Но этого следует избегать при любых других условиях.

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

+ 1 для обоих остальных ответов. События являются лучшими, потому что тогда Компоненты слабо связаны

Обратите внимание, что в detail пользовательского события вы можете отправлять все, что захотите.

Выполнение управляемой событиями функции:

Поэтому я использую (код псевдо):

Элементы, определяющие игру пасьянс / свободная ячейка:

-> game Element
  -> pile Element
    -> slot Element
      -> card element
  -> pile Element
    -> slot Element
      -> empty

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

он посылает Событие (поднимая DOM к игровому элементу)

    //triggered by .dragend Event
    card.say(___FINDSLOT___, {
                                id, 
                                reply: slot => card.move(slot)
                            });    

Примечание: replyявляется функцией определение

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

   pile.on(game, ___FINDSLOT___, evt => {
                                      let foundslot = pile.free(evt.detail.id);
                                      if (foundslot.length) evt.detail.reply(foundslot[0]);
                                    });

Отвечает только одна куча, соответствующая evt.detail.id:

!!! выполняя функцию card, отправленную в evt.detail.reply

И получая техническую информацию: функция выполняется в pile scope!

(приведенный выше код является псевдокодом! )

Почему?!

Может показаться сложным;
Важная часть заключается в том, что элемент pile НЕ связан к методу .move() в элементе card.

Связь only - это имя события: ___FINDSLOT___ !!!

Это означает, что card всегда находится под контролем, и одно и то же событие (имя) может использоваться для:

  • Куда может пойти карта?
  • Какое лучшее место?
  • Какая карта на реке 1079 * pile делает фулл-хаус?
  • ...

В моем электронном коде pile тоже не связан с evt.detail.id,

Пользовательские события отправляют только функции



.say() и .on() - мои собственные методы (для каждого элемента) для dispatchEvent и addEventListener

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

.. появится на GitHub позже в этом месяце

sneak peek:

Нет необходимостилюбые библиотеки, напишите свой собственный 'Message Bus'

Мой метод element.on() - это всего лишь несколько строк кода, обернутых вокруг функции addEventListener, поэтому их можно легко удалить:

    $Element_addEventListener(
        name,
        func,
        options = {}
    ) {
        let BigBrotherFunc = evt => {                     // wrap every Listener function
            if (evt.detail && evt.detail.reply) {
                el.warn(`can catch ALL replies '${evt.type}' here`, evt);
            }
            func(evt);
        }
        el.addEventListener(name, BigBrotherFunc, options);
        return [name, () => el.removeEventListener(name, BigBrotherFunc)];
    },
    on(
        //!! no parameter defintions, because function uses ...arguments
    ) {
        let args = [...arguments];                                  // get arguments array
        let target = el;                                            // default target is current element
        if (args[0] instanceof HTMLElement) target = args.shift();  // if first element is another element, take it out the args array
        args[0] = ___eventName(args[0]) || args[0];                 // proces eventNR
        $Element_ListenersArray.push(target.$Element_addEventListener(...args));
    },

.say( ) является абонентом:

    say(
        eventNR,
        detail,             //todo some default something here ??
        options = {
            detail,
            bubbles: 1,    // event bubbles UP the DOM
            composed: 1,   // !!! required so Event bubbles through the shadowDOM boundaries
        }
    ) {
        el.dispatchEvent(new CustomEvent(___eventName(eventNR) || eventNR, options));
    },

    Danny.say(
      __NATIVE_ELEMENTS_LOVERS__, 
      () => mail('danny@engelman.nl' , 'Re: early access to your E-lements GitHub')
    );
1 голос
/ 05 марта 2019

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

Напротив, если один пользовательский элемент знает другой по его ссылке, он может вызывать свое пользовательское свойство или метод :

//in chatForm element
chatHistory.attachedForm = this
chatHistory.addMessage( message )
chatHistory.api.addMessage( message )

В последнем примере, приведенном выше, связь осуществляется через устаревший объект, выставленный через свойство api.

Вы также можете использовать сочетание событий (одним способом) и методов (другим способом) в зависимости от того, как связаны пользовательские элементы.

Наконец, в некоторых ситуациях, когда сообщения являются базовыми, вы можете передавать (строковые) данные через атрибуты HTML :

chatHistory.setAttributes( 'chat', 'active' )
chatHistory.dataset.username = `$(this.name)`
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...