Передать функции в компонент трафарета
Можно ли передать функцию 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
). Ссылки на объекты и, следовательно, функции не могут использоваться в качестве значения атрибута. Технически только
string
s могут быть значениями атрибутов, но 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() }