将函数传递给模板组件

时间:2018-03-20 15:16:14

标签: html function web-component stencils

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

类似的东西:

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

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

2 个答案:

答案 0 :(得分:2)

您只需向任何组件添加@Prop() someFunc: Function,然后从外部传递即可     <any-component someFunc={() => console.log('coming from the outside')} />

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

即可

答案 1 :(得分:2)

是的,可以。它只是一个普通的@Prop()声明,在TSX中可以很好地发挥作用。但是...

如另一个答案和注释中所述,如果您使用纯HTML格式的Stencil组件,则将无法使用Stencil的attribute-prop绑定将函数(或任何非标量值)传递给道具通过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很重要。道具是JavaScript Properties,在这种情况下,代表元素的DOM对象的属性。 Attributes是XML属性,尽管HTML属性具有一些独特的特征,并且其行为与典型的XML稍有不同。

在可能的情况下,模具将自动为您的属性“绑定” HTML属性,尤其是标量值(booleannumberstring)。对象引用及其功能不能用作属性的值。从技术上讲,只有string是属性值,但是当您指定类型时,Stencil足够聪明,可以将string转换为其他标量类型(booleannumber)。您的@Prop()


其他解决方案

我为团队开发了一种解决方案,可以使用MutationObserver将包含JSON的属性绑定到Stencil属性。它基本上会监视特殊属性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,而且对all kinds of other reasons I won't get into here来说也是个问题,使用它实际上会使您的应用在任何现代安全检查中都自动失效。

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

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>
  `
}