从原生web组件到框架组件源码(三)
快乐的时光都是这么短暂,转眼间,web原生组件的知识点已经学完了,这个虽然暂时不一定有用,但是随着时间的积累,一步一个脚印的积累,你会有相应的收获,希望能变得更强,比如两年前我也会想有现成的东西不用,干嘛要自己写呢?但是你确定一直用上层的东西,你的收获有自己写快吗? 在开发的过程过能节约下来的时间,我们可以用这个时间拿来学习,这样随着时间的积累我们会变得更强,也会慢慢有更多的时间投入生活,进行正向循环
css问题
自定义元素然后是普通的HTML元素,也可以使用css设置样式
在我们没有设置shadow DOM
的组件,进行全局样式设置
<app-element></app-element>
<style>
/* CSS Global */
app-element {
display: inline-block;
padding: 6px 20px;
background: steelblue;
color: white;
}
app-element span {
font-weight: bold;
vertical-align: super;
font-size: small;
color: gold;
}
</style>
<script>
customElements.define("app-element", class extends HTMLElement {
connectedCallback() {
this.innerHTML = `<div class="element">AppElement <span>New!</span></div>`;
}
});
</script>
- 无论文档是否具有Shadow DOM,都可以从文档的全局CSS(从组件外部)对组件本身进行样式设置。
- 只要没有Shadow DOM可以“保护”组件,就可以对组件中的元素进行全局样式设置
HTML 外部引入
<app-element></app-element>
<script>
customElements.define("app-element", class extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<link rel="stylesheet" href="/components/AppElement.css">
<style>
@import "/components/AppElement.css";
</style>
<div class="element">
AppElement <span>New!</span>
</div>
`;
}
});
</script>
程序化动态的方法
<app-element></app-element>
<script>
import css from "./AppElement.css";
customElements.define("app-element", class extends HTMLElement {
connectedCallback() {
document.adoptedStyleSheets = [...document.adoptedStyleSheets, css];
this.innerHTML = `
<div class="element">
AppElement <span>New!</span>
</div>
`;
}
});
</script>
this.shadowRoot.adoptedStyleSheets = [...document.adoptedStyleSheets, css];
我们通过import
加载css,在这种情况下,它是组件的相对路径,在加载css内容中并生成一个对象cssStyleSheet
,然后通过.adoptedStyleSheets
导入css
这种方法直接使用是错误的,需要引入插件css-loader
,应该要借助webpack ,原生不能直接使用
import css from "./AppElement.css"
css自定义属性
var(--color,red)
// 第一个变量不存在,用第二个
全局设置,穿透到里面
<app-element></app-element>
<app-element></app-element>
<app-element></app-element>
<style>
/* CSS Global */
app-element:first-of-type {
--color: orangered;
}
</style>
<script>
customElements.define("app-element", class extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<style>
/* CSS Local */
.element {
display: inline-block;
padding: 6px 20px;
background: var(--color, steelblue);
color: white;
}
span {
font-weight: bold;
vertical-align: super;
font-size: small;
color: gold;
}
</style>
<div class="element">
AppElement <span>New!</span>
</div>
`;
}
});
</script>
css 作用域
css 伪类,仅在定义了shadow DOM
有效
伪类 | 描述 |
---|---|
:host |
它允许我们设置自定义元素(组件自己的容器)的样式。 |
:host(``css) |
同上一个,但前提是它与中定义的选择器匹配css 。 |
:host-context(``css) |
同上,但前提是您有与选择器匹配的父母css 。 |
<app-element></app-element>
<app-element disabled></app-element>
<div class="box">
<app-element></app-element>
</div>
<script>
customElements.define("app-element", class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
:host {
display: inline-block;
padding: 6px 20px;
background: steelblue;
color: white;
}
:host([disabled]) {
background: #aaa;
}
:host-context(.box) {
background: red;
}
span {
font-weight: bold;
vertical-align: super;
font-size: small;
color: gold;
}
</style>
<div class="element">
AppElement <span>New!</span>
</div>
`;
}
});
</script>
修改最外层的盒子的css
影子DOM操作事件
<app-element></app-element>
<script>
customElements.define("app-element", class AppElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
}
sendMessage() {
alert("Hello!");
}
connectedCallback() {
this.shadowRoot.innerHTML = "<button>点我!</button>";
this.button = this.shadowRoot.querySelector("button");
this.button.addEventListener("click", () => this.sendMessage());
}
// 离开页面删除事件
disconnectedCallback() {
this.button.removeEventListener("click", () => this.sendMessage());
}
});
</script>
第二种方法
不用addEventListener
this.button.onclick=()=>this.sendMessage()
// 离开页面删除事件
disconnectedCallback() {
this.button.onclick=null;
}
第三种方法
神奇的handleEvent函数
<app-element></app-element>
<script>
customElements.define("app-element", class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
}
handleEvent(event) {
if (event.type === "click"){
console.log(3)
}
}
connectedCallback() {
this.shadowRoot.innerHTML = "<button> Press me!</button>";
this.button = this.shadowRoot.querySelector("button");
this.button.addEventListener("click", this);
}
disconnectedCallback() {
this.button.removeEvenetListener("click", this);
}
});
</script>
我们发现当我们简单的放置this
浏览器会奇特找到.handleEvent
函数,存在就进行处理,这种方法我们可以通过检测event.type
,我们可以通过这种方法进行集中处理
自定义事件
选择项 | 值 | 描述 |
---|---|---|
detail |
假 | 包含我们要传输的所有信息的对象。 |
bubbles |
假 | 指示该事件是否应气泡在DOM“到表面”或没有。 |
composed |
假 | 指示传播是否可以遍历Shadow DOM。 |
cancelable |
假 | 指示是否可以使用取消行为.preventDefault() 。 |
事件传递冒泡
<div class="box1">
<div class="box2"></div>
</div>
<script>
let box2 = document.querySelector('.box2');
let box1 = document.querySelector('.box1');
box2.addEventListener('click',()=>{
box2.dispatchEvent(
new CustomEvent('messages', {
detail: {
message: 'hello'
},
bubbles:true,
})
)
})
box1.addEventListener('messages',(e)=>{
console.log(333);
console.log(e.detail);
})
</script>
bubbles=true
通过冒泡传递给父级,event.target
拿到dom元素,event.detail
拿到创建事件的数据
默认情况下
<div class="box1">
<div class="box2">
<div class="box3"></div>
</div>
</div>
<script>
let box1 = document.querySelector('.box1');
let box2 = document.querySelector('.box2');
let box3 = document.querySelector('.box3');
box3.addEventListener('click',()=>{
console.log(1);
box3.dispatchEvent(
new CustomEvent('messages', {
detail: {
message: 'hello'
},
bubbles:true,
})
)
})
box2.addEventListener('click',()=>{
console.log(2);
})
box1.addEventListener('click',()=>{
console.log(3);
})
</script>
我们发现默认情况下冒泡是从里到外1,2,3
当我们在最外层添加
box3.addEventListener("messages", (event) => {
console.log(4);
},{capture:true});
我们发现执行的顺序为1,4,2,3
跨组件的通信
组件1发送数据
<first-element></first-element>
customElements.define("first-element", class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
}
handleEvent(event) {
if (event.type === "click") {
const MessageEvent = new CustomEvent("messages", {
detail: {from: "Manz", message: ++this.i},
bubbles: true,
composed: true // 影子
});
this.dispatchEvent(MessageEvent);
}
}
connectedCallback() {
this.shadowRoot.innerHTML = `<button>点我</button>`;
this.shadowRoot.querySelector("button").addEventListener("click", this);
}
});
接受传递来的数据
customElements.define("second-element", class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
}
handleEvent(event) {
if (event.type === "messages") {
event.detail.from = "Robot";
const data = event.detail;
this.shadowRoot.innerHTML = `
<div>
From ${data.from}:
<span style="color:red">${data.message}</span>
</div>
`;
}
}
connectedCallback() {
this.shadowRoot.innerHTML = `<div>No messages</button>`;
document.addEventListener("messages", this);
}
});
这样想不想两个异步组件之间的通信
从原生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 ...
随机推荐
- mysql 空值(null)和空字符('')的区别
日常开发中,一般都会涉及到数据库增删改查,那么不可避免会遇到Mysql中的NULL和空字符. 空字符(")和空值(null)表面上看都是空,其实存在一些差异: 定义: 空值(NULL)的长度 ...
- Layman 使用ffmpeg-php扩展库实现视频截图(默认图)
这几天做项目,其中一个需求是用户上传视频文件到服务器,然后服务器自动截取该视频的一帧作为该视频对应的缩略图,服务器端语言采用php编写,找了半天资料,发现ffmpeg-php可以满足该需求,所以下面简 ...
- 剑指Offer(一):二维数组中的查找
一.前言 刷题平台:牛客网 二.题目 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整 ...
- Python 自动化测试全攻略:五种自动化测试模型实战详解
随着移动互联网的发展,软件研发模型逐步完善,软件交付质量越来越受到软件公司的重视,软件测试技术特别是自动化测试技术开始在软件系统研发过程中发挥着越来越重要的作用. 与传统的手工测试技术相比,自动化测试 ...
- 启动你的Android应用:运行设备模拟器和调试代码(第3部分)
下载all source for Test Proj: Test.zip - 306 KB 文章指出 本文包含了我即将出版的新书<启动Android应用程序>中的第三章. 在我完成这本书之 ...
- 不出意外,排名第一的还是它,程序员为什么都喜欢用Chrome?
程序员为什么喜欢使用Chrome? 其实不单单是程序员喜欢使用Chrome,现在大多数的小伙伴都使用Chrome. 我们可以看到Netmarketshare发布了2020年7月的操作系统与浏览器市场份 ...
- BOOST库 消息队列
直接贴实验代码: /******* boost 消息队列 **********/ #if 1 #include <boost/thread/thread.hpp> #include < ...
- spring boot:方法中使用try...catch导致@Transactional事务无效的解决(spring boot 2.3.4)
一,方法中使用try...catch导致@Transactional事务无效的解决方法 1,问题的描述: 如果一个方法添加了@Transactional注解声明事务, 而方法内又使用了try catc ...
- CentOS 6编译安装RabbitMQ
编译安装Python 下载python源文件 [root@localhost src]# tar -xzvf python-2.7.11.tar.gz [root@localhost src]# cd ...
- 2020-2021-1 20209313 《Linux内核原理与分析》第一周作业
遇到的问题:安装ubuntu遇到问题 描述:在本机上虚拟机的安装包点开就闪退,无法安装VMware 解决方案: 清理VMware相关注册表,更改用户名为英文,查阅相关资料,重装系统. 更换linux安 ...