Передать функции в компонент трафарета

Можно ли передать функцию stencilJs составная часть?

Что-то вроде:

@Prop() okFunc: () => void;

У меня есть модальное и хочу динамически вызывать переданную функцию на Ok кнопка нажата в модальном нижнем колонтитуле, как onClick на обычной кнопке HTML.

1 ответ

Да, ты можешь. Это просто нормальный @Prop()декларация и очень хорошо играет в TSX. Тем не мение...

Как отмечено в другом ответе и комментариях, если вы используете компонент Stencil в простом HTML, вы не сможете использовать привязку атрибута-prop в Stencil для передачи функции (или любого нескалярного значения) в опору через Атрибут HTML.

Используйте DOM API

Это означает, что вам нужно взаимодействовать с DOM, если вы хотите прикреплять события или передавать свойства функций компонентам Stencil. Как только ваш компонент попадает в DOM, в нем действительно нет ничего особенного по сравнению с любым другим настраиваемым элементом.

Без JSX или другого шаблона DSL (например, Angular) вам нужно будет прикрепить события и установить свойства ссылки на функцию или объект с помощью JavaScript DOM API:

const componentInstance = document.querySelector('my-stencil-component')

// This works and will trigger a rerender (as expected for a prop change)
componentInstance.someFunc = (...) => { ... }

// This works for any event, including custom events fired from Stencil's EventEmitter
componentInstance.addEventListener('myCustomEvent', (event: MyCustomEvent) => { ... })

Если по какой-то причине вам абсолютно необходимо сделать это в своем HTML-документе:

<my-stencil-component ... >...</my-stencil-component>
<script>
  var componentInstance = document.currentScript.previousElementSibling
  componentInstance.someFunc = function(...) { ... }
</script>

Почему я должен это делать?

Важно понимать, что Properties ≠ Attributes. Props - это свойства JavaScript, в данном случае свойства объекта DOM, представляющего элемент. Атрибуты - это атрибуты XML, хотя атрибуты HTML обладают некоторыми уникальными характеристиками и ведут себя несколько иначе, чем обычный XML.

Stencil автоматически "привяжет" атрибуты HTML к свойствам, где это возможно, в частности, для скалярных значений (boolean, number, string). Ссылки на объекты и, следовательно, функции не могут использоваться в качестве значения атрибута. Технически только strings могут быть значениями атрибутов, но Stencil достаточно умен, чтобы преобразовать string к другому другому скалярному типу (boolean или же number) при указании типа вашего @Prop().


Другие решения

Я разработал для своей команды решение для привязки атрибутов, содержащих JSON, к свойствам Stencil с помощью MutationObserver. Он в основном следит за особым атрибутом bind-json, затем сопоставляет атрибуты, начинающиеся с json-на соответствующие свойства модели camelCase DOM. Использование выглядит так:

<my-stencil-component
  bind-json
  json-prop-name='{ "key": "value" }'>
</my-stencil-component>

С MutationObserver на месте это идентично:

const componentInstance = document.querySelector('my-stencil-component')
componentInstance.propName = JSON.parse(componentInstance.getAttribute('json-prop-name'))

Однако на самом деле нет удовлетворительного решения для привязки функций в обычном HTML. Это действительно невозможно без какого-нибудь уродливого хака вроде evalописано в другом комментарии. Это не только загрязняет API вашего компонента, но и проблематично по множеству других причин, о которых я не буду говорить здесь, и его использование автоматически приведет к сбою вашего приложения практически при любой современной проверке безопасности.

В наших историях из сборника рассказов мы привязываем определения функций обратного вызова к window, и используйте <script> теги и document.currentScript или же querySelector чтобы передать свойства функций и привязки событий экземпляру компонента:

const MyStory = ({ ... }) => {
  window.myStoryFunc = () => { ... }
  window.myStoryClickHandler = () => { ... }
  return `
    <my-stencil-component ... >...</my-stencil-component>
    <script>
      const componentInstance = document.currentScript.previousElementSibling
      componentInstance.someFunc = window.myStoryFunc
      componentInstance.addEventListener('click', window.myStoryClickHandler)
    </script>
  `
}

Вы можете просто добавить @Prop() someFunc: Function к любому компоненту и передать его извне, как <any-component someFunc={() => console.log('coming from the outside')} />

В рамках любого компонента просто проверьте if (this.someFunc) { this.someFunc() }

Другие вопросы по тегам