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奠定了基础

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

这是一个简单的关于transition与overflow属性的小demo

在线示例
body {
    margin: 0;
    padding: 0;
}

html {
    font-size: 62.5%;
}

#test-box,
#test-box-1 {
    width: 20%;
    height: 20rem;
    background-color: skyblue;
    transition: height 0.5s;
    margin-left: 1rem;
    margin-bottom: 1rem;
    /* div块高度为0时,内部元素都因溢出而隐藏,但有滚动条,可隐藏。 */
    overflow: auto;
}

#test-box h1 {
    /* 给定宽度*/
    width: 100%;
    /* 换行处理:不换行 */
    white-space: nowrap;
    /* 溢出内容做隐藏处理 */
    overflow: hidden;
    /* 溢出的隐藏内容用省略号替代 */
    text-overflow: ellipsis;
}

#test-box::-webkit-scrollbar {
    display: none;
}

.box-close {
    height: 0 !important;
    /* display: none;  不可配合transiton使用 */
}

#btn-box {
    display: flex;
    flex-direction: row;
    align-items: center;
    margin-left: 1rem;
}

#btn {
    border: 1px solid red;
    width: 1rem;
    height: 1.5rem;
    margin: 0.5rem;
    border-radius: 0.5rem;
    margin-right: 1rem;
    transition: 0.5s;
}

.btn-change {
    transform: rotate(360deg);
}
<body>
    <div id="btn-box">
        <!-- 触发一个事件若要调用多个函数,可用逗号相隔 -->
        <div id="btn" onclick="div_change(),btn_change(this)"></div>
        <span class="btn-span">点我</span>
    </div>
    <div id="test-box">
        <h1>1This is a transition test!This is a transition test!</h1>
        <h1>2This is a transition test!</h1>
        <h1>3This is a transition test!</h1>
        <h1>4This is a transition test!</h1>
        <h1>5This is a transition test!</h1>
        <h1>6This is a transition test!</h1>
    </div>
    <div id="test-box-1">
        <h1>1This is a transition test!</h1>
    </div>
</body>
<script>
    function div_change() {
        let testBox = document.getElementById('test-box');
        if (!testBox.className) {
            testBox.className = 'box-close';
        } else {
            testBox.className = '';
        }
    }

    function btn_change(e) {
        if (!e.className) {
            e.className = 'btn-change';
        } else {
            e.className = '';
        }
    }
<script>
2020-02-02
By Hokori

在这篇文章中记录一下自己已知的HTML5移动端与PC端的差异

在移动端中

  • 伪类:hover的表现比较奇怪,点击之后效果不会消失

    移动端并没有鼠标,也没有:hover存在的必要,响应式页面可以通过media query区别PC和移动端来按需添加:hover效果

  • click会有300ms的延迟,主要原因是苹果手机在设计时,考虑到用户在浏览网页时需要放大,所以,在用户点击的300ms之后,才触发click,如果300ms之内还有click,就会进行放大缩小。

    为了解决这个问题,有不同的方案:

    但即便如此,在某些业务场景中还是不够方便的,因此诞生了许多手势库,如
    Hammer.js 支持drag,swipe,hold,doubleTap等手势

  • 在PC端,CSS的1px一般对应着电脑屏幕的1个物理像素,但在移动端,CSS的1px等于几个物理像素是和屏幕像素密度有关的。
    比如从iPhone4开始,苹果公司便推出了所谓的Retina屏,分辨率提高了一倍,变成640x960,但屏幕尺寸却没变化,这就意味着同样大小的屏幕上,像素却多了一倍,这时,一个css像素是等于两个物理像素的。
    详细请见 -> 移动前端开发之viewport,devicePixelRatio的深入理解

    我们常在移动端开发的时候在HTML开头添加这个meta标签来解决这个问题
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

    其中

    width=device-width :表示宽度是设备屏幕的宽度
    initial-scale=1.0:表示初始的缩放比例,1.0就是占网页的100%
    minimum-scale=1.0:表示最小的缩放比例
    maximum-scale=1.0:表示最大的缩放比例
    user-scalable=no:表示用户是否可以调整缩放比例

参考链接:
1.https://www.cnblogs.com/freefly-an/p/8665451.html
2.https://www.jianshu.com/p/413a25b2c503