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>
)。
第一个解决方案:此处onclick
在foo()
(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)
。
答案 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
可以在元素中的任何位置。