是否可以将函数传递给stencilJs
组件?
像这样:
@Prop() okFunc: () => void;
我有一个模态,想要在模态页脚中单击的Ok
按钮上动态调用传递的函数,就像普通 HTML 按钮上的onClick
一样。
是的,你可以。这只是一个普通的@Prop()
声明,在多伦多证券交易所发挥得非常好。然而。。。
如另一个答案和评论中所述,如果您在纯 ol' HTML 中使用 Stencil 组件,您将无法使用 Stencil 的属性-prop 绑定通过 HTML 属性将函数(或任何非标量值)传递给 prop。
使用 DOM API
这意味着如果你想附加事件或将函数道具传递给 Stencil 组件,你必须与 DOM 交互。一旦您的组件进入 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 略有不同。
在可能的情况下,模板会自动将HTML属性"绑定"到属性 - 特别是标量值(boolean
,number
,string
)。对象引用(因此不能将函数)用作属性的值。从技术上讲,只有string
s可以是属性值,但是当您指定@Prop()
的类型时,Stencil足够聪明,可以将string
转换为其他其他标量类型(boolean
或number
)。
其他解决方案
我为我的团队开发了一个解决方案,使用MutationObserver
将包含 JSON 的属性绑定到 Stencil 属性。它基本上监视一个特殊的属性bind-json
,然后将以json-
开头的属性映射到相应的驼峰案例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() }