在没有任何框架的情况下使用Web Components,实现自定义事件的正确方法是什么?例如,假设我有一个自定义元素x-pop-out
,其自定义事件为pop
我希望以下所有内容都能正常工作:
<x-pop-out onpop="someGlobal.doSomething()"/>
var el = document.getElementsByTagName('x-pop-out')[0];
el.onpop = ()=> someGlobal.doSomething();
//or
el.addEventListener('pop', ()=> someGlobal.doSomething());
我得到的最后一个怎么做,但我是否需要为每个人自定义实现属性和getter / setter?另外,eval()
是从属性执行字符串的适当方法吗?
答案 0 :(得分:3)
事件监听器解决方案(第三个)是最简单的,因为您不必定义任何特殊的事件来捕获事件。
事件处理程序解决方案需要创建eval()
(第一个,来自属性)或明确调用该函数(第二个)。
如果您不能使用eval
,则可以改为解析属性字符串。
customElements.define( 'x-pop-out', class extends HTMLElement {
connectedCallback() {
this.innerHTML = `<button id="Btn">pop</button>`
this.querySelector( 'button' ).onclick = () => {
this.dispatchEvent( new CustomEvent( 'pop' ) )
if ( this.onpop )
this.onpop()
else
eval( this.getAttribute( 'onpop' ) )
}
}
} )
XPO.addEventListener( 'pop', () => console.info( 'pop' ) )
&#13;
<x-pop-out id=XPO onpop="console.log( 'onpop attribute' )"></x-pop-out>
<hr>
<button onclick="XPO.onpop = () => console.log( 'onpop override' )">redefine onpop</button>
&#13;
答案 1 :(得分:1)
基于SuperSharp answer。他的建议只适用于控制台日志而不是事件。我使用的解决方案是覆盖dispatchEvent并使其也创建自定义HTML事件属性。
遵循使用'on'+ event.type的标准。我们使用with在新函数中屏蔽属性,并检查属性是否为函数,并在需要时传入事件。
dispatchEvent(event) {
super.dispatchEvent(event);
const eventFire = this['on' + event.type];
if ( eventFire ) {
eventFire(event);
} else {
const func = new Function('e',
'with(document) {'
+ 'with(this) {'
+ 'let attr = ' + this.getAttribute('on' + event.type) +';'
+ 'if(typeof attr === \'function\') { attr(e)};
+ }'
+ '}'
);
func.call(this, event);
}
}
示例:
class UserCard extends HTMLElement {
constructor() {
// If you define a constructor, always call super() first as it is required by the CE spec.
super(); //
}
dispatchEvent(event) {
super.dispatchEvent(event);
const eventFire = this['on' + event.type];
if (eventFire) {
eventFire(event);
} else {
const func = new Function('e',
'with(document) {' +
'with(this) {' +
'let attr = ' + this.getAttribute('on' + event.type) + ';' +
'if(typeof attr === \'function\') { attr(e)};' +
'}' +
'}');
func.call(this, event);
}
}
connectedCallback() {
this.innerHTML = `<label>User Name</label> <input type="text" id="userName"/>
<label>Password</label> <input type="password" id="passWord"/>
<span id="login">login</span>`;
this.test = this.querySelector("#login");
this.test.addEventListener("click", (event) => {
this.dispatchEvent(
new CustomEvent('pop', {
detail: {
username: 'hardcodeduser',
password: 'hardcodedpass'
}
})
);
})
}
}
customElements.define('user-card', UserCard);
function onPop2(event) {
debugger;
console.log('from function');
}
<user-card id="XPO" onpop="onPop2"></user-card>
<hr>
<user-card id="XPO" onpop="console.log('direct Console')"></user-card>