温馨提醒,当你觉得看我写的很乱的时候,就对了,那是因为我查阅了大量的资料提取出来的,因为有点东西不太理解,所以你会感觉有的部分重复了,也不是重复,只是后面对前面的内容进行梳理了一些,需要耐心的看到最后

自定义元素

我们发现自定义元素总是有破折号的Q,<my-component><bacon-cheese>

因为浏览器供应商已承诺不创建其名称中包含短划线的新内置元素,以防止冲突

  1. <app-element></app-element>
  2. <element></element>
  3. const appElement = document.querySelector('app-element');
  4. console.log(appElement.constructor.name);
  5. // HTMLElement类型的
  6. const element=document.querySelector('element')
  7. console.log(element.constructor.name);
  8. // HTMLUnknownElement

上面两个自定义元素,我们通过constructor.name 知道HTML 元素类型

  • <app-element> 实际上是一个自定义元素, 他基于HTMLElement 上标记的基本数据类型
  • <element> 数据类型HTMLUnknownElement, 是一个无效的HTML元素,浏览器并不知道它是什么元素
  1. class MyComponent extends HTMLElement {
  2. connectedCallback() {
  3. this.innerHTML = `<h1>Hello world</h1>`;
  4. }
  5. }
  6. customElements.define('my-component', MyComponent);
  7. <my-component></my-component>

customElements

引用customElements ,将返回浏览器加载自定义元素的全局记录,类似于注册表

方法 描述
customElement.define(``name,class(function)) 在页面上定义一个自定义元素
customElement.get(``name) 获取已定义的自定义元素的类。
customElement.whenDefined(``name) 带回 定义自定义元素时。
customElement.upgrade(``node) 允许您手动更新自定义元素

我们通过customElements.define() 定义自定义元素

获取自定义元素

  1. class AppElement extends HTMLElement {
  2. /* ... */
  3. }
  4. customElements.define("app-element", AppElement);
  5. customElements.get("app-element") === AppElement; // true

.get() 获得所请求的自定义元素的类

特定的操作

  1. customElements.define('my-counter', MyCounter);
  2. customElements.whenDefined('my-counter').then(()=>{
  3. console.log('xxx');
  4. })

简单的理解,我们在自定义元素 初始化后,进行的一些操作

更新操作

customElements.upgrade

  1. // 创建一个自定义元素
  2. const element = document.createElement("app-element");
  3. // 我们把这个自定义元素定义好
  4. class AppElement extends HTMLElement { /* ... */ }
  5. customElements.define("app-element", AppElement);
  6. console.log(element.constructor === HTMLElement); // true
  7. //我们更新下这个元素,他已经从 HTMLElement=>AppElement
  8. customElements.upgrade(element)
  9. ae.constructor === HTMLElement; // false
  10. ae.constructor === AppElement; // true

我们在.createElement() 定义前,他是HTMLElment类型,但是upgrade更新后,他就是AppElement ,

所以有必要进行手动更新

自定义元素的生命周期

connectedCallback() 是从元素的分离constructor 出来的

connectedCallback通过用于讲内容添加到元素

影子DOM

影子dom的特点

  1. <div class="element">
  2. #shadow-root
  3. <div class="inner-element">
  4. ...
  5. </div>
  6. </div>

shadowRootInit

  1. element.attachShadow(shadowRootInit);

shadowRootInit设置

  1. {mode:'open'}
  2. element.shadowRoot // 返回一个ShadownRoot对象

root元素可以从js外部访问根节点

  1. {mode:'closed'}
  2. element.shadowRoot // null

拒绝js外部返回关闭的shadow

<slot> 包含文档内容的内容

  1. <div id="example">我是本来的元素,</div>
  2. <script>
  3. let example = document.getElementById('example');
  4. let shadowRoots = example.attachShadow({mode: 'open'});
  5. shadowRoots.innerHTML = `<style>
  6. button {
  7. background: tomato;
  8. color: white;
  9. }
  10. </style>
  11. <button id="button"><slot></slot> 我是添加的内容</button>`;
  12. </script>

HMTL模板

template 元素是HTML流中可以标记重复使用的代码模块,但是这些模块不能立即呈现

  1. <template id="books">
  2. <li><span class="title"></span> &mdash; <span class="author"></span></li>
  3. </template>
  4. <ul id="contents"></ul>
  5. <script>
  6. const books = [
  7. { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },
  8. { title: 'A Farewell to Arms', author: 'Ernest Hemingway' },
  9. { title: 'Catch 22', author: 'Joseph Heller' }
  10. ];
  11. const fragment=document.querySelector('#books')
  12. const contents = document.querySelector('#contents');
  13. books.forEach(book=>{
  14. // 创建内容实例
  15. const instance=document.importNode(fragment.content,true)
  16. instance.querySelector('.title').innerText=book.title;
  17. instance.querySelector('.author').innerText=book.author;
  18. // 添加到dom上
  19. contents.appendChild(instance)
  20. })
  21. </script>

我们发现我们使用模板的时候,我们需要把javascript

  1. // 拿到 <template></template> 标签
  2. const template = document.querySelector('template');
  3. const node = document.importNode(template.content, true);
  4. document.body.appendChild(node);

使用document.importNode 允许我们在多个位置重用相同模板内容的实例

webComponent 在项目的使用

新建一个最小的基点

  1. class AppElement extends HTMLElement {
  2. constructor() {
  3. super();
  4. }
  5. }
  6. customElements.define("app-element", AppElement);

我们命令的时候要养成一个良好的习惯,文件通过与类命名AppElement.js

在文档中加载组件javascript 文件

  1. <script src="/components/AppElement.js"></script>

这样我们就可以在html添加这个组件

  1. <app-element></app-element>
  2. 或者我们用js的形式添加
  3. const appElement = document.createElement("app-element");
  4. document.body.appendChild(appElement);

或者我们放在一个根文件中

  1. <script type="module" src="/js/index.js"></script>

这样我们就可以在index.js中使用

  1. import "./components/AppElement.js";

组件属性

我们可以在constructor 添加属性或者成员

  1. class AppElement extends HTMLElement {
  2. #role='devel'
  3. constructor() {
  4. super();
  5. this.name = "Manz";
  6. this.life = 5;
  7. this.#role='js Devel'
  8. }
  9. test(){
  10. }
  11. #provateTest(){
  12. }
  13. }

也可以添加私有属性和方法

执行方法

上面我们在自定义元素内部写了一些方法

  1. <app-element onClick="this.test()"></app-element>

我们发现他会执行public公共类型的方法,私有方法只能在类内部执行

对于自身而且创建就执行静态方法,默认的情况的其实this可以不写因为默认调用的就是内部的方法

生命周期

特性 描述
constructor() 已创建一个特定的自定义元素,该元素已在注册表中定义。
connectedCallback() 自定义元素已连接到HTML文档的DOM。
disconnectedCallback() 自定义元素已从HTML文档的DOM断开。
adoptedCallback() 自定义元素被移动到一个新文件(常见于iframes)。
attributeChangedCallback() 自定义元素的观察属性已被修改。

我们可以通过document.createElementnew AppElement() 手动创建元素

不要忘记写super(),因为我要扩展到HTMLElement

  1. // 调用dom时候执行
  2. connectedCallback() {
  3. this.textContent='ddd'
  4. }
  5. // 删除dom时候执行
  6. disconnectedCallback(){
  7. console.log(333);
  8. }

我们发现在操作dom的时候connectedCallback一些方法

在删除了dom的时候,会调用disconnectedCallback

adoptedCallback() 自定义元素移动一个新文件(这个我暂时不清楚),不太清楚现实的用意在哪

变更检测

可以使用HTML元素的属性

方法 描述 返回值
.hasAttributes() 元素有属性吗? boolean
.getAttributeNames() 返回一个array属性的小写属性值 Array
.hasAttribute(name) 查询某个name是否存在 boolean
.getAttribute(name) 返回name的属性值,不存在返回null string
.removeAttribute(name) 删除属性name
.setAttribute(name,value) 将属性设置name-value
.toggleAttribute(name,[boolean]) 如果存在则删除,不存在则添加 boolean
特性 描述
static get observedAttributes() 观察属性以通知更改。
attributeChangedCallback(``name,``old,``now) 它会关闭,当他们改变。
  1. class AppElement extends HTMLElement {
  2. static get observedAttributes() {
  3. return ["value", "isEnabled"];
  4. }
  5. attributeChangedCallback(name, old, now) {
  6. console.log(` ${name} ------ ${old} ---- ${now}.`);
  7. }
  8. }

static getter observedAttributes()返回我们要观察的属性名称

每当我们的属性修改的时候,都会调用attributeChangedCallback() 方法

属性名称name,之前的old 值和当前的值now

每当属性的修改都会调用这个函数

写一个类似vue的完整版实例

  1. <div id="templates"></div>
  2. <template id="templateOne">
  3. <style>
  4. .aaa{
  5. color:red;
  6. font-size: 12px;
  7. }
  8. </style>
  9. <div class="aaa">12211212</div>
  10. <button onClick="clickDown()">Click</button>
  11. <script>
  12. function clickDown(){
  13. alert(1)
  14. }
  15. </script>
  16. </template>
  17. <script>
  18. let template=document.querySelector('#templateOne')
  19. let content=document.querySelector('#templates')
  20. content.appendChild(
  21. document.importNode(template.content,true)
  22. )
  23. </script>

自定义组件的完整样例

  1. <my-counter></my-counter>
  2. <script>
  3. const template = document.createElement('template');
  4. template.innerHTML = `
  5. <style>
  6. * {
  7. font-size: 200%;
  8. }
  9. span {
  10. width: 4rem;
  11. display: inline-block;
  12. text-align: center;
  13. }
  14. button {
  15. width: 4rem;
  16. height: 4rem;
  17. border: none;
  18. border-radius: 10px;
  19. background-color: seagreen;
  20. color: white;
  21. }
  22. </style>
  23. <button id="dec">-</button>
  24. <span id="count"></span>
  25. <button id="inc">+</button>`;
  26. class MyCounter extends HTMLElement {
  27. constructor() {
  28. super();
  29. this.count = 0;
  30. this.attachShadow({ mode: 'open' });
  31. }
  32. connectedCallback() {
  33. this.shadowRoot.appendChild(template.content.cloneNode(true));
  34. this.shadowRoot.getElementById('inc').onclick = () => this.inc();
  35. this.shadowRoot.getElementById('dec').onclick = () => this.dec();
  36. this.update(this.count);
  37. }
  38. inc() {
  39. this.update(++this.count);
  40. }
  41. dec() {
  42. this.update(--this.count);
  43. }
  44. update(count) {
  45. this.shadowRoot.getElementById('count').innerHTML = count;
  46. }
  47. }
  48. customElements.define('my-counter', MyCounter);
  49. </script>

从原生web组件到框架组件源码(一)的更多相关文章

  1. Web前端三大框架_vue源码笔记

    一.VUE 1.1 MVVM VUE也是基于MVVM模式实现的.特点就是数据双向绑定 在MVVM模式中,分成三个部分: M 模型 model V 视图 view VM 视图-模型 view-model ...

  2. DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render

    DRF框架    全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...

  3. robotlegs2.0框架实例源码带注释

    robotlegs2.0框架实例源码带注释 Robotlegs2的Starling扩展 有个老外写了robotleges2的starling扩展,地址是 https://github.com/brea ...

  4. 框架-springmvc源码分析(一)

    框架-springmvc源码分析(一) 参考: http://www.cnblogs.com/heavenyes/p/3905844.html#a1 https://www.cnblogs.com/B ...

  5. JUC同步器框架AbstractQueuedSynchronizer源码图文分析

    JUC同步器框架AbstractQueuedSynchronizer源码图文分析 前提 Doug Lea大神在编写JUC(java.util.concurrent)包的时候引入了java.util.c ...

  6. 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(2)-easyui构建前端页面框架[附源码]

    原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(2)-easyui构建前端页面框架[附源码] 开始,我们有了一系列的解决方案,我们将动手搭建新系统吧. 用 ...

  7. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  8. WEB前端开发学习:源码canvas 雪

    WEB前端开发学习:源码canvas 雪 双旦节要到了,程序员们为了响应气氛,特别用代码制作了动态雪花,WEB前端开发学习的初学者们一起跟着案例做一遍吧! <!DOCTYPE html> ...

  9. 如何查看JDK以及JAVA框架的源码

    如何查看JDK以及JAVA框架的源码 设置步骤如下: 1.点 “window”-> "Preferences" -> "Java" -> &q ...

  10. 高性能网络I/O框架-netmap源码分析

    from:http://blog.chinaunix.net/uid-23629988-id-3594118.html 博主这篇文章写的很好 感觉很有借签意义 值得阅读 高性能网络I/O框架-netm ...

随机推荐

  1. HTML你好!

    初识HTML 什么是HTML web的本意是蜘蛛网和网的意思,在网页设计中我们称为网页的意思.现广泛译作网络.互联网等技术领域.表现为三种形式,即超文本(hypertext).超媒体(hypermed ...

  2. Centos-yum软件包安装-yum

    yum 自动安装相关软件依赖,可以同时配置多个yum源,初始启动yum时候首先会缓存资源包到 /var/cache/yum目录下 yum确认 -y yum安装和卸载 install 安装,自动安装软件 ...

  3. 0923 lca练习

    P1967 货车运输 题目描述 A 国有 nnn 座城市,编号从 11 1 到 n nn,城市之间有 mmm 条双向道路.每一条道路对车辆都有重量限制,简称限重. 现在有 qqq 辆货车在运输货物, ...

  4. 04 ArcPython实战篇二

    1.删除Default.gdb中的所有要素类.表.栅格 2.空间随机抽取若干数 3.地震目录自动空间化 参考:esrichina易智瑞中国公开课

  5. linux centos7使用docker安装elasticsearch,并且用Django连接使用

    一:elasticsearch安装及配置 1:需求分析 当用户在搜索框输入关键字后,我们要为用户提供相关的搜索结果.这种需求依赖数据库的模糊查询like关键字可以实现,但是like关键字的效率极低,而 ...

  6. OpenCV计算机视觉学习(2)——图像算术运算 & 掩膜mask操作(数值计算,图像融合,边界填充)

    在OpenCV中我们经常会遇到一个名字:Mask(掩膜).很多函数都使用到它,那么这个Mask到底是什么呢,下面我们从图像基本运算开始,一步一步学习掩膜. 1,图像算术运算 图像的算术运算有很多种,比 ...

  7. C++ CComboBox控件详解

    转载:http://blog.sina.com.cn/s/blog_46d93f190100m395.html C++ CComboBox控件详解 (2010-09-14 14:03:44) 转载▼ ...

  8. 数字PLL,什么是数字PLL

    来源:http://www.elecfans.com/baike/bandaoti/bandaotiqijian/20100323203306.html 数字PLL,什么是数字PLL 数字PLL PL ...

  9. abp(net core)+easyui+efcore实现仓储管理系统——出库管理之二(五十)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统--ABP总体介绍(一) abp(net core)+ ...

  10. 二进制K8S集群使用Bootstrap Token 方式增加Node

    TLS Bootstraping:在kubernetes集群中,Node上组件kebelet和kube-proxy都需要与kube-apiserver进行通信,为了增加传输安全性,采用https方式, ...