将函数传递给模板组件

mah*_*hau 5 html function stencils web-component

是否可以将函数传递给stencilJs组件?

就像是:

@Prop() okFunc: () => void;
Run Code Online (Sandbox Code Playgroud)

我有一个模态,想Ok在模态页脚中单击的按钮上动态调用传递的函数,就像onClick在普通 HTML 按钮上一样。

Jon*_*ieb 5

是的你可以。它只是一个普通的@Prop()声明,在 TSX 中表现得非常好。然而...

正如另一个答案和评论中所指出的,如果您使用纯 ol' HTML 中的 Stencil 组件,您将无法使用 Stencil 的属性属性绑定将函数(或任何非标量值)通过HTML 属性。

使用 DOM API

这意味着如果你想附加事件或将函数 props 传递给 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) => { ... })
Run Code Online (Sandbox Code Playgroud)

如果您出于某种原因绝对必须在 HTML 文档中执行此操作:

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

为什么我必须这样做?

意识到这一点很重要Properties ? Attributes。道具是JavaScript 属性,在这种情况下,是表示元素的 DOM 对象的属性。属性是 XML 属性,尽管 HTML 属性具有一些独特的特征并且其行为与典型的 XML 略有不同。

Stencil 会在可能的情况下自动为您“绑定”HTML 属性到属性 - 特别是对于标量值 ( boolean, number, string)。对象引用和函数不能用作属性的值。从技术上讲,只有stringS可以是属性值,但模板是足够聪明,转换string到其它另一个标量型(booleannumber)当您指定的类型@Prop()


其他解决方案

我为我的团队开发了一个解决方案,使用MutationObserver. 它主要是监视一个特殊的属性bind-json,然后将 以 开头的属性映射json-到相应的驼峰 DOM 属性上。用法如下所示:

<my-stencil-component
  bind-json
  json-prop-name='{ "key": "value" }'>
</my-stencil-component>
Run Code Online (Sandbox Code Playgroud)

随着MutationObserver到位,这是相同的:

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

但是,对于纯 HTML 中的绑定函数,确实没有令人满意的解决方案。如果没有eval另一条评论中描述的某种丑陋的黑客攻击,它真的无法完成。这不仅会污染您的组件的 API,还会由于各种其他原因而出现问题,我不会在这里介绍,而且它的使用会在几乎所有现代安全检查中自动使您的应用程序失败。

在我们的 Storybook 故事中,我们将回调函数定义绑定到window, 并使用<script>标签和document.currentScriptquerySelector将函数道具和事件绑定传递给组件实例:

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>
  `
}
Run Code Online (Sandbox Code Playgroud)


Sch*_*enn 0

您可以将 a 添加@Prop() someFunc: Function到任何组件并从外部传递它,例如 <any-component someFunc={() => console.log('coming from the outside')} />

在任何组件中只需检查if (this.someFunc) { this.someFunc() }

  • 上述解决方案仅适用于 JSX (React) 。由于 Stencil 是通用 Web 组件,这不是正确的解决方案。 (2认同)