JS>将HTML onclick事件绑定到Custom Element v1对象

时间:2017-08-04 07:48:32

标签: javascript events onclick bind custom-element

TL; DR

如何将div元素的内联onclick事件的回调绑定到放置div的自定义元素? 我想使用onclick="foo('bar')"代替onclick="this.foo('bar')"

长版

自定义元素可点击的div 附加到DOM,如下所示:

<my-element>
    <!-- 1. works  -->
    <div onclick="this.foo('bar')">click me</div>

    <!-- 2. not working -->
    <div onclick="foo('bar')">click me</div>

    <!-- edit: 3. playground (works) -->
    <div onclick="me.foo('bar')">click me</div>
</my-element>

...现在我想将foo() - 函数绑定到我的自定义元素(<my-element>)。

第一个解决方案:此处onclickfoo()this)上调用this.foo() - 函数,其中this稍后获得绑定到我的自定义元素(参见下面的代码)。

第二个解决方案:这里我想省略this.并再次将其绑定到我的自定义元素。但是:虽然绑定适用于上述解决方案(1.),但它没有前置this. - 这是我的问题。

已编辑的第3个解决方案:使用代理将函数调用从me投影到this自定义元素。它没有解决问题,但至少我试过了。

所以问题是:如何让解决方案2工作?

我的自定义元素v1类 - 包括我尝试的一些代码:

class MyElement extends HTMLElement
{
    constructor()
    {
        super()
    }

    connectedCallback()
    {
        var self = this

        this.addEventListener('click', this.handleClick, true)

        // Proxy for solution 3
        window.me = new Proxy({}, 
        {
            get: function(target, prop) 
            {
                return self[prop]
            }
        })
    }

    handleClick(ev)
    {
        console.log(ev.target.onclick)
            // returns: ƒ onclick(event) { foo("bar") }
            // > is typeof function

        // provides the binding to "this" for solution 1
        ev.target.onclick = ev.target.onclick.bind(this)

        // call
        ev.target.onclick()
            // works on first solution
            // throws error in 2nd solution: foo is not defined
    }

    foo(str)
    {
        console.log(str)
    }
}

customElements.define('my-element, MyElement)

一些解释:

  • 使用addEventListener并将其第三个参数(useCapture)设置为true,我会在执行之前捕获该事件。

  • 我能够将foo() - 功能记录到控制台。它被封装在一个可调用的函数中,这似乎是为什么我不能将我的上下文绑定到foo() - 函数本身。

  • 通过ev.target.onclick()调用该函数会引发错误,如在给定的上下文(window)中没有foo() - 函数存在。

一些想法:

  • React 做了类似的事情(我还没有使用React),但我无法看到如何转移他们的解决方案,因为他们最终以某种方式预处理他们的onclick事件(有eval?)。这可能是他们的语法为onclick={foo}而不是onclick="foo()"的原因。我也不知道,如果在React中可以传递参数。 请参阅:https://facebook.github.io/react/docs/handling-events.html

  • 参考这个,可能是一个问题,在我的解决方案中,foo()函数可能已经以某种方式在窗口上下文中调用,这意味着,它的上下文已经设置并且不能再改变了......?无论如何,尝试将onclick="foo"设置为无括号并稍后调用它也不起作用。

很好地阅读了这个主题:

http://reactkungfu.com/2015/07/why-and-how-to-bind-methods-in-your-react-component-classes/

所以,我根本不知道是否有解决方案。无论如何,欢迎提出想法或解释!

编辑2:已修复。

当元素从元素类内部创建并追加时,它也有效:

var el = document.createElement('div')
el.innerHTML = 'click me'
el.onclick = () => {
    this.foo('bar')
}
this.appendChild(el)

编辑3,4,5: 玩了一下(见解决方案3)并将一个Proxy对象分配给一个全局变量(&#39; me&#39;),它将任何函数调用投射到this自定义元素 - 有点__noSuchMethod__。所以...通过选择1或2个字符变量,可以通过不键入this.me.vm.甚至{{}来键入至少几次点击键盘1}} ...迄今为止的最佳解决方案。伤心! 不幸的是,解决方案3也不能用作所有元素的一般模式,因为它只将上下文绑定到一个(即最后连接的)自定义元素。

编辑6 - 初步结论

事实证明,似乎无法将html-inline onclick-event(i.)绑定到自定义元素类,其中嵌入了可点击元素。

所以最明显的方式是:

A)使用this关键字(如onclick="foo('bar')")并将其绑定到类,如上所示。为什么onclick="this.foo('bar')"是可绑定的,而this.foo()没有foo()则不可约束,目前仍不清楚。我想知道bc这两个函数并没有真正区别 - 两者都已绑定:this)绑定到可点击元素,this.foo(绑定到foo()

B)使用@Supersharp建议的eval,即向自定义元素添加一个事件监听器,监听点击,将onclick-attribute的值作为字符串,prepend&#34; this。&#34;到字符串并有效地执行此操作:window

C)或者内联onclick,我倾向于使用事件委托并使用声明性html属性来指示行为。为此,请再次向Custom Element类添加一个click事件侦听器:

eval("this." + "foo()")

您的可点击元素看起来像myElement.addEventListener('click', function(ev) { if (ev.target.dataset.action) { this[ev.target.dataset.action]() } }, false)

1 个答案:

答案 0 :(得分:0)

解决方案是在eval()的连接和"this."属性onclick元素的内容上使用event.target

请勿忘记使用event.stopPropagation()停止发送活动。

handleClick( ev )
{
    eval( 'this.' + ev.target.getAttribute( 'onclick' ) )

    ev.stopPropagation()
}

如果您不想使用eval(),则应解析ev.target.getAttribute( 'onclick' )的内容以提取函数名称和参数,然后调用元素方法(如果存在):

if ( typeof this.name === 'function ) 
    this[name](arguments)

<强>更新

我建议你给自定义元素id,然后调用id +方法:

<my-element id="me">
    <div onclick="me.foo('bar')">click me</div>
</my-element>

这样您就不需要重定向/捕获事件,div可以在元素中的任何位置。