200 Success
200 Success 博客
200 Success
常用标签
组员
2020-05-03
By Hokori
  1. 论坛
  2. 集成程序(模块化开放)

    • marble1.0
    • 互帮互助
    • 考研资料
    • 题库+做题记录
    • 作业板(老师发布)
    • app后台推送
  3. 面向客户定制功能

相比<p>、<div>这样的标签,
input标签表现得更加复杂,而它是怎么实现的呢?

在这里我们要引出一个概念

Shadow DOM

Shadow DOM是HTML的一个规范 ,它允许浏览器开发者封装自己的HTML标签、CSS样式和特定的javascript代码,同时也可以让开发人员创建类似<video>这样的自定义一级标签,创建这些新标签内容和相关的的API被称为Web ComponentWeb Component内容比较多不在这里讲,有空再写一篇



在平时我们是没办法从DevTools中看到Shadow DOM的,因为默认是隐藏的,需要手动设置,

DevToolsDevTools



来一个例子,我们来看看一个input组件

在没有显示Shadow DOM之前 它在HTML中是长这个样子的

展开之后 是这个样子

可以看出在input标签内出现了#shadow-root(user-agent),它包含了input组件内的DOM结构,
这就是所谓的Shadow DOM

Shadow DOMShadow DOM

结合代码和这两张图片我们可以来理一理Shadow DOM的结构
从外到内分别是shadow-hostshadow-rootshadow-tree

我们可以来看看W3C对Shadow DOM的描述

Shadow host: The regular DOM node that the shadow DOM is attached to.
Shadow host是一个被Shadow DOM附着的普通DOM节点
Shadow tree: The DOM tree inside the shadow DOM.
Shadow tree是属于Shadow DOM下的节点树
Shadow root: The root node of the shadow tree.
Shadow root是Shadow tree的根节点
Shadow boundary: the place where the shadow DOM ends, and the regular DOM begins.
Shadow boundary是Shadow DOM结束,普通DOM开始的分界线

同时我们可以看见shadow-tree的元素中出现了我们不熟悉的属性pseudo

何为pseudo
我们可能用过这样的方式来隐藏掉浏览器默认的丑陋滚动条

body::-webkit-scrollbar{display:none;}

对的,这个pseudo就是伪元素Pseudo Element

有了它,
我们可以在css中从shadow-host通过pseudo来访问shadow-root下的元素


Shadow DOM的好处

一个东西存在必然有它的价值,Shadow DOM为我们提供了简单有效的样式隔离,除此之外和普通DOM元素没有差别
在某个Shadow DOM内写的css代码并不会对该Shadow DOM以外的元素生效,于是我们可以通过Shadow DOM来隐藏控件的内部实现,就不用担心对样式表进行修改时对控件造成影响了

下面我们来看看Shadow DOM的简单使用

笔者找到两种方式来创建Shadow root

  • 源自MDNElement.attachShadow(shadowRootInit)
    最后修改时间: 2020.01.08
  • 源自简书帖子的Element.createShadowRoot()
    最后修改时间: 2018.10.11

都可以通过来创建Element(Shadow host)下的Shadow root

笔者测试Element.attachShadow(shadowRootInit)在现代浏览器的兼容性更强
并且Element.createShadowRoot()不是W3C标准,MDN并不建议使用
于是以下例子均用Element.attachShadow(shadowRootInit)
Element.createShadowRoot()有兴趣的可以跳转简书帖子阅读

详细说一说MDNElement.attachShadow(shadowRootInit)

可以作为Shadow host使用attachShadow()的标签有

一个有合法名字的自定义标签、<article>、<aside>、<blockquote>、<body>、<div>、<footer>、<h1>、<h2>、<h3>、<h4>、<h5>、<h6>、<header>、<main>、<nav>、<p>、<section>、<span>

其中的shadowRootInit包括以下字段

mode

  1. open

    • 可以从根外部的JavaScript访问Shadow root的元素
    • Element.shadowRoot; // Returns a ShadowRoot obj
  2. closed

    • 不可以从根外部的JavaScript访问Shadow root的元素
    • Element.shadowRoot; // Returns null

delegatesFocus

  1. true

    • 点击Shadow Root的某个不可focus元素时,会聚焦到另外第一个可以focus的元素上,并为Shadow host提供任何可用的:focus样式
  2. false

    • 和true反过来

这是MDN提供的兼容图

下面我们用一些例子来帮助我们理解

比方说现在的HTML代码是这样的

<body>
    <h1>outer h1</h1>
    <div id='test'>
    </div>
</body>

然后我们对#test添加Shadow DOM并且在Shadow DOM里添加css样式

if (document.body.attachShadow) { //做兼容性处理
    let test = document.querySelector('#test');
    let shadow = test.attachShadow({
        mode: 'open'
    });
    shadow.innerHTML = `
        <h1>inner h1</h1>
        <style>
            h1{color:red;text-align:center}
        </style>
    `;
}

效果图

代码图

可以看到Shadow DOM里的样式并没有泄露出来,这给我们创建Web Component奠定了基础

一、写在前面

我们首先来通过一个银行转账的小案例来介绍一下数据库中的事务,并引出动态代理的概念。

1.1 功能需求

模拟一个银行转账功能,能实现A用户向B用户转账指定金额。

一、写在前面

主要有三种模式:纯XML,不完全注解,纯注解。

2020-02-09
By Hokori

讲一讲我一开始学JS时迷惑了我很久的一个东西
就是

基本包装类型

我们知道像C++Java这样的强类型语言
数据类型引用类型之分
因为数据类型开辟的内存是固定的,所以放在了栈内存,给人一种线性排列的感觉
引用类型因为各自所含的方法、属性不同,数量也不同,需要开辟的内存是不定的,所以只能放在堆内存,并用指针去进行索引和绑定。

而JavaScript也是如此,拥有数据类型引用类型之分,
数据类型

NumberStringBooleanUndefinedNull
以及ECMAScript6规范的
Symbol(不一定齐全且准确)

引用类型

ObjectArrayDateRegExpFunction
以及ECMAScript6规范的
SetMapWeakMapPromiseProxy(不一定齐全且准确)

铺垫那么多,其实都是为了引出

JavaScript为NumberStringBoolean封装的基本包装类型

在C++和Java中,int、float等数据类型变量,是不能通过对象访问符“.”来访问它们的方法,因为它们是简单的数据类型变量,不存在方法,也就称不上对象
但是在JavaScript中,Number、String类型的变量,却可以拥有toString()、toNumber()等方法
来段代码看看

var s1 = "some text"; 
var s2 = s1.substring(2);

这是因为它们封装了相应的基本包装类型
基本包装类型是和引用类型是一致的,所以可以拥有方法

实际上后台自动完成了一系列处理,上面的代码等同于

var s1 = "some text";
var temp = new String(s1)
var s2 = temp.substring(2); 
temp = null;

可以看到这里的temp变量作为一个中间者,使得数据类型看起来拥有了方法
再来一段代码,让我们更好去理解 为什么它们都叫String | Number | Boolean,但是它们就不一样

var s1 = "test";
var s2 = new String(s1);
console.log(typeof s1);     //String
console.log(typeof s2);     //Object
console.log(s2 instanceOf String);     //true