7

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

就像是:

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

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

4

2 回答 2

6

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

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

使用 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 Properties,在这种情况下,是表示元素的 DOM 对象的属性。属性是 XML 属性,尽管 HTML 属性具有一些独特的特性并且行为与典型的 XML 略有不同。

Stencil 会在可能的情况下为您自动将 HTML 属性“绑定”到属性 - 特别是对于标量值 ( boolean, number, string)。对象引用和函数不能用作属性的值。从技术上讲,只有strings 可以是属性值,但 Stencil 足够聪明,可以stringbooleannumber指定@Prop().


其他解决方案

我为我的团队开发了一个解决方案,使用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,而且由于我不会在这里讨论的各种其他原因,它的使用会在几乎任何现代安全检查中自动使你的应用程序失败。

在我们的 Storybook 故事中,我们将回调函数定义绑定到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>
  `
}
于 2020-09-24T18:43:03.553 回答
1

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

在 anyComponent 中只需检查if (this.someFunc) { this.someFunc() }

于 2018-04-11T12:44:30.423 回答