StencilJS Web 组件:如何让最终用户通过自定义点击事件来防止默认?
StencilJS Web Component: How to allow end-user to prevent default via custom click event?
示例 Stencil.js 网络组件:
import { Component, ComponentInterface, Event, EventEmitter, h, Host } from "@stencil/core";
@Component({
tag: 'foo-testwebcomponent'
})
export class TestWebComponent implements ComponentInterface {
@Event({
eventName: 'foo-click',
cancelable: true
}) fooClick: EventEmitter;
fooClickHandler() {
this.fooClick.emit();
}
render() {
return(
<Host>
<a href="#"
onClick={this.fooClickHandler.bind(this)}
>Testing</a>
</Host>
)
}
}
HTML:
<foo-testwebcomponent id="test"></foo-testwebcomponent>
<script>
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('test')
.addEventListener('foo-click', event => {
event.preventDefault();
console.log(`Foo Test Web Component clicked!`);
});
});
</script>
问题:
在 HTML 实现中,阻止默认值不会阻止 link 工作。
问题:
如何让我的 Web 组件的最终用户防止默认,并阻止 link 工作?
我知道我可以在 fooClickHandler()
中添加 preventDefault()
(见下文),但这对我来说似乎很奇怪。我想将控制权交给 Web 组件的最终用户。
@Event({
eventName: 'foo-click',
cancelable: true
}) fooClick: EventEmitter<MouseEvent>;
fooClickHandler(event: MouseEvent) {
event.preventDefault();
this.fooClick.emit();
}
一种方法是重载 addEventListener
函数并捕获函数 reference
(需要更多工作才能使其与嵌套元素一起使用,你会漂移)
或者使用自定义方法addClick(name,func)
这样用户仍然可以添加任何侦听器
<script>
customElements.define(
"my-element",
class extends HTMLElement {
connectedCallback() {
this.clicked = (evt)=>{
document.body.append("component handler")
}
this.onclick = (evt) => {
this.clicked(evt);
}
}
addEventListener(name, func) {
this.clicked = func;
}
}
);
document.addEventListener('DOMContentLoaded', () => {
document.querySelector('my-element')
.addEventListener('click', event => {
document.body.append(`user handler`);
});
});
</script>
<my-element>Hello Web Components World!</my-element>
您也可以使用旧的 onevent
处理程序:
<script>
customElements.define(
"my-element",
class extends HTMLElement {
connectedCallback() {
this.onclick = (evt) => console.log("component handler")
}
}
);
document.addEventListener('DOMContentLoaded', () => {
let el = document.querySelector('my-element');
el.onclick = event => console.log(`user handler`, el.onclick);
});
</script>
<my-element onclick="console.log('inline')">Hello Web Components World!</my-element>
有两个单独的事件:
- 用户发起的点击事件
- 您的
fooClick
自定义事件
在您的示例中,您在自定义事件上调用了 preventDefault()
,但您需要在原始点击事件上调用它以防止 link 导航。
我知道有两种方法可以做到这一点:
1:跟踪您的自定义事件是否被取消
您可以使用 defaultPrevented
属性 检查用户是否在您的自定义事件中调用了 preventDefault()
。 fooClick
事件处理程序可以保持不变。
fooClickHandler(clickEvent: MouseEvent) {
const customEvent = this.fooClick.emit();
if (customEvent.defaultPrevented) {
clickEvent.preventDefault();
}
}
查看 this online demo。
2:传递点击事件
将点击事件传递给 fooClick
事件处理程序,以便用户可以取消它。
fooClickHandler(clickEvent: MouseEvent) {
this.fooClick.emit({ originalEvent: clickEvent });
}
在处理程序中:
element.addEventListener('foo-click', event => {
event.detail.originalEvent.preventDefault();
console.log(`Foo Test Web Component clicked!`);
});
示例 Stencil.js 网络组件:
import { Component, ComponentInterface, Event, EventEmitter, h, Host } from "@stencil/core";
@Component({
tag: 'foo-testwebcomponent'
})
export class TestWebComponent implements ComponentInterface {
@Event({
eventName: 'foo-click',
cancelable: true
}) fooClick: EventEmitter;
fooClickHandler() {
this.fooClick.emit();
}
render() {
return(
<Host>
<a href="#"
onClick={this.fooClickHandler.bind(this)}
>Testing</a>
</Host>
)
}
}
HTML:
<foo-testwebcomponent id="test"></foo-testwebcomponent>
<script>
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('test')
.addEventListener('foo-click', event => {
event.preventDefault();
console.log(`Foo Test Web Component clicked!`);
});
});
</script>
问题:
在 HTML 实现中,阻止默认值不会阻止 link 工作。
问题:
如何让我的 Web 组件的最终用户防止默认,并阻止 link 工作?
我知道我可以在 fooClickHandler()
中添加 preventDefault()
(见下文),但这对我来说似乎很奇怪。我想将控制权交给 Web 组件的最终用户。
@Event({
eventName: 'foo-click',
cancelable: true
}) fooClick: EventEmitter<MouseEvent>;
fooClickHandler(event: MouseEvent) {
event.preventDefault();
this.fooClick.emit();
}
一种方法是重载 addEventListener
函数并捕获函数 reference
(需要更多工作才能使其与嵌套元素一起使用,你会漂移)
或者使用自定义方法addClick(name,func)
这样用户仍然可以添加任何侦听器
<script>
customElements.define(
"my-element",
class extends HTMLElement {
connectedCallback() {
this.clicked = (evt)=>{
document.body.append("component handler")
}
this.onclick = (evt) => {
this.clicked(evt);
}
}
addEventListener(name, func) {
this.clicked = func;
}
}
);
document.addEventListener('DOMContentLoaded', () => {
document.querySelector('my-element')
.addEventListener('click', event => {
document.body.append(`user handler`);
});
});
</script>
<my-element>Hello Web Components World!</my-element>
您也可以使用旧的 onevent
处理程序:
<script>
customElements.define(
"my-element",
class extends HTMLElement {
connectedCallback() {
this.onclick = (evt) => console.log("component handler")
}
}
);
document.addEventListener('DOMContentLoaded', () => {
let el = document.querySelector('my-element');
el.onclick = event => console.log(`user handler`, el.onclick);
});
</script>
<my-element onclick="console.log('inline')">Hello Web Components World!</my-element>
有两个单独的事件:
- 用户发起的点击事件
- 您的
fooClick
自定义事件
在您的示例中,您在自定义事件上调用了 preventDefault()
,但您需要在原始点击事件上调用它以防止 link 导航。
我知道有两种方法可以做到这一点:
1:跟踪您的自定义事件是否被取消
您可以使用 defaultPrevented
属性 检查用户是否在您的自定义事件中调用了 preventDefault()
。 fooClick
事件处理程序可以保持不变。
fooClickHandler(clickEvent: MouseEvent) {
const customEvent = this.fooClick.emit();
if (customEvent.defaultPrevented) {
clickEvent.preventDefault();
}
}
查看 this online demo。
2:传递点击事件
将点击事件传递给 fooClick
事件处理程序,以便用户可以取消它。
fooClickHandler(clickEvent: MouseEvent) {
this.fooClick.emit({ originalEvent: clickEvent });
}
在处理程序中:
element.addEventListener('foo-click', event => {
event.detail.originalEvent.preventDefault();
console.log(`Foo Test Web Component clicked!`);
});