Vanilla Web Component 自定义事件属性和特性
Vanilla Web Component custom event attributes and properties
在没有任何框架的情况下使用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()
是从属性执行字符串的适当方法吗?
事件侦听器解决方案(第三个)是最简单的,因为您不必定义任何特殊的东西来捕捉事件。
事件处理程序解决方案需要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' ) )
<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>
基于 SuperSharp 。他的建议仅适用于控制台日志,实际上不适用于事件。我使用的解决方案是覆盖 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>
在没有任何框架的情况下使用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()
是从属性执行字符串的适当方法吗?
事件侦听器解决方案(第三个)是最简单的,因为您不必定义任何特殊的东西来捕捉事件。
事件处理程序解决方案需要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' ) )
<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>
基于 SuperSharp
按照'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>