zoukankan      html  css  js  c++  java
  • 从原生web组件到框架组件源码(二)

    innerHTML outerHTML textContent innerText 区别

    <div id="test">
      <span>sdsdsdsd <span>555</span></span>
      bbbb
    </div>
    
    • innerHTML

    ​ 从对象的起始位置到终止位置的全部内容,包括Html标签

    <span>sdsdsdsd <span>555</span></span>bbbb

    • innerText

      从起始位置到终点位置的内容,去掉HTML内容,并且如果里面有多个标签或者迭代子代都是去除标签的

      sdsdsdsd 555 bbb

    • outerHTML

      除了包含innerHTML的全部内容外,还包含对象标签本身

    • textContent

      跟innerText 返回的结果一样

    重要

    根据W3C标签,尽量用innerHTML,textContent,而少用innerText,outerHTML

    动态访问DOM

    方法 描述
    document.createElement(``tag) 创建并返回一个HTML标签tag
    element.appendChild(``child) 添加的元素child里面element
    element.insertAdjacentHTML(``pos,``html) 将代码插入htmlelement
    element.insertAdjacentElement(``pos,``node) 将元素node插入element

    正常情况下我们使用的时候

    class AppElement extends HTMLElement {
    
      name = this.getAttribute("name") || "Desconocido";
    
      connectedCallback() {
        const element = document.createElement("div");
        element.className = "element";
        this.appendChild(element);
    
        const innerElement = document.createElement("div");
        innerElement.textContent = this.name;
        element.appendChild(innerElement);
      }
    }
    
    数据类型 特定类型 标签 描述
    HTMLElement HTMLDivElement <div> 看不见的分隔层(块中)。
    HTMLElement HTMLSpanElement <span> 不可见的分隔层(在线)。
    HTMLElement HTMLImageElement <img> 图片。
    HTMLElement HTMLAudioElement <audio> 音频容器。

    inserAdjacentHTML

    element.insertAdjacentHTML(position, text);
    

    position

    插入内容的位置

    • 'beforebegin':元素自身的前面。
    • 'afterbegin':插入元素内部的第一个子节点之前。
    • 'beforeend':插入元素内部的最后一个子节点之后。
    • 'afterend':元素自身的后面。

    text

    • 解析为html,并插入到DOM树上,字符串类型
    // 原为 <div id="one">one</div> 
    var d1 = document.getElementById('one'); 
    d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');
    
    // 此时,新结构变成:
    // <div id="one">one</div><div id="two">two</div>
    

    insertAdjacentElement(position, element);

    个人觉得这个用的比较多

    position

    DOMString 表示相对于该元素的位置;必须是以下字符串之一:

    • 'beforebegin': 在该元素本身的前面.
    • 'afterbegin':只在该元素当中, 在该元素第一个子孩子前面.
    • 'beforeend':只在该元素当中, 在该元素最后一个子孩子后面.
    • 'afterend': 在该元素本身的后面.
    <div id="one">one</div>
    <script>
      let span = document.createElement('span');
      span.textContent='3333';
      let one=document.querySelector('#one');
      one.insertAdjacentElement('beforebegin',span)
    </script>
    

    content.cloneNode(deep)

    deep为 true 的时候,就是创建一个深层克隆,为false就是浅拷贝

    我们要目标这个适用于自定义元素

    // 创建一个自定义组件
    const template = document.createElement("template");
    template.innerHTML = `
      <div class="element">
        <div class="name"></div>
      </div>`;
    
    // 讲自定义组件拷贝到AppElement 里面
    class AppElement extends HTMLElement {
    
      name = this.getAttribute("name") || "Desconocido";
    
      connectedCallback() {
        const markup = template.content.cloneNode((true));
        markup.querySelector(".name").textContent = this.name;
        this.appendChild(markup);
      }
    }
    

    shadow DOM

    影子DOM

    在javascript不同框架出现后,他们设计了Virstual DOM: 页面DOM的内存中副本,可以直接管理更改,以便后面转换为文档的真实DOM,目的是加快优化页面的DOM更改

    例如:react 引入虚拟DOM,已检测更改(树之间的差异), 更新受影响的节点,然后再将其传递给真实的dom

    语法

    const div = document.createElement("div");
    const shadow = div.attachShadow({ mode: "open" });
    div.shadowRoot === shadow; // true
    

    mode 定义了shadow DOM的封装模式,创建shadow Dom元素将具有一个属性,通过.shadowRoot 访问

    封装css

    我们知道css具有全局特性,Shadow DOM 中css不会影响文档的css,也不会使全局css传递到shaDow DOM 的css,就是具有沙箱形式

      <style>
        h1{
          color:red;
        }
      </style>
    <app-element></app-element>
    <span>33233</span>
    <script>
      customElements.define("app-element", class App extends HTMLElement {
        constructor() {
          super();
          this.attachShadow({ mode: "open" });
        }
        connectedCallback() {
          this.shadowRoot.innerHTML = `
          <style>
            span {
              background: steelblue;
              padding: 5px;
              color: white;
            }
          </style>
          <div>
            <span>CSS</span>
            <h1>3333</h1>
          </div>
        `;
        }
      });
    </script>
    <h1>h1</h1>
    

    我们发现,css被完全隔离开了

    自定义元素

    <app-element></app-element>
    
    <script>
      customElements.define("app-element", class extends HTMLElement {
        connectedCallback() {
          this.innerHTML = "<div>Hello, friend!</div>";
        }
      });
    </script>
    

    在自定义元素里面插入 shadow DOM

    <app-element>
      <div class="container">Contenido previo del elemento</div>
    </app-element>
    
    <script>
      customElements.define("app-element", class extends HTMLElement {
        constructor() {
          super();
          this.attachShadow({ mode: "open" });
        }
    
        connectedCallback() {
          this.shadowRoot.innerHTML = "<div>Hello, friend!</div>";
        }
      });
    </script>
    

    我们发现创建页面上的Shadow DOM 后,页面上.container 的dom被隐藏了

    换句话说当我们附加shadow DOM 时,它将隐藏Light DOM,但是尽管Light DOM 被隐藏了,但是可以通过浏览器查询到代码

    <app-element>
      #shadow-root (open)
        <div>Hello, friend!</div>
      <div class="container">Contenido previo del elemento</div>
    </app-element>
    

    我们this.shadowRoot.innerHTML用于修改Shadow DOM。如果使用,我们将this.innerHTML只修改Light DOM

    插槽

    <slot> 插槽中插入我们放置的Light DOM

    connectedCallback() {
          this.shadowRoot.innerHTML = "<div>Hello, friend! <slot>默认插槽</slot></div>";
        }
    

    我们发现默认插槽会被填充.container 的内容,当<app-element> 里面为空的话,会填充默认的插槽

    命名插槽

    <app-element>
      <h2 slot="name">Manz</h2>
      <span slot="role">Developer</span>
      <p slot="description">I hate Internet Explorer.</p>
    </app-element>
    
    <script>
      customElements.define("app-element", class extends HTMLElement {
        constructor() {
          super();
          this.attachShadow({ mode: "open" });
        }
    
        connectedCallback() {
          this.shadowRoot.innerHTML = `
            <div class="card">
              <slot name="name"></slot>
              <slot name="description"></slot>
              <slot name="role"></slot>
            </div>
          `;
        }
      });
    </script>
    

    通过在外部定义css,修改插槽中的css,通过我们给出<slot></slot>给出一个默认信息

    ::sloted 伪类

        connectedCallback() {
          this.shadowRoot.innerHTML = `
            <style>
              ::slotted(h2) { color: blue; }  
            </style>
            <div class="card">
              <slot name="name"></slot>
              <slot name="description"></slot>
              <slot name="role"></slot>
            </div>
          `;
        }
    

    会优先考虑全局css,但是如果有!important 会考虑优先级进行替换

    正常情况下,全局的css大于自身的

      ::slotted(h2) { color: blue; }  
    

    插槽的事件检测

    事件 描述
    slotchange 当它检测到插槽元素关联已更改时,将触发该事件。

    们将像处理任何事件一样使用.addEventListener()该事件,使用有<slot>问题的事件来监听它并检测它何时被触发,并执行关联的功能

    const slot = this.shadowRoot.querySelector("slot");
    slot.addEventListener("slotchange", () => console.log("¡El slot ha cambiado!"));
    

    例子,能监控到变化

    element.setAttribute('slot', slotName);
    // element.assignedSlot = $slot
    element.removeAttribute('slot');
    // element.assignedSlot = null
    

    提地写了一个完整的demo,方便理解

    <app-element>
      <button onClick="add()">++</button>
      <h1>xxxx</h1>
    </app-element>
    

    js部分

      class AppElement extends HTMLElement {
        constructor() {
          super();
          this.attachShadow({mode: "open"});
        }
        slot;
        connectedCallback() {
          // 添加到页面上
          this.shadowRoot.innerHTML = `<slot></slot>`;
          // 查找到slot,并且监控属性的变化
          this.slot = document.querySelector('app-element').shadowRoot.querySelector('slot');
          this.slot.addEventListener('slotchange',e=>{
            console.log('触发');
          })
        }
      }
    
      customElements.define("app-element", AppElement)
    // 点击的时候修改属性
      function add() {
        let slot = document.querySelector('app-element').shadowRoot.querySelector('slot');
        slot.setAttribute('name','333')
      }
    

    决定自己的高度的是你的态度,而不是你的才能

    记得我们是终身初学者和学习者

    总有一天我也能成为大佬

  • 相关阅读:
    Mysql update from
    抽象类
    表自链接递归查询死循环
    复制订阅服务器和 AlwaysOn 可用性组 (SQL Server)
    C#找出接口的所有实现类并遍历执行这些类的公共方法
    Cors Http 访问控制
    返回参数去掉xml格式,以纯json格式返回(转)
    混布技术提升资源利用率
    fair scheduler配置
    ambari安装
  • 原文地址:https://www.cnblogs.com/fangdongdemao/p/13915202.html
Copyright © 2011-2022 走看看