es6封装一个组件---按钮组 (第一篇)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangshab/article/details/83589661

写的比较简单,还在学习中,欢迎大家指教。

知识点:

WebComponent

  CustomElementRegistry - customElements 对象

  该接口提供注册自定义元素和查询已注册元素的方法

  customElements.define(name, constructor, options)

  name:自定义元素名称,注意:自定义的元素名称必须是使用 - ,且不能包含大写字母

  constructor:自定义元素构造器

  options :控制元素如何定义. 目前有一个选项支持

  extends:指定继承的已创建的元素. 被用于创建自定义元素

 

Shadow DOM

  一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突

 

  - 自定义元素的容器

  - 组件作用域

Element.attachShadow(shadowRootInit)

  shadowRootInit包含:

  mode:一个指定Shadow DOM封装模式的字符串,可以是下列之一:

  open开放的封装模式

  closed关闭的封装模式

Shadow DOM

获取子元素

  组件.childNodes

  获取组件内部元素

  组件.shadowRoot

  modeopen,则返回shadowRoot

  modeclosed,返回null

 

Component

  插槽(SLOT

  浏览器默认情况只渲染shadowDOM,不渲染子元素

  我们可以通过组件内部使用 <slot></slot> 来获取包含的子元素,并在组件内部适当的位置插入子元素

 

  具名插槽

  我们还可以在子元素上添加 slot属性并赋值

  <div slot=”a”></div>

  那么在组件内部就是使用 <slot name=”a”></slot>的方式来调用具名插槽了

 

 

Component

  生命周期回调

  定义在自定义元素的类定义中的特殊回调函数 

  connectedCallback当自定义元素第一次被连接到文档DOM时被调用

  disconnectedCallback当自定义元素与文档DOM断开连接时被调用

Component

  生命周期回调

  adoptedCallback当自定义元素被移动到新文档时被调用,比如移动到一个iframe窗口等

 

  attributeChangedCallback当自定义元素的一个属性被增加、移除或更改时被调用

  - 需要配合observedAttributes属性来监听指定的属性

 

  static get observedAttributes() {return [要监听的属性列表] }

自定义事件:

CustomEvent

  new CustomEvent(typeArg, customEventInit)

  typeArg:一个表示 event 名字的字符串

  customEventInit:一个字典类型参数,有如下字段

  detail:可选的默认值是 null 的任意类型数据,是一个与 event 相关的值(对象)

  bubbles:一个布尔值,表示该事件能否冒泡,默认值为 false

  cancelable:一个布尔值,表示该事件是否可以取消,默认值为 false

  composed:一个布尔值,表示事件是否会在影子DOM根节点之外触发侦听器,默认值为 false

CustomEvent

  HTMLElement.dispatchEvent(event)

  event:通过new CustomEvent创建的事件

  HTMLElement.addEventListener(event, callback, options)

  event:事件名称

  callback:事件回调

  options:选项

代码:

//自定义一个组件的基类,自定义的html标签组件都需要继承HTMLElement父类
class component extends HTMLElement{
    constructor(){
        super(); 
        this._data = {};
        this._data.tabData = [];
        this._data.index = 0;
        
    };
    /*
    * begin 给自定义元素用setAttribute设置属性时
    *必需要用static get observedAttributes -- 注册用setAttribute的属性
    *和attributeChangedCallback配合使用--当使用setAttribute之后会自动调用该方法,
    *在这个用getAttribute得到相应属性值
    * 
    */ 
    static get observedAttributes() {
        return ["tabData","index"];
    };
    attributeChangedCallback(){
        try{
            this._data.tabData = JSON.parse(this.getAttribute("tabData"));
            this._data.index = this.getAttribute("index");
        }catch(e){};
        this.creatLis(); 
    }; 
    initData(){
        //shadow不是<m-radio>中的子元素,它是一个容器,容器里的内容替换<m-radio>在html中的的
//位置,我是把shadow当作一个document来看的,相当于在元素中也有一个document
        let shadow = this.attachShadow({
            mode: "open"
        });
    };
    //创建tab元素
    createTabDom(){
        /* 创建选项卡dom结构 */

        //创建div
        let container = document.createElement("div");
        container.classList.add("container");
        
        let fragment = document.createDocumentFragment();
        //创建ul
        let ul = document.createElement("ul");
        ul.classList.add("tabUl");
        fragment.appendChild(ul);
        container.appendChild(fragment);
        this.shadowRoot.appendChild(container);
        this.creatLis();   
    };
    
}
//选项卡构造方法 this指向的<my-radio>  dom元素
class MyTab extends component{
    constructor(){
        super();
        this.initData();
        this.htmlStyle();
        this.createTabDom();
        this.createTabEvent();

    };
    //style样式
    htmlStyle(){
         /* style样式 */
         let style = document.createElement("style");
         style.textContent = `ul{
             margin:0;
             padding:0;
         }
         ul,li{
             list-style: none;
         }
         li,div{
             padding:0;
         }
         ul{
             float: left;
         }
         li{
             padding: 10px 20px; 
             border: 1px solid #eeeeee;
             float:left;
             font-size: 14px;
             cursor: pointer;
             color: #666666;
         }
         li:hover{
             color:#ffffff;
             background: -webkit-linear-gradient(left,rgb(82, 211, 243),#eeeeee45,rgb(82, 211, 243));
         }
         .active{
             color:#ffffff;
             background: -webkit-linear-gradient(left,rgb(82, 211, 243),#eeeeee45,rgb(82, 211, 243));
         }
         .container{
             overflow: auto;
         }`;
         
         this.shadowRoot.appendChild(style);
    };
    
    creatLis(){
       
        //创建li
        
        let tabData = this._data.tabData;
        if(tabData.length > 0){
            
            let lis = tabData.map((item,index) => {
                if(this._data.index === index.toString()){
                    return `<li class="active" data-num="${index}">${item}</li>`
                }else{
                    return `<li data-num="${index}">${item}</li>`
                }
            }).join("");
            let ul = this.shadowRoot.querySelector(".tabUl");
            ul.innerHTML = lis;
            
        }
        
       
    };
    createTabEvent(){
        let me = this;
        
        /* 绑定事件 */
        this.shadowRoot.addEventListener("click",function(e){
            if(e.target.tagName.toUpperCase() == "LI"){
                me._data.index = e.target.dataset.num;
                me.setAttribute("index", me._data.index);
                me.creatLis();
               
                //创建一个自己定义对象
                let changeEvent = new CustomEvent("change",{
                    detail:{
                        index: me._data.index
                    }
                });
                 //触发自定义事件
                me.dispatchEvent(changeEvent);

            }
        });
        
        //this.shadowRoot.onclick this.shadowRoot不支持onclick这种绑定事件的方式(不支持dom0级的绑定方式)
        /* this.shadowRoot.onclick = function(e){
            console.log(e);
            if(e.targe == 'li'){
                console.log(e);
                                
            }
        } */
    }
};

customElements.define("my-tab",MyTab);  //html中写<my-tab></my-tab>标签,自动会调用MyTab类。
<!--html中调用组件的方式-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
   
</head>
<body>
    <!--begin 调用了我封装的组件调用几次就会用几个组件显示-->
    <my-tab></my-tab>
    <my-tab tabData='["美国","伊朗"]' index="1"></my-tab>
    <!--end调用了我封装的组件-->
    <!-- <script src="./选项卡封装.js"></script> -->
    <script src="./选项卡继承式封装.js"></script>
    <script>
        let city = ["北京","上海","成都","重庆"];
        let tab = document.querySelector('my-tab');//或者第一个控件<my-tab></my-tab>
        tab.setAttribute("tabData",JSON.stringify(city));
//动态的将数据传入组件中,用JSON的原因是setAttribute不接受复杂数据类型(对象,数组等)所以将这些转化成字符串,再在组件中用JSON转回来。
        //tab.setAttribute("index",0);//动态的给自定义元素设置属性及属性值,必须在对应的类中加入attributeChangedCallback:当自定义元素的一个属性被增加、移除或更改时被调用
			//- 需要配合observedAttributes属性来监听指定的属性
	
	//static get observedAttributes() {return [要监听的属性列表] } 这两个方法

//监听自定义事件
        tab.addEventListener("change",function(e){
            console.log(e.detail.index);
        })
    </script>
    
</body>
</html>

猜你喜欢

转载自blog.csdn.net/zhangshab/article/details/83589661