小别致真东西
文章77
标签31
分类26
BFC 浅谈

BFC 浅谈

写在前面


Block formatting context (块级格式化上下文)

一块独立的渲染区域、内部元素的渲染不会影响边界以外的元素

页面文档由块block构成 每个block在页面上占据自己的位置
使用新的元素构建BFC overflow:hidden | auto | scroll; 只要不为visible 新的空间
告诉浏览器,外面的环境影响不到我了 我重新来进行Block formatting 布局和定位

核心:
新的BFC,给出了新的不受外界影响的块级格式化环境
block 块级-> 页面的基础
formatting context 格式化-> 渲染

浏览器构建文档树的时候 布局和定位元素

网页的定位(大) 文档流正常,浮动,定位,flex,table
广义的定位 块级元素的定位 垂直的定位;行内元素 左右定位 通过内容来确定
狭义的定位:
float 浮动元素,在一行的开始或者结束
flex 弹性布局
position

BFC 在正常的文档流里面重建一个新的上下文环境

BFC的约束规则

  • 一、在浏览器进行页面元素布局的时候 同一个BFC的两个相邻的Box的margin 会重叠,与方向无关

    破坏规则 创建新的BFC Context上下文的概念

    如何创建BFC?=>重新规划一个(独立)渲染区域

    • 根元素body,天然是一个BFC
    • overflow:hidden;
    • float 不为none
    • display:inline-block | table-cell | table-caption | flex
    • position:absolute | fixed 只要不为static

      好像只剩块级元素和行内元素不是BFC

  • 二、BFC的高度,浮动元素也要参与计算

    在元素float 之后脱离了文档流没有办法计算确切高度,这种情况我们称之为高度塌陷。解决高度塌陷的前提就是能识别并包含到浮动元素。BFC就有这个特性,所以BFC也可以计算浮动元素的高度。新建BFC让浮动元素也参与计算

        <style>
    *{padding: 0;margin: 0;}
    .par{
    border: 5px solid #fcc;
    width: 300px;
    /*这里的overflow并不是为了超出则隐藏,而是为了创建一个BFC*/
    /* overflow: hidden; */
    display: inline-block;
    }
    .child{
    border: 5px solid #f66;
    width: 100px;
    height: 100px;
    float: left;
    /* clear: both; */
    }
    </style>
    </head>
    <body>
    <!-- 网页的定位(大) 文档流正常,浮动,定位,flex,table -->
    <div class="par">
    <div class="child"></div>
    <div class="child"></div>
    </div>
    </body>
    ```
    - 三、每个元素的左边,要与包含盒子的左边相接触
    - 四、BFC的区域不会与float box重叠
    ```html
    <style>
    *{padding: 0;margin: 0;}
    .aside{
    float: left;
    width: 100px;
    height: 150px;
    background-color: #ff6666;
    }
    .main{
    height: 200px;
    background: #ffcccc;
    /* clear: left; */
    overflow: hidden;
    }
    </style>
    </head>
    <body>
    <!-- 自适应两栏式布局 类似于flex:1;
    aside 和 main 处于同一BFC(body)下
    BFC布局规则3 规则4 -->
    <div class="aside"></div>
    <div class="main"></div>
    </body>
    ```
    ```html
    /*BFC在三栏式布局中的应用*/
    <style>
    *{padding: 0;margin: 0;}
    .container{
    height: 200px;
    }
    .left,.right,.center{
    height: 200px;
    }
    .left{
    background: pink;
    float: left;
    width: 180px;
    }
    .right{
    background: lightblue;
    width: 180px;
    float: right;
    }
    .center{
    background: yellow;
    overflow: hidden;
    }
    </style>
    </head>
    <body>
    <!-- 三栏式布局 -->
    <div class="container">
    <!-- 页面的结构与呈现效果不一致?想一下 -->
    <div class="left">Left</div>
    <div class="right">Right</div>
    <div class="center">Center</div>
    </div>
    </body>
    ```

    **注意:**
    > 通过 overflow:hidden将元素转换为BFC,固然可以解决高度塌陷的问题,但是大范围的应用在布局上是肯定是行不通的,毕竟overflow会造成溢出隐藏的问题,特别是与JS交互的效果时。

    那有没有一个更好的高度检测方法呢?
    答案是有的,就是我们经常用到的clearfix。
    ```css
    .clearfix:after{
    content:'';
    display:table;
    clear:both
    }
    .clearfix{
    *zoom:1;/* IE6,7不支持BFC,所以需要通过专有的CSS属性,触发hasLayout。*/
    }

    关于zoom:1

让div在屏幕上居中(水平居中+垂直居中)的方法总结

让div在屏幕上居中(水平居中+垂直居中)的方法总结

  • html代码如下:

        <div class="book">
                <div class="front-cover">
                   
                </div>
        </div>
    
  • Css居中方法 (敲黑板)重点

    • 首先将元素设置成为绝对定位,然后距顶部和左各50%,此时的元素还不是居中的,因此需要通过一定的偏移将其移到理想位置,两种方法的主要思想都是一样的,第一种通过margin-left和margin-top移动元素自身宽高的一半,另一种通过css3的属性transform的translate方法平移元素自身宽高的一半, 代码展示如下:
      ```css
      body {
      color: #ffffff;
      background: #444444;
      }

    .book {

     width: 300px;
     height: 300px;
     position: absolute;
     top: 50%;
     left: 50%;
     /* 第一种 */
     /* 兼容性 未使用css3, ie678 */
     /* margin-left: -150px; */
     /* margin-top: -150px; */
     /*第二种*/
     -webkit-transform: translate(-50%, -50%);
     transform: translate(-50%, -50%);
    

    }
    ```

    两种方法第一种的兼容性更加的好一些,因为其中没有使用Css3的属性 对于ie678的兼容比较友好

stylus之变量与mixin

stylus之变量与mixin

混合书写(Mixins)


变量

  • stylus中 可以将常用的样式像表达式中变量赋值一样保存给一个变量、如下:
    /*进行变量的声明*/
    bg_color = #123456;
    box_size = 100px;
    /* 使用 */
    .box
    background-color bg_color
    width box_size
    height box_size
    编译后:
    .box {
    background-color: #123456;
    width: 100px;
    height: 100px;
    }
  • 属性查找
    Stylus有另外一个很酷的独特功能,不需要分配值给变量就可以定义引用属性。下面是个很好的例子,元素水平垂直居中对齐(典型的方法是使用百分比和margin负值),如下:
    #logo
    position: absolute
    top: 50%
    left: 50%
    width: w = 150px
    height: h = 80px
    margin-left: -(w / 2)
    margin-top: -(h / 2)
    stylus中可以不使用这里的变量w和h, 而是简单地前置@字符在属性名前来访问该属性名对应的值:
    #logo
    position: absolute
    top: 50%
    left: 50%
    width: 150px
    height: 80px
    margin-left: -(@width / 2)
    margin-top: -(@height / 2)

    混合书写

  • 混合书写和函数定义方法一致,但是应用却大相径庭。

例如,在书写Css3样式时我们经常要进行兼容性处理,需要在属性前加上相应的前缀,下面有定义的border-radius(n)方法,其却作为一个mixin(如,作为状态调用,而非表达式)调用。

    bg_color = #123456;
box_size = 100px;

/*定义mixin*/
border-radius(n)
-webkit-border-radius n
-moz-border-radius n
-ms-border-radius n
-o-border-radius n
border-radius n
.box
background-color bg_color
width box_size
height box_size
border-radius(5px)
```
进一步,我们可以利用arguments这个局部变量,传递可以包含多值的表达式,这样就可以給属性传递多个值。
```css
border-radius()
-webkit-border-radius arguments
-moz-border-radius arguments
-ms-border-radius arguments
-o-border-radius arguments
border-radius arguments

Stylus支持通过使用{}字符包围表达式来插入值,其会变成标识符的一部分。例如,-webkit-{‘border’ + ‘-radius’}等同于-webkit-border-radius.

再进一步,在stylus中我们还可以对border-radius再做进一步的处理 类似与js中的函数封装 ,如下(这样对于任何需要做兼容性处理的属性 我们只需要调用两次mixin出入所需参数,大大的简化了一下琐碎代码工作):

 vendor(prop,args)
-webkit-{prop} args
-moz-{prop} args
-ms-{prop} args
-o-{prop} args
{prop} args

border-radius(n)
vendor('border-radius',arguments)
box-shadow(n)
vendor('boa-shadow',arguments)
.box
background-color bg_color
width box_size
height box_size
border-radius(5px)

编译后:
 .box {
background-color: #123456;
width: 100px;
height: 100px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
-webkit-box-shadow: 1px 1px 10px rgba(0,0,0,0.5);
-moz-box-shadow: 1px 1px 10px rgba(0,0,0,0.5);
-ms-box-shadow: 1px 1px 10px rgba(0,0,0,0.5);
-o-box-shadow: 1px 1px 10px rgba(0,0,0,0.5);
box-shadow: 1px 1px 10px rgba(0,0,0,0.5);
}

如何手动实现一个New操作

如何手动实现一个New操作

写在前面


在所有的前端面试中常常喜欢考面试者如何手写一个new操作符,作为在准备秋招的大三党,我也要考虑这些。
那么我们先看看new操作符都干了什么事情,有哪些操作?通过下面的代码来进行思考:

// 新建一个类(构造函数)
function Otaku(name, age) {
this.name = name;
this.age = age;
// 自身的属性
this.habit = 'pk';
}
// 给类的原型上添加属性和方法
Otaku.prototype.strength = 60;
Otaku.prototype.sayYourName = function () {
console.log('I am ' + this.name);
}
// 实例化一个person对象
const person = new Otaku('乔峰',5000);
person.sayYourName();
console.log(person);//打印出构造出来的实例
```
![控制台打印结果](http://p9utic4op.bkt.clouddn.com/new.png)


## 解析

从控制台打印出来的结果我们可以看出new操作符大概做了一下几件事情:

1. 返回(产生)了一个新的对象
2. 访问到了类Otaku构造函数里的属性
3. 访问到Otaku原型上的属性和方法 并且设置了this的指向(指向新生成的实例对象)

通过上面的分析展示,可以知道new团伙里面一定有Object的参与,不然对象的产生就有点说不清了。 先来边写写:

```js
// 需要返回一个对象 借助函数来实现new操作
// 传入需要的参数: 类 + 属性
const person = new Otaku('乔峰',5000);
const person1 = objectFactory(Otaku, '鸠摩智', 5000);

// 开始来实现objectFactory 方法
function objectFactory(obj, name, age) {}
// 这种方法将自身写死了 如此他只能构造以obj为原型,并且只有name 和 age 属性的 obj
// 在js中 函数因为arguments 使得函数参数的写法异常灵活,在函数内部可以通过arguments来获得函数的参数
function objectFactory() {
console.log(arguements); //{ '0': [Function: Otaku], '1': '鸠摩智', '2': 5000 }
// 通过arguments类数组打印出的结果,我们可以看到其中包含了构造函数以及我们调用objectfactory时传入的其他参数
// 接下来就是要想如何得到其中这个构造函数和其他的参数
// 由于arguments是类数组,没有直接的方法可以供其使用,我们可以有以下两种方法:
// 1. Array.from(arguments).shift(); //转换成数组 使用数组的方法shift将第一项弹出
// 2.[].shift().call(arguments); // 通过call() 让arguments能够借用shift方法
const Constructor = [].shift.call(arguments);
const args = arguments;
// 新建一个空对象 纯洁无邪
let obj = new Object();
// 接下来的想法 给obj这个新生对象的原型指向它的构造函数的原型
// 给构造函数传入属性,注意:构造函数的this属性
// 参数传进Constructor对obj的属性赋值,this要指向obj对象
// 在Coustructor内部手动指定函数执行时的this 使用call、apply实现
Constructor.call(obj,...args);
return obj;
}

```

- 上面的代码注释太多,剔除注释以后的代码:

```js
function objectFactory() {
let Constructor = [].shift.call(arguments);
const obj = new Object();
obj.__proto__ = Conctructor.prototype;
Constructor.call(obj,...arguments);
return obj;
}
```
- 还有另外一种操作:

```js
function myNew(Obj,...args){
var obj = Object.create(Obj.prototype);//使用指定的原型对象及其属性去创建一个新的对象
Obj.apply(obj,args); // 绑定 this 到obj, 设置 obj 的属性
return obj; // 返回实例
}
React Hook学习

React Hook学习

Hooks 在React 16.8 以上的版本中才可以使用
eslint-plugin-react-hooks

Hook 定义

Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数

React中的Refs

React中的Refs

Refs

官方说明Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素

在React开发中、想要操作元素的状态一般是修改State、或者是修改传入的props。但是有时候一些效果不能通过如此操作实现,例如开发中常常碰到的:

  • 输入框的焦点获取、比如打开登录界面登录框自动获取焦点
  • 动态的根据一个元素的大小/距离 计算另外一个元素的大小

使用 Ref

目前的React版本(16.11.0)中 Refs 的用法如下:

import React form 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
// 创建
this.myRef = React.createRef();
}

render() {
// 传入
return <div ref={this.myRef} />;
}
}

对于节点的访问:

const node = this.myRef.current;

说明:

  • 1.通过调用 React.createRef 创建了一个 React ref 并将 DOM节点的引用current赋值给 this.myRef 变量。
    1. 指定 ref 为 JSX 属性,将this.myRef 传入; ref 和 key 一样不属于 props属性,二者都会被 React 特殊处理和维护。
    1. ref 挂载以后,ref.current 指向 ref 所在节点

如果之前用过 React,你可能了解之前的 ref 可以通过 this.refs.inputRef 来访问 DOM 节点、如下所示,这个 ref 是字符串类型的,在使用上来说似乎更加方便。现在官方版本不建议再使用它,因为 string 类型的 refs 存在问题。它属于过时 API 并可能会在未来的版本被移除。

import React form 'react';
class MyInput extends React.Component {
componentDidMount() {
this.refs.inputRef.focus();
}
render() {
// 还能用 但不建议
return <input ref="inputRef" />;
}
}

Ref的值

官方文档中有说明,ref 的值根据节点的类型不同而有所不同:

  • 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 对象 接收底层 DOM 元素作为其 current 属性。可以访问元素的宽高等属性、input框还可以调用focus方法实现自动聚焦
  • 当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性。即可以通过 current 调用组件中的方法

不能在函数组件上使用 ref 属性,因为他们没有实例。

回调 Refs

更加精细的控制 refs 的传递, 可以达到类似 props 的传递效果,在需要的地方传入inputRef

// 官方 Demo
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}

class Parent extends React.Component {
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el}
/>
);
}
}

官方说明

如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。

Refs 转发

ref Hook

useRef() 是 React 提供的在 Hooks 中获取 DOM 元素的方法。
使用方法如下:

import React, { useRef} from 'react';
function RefDemo(){
const inputEl = useRef(null);
const onButtonClick=()=>{
inputEl.current.value="Hello, Ref";
console.log(inputEl); //输出获取到的DOM节点
};
return (
<>
{/*保存input的ref到inputEl */}
<input ref={inputEl} type="text"/>
<button onClick = {onButtonClick}>展示</button>
</>
);
}
export default RefDemo;

官方文档

数组

数组

数组

定义:

一个存储元素的线性集合, 元素可以通过索引(通常为数字)来任意存取。

数字索引在内部被转换为字符串类型、这是因为在javaScript中对象的属性名必须是字符串。而数组只是一种特殊的对象

创建数组

  • 通过构造函数
    <!-- 传入一组元素进行数组初始化 -->
    var arr = New Array(1, 2, 3, 4, 5);
    print(arr.length); // 5
    <!-- 只传一个元素,声明数组的初始化长度, 其中每个元素初始化为 undefined -->
    var arr1 = new Array(10);
    print(arr1.length); // 10
JS 基本数据类型和引用类型

JS 基本数据类型和引用类型

Js 基本数据类型

js基本数据类型包括:undefined, null, number, boolean, string, symbol, bigInt(新增)。基本数据类型是按值访问的,就是说我们可以操作保存在变量中的实际的值

1.基本数据类型的值是不可改变的

任何方法都无法改变一个基本类型的值是不可改变的,比如一个字符串:

var name = "change";
name.substr();//hang
console.log(name);//change

var s = "hello";
s.toUpperCase()//HELLO;
console.log(s)//hello

通过这两个例子, 我们原来发现定义的变量 name 的值始终没有发生改变,而调用 substr() 和 toUpperCase() 方法后返回的是一个新的字符串,跟原先定义的变量 name 并没有关系

按值访问

按值进行访问,操作的是保存在变量中实际的值

不可添加方法属性

基础类型的比较是值的比较

基础类型存放在栈区 变量标识符 + 变量值

引用类型

同时保存在栈区和堆区中

栈区保存变量标识符和指向堆区的方法

基本包装类型(包装对象)

性能优化之浏览器篇

性能优化之浏览器篇

把 Css 放在head 中加载

在浏览器解析完head 部分后、让浏览器知道需要引入哪些css文件,开始并行的去下载css资源,一边下载Css文件一边解析Html, 能够使页面更早的开始渲染

  • 让页面更早的开始渲染、避免闪屏 (DOM 结构先加载出来,css慢了一拍 页面重新渲染)
  • 最好能包含关键渲染路径的样式、首页的样式应该尽快的完成加载、提高用户体验

JS放在 body 标签结束前加载

js 资源的加载会阻塞 HTML 的解析 和 Css的渲染

不使用CSS 表达式

在css属性后使用 expression() 连接一段JavaScript表达式,css属性的值是JavaScript表达式的结果。

background-color: expression((new Date()).getHours()%2?"#FFFFFF": "#000000" );

看似强大, 实际性能开销很大,可能导致页面卡顿

表达式的问题就在于它的计算频率要比我们想象的多。不仅仅是在页面显示和缩放时,就是在页面滚动、乃至移动鼠标时都会要重新计算一次。给 CSS 表达式增加一个计数器可以跟踪表达式的计算频率。在页面中随便移动鼠标都可以轻松达到 10000 次以上的计算量。
calc() 性能待验证

移除无匹配的样式

移除无匹配的样式,有两个好处:

  • 删除无用的样式后可以缩减样式文件的体积,加快资源下载速度;

  • 对于浏览器而言,所有的样式规则的都会被解析后索引起来,即使是当前页面无匹配的规则。移除无匹配的规则,减少索引项,加快浏览器查找速度;

用外链的方式引入css 和 js

  • 通过使用外链可以减少html 文件的体积
  • 作为外链文件、Css/Js 可以作为静态资源、通过合理的利用浏览器的缓存对需要的文件进行缓存; 在第二次访问时可以加快页面的加载速度

不要重复加载JS

  • 在IE中,例如在加载一个jquery以后再加载一个jquery,仍然是算作两个不同的请求,不能发挥缓存的优势
  • 重复加载js意味着更长的JS执行时间

用 Get 方式发起 Ajax 请求

  • Get 方式可以缓存
  • 如果是获取信息 Get 更加语义化

如果是提交数据 使用Post 更加语义化

组件延迟加载

规划页面中引用的姿态资源加载顺序、优先级的能力

  • 保障关键页面资源的优先加载: 浏览器的并发数限制

    在同一个域名下面,一般现代浏览器的并发数为6

  • 按需加载 Lazyload 典型: 电商网站

    在图片比较多的电商网站中,lazyload 十分实用 data-src -> src

避免在页面中使用iFrame

  • 会阻塞父文档的 onload 事件
  • 即使是空白iFrame 也比较耗时

减少COOKIE体积

  • COOKIE每次请求都会全都带上
    COOKIE了解更多

    每次请求跟主文档相关的信息,所有的cookie都会带上

减少 JS 中的 DOM 访问

JS中对DOM 的访问是不可避免的, 但可以进行一下优化

  • 对于查找到的元素, 先将其缓存在变量中
  • 节点增加时合理利用 DocumentFragment
  • 不要用JS 去频繁修改样式

使用常见的图片优化手段

相比代码, 图片的体积很大

不要在HTML中缩放图片

在实际中使用什么尺寸的图片就提供多大尺寸的图片

  • 徒增渲染开销, 提供适当尺寸即可

    不要把图片的src置空

  • 在主流浏览器中 IE、Chrome、FireFox 都会引发指向当前主文档的额外请求

参考文档

高性能 CSS

RegExp 正则表达式

RegExp 正则表达式

RegRxp(正则表达式)

正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等,简化对字符串的操作