(6.1-6.7)的安排

  • vuex手写以及原理
  • mvvm理解(拖延症)
  • css问题(1px以及清楚浮动原理)
  • js基础(es5继承和es6继承的区别)

第二版vuex手写

mvvm理解

css之移动端 1px 问题

两个概念,一个是像素(pixel)可以简写为px,另外一个是设备像素比(DPR)devicePixelRadio

1
2
像素 :指在由一个数字序列表示的图像中的一个最小单元,单位是 px,不可再次分割了。
设备像素比(DPR): 设备像素比 = 设备像素 / 设备独立像素。

造成边框变粗的原因
其实这个原因很简单,因为css中的1px并不等于移动设备的1px,这些由于不同的手机有不同的像素密度。在window对象中有一个devicePixelRatio属性,他可以反应css中的像素与设备的像素比。

设计稿上的是物理像素,css中的像素是逻辑像素
如果window.devicePixelRadio是2.0,即设计稿上的1px等于css中的0.5px
目前主流屏幕的DPR是2(8P+),拿2倍屏来说,设备的物理像素要实现1像素,而DPR=2,所以css 像素只能是 0.5。一般设计稿是按照750来设计的,它上面的1px是以750来参照的,而我们写css样式是以设备375为参照的,所以我们应该写0.5px

主流方案一:利用伪元素(::after + transform)进行缩放

为什么用伪元素? 因为伪元素::after或::before是独立于当前元素,可以单独对其缩放而不影响元素本身的缩放
实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.border-1px {
position: relative;
&::before{
content: "";
position: absolute;
left: 0;
top: 0;
width: 200%;
border:1px solid red;
color: red;
height: 200%;
-webkit-transform-origin: left top;
transform-origin: left top;
-webkit-transform: scale(0.5);
transform: scale(0.5);
pointer-events: none; /* 防止点击触发 */
box-sizing: border-box; /*IE 盒模型 元素内容宽高 == 内容+ 内边距 + 边框*/
}
}

主流方案二:针对不同的DPR设备增加媒体查询,进行对应的缩放

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
.border-1px {
position: relative;
&::before{
content: "";
position: absolute;
left: 0;
top: 0;
width: 200%;
border:1px solid red;
color: red;
height: 200%;
-webkit-transform-origin: left top;
transform-origin: left top; /* 允许改变转换元素的位置 */
-webkit-transform: scale(0.5);
transform: scale(0.5);
pointer-events: none; /* 防止点击触发 */
box-sizing: border-box; /* IE 盒模型 元素内容宽高 == 内容+ 内边距 + 边框 */

@media screen and (min-device-pixel-ratio:3),(-webkit-min-device-pixel-ratio:3) {
width: 300%;
height: 300%;
-webkit-transform: scale(0.33);
transform: scale(0.33);
}
@media screen and (min-device-pixel-ratio:2.75),(-webkit-min-device-pixel-ratio:2.75) {
width: 300%;
height: 300%;
-webkit-transform: scale(1/2.75);
transform: scale(1/2.75);
}
@media screen and (min-device-pixel-ratio:2),(-webkit-min-device-pixel-ratio:2){
width: 300%;
height: 300%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
}
}
}

css之清除浮动原理

清除浮动主要有两种方式,分别是clear清除浮动和BFC清除浮动

浮动的三个特点很重要。

  1. 脱离文档流。
  2. 向左/向右浮动直到遇到父元素或者别的浮动元素。
  3. 浮动会导致父元素高度坍塌。

clear

clear属性不允许被清除浮动的元素的左边/右边挨着浮动元素,底层原理是在被清除浮动的元素上边或者下边添加足够的清除空间

要注意了,我们是通过在别的元素上清除浮动来实现撑开高度的,而不是在浮动元素上。

clear浮动元素最佳实现

1
2
3
4
5
6
7
8
9
10
11
12
// 同时加入:before以解决现代浏览器上边距折叠的问题
.clearfix:before,
.clearfix:after {
display: table;
content: " ";
}
.clearfix:after {
clear: both;
}
.clearfix{
*zoom: 1; // 引入了zoom以支持IE6/7
}

BFC清除浮动

原理就是 浮动盒区域不会叠加到BFC上,(BFC区域不会与float的元素区域叠加),BFC的五条约束规则之一
实现就是触发BFC即可

1
2
3
4
5
6
7
- 根元素或其它包含它的元素;
- 浮动 (元素的float不为none);
- 绝对定位元素 (元素的position为absolute或fixed);
- 行内块inline-blocks(元素的 display: inline-block);
- 表格单元格(元素的display: table-cell,HTML表格单元格默认属性);
- overflow的值不为visible的元素;
- 弹性盒 flex boxes (元素的display: flex或inline-flex);

平常中,设置overflow: hidden/scroll, float: right/left,position: absolute,display: flex/inline-flex;即当前元素创建了一个BFC

原型和es5继承和es6继承的区别

原型(prototype) 和 实例属性的(proto)

  • 原型: 给其他对象提供共享属性的对象
  • 隐式引用(proto): 所有实例对象都存在一个隐式引用,指向他的原型

构造函数(constructor): 它的原型指向实例的原型(Person.prototype === person.proto)
构造函数和普通函数的区别

  • 使用new操作符生成实例的函数就是构造函数
  • 直接调用的就是普通函数
  • Symbol是基础类型不是构造函数

两者区别

之前已经详细阐述过es5中的继承,主要是经典继承(构造函数继承)/原型链继承/组合继承以及常用的寄生式组合继承,前文链接,(通过原型链实现原型属性的继承,通过构造函数实现实例属性的继承)

ES5 的继承,通过prototype或构造函数机制来实现, 实质是先创造子类的实例对象this,再将父类的方法添加到this上面(Parent.apply(this))。
ES6 的继承机制完全不同,实质是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。

ES6中新增了class关键字来定义类,通过保留的关键字extends实现了继承。实际上这些关键字只是一些语法糖,底层实现还是通过原型链之间的委托关联关系实现继承

如果子类没有定义constructor方法,这个方法会被默认添加,代码如下。也就是说,不管有没有显式定义,任何一个子类都有constructor方法。

super()

在 super() 执行时,它指向的是 子类 B 的构造函数,而不是父类 A 的构造函数。也就是说,super() 内部的 this 指向的是 B
super()相当于Parent.prototype.constructor.call(this. props)
super本身是指向父类的构造函数但做函数调用后返回的是子类的实例,实际上做了parent.prototype.constructor.call(this),做对象调用时指向父类.prototype,从而实现继承

static 静态属性

顾名思义是静态方法的意思,类相当于实例的原型,所有在类中定义的方法, 都会被实例继承。
如果在一个方法前, 加上static关键字, 就表示该方法不会被实例继承, 而是直接通过类来调用, 这就称为“ 静态方法”。静态方法调用直接在类上进行,而在类的实例上不可被调用。静态方法通常用于创建 实用/工具 函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Point {
public x!: any;
public y!: any;
public z!: any;
constructor(x: any, y: any) {
this.x = 1
this.y = 2
}
public static print() {
console.log('子类的print方法', this);
}
}
Point.prototype.z = 3
export default class ColorPoint extends Point {
constructor(x: any, y: any) {
super(x, y)
// Point.prototype.constructor.call(this, x, y)
this.x = x
}
public m() {
// super.print() 难以调用,父类的print是静态属性,只能在类上直接调用
}
}

最后,父类的静态方法,也会被子类继承。

1
2
3
4
5
6
7
8
9
10
class A {
static hello() {
console.log('hello world');
}
}

class B extends A {
}

B.hello() // hello world

上面代码中,hello()是A类的静态方法,B继承A,也继承了A的静态方法。

参考链接