Делегирование события x-tag: доступ к корневому элементу

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

xtag.register('settings-pane', {
  lifecycle: {
    created: function () {
      var tpl = document.getElementById('settings-pane'),
          clone = document.importNode(tpl.content, true);
      
      this.appendChild(clone);
    }
  },
  events: {
    'tap:delegate(button.close)': function (e) {
      rootElement.close(); // <- I don't know the best way to get rootElement
    }
  },
  methods: {
    close: function () {
      this.classList.add('hidden');
    }
  }
});
<template id="settings-pane">
  <button class="close">✖</button>
</template>

2 ответа

Решение

Привет, это автор библиотеки, позвольте мне прояснить это:

Для любого слушателя, установленного вами в DOM, X-Tag или vanilla JS, вы всегда можете использовать стандартное свойство e.currentTarget чтобы получить доступ к узлу, к которому был прикреплен слушатель. Для X-Tag, используете ли вы delegate псевдо или нет, e.currentTarget всегда будет ссылаться на ваш пользовательский элемент:

xtag.register('x-foo', {
  content: '<input /><span></span>',
  events: {
    focus: function(e){
      // e.currentTarget === your x-foo element
    },
    'tap:delegate(span)': function(e){
      // e.currentTarget still === your x-foo element
      // 'this' reference set to matched span element
    }
  }
});

Помните, что это стандартный API для доступа к элементу, к которому был прикреплен прослушиватель событий, подробнее здесь: https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget

Лучший подход к этой проблеме после нескольких месяцев ее решения - создать еще одно "псевдо", похожее на :delegate() псевдо, но это вызывает обратный вызов по-другому. Это добавляет :descendant() псевдо к xtag:

xtag.pseudos.descendant = {
    action: function descendantAction(pseudo, event) {
        var match,
            target = event.target,
            origin = target,
            root = event.currentTarget;
        while (!match && target && target != root) {
            if (target.tagName && xtag.matchSelector(target, pseudo.value)) match = target;
            target = target.parentNode;
        }
        if (!match && root.tagName && xtag.matchSelector(root, pseudo.value)) match = root;
        return match ? pseudo.listener = pseudo.listener.bind({component: this, target: match, origin: origin}) : null;
    }
};

Вы бы использовали это именно так, как вы бы :delegate(), но this будет ссылаться на объект, который, в свою очередь, будет ссылаться на целевой элемент (элемент, соответствующий селектору CSS, например, button.close), источник (элемент, получивший событие) и компонент (сам пользовательский элемент). Пример использования:

xtag.register('settings-pane', {
    methods: {
        close: function () {
            this.classList.add('hidden');
        }
    },
    events: {
        'tap:descendant(button.close)': function (e) {
            this.origin;    // <button> or some descendant thereof that was tapped
            this.target;    // <button> element
            this.component; // <settings-pane> element

            this.component.close(); 
        }
    }
});
Другие вопросы по тегам