从原生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 bbbouterHTML
除了包含innerHTML的全部内容外,还包含对象标签本身
textContent
跟innerText 返回的结果一样
重要
根据W3C标签,尽量用innerHTML,textContent,而少用innerText,outerHTML
动态访问DOM
| 方法 | 描述 | 
|---|---|
document.createElement(``tag) | 
创建并返回一个HTML标签tag。 | 
element.appendChild(``child) | 
添加的元素child里面element。 | 
element.insertAdjacentHTML(``pos,``html) | 
将代码插入html中element。 | 
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')
  }
												
											从原生web组件到框架组件源码(二)的更多相关文章
- Web前端三大框架_vue源码笔记
		
一.VUE 1.1 MVVM VUE也是基于MVVM模式实现的.特点就是数据双向绑定 在MVVM模式中,分成三个部分: M 模型 model V 视图 view VM 视图-模型 view-model ...
 - DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render
		
DRF框架 全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...
 - robotlegs2.0框架实例源码带注释
		
robotlegs2.0框架实例源码带注释 Robotlegs2的Starling扩展 有个老外写了robotleges2的starling扩展,地址是 https://github.com/brea ...
 - 框架-springmvc源码分析(一)
		
框架-springmvc源码分析(一) 参考: http://www.cnblogs.com/heavenyes/p/3905844.html#a1 https://www.cnblogs.com/B ...
 - JUC同步器框架AbstractQueuedSynchronizer源码图文分析
		
JUC同步器框架AbstractQueuedSynchronizer源码图文分析 前提 Doug Lea大神在编写JUC(java.util.concurrent)包的时候引入了java.util.c ...
 - 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(2)-easyui构建前端页面框架[附源码]
		
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(2)-easyui构建前端页面框架[附源码] 开始,我们有了一系列的解决方案,我们将动手搭建新系统吧. 用 ...
 - 框架-springmvc源码分析(二)
		
框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...
 - WEB前端开发学习:源码canvas 雪
		
WEB前端开发学习:源码canvas 雪 双旦节要到了,程序员们为了响应气氛,特别用代码制作了动态雪花,WEB前端开发学习的初学者们一起跟着案例做一遍吧! <!DOCTYPE html> ...
 - 如何查看JDK以及JAVA框架的源码
		
如何查看JDK以及JAVA框架的源码 设置步骤如下: 1.点 “window”-> "Preferences" -> "Java" -> &q ...
 - 高性能网络I/O框架-netmap源码分析
		
from:http://blog.chinaunix.net/uid-23629988-id-3594118.html 博主这篇文章写的很好 感觉很有借签意义 值得阅读 高性能网络I/O框架-netm ...
 
随机推荐
- Python对象的空间边界:独善其身与开放包容
			
导读:Python猫是一只喵星来客,它爱地球的一切,特别爱优雅而无所不能的 Python.我是它的人类朋友豌豆花下猫,被授权润色与发表它的文章.如果你是第一次看到这个系列文章,那我强烈建议,请先看看它 ...
 - Arduino 串行外设接口(SPI)
			
时间有限有其他项目工作在忙,感觉作者写的不错,就先记录下来了. 这几天用SPI--Arduino 在供应商的电子原件上游离游走,重要的是可以读写了, 下面是在查资料看到的一篇不错的文章关于用Ardui ...
 - IntelliJ IDEA Commons IO环境搭建
			
IntelliJ IDEA版本信息 1.打开.或新建工程之后,点击菜单File > Project Structure... 2.在Project Structure窗口中,选Project S ...
 - 编程体系结构(06):Java面向对象
			
本文源码:GitHub·点这里 || GitEE·点这里 一.基础概念 1.面向对象概念 面向对象编程的主要思想是把构成问题的各个事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙一 ...
 - Vuejs上传
			
下载 Vuejs上传Vuejs上传 多部分上传Vue组件. 上传器可以选择上传多部分的文件. 这是关于最大的上传尺寸,允许你上传大文件. 如果prop multiple为真,文件列表将在选择文件时呈现 ...
 - 初始python模块
			
Python语言中,模块分为三类. 第一类:内置模块,也叫做标准库.此类模块就是python解释器给你提供的,比如我们之前见过的 time模块,os模块.标准库的模块非常多(200多个,每个模块又有很 ...
 - win7如何安装maven
			
1.Maven的简介Maven是一个项目管理工具,主要用于Java平台的项目构建.依赖管理和项目生命周期管理. 当然对于我这样的程序猿来说,最大的好处就是对jar包的管理比较方便,只需要告诉Maven ...
 - ttl转以太网
			
ttl转以太网 ttl转以太网ZLSN3007S是实现TTL电平串口转以太网的"超级网口",产品自带网络变压器和RJ45网口,可以方便实现单片机.各类TTL电平串口设备的联网.首先 ...
 - 快速掌握ES6语法
			
常量变量 let and const 先说说常量和变量的概念吧, 常量是说那种进行一次赋值后不会更改的值,比如说游戏账户的 ID, 变量是说赋值后有更改的需求的,比如游戏名,游戏密码. 在之前的 Ja ...
 - selenium环境配置学习笔记
			
一 为什么进行自动化测试 缩短测试周期 避免人为出错 测试信息存储 轻易获取覆盖率 二 web/ui自动化条件和适用范围 手工测试已经完成,后期在不影响进度的前提下逐渐实现自动化 项目周期长,重复性工 ...