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>
)。
第一个解决方案:这里 onclick
在 this
(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)
一些解释:
使用addEventListener
并将其第三个参数(useCapture
)设置为真,我在执行之前捕获事件。
我可以将 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()
函数可能已经以某种方式在 window 上下文中被调用,这意味着它是上下文已经设置并且不能再更改......?无论如何,尝试设置 onclick="foo"
不带括号并稍后调用它也不起作用。
很好地阅读了这个主题:
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()
是可绑定的,而没有 this
的 foo()
不是,目前还不清楚。我想知道 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
可以在元素中的任何位置。
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
在 this
(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)
一些解释:
使用
addEventListener
并将其第三个参数(useCapture
)设置为真,我在执行之前捕获事件。我可以将
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()
函数可能已经以某种方式在 window 上下文中被调用,这意味着它是上下文已经设置并且不能再更改......?无论如何,尝试设置onclick="foo"
不带括号并稍后调用它也不起作用。
很好地阅读了这个主题:
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()
是可绑定的,而没有 this
的 foo()
不是,目前还不清楚。我想知道 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
可以在元素中的任何位置。