前端知识点总结

vue组件通信

1.props/$emit

父传子:props

子传父:emit

2.provide/inject

在父组件用provide提供数据,在子组件用 inject 接收数据

3.vuex

数据管理模式

4.$parent/$child

子组件内部通过$parent对父组件操作

父组件内部通过 $children 对子组件操作

5.eventbus

使用一个空的vue实例作为中央事件总线,

使用$emit 发送事件

使用$on来接收

6.$attrs/$listeners

css垂直居中

设置行高(适用于单行文本)

1
2
3
4
5
#parent {
height: 100px;
line-height: 100px;
border: solid 1px #333;
}

position:absolute/margin-top

1
2
3
4
5
6
7
8
9
10
11
12
#parent {
height: 100px;
position: relative;
border: solid 1px #333;
}

#child {
height: 20px;
margin-top: -10px;
position: absolute;
top: 50%;
}

设置padding-top/padding-bottom

1
2
3
4
5
#parent {
padding-top: 20px;
padding-bottom: 20px;
border: solid 1px #333;
}

flex

1
2
3
{
align-items:center;
}

前端设计模式

  • 单例模式

确保一个类只有一个实例,一般用于全局缓存,可以通过闭包来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var single = (function(){
let instance;

function getInstance(){
    // 如果该实例存在,则直接返回,否则就对其实例化
if( instance=== undefined ){
instance= new Construct();
}
return instance;
}

function Construct(){
// ... 生成单例的构造函数的代码
}

return {
getInstance : getInstance
}
})();
  • 工厂模式

创建对象的常用设计模式,为了不暴露创建对象的具体逻辑,将逻辑封装在一个函数中,这个函数就称为一个工厂

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
//安全模式创建的工厂方法函数
let UserFactory = function(role) {
if(this instanceof UserFactory) {
var s = new this[role]();
return s;
} else {
return new UserFactory(role);
}
}

//工厂方法函数的原型中设置所有对象的构造函数
UserFactory.prototype = {
SuperAdmin: function() {
this.name = "超级管理员",
this.viewPage = ['首页', '通讯录', '发现页', '应用数据', '权限管理']
},
Admin: function() {
this.name = "管理员",
this.viewPage = ['首页', '通讯录', '发现页', '应用数据']
},
NormalUser: function() {
this.name = '普通用户',
this.viewPage = ['首页', '通讯录', '发现页']
}
}

//调用
let superAdmin = UserFactory('SuperAdmin');
let admin = UserFactory('Admin')
let normalUser = UserFactory('NormalUser')
  • 代理模式

代理模式为其他对象提供一种代理,当其他对象直接访问该对象时,如果开销较大,就可以通过这个代理层来控制该对象的访问

1
2
3
4
5
6
7
8
9
10
11
12
(function(){
// 目标对象,是真正被代理的对象
function Subject(){}
Subject.prototype.request = function(){};

function Proxy(realSubject){
this.realSubject = realSubject;
}
Proxy.prototype.request = function(){
this.realSubject.request();
};
}());
  • 观察者模式

也叫发布/订阅模式,一个订阅者和一个发布者,当一个特定的时间发生时,发布者会通知调用所有的订阅者.

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
var EventCenter = (function(){
var events = {};
function on(event, handler){
events[event] = events[event] || [];
events[event].push({
handler: handler
});
}

function fire(event, args){
if (!events[event]) {return}
for (var i = 0; i < events[event].length; i++) {
events[event][i].handler(args);
}
}

function off(event){
delete events[event];
}

return {
on: on,
fire: fire,
off: off
}
})();

EventCenter.on('event', function(data){
console.log('event received...');
});
  • 模块模式

可以指定想暴露的属性和方法,并且不会污染全局.

1
2
3
4
5
6
7
8
9
10
var Person = (function() {
var name = 'xxx'
function sayName() {
console.log(name)
}
return{
name: name,
sayName: sayName
}
})()
  • 构造函数模式和混合模式

构造函数和混合模式就是js中继承的两种实现方式,前者通过构造函数的形式定义类,通过new新增实例。而后者是将构造函数的引用属性和方法放到其原型上,子类是父类原型的一个实例。

js实现继承的方法

定义父类:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 定义一个动物类
function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
  • 原型链继承

将父类的实例作为子类的原型

1
2
3
4
5
6
7
8
9
10
11
12
function Cat(){ 
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
  • 构造继承

使用父类的构造函数来增强子类实例,等于复制父类的实例属性给子类

1
2
3
4
5
6
7
8
9
10
11
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
  • 实例继承

为父类实例添加新特性,作为子类的实例返回

1
2
3
4
5
6
7
8
9
10
11
12
function Cat(name){
var instance = new Animal();
instance.name = name || 'Tom';
return instance;
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
  • 组合继承

通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类的实例作为子类原型实现函数复用.

1
2
3
4
5
6
7
8
9
10
11
12
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
  • 继承组合继承

通过寄生方式,砍掉父类的实例属性,这样在调用父类的构造时,就不会初始化两次实例方法/属性.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
(function(){
// 创建一个没有实例方法的类
var Super = function(){};
Super.prototype = Animal.prototype;
//将实例作为子类的原型
Cat.prototype = new Super();
})();

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
Cat.prototype.constructor = Cat; // 需要修复下构造函数

前端优化图片加载

  • 对于较小的图片考虑base64
  • 图片懒加载
  • 图片压缩
  • cdn
  • 雪碧图

面向对象语言的特征

  • 封装
  • 继承
  • 多态

确定数据类型

  • typeof
1
2
3
4
5
6
7
8
9
10
console.log(typeof a)   ------------> string
console.log(typeof b) ------------> number
console.log(typeof c) ------------> object
console.log(typeof d) ------------> object
console.log(typeof e) ------------> function
console.log(typeof f) ------------> function
其中typeof返回的类型都是字符串形式,需注意,例如:
console.log(typeof a == "string") -------------> true
console.log(typeof a == String) ---------------> false
另外typeof 可以判断function的类型;在判断除Object类型的对象时比较方便。
  • instanceof

    1
    2
    3
    4
    5
    alert(c instanceof Array) ---------------> true
    alert(d instanceof Date)
    alert(f instanceof Function) ------------> true
    alert(f instanceof function) ------------> false
    注意:instanceof 后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。
  • Object.prototype.toString.call()

事件执行机制

事件机制会经历三个阶段:

  • 捕获阶段
  • 触发阶段
  • 冒泡阶段
1
element.addEventListener(eventName,handler,useCapture);
  • event 时间名称
  • handler 回调函数
  • useCapture 执行机制(当useCapture==true)是在捕获阶段实行,否则在冒泡阶段执行.

捕获阶段由内到外,冒泡阶段由外到内

回流/重绘

渲染树=dom树+css对象模型树

渲染树布局生成盒模型

img

回流必定导致重绘

重绘不会回流

导致回流的原因(dom尺寸变化,添加修改):

  • 宽高变化
  • display:none
  • 浏览器窗口大小改变等

导致重绘的原因(颜色变化)

  • background-color变化
  • color 变化等等

如何优化前端性能

减少http请求

一个完整的http请求,需要经历dns查询/tcp握手/客户端http请求/服务端接收请求/服务端处理请求并发回响应/浏览器接收响应等过程.

通过将多个小文件合并为一个大文件,可以减少http请求的此时.

使用 http2

http2的优点

  • 解析速度快(http2是基于帧的协议)
  • 多路复用(多个请求共用一个http连接)
  • 首部压缩
  • 优先级
  • 流量控制
  • 服务端推送

服务端渲染

ssr

静态资源使用cdn

css文件放在头部/js文件放在底部

使用字体图标iconfont代替图片图标

善用缓存

压缩文件

  • JavaScript:UglifyPlugin
  • CSS :MiniCssExtractPlugin
  • HTML:HtmlWebpackPlugin
  • gzip压缩(accept-encoding:gzip)

图片优化

  • 图片延迟加载
  • 响应式图片
  • 调整图片大小
  • 降低图片质量
  • 使用css3替代图片
  • 使用webp格式的图片

通过webpack按需加载代码

根据文件内容生成文件名,结合import动态引入组件实现按需加载

提取第三方库

减少重绘重拍

浏览器渲染过程

  • 解析html生成dom树
  • 解析css生成css规则树
  • 将dom树与css树合并生成渲染树
  • 遍历渲染树开始布局,计算每个节点的位置大小信息
  • 将渲染树每个节点绘制到屏幕

img

  • 重拍

当改变 DOM 元素位置或大小时,会导致浏览器重新生成渲染树,这个过程叫重排。

  • 重绘

当重新生成渲染树后,就要将渲染树每个节点绘制到屏幕,这个过程叫重绘。不是所有的动作都会导致重排,例如改变字体颜色,只会导致重绘。记住,重排会导致重绘,重绘不会导致重排 。

使用事件委托

时间委托利用了事件冒泡,只指定一个时间处理程序,就可以管理某一类型的所有事件.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<ul>
<li>苹果</li>
<li>香蕉</li>
<li>凤梨</li>
</ul>

// good
document.querySelector('ul').onclick = (event) => {
const target = event.target
if (target.nodeName === 'LI') {
console.log(target.innerHTML)
}
}

// bad
document.querySelectorAll('li').forEach((e) => {
e.onclick = function() {
console.log(this.innerHTML)
}
})

使用requestAnimationFrame

1
2
3
4
5
6
7
8
9
/**
* If run as a requestAnimationFrame callback, this
* will be run at the start of the frame.
*/
function updateScreen(time) {
// Make visual updates here.
}

requestAnimationFrame(updateScreen);

使用位操作

1
2
3
4
5
6
7
8
9
10
11
12
13
//取模

if (value % 2) {
// 奇数
} else {
// 偶数
}
// 位操作
if (value & 1) {
// 奇数
} else {
// 偶数
}
1
2
3
4
5
6
//取整
~~10.12 // 10
~~10 // 10
~~'1.5' // 1
~~undefined // 0
~~null // 0
1
2
3
4
5
//位掩码
const a = 1
const b = 2
const c = 4
const options = a | b | c

不要覆盖原生方法

降低css选择器的复杂性

浏览器读取选择器原则:从右到左

1
2
3
#block .text p {
color: red;
}
  • 查找所有的 p元素
  • 查找结果1中是否有类名为text
  • 查找结果2中是否有id为block

css选择器优先级

1
内联 > ID选择器 > 类选择器 > 标签选择器

使用flex布局

使用transform和opacity属性更改来实现动画

transformopacity属性的更改不会导致触发重绘与重拍.

thank u !