美文网首页Web前端之路前端
Web Components使用(一)

Web Components使用(一)

作者: 张中华 | 来源:发表于2020-09-23 20:49 被阅读0次

    在使用Web Components之前,我们先看看上一篇文章Web Components简介,其中提到了相关的接口、属性和方法。
    正是这些接口、属性和方法才实现了Web Components的主要技术:Custom elements(自定义元素)、Shadow DOM(影子DOM)、HTML templates(HTML模板)。
    由于并不是所有的接口以及接口所包含的方法都会被用到,所以我们从实际的案例出发,逐步了解Web Components的使用。

    需求1:创建一个基础的组件,包含一个输入框,和一个button。

    mian.js

    class SearchInput extends HTMLElement {
        constructor() {
            super();
            // 创建一个 shadow root
            let shadow = this.attachShadow({mode: 'open'});
    
            const input = document.createElement('input');
            input.setAttribute('type', 'text');
            input.setAttribute('class', 'input-vlaue');
    
            const button = document.createElement('input');
            button.setAttribute('type', 'button');
            button.setAttribute('value', 'Search');
    
            // 创建一些 CSS,并应用到 shadow dom上
            let style = document.createElement('style');
            style.textContent=".input-vlaue{margin:5px; color:red;}";
    
    
            shadow.append(input);
            shadow.append(button);
            shadow.append(style);
        }
    }
    
    // declare var customElements: CustomElementRegistry;
    customElements.define('search-input', SearchInput);
    

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script src="./main.js"></script>
    </head>
    <body>
        <search-input></search-input>
        <search-input></search-input>
        <search-input></search-input>
    </body>
    </html>
    
    运行结果

    这样子,一个input + button的组件就实现了。这里用到的技术有Custom elements(自定义元素)、Shadow DOM(影子DOM)。

    使用Shadow DOM的好处:Shadow DOM 内部的元素始终不会影响到它外部的元素

    要注意的是,不是每一种类型的元素都可以附加到shadow root(影子根)下面。出于安全考虑,一些元素不能使用 shadow DOM(例如<a>),以及许多其他的元素。

    Element.attachShadow() 方法给指定的元素挂载一个Shadow DOM,并且返回对 ShadowRoot 的引用。具体方法:创建一个ShadowRoot并返回它:

    attachShadow(init: ShadowRootInit): ShadowRoot;
    

    attachShadow()的参数是一个对象,里面包含两个属性,mode和delegatesFocus。

    mode:可以是open/closed。
    • open:shadow root元素可以从js外部访问根节点
    • closed:拒绝从js外部访问关闭的shadow root节点
    delegatesFocus 焦点委托

    一个布尔值, 当设置为 true 时, 指定减轻自定义元素的聚焦性能问题行为.
    当shadow DOM中不可聚焦的部分被点击时, 让第一个可聚焦的部分成为焦点, 并且shadow host(影子主机)将提供所有可用的 :focus 样式.

    使用Custom elements(自定义元素)的好处:语义化,简单明了。
    customElements.define('search-input', SearchInput)实现了CustomElementRegistry接口,无返回值:
    interface CustomElementRegistry {
        define(name: string, constructor: CustomElementConstructor, options?: ElementDefinitionOptions): void;
        get(name: string): any;
        upgrade(root: Node): void;
        whenDefined(name: string): Promise<void>;
    }
    
    需求2:可是真正的组件不仅仅有显示的功能,还需要绑定一些事件,例如上面的例子,点击了如何触发search事件呢?
    核心:element.addEventListener()

    代码示例(index.html不变):

    class SearchInput extends HTMLElement {
        constructor() {
            super();
            // 创建一个 shadow root
            let shadow = this.attachShadow({mode: 'open'});
    
            const input = document.createElement('input');
            input.setAttribute('type', 'text');
            input.setAttribute('class', 'input-vlaue');
    
            const button = document.createElement('input');
            button.setAttribute('type', 'button');
            button.setAttribute('value', 'Search');
    
            const text = document.createElement('p');
    
            // 创建一些 CSS,并应用到 shadow dom上
            let style = document.createElement('style');
            style.textContent=".input-vlaue{margin:5px; color:red;}";
    
            shadow.append(input);
            shadow.append(button);
            shadow.append(text);
            shadow.append(style);
    
            button.addEventListener('click', e => {
                text.textContent = '按钮被点击了~'
            });
        }
    }
    
    // declare var customElements: CustomElementRegistry;
    customElements.define('search-input', SearchInput);
    
    需求3:我们知道,像react、vue都有组件自身的状态管理,和利用Props进行数据传递,那么,在web components中是怎么实现的呢?
    核心:this.getAttribute(props),class内部属性,生命周期

    main.js

    class SearchInput extends HTMLElement {
        constructor() {
            super();
            this.state = { count:0 };
            // 创建一个 shadow root
            let shadow = this.attachShadow({mode: 'open'});
    
            const input = document.createElement('input');
            input.setAttribute('type', 'text');
            input.setAttribute('class', 'input-value');
    
            const button = document.createElement('input');
            button.setAttribute('type', 'button');
            button.setAttribute('value', 'Search');
    
            const text = document.createElement('p');
    
            // 创建一些 CSS,并应用到 shadow dom上
            let style = document.createElement('style');
            style.textContent=".input-vlaue{margin:5px; color:red;}";
    
            shadow.append(input);
            shadow.append(button);
            shadow.append(text);
            shadow.append(style);
    
            button.addEventListener('click', e => {
                this.state.count++;
                text.textContent = `按钮被点击了${this.state.count}次。`
            });
        }
    
        connectedCallback () {
            const defaultValue = this.getAttribute('defaultValue');
            const input = this.shadowRoot.querySelector('.input-value');
            input.value = defaultValue;
        }
    }
    
    // declare var customElements: CustomElementRegistry;
    customElements.define('search-input', SearchInput);
    

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script src="./main.js"></script>
    </head>
    <body>
        <search-input defaultValue="input1"></search-input>
        <search-input defaultValue="input2"></search-input>
        <search-input defaultValue="input3"></search-input>
    </body>
    </html>
    
    运行结果
    到此,我们已经了解了利用Web Components创建一个组件,如何触发组件的事件,如何利用props向组件内部传递数据以及组件内部的状态管理。

    目前来看缺乏的就是组件间的通信了,目前还没发现有类似react、vue的组件间通信的方法,不过我们可以利用localStorage,StorageEvent间接的发生组件间的通信、界面渲染。

    相关文章

      网友评论

        本文标题:Web Components使用(一)

        本文链接:https://www.haomeiwen.com/subject/diqaektx.html