JS > 将 HTML onclick 事件绑定到自定义元素 v1 对象

JS > bind HTML onclick event to a Custom Element v1 object

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>)。

第一个解决方案:这里 onclickthis (this.foo()) 上调用 foo() 函数,其中 this 稍后绑定到我的自定义元素(参见以下代码)。

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

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

所以问题是:如何使解决方案 2 起作用?

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

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)

一些解释:

一些想法:

很好地阅读了这个主题:

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

所以,我完全不知道有没有解决办法。无论如何,欢迎提出想法或解释!

编辑 2:已修复。

当从元素内部创建和附加元素时,它也有效 class:

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

编辑 3、4、5: 试了一下(参见解决方案 3)并将代理对象分配给全局变量 ('me'),该变量将任何函数调用投射到 this 自定义元素 - 有点 __noSuchMethod__。所以...通过选择一个 1 或 2 个字符的变量,通过不输入 this. 而输入 me.vm. 甚至 [=,至少可以节省键盘上的几次点击44=] ... 迄今为止最好的解决方案。伤心! 不幸的是,解决方案 3 也不能用作所有元素的通用模式,因为它仅将上下文绑定到一个(即最后连接的)自定义元素。


编辑 6 - 初步结论

事实证明,似乎无法将 html 内联 onclick 事件 (onclick="foo('bar')") 绑定到自定义元素 class,其中可点击元素是嵌入式。

所以最明显的方法是:

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

B) 按照@Supersharp 的建议使用 eval,即将事件侦听器添加到自定义元素,侦听点击,将 onclick 属性的值作为字符串获取,将 "this." 添加到字符串之前,然后有效地做到这一点:eval("this." + "foo()").

C) 除了内联 onclick,我倾向于使用事件委托并使用声明性 html 属性来指示行为。为此,再次向自定义元素添加点击事件侦听器 class:

myElement.addEventListener('click', function(ev) {

        if (ev.target.dataset.action)
        {
            this[ev.target.dataset.action]()
        }

    }, false)

您的可点击元素看起来像 <div data-action="next">Show more</div>

一个解决方案是在 "this."onclick 属性 event.target 元素的内容的串联上使用 eval()

不要忘记使用 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>

这样您就不需要 redirect/catch 事件,并且 div 可以在元素中的任何位置。