web components 事件处理

自定义事件

一个弹窗组件例子,支持close,confirm自定义事件.

image-20231026195428784

<button onclick="openDialogHandler()">打开弹窗</button>
    <hr />
<x-dialog status="closed" onclose="onDialogClose()"></x-dialog>
<script>
    

    // 打开弹窗
    function openDialogHandler(){
        document.querySelector('x-dialog').show();
    }

    // close事件
    function onDialogClose() {
        console.log('dialog closed');
    }

    // 监听x-dialog的confirm事件
    document.querySelector('x-dialog')
    .addEventListener('confirm',(e)=>{
        console.log('dialog confirm',e.detail.data);
        e.target.setAttribute('status','closed')

    });

    // XDialog 组件
    customElements.define('x-dialog',
    class  extends HTMLElement {
        static get observedAttributes() {
            return ["status"];
        }
        constructor() {
            super();
            this.attachShadow({ mode: 'open' });
            
            this.shadowRoot.innerHTML = `
                <style>
                    .dialog {
                        box-shadow: 0 0 10px #ccc;
                        width: 300px;
                    }
                    header,article,footer{
                        border-bottom: 1px solid #ccc;
                        padding: 10px;
                    }
                </style>
                <div class="dialog" style="display:${this.status?'block':'none'}">
                    <header>弹窗</header>
                    <article>
                    <form>
                        <p><label for="name">姓名:
                            <input type="text" name="name" placeholder="请输入姓名">
                        </label>
                        </p>
                        <p>
                        <label for="email">Email:
                            <input type="email" name="email" placeholder="请输入邮箱">
                        </label>
                        </p>
                    </form>
                    </article>
                    <footer>
                        <button class="close-btn">关闭窗口</button>
                        <button class="confirm-btn">提交</button>
                    </footer>
                </div>
            `;
            this.shadowRoot.querySelector('.close-btn')
            .addEventListener('click',this.closeHandler);
            
            this.shadowRoot.querySelector('.confirm-btn')
            .addEventListener('click',this.confirmHandler);
        }
        attributeChangedCallback(name, oldValue, newValue){
            if(name=='status'){
                if(newValue=='opened'){
                    this.shadowRoot
                    .querySelector('.dialog').style.display='block';
                }else{
                    this.shadowRoot
                    .querySelector('.dialog').style.display='none';
                }
            }
        }
        closeHandler =()=>{
            console.log('关闭弹窗',this.shadowRoot);
            this.shadowRoot
            .querySelector('.dialog').style.display='none';
            this.dispatchEvent(new CustomEvent('close'));
            this.setAttribute('status','closed');
        }
        confirmHandler=()=>{
            const form=this.shadowRoot.querySelector('form');
            // 获取
            const data=Object.fromEntries((new FormData(form)).entries());
            this.dispatchEvent(new CustomEvent('confirm',{detail:{data}}));
        }
        show=()=>{
            this.shadowRoot
            .querySelector('.dialog').style.display='block';
            this.setAttribute('status','opened');
        }

    })
    
</script>

自定义事件:

const event=new CustomEvent("custom-event",{});

触发事件:

dom.dispatchEvent(event);

监听自定义事件:

<x-foo></x-foo>
document.addEventlistener("custom-event",function(){})

Shadow DOM中的事件处理

Shadow DOM 中的事件.

<div id="my-element"></div>
<script>
    const element = document.querySelector('#my-element');
    const btn=document.createElement('button');
    btn.innerText='click me';

    const shadowRoot = element.attachShadow({mode: 'open'});
    shadowRoot.appendChild(btn);
    shadowRoot.addEventListener('click',function(e){
        // 返回 button
        console.log('shadowDom clicked',e.target);
    });
    element.addEventListener('click',function(e){
        // 返回 my-element
        console.log('element clicked',e.target);
    });
</script>
  1. 在shadow外监听target元素为shadow.
  2. 在shadow内监听target为实际的元素.

组件间的事件通信

通过自定义事件,组件之间监听通过同一父级组件.

customElements.define('x-b', class extends HTMLElement{
    constructor(){
        super()
        this.attachShadow({mode: 'open'})
        this.shadowRoot.innerHTML = `
            <div>
                B:
                <button id="btn2">按扭B</button>
            </div>
        `
        this.shadowRoot.querySelector('#btn2')
        .addEventListener('click',()=>{
            const event = new CustomEvent('custom-b',{
                bubbles: true,//允许冒泡
            })
            this.dispatchEvent(event)
        })

    }
})

监听

document.addEventListener('custom-b',function(e){
     console.log('组件B的事件',e.target)
 })

event.stopPropagation() 被阻止冒泡.可以在捕获阶段

document.addEventListener('custom-b',function(e){
     console.log('组件B的事件',e.target)
},true)

原作者:阿金
本文地址:https://hi-arkin.com/archives/web-components-6.html

标签: javascript web components

(本篇完)

评论