你不得不熟悉且熟练掌握的前端知识

4 篇文章 0 订阅
1 篇文章 0 订阅

提示:内容较多,建议先收藏方便下次查看

文章目录


一、HTML+CSS+JS

1.1 语义化的理解

含义:语义化是指用合理HTML标记以及其特有的属性去格式化文档内容。
使用合适的标签干合适的事(各司其职)。
语义化的标签能够使代码更加的清晰,结构明了。
有利于SEO,搜索引擎根据标签来确定上下文和各个关键字的权重。

1.2 常见语义化标签及说明

常见标签:
<title></title> // 页面主体内容,用于提升搜索引擎排名

<header></header> // 页眉,包括网站标志、主导航、全站链接以及搜索框

<nav></nav> // 导航 常用于页面的导航部分

<main></main> // 主要内容,一个页面只能使用一次;若是 web 应用,则包含其主要功能

<section></section> // 区块 一般用于一组相似的内容,比如文章的章节,标签页等

<aside></aside> // 侧边栏 表示内容与页面主体内容无关的部分

<footer></footer> // 页脚
其它不常见标签:
<small>:呈现小号字体效果,指定细则,输入免责声明、注解、署名、版权。
<strong>:和 em 标签一样,用于强调文本,但它强调的程度更强一些。
<em>:将其中的文本表示为强调的内容,表现为斜体。
<mark>:使用黄色突出显示部分文本。
<figure>:规定独立的流内容(图像、图表、照片、代码等等)(默认有40px左右margin)。
<figcaption>:定义 figure 元素的标题,应该被置于 figure 元素的第一个或最后一个子元素的位置。
<cite>:表示所包含的文本对某个参考文献的引用,比如书籍或者杂志的标题。
<blockquoto>:定义块引用,块引用拥有它们自己的空间。
<time>:datetime属性遵循特定格式,如果忽略此属性,文本内容必须是合法的日期或者时间格式。
<abbr>:简称或缩写。
<dfn>:定义术语元素,与定义必须紧挨着,可以在描述列表dl元素中使用。
<address>:作者、相关人士或组织的联系信息(电子邮件地址、指向联系信息页的链接)。
<del>:移除的内容。
<ins>:添加的内容。
<code>:标记代码。
<meter>:定义已知范围或分数值内的标量测量。(Internet Explorer 不支持 meter 标签)
<progress>:定义运行中的进度(进程)。

1.3 浏览器渲染html过程(主要分为四个步骤)

1. 解析HTML生成DOM树-渲染引擎首先解析HTML文档,生成DOM树
2. 构建render树-dom树结合css文件生成渲染树(Render树)
3. 布局Render树-对渲染树的每个节点进行布局处理,确定其在屏幕上的显示位置
4. 绘制Render树-遍历渲染树并用UI后端层将每一个节点绘制出来

说明:
解析html和构建dom树是同步进行的,这个过程就是逐行解析代码,包括html标签和js动态生成的标签,最终生成dom树。
构建render树,就是把css文件和style标签的中的内容,结合dom树的模型,构建一个rendeer树,写到内存,等待进一步生成界面。
结合render树,把dom节点的大小、位置计算出来。
把css中有关颜色的设置,背景、字体颜色等呈现出来

1.4 重绘与回流(重排)

repaint : 当诸如颜色背景等不会引起页面布局变化,而只需要重新渲染的过程叫做重绘
reflow : 当render树的一部分或者全部因为大小边距等问题发生改变而需要重建的过程,叫做回流

什么会引起回流?

页面渲染初始化
窗口resize事件触发
改变浏览器的字体大小(回流+重绘)
改变元素的padding、border、margin(回流+重绘)
添加、删除元素(回流+重绘)
读取元素的某些属性(offsetLeft,offsetTop,offsetHeight,offsetWidth,scrollTop… …)

减少回流

避免逐项更改样式。最好一次性更改style属性,或者将样式列表定义为class并一次性更改class属性。
避免循环操作DOM。
避免多次读取offsetLeft等属性。无法避免则将它们缓存到变量。
将复杂的元素绝对定位或固定定位,使它脱离文档流。否则回流代价十分高
用transform做形变和位移.

display:none与visibility:hidden

display:none指的是元素完全不陈列出来,不占据空间,涉及到了DOM结构,故产生reflow与repaint
visibility:hidden指的是元素不可见但存在,保留空间,不影响结构,故只产生repaint (重绘)

1.5 CSS阻塞与JS阻塞详解

CSS加载不会阻塞DOM树解析,但会阻塞DOM树的渲染
CSS加载会阻塞后面js语句的执行

关于CSS阻塞有几下几点需要特别说明:

CSS阻塞只有link引入的外部css才能够产生css阻塞
在style标签中的样式是交给html解析器进行的,因此不会阻塞浏览器渲染(可能会产生闪屏)和DOM解析
如果css加载不阻塞render树渲染的话,那么当css加载完之后,render树可能又得重新重绘或者回流了,这就造成了一些没有必要的损耗。

为了避免这种闪屏现象,所以一般推荐使用link引入的外部CSS样式,但是这种方式会阻塞其后面JS语句的执行,因此我们需要注意以下几点(如何提供CSS加载速度 ):

使用CDN节点进行外部资源加速。
对css进行压缩(利用打包工具,比如webpack,gulp等)。
减少http请求数,将多个css文件合并。
优化样式表的代码

js阻塞

阻塞DOM解析

解析过程中无论遇到的JavaScript是内联还是外链,只要浏览器遇到 script 标记,唤醒 JavaScript解析器,就会进行暂浏览器解析HTML,并等到 CSSOM 构建完毕,才去执行js脚本。所以实际工程中,我们常常将资源放到文档底部

改变脚本加载次序defer与async

defer 与 async 可以改变之前的那些阻塞情形,这两个属性都会使 script 异步加载,然而执行的时机是不一样的。
注意:在加载多个JS脚本的时候,async是无顺序的加载,而defer是有顺序的加载,在有async的情况下,js一旦下载好了就会执行,所以很有可能不是按照原本的顺序来执行的。如果js前后有依赖性,用async,就很有可能出错。`

defer 属性表示延迟执行引入 JavaScript,即 JavaScript 加载时 HTML 并未停止解析,这两个过程是并行的。
整个 document 解析完毕且 defer-script 也加载完成之后(这两件事情的顺序无关),会执行所有由 defer-script 加载的 JavaScript 代码,再触发 DOMContentLoaded(初始的 HTML 文档被完全加载和解析完成之后触发,无需等待样式表图像和子框架的完成加载) 事件 。

async 属性表示异步执行引入的 JavaScript,与 defer 的区别在于,如果已经加载好,就会开始执行.

1.6 理解堆栈,基本数据类型与引用数据类型

1、堆栈

栈(stack):系统自动分配的内存空间,内存会由系统自动释放,用来存放函数的参数值,局部变量的值等,特点是先进后出。
堆(heap):系统动态分配的内存,内存大小不一,内存不会自动释放。一般由程序员分配释放,主要负责像Obejct这种变量类型的存储。

2、基本数据类型

概念:存放在栈内存中的简单数据段,数据大小确定,内存空间大小确定。
6种基本数据类型:Undefined、Null、Boolean、Number、String、Symbol

3、引用数据类型

概念:存放在堆内存中的数据,如对象、数组、函数等。
名存在栈内存,值存在堆内存,栈内存会提供一个引用的地址指向堆内存中的值

1.7 进程与线程的区别

最大区别:进程是资源分配最小单位,线程是程序执行的最小单位。
进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,建立数据表来维护代码段、堆栈段和数据段;
线程没有独立的地址空间,同一进程的线程共享本进程的地址空间。


二、CSS

2.1 position的属性

static 默认值,在没有设置position属性的时候,position默认为static 在文档(页面)中占位置
relative 相对定位。在使用top或者left进行位置移动的时候,参考的位置是自己原先(没有定位时)所在的位置。 在文档(页面)中占位置。
absoluate 绝对定位。
fixed 固定定位。固定在当前可视窗口,不管页面怎么上下,左右滑动,固定在窗口,都不会进行移动。 脱离文档流,当与其他位置的元素发生重叠是,一直在其他元素上方。
sticky:粘性定位。即当元素在页面中,网页向上滑动,页面顶部与元素刚开始 想重叠是,就可以设置吸顶效果,随后就像固定定位一定定位在页面顶部。为c3新增加的属性。兼容性不好

2.2 css选择器

id选择器,类选择器,标签选择器
后代选择器:(#box div),选择id为box元素内部所有的div元素
子选择器:(.one>one_1),选择父元素为.one的所有.one_1的元素
相邻同胞选择器:(.one+.two),选择紧接在.one之后的所有.two元素
群组选择器:(div,p),选择div、p的所有元素

伪类选择器

:link :visited :active
:hover 鼠标指针浮动在上面的元素
:focus 选择具有焦点的
:first-child 父元素的首个子元素
:nth-child(n) 选择父元素中第N个子元素
:last-child 父元素的最后一个元素
:disabled 选择被禁用元素
:checked 选择选中的元素

伪元素选择器

::before 选择器在被选元素的内容前面插入内容
::after 选择器在被选元素的内容后面插入内容
::first-letter :用于选取指定选择器的首字母
::first-line :选取指定选择器的首行

举例分析
伪元素::before. ::after 可实现效果如下:在这里插入图片描述
伪元素妙用

伪元素实现换行,替代换行标签
增强用户体验,使用伪元素实现增大点击热区(伪元素也是可以代表其宿主元素来响应的鼠标交互事件的)
利用 :after 清除浮动

2.3 浮动

float的属性值有none、left、right
只有横向浮动,并没有纵向浮动
当元素应用了float属性后,将会脱离普通流,其容器(父)元素将得不到脱离普通流的子元素高度。
如下代码

.box1{width:200px;height:50px;background-color: lightgray;
   float:left;
}
.box2{width:200px;height:100px;background-color: lightblue;
    float:left;
}
.parent2{width:300px;height: 300px;background-color:blue;color:#fff;
    text-align:center;font-size:20px;
}
<div class="parent">
    <div class="box1"></div>
    <div class="box2"></div>
</div>
<div class="parent2"></div>

效果如下:
在这里插入图片描述

2.4 清除浮动的方法

方法一:使用带 clear 属性的空元素 (在浮动元素后使用一个空元素,并在 CSS 中赋 予.clear{clear:both;}属性即可清除浮动。)
方法二:使用 CSS 的 overflow 属性
方法三:使用 CSS 的:after 伪元素

方法一:优点:简单,代码少,浏览器兼容性好。缺点:需要添加大量无语义的html元素,代码不够优雅,后期不容易维护。
方法二:触发浮动元素父元素的 BFC (Block Formatting Contexts, 块级格式化上下文),使到该父元素可以包含浮动元素。
方法三:利用::after伪元素在元素末尾添加一个内容为一个点并带有clear:both属性元素实现的。

方法三举例:如下代码会将2.3中的效果变成

 .parent:after{content:"";display:block;clear:both;}

在这里插入图片描述

2.5 深入理解CSS盒模型

盒模型的组成大家肯定都懂,由里向外content,padding,border,margin.
盒模型是有两种标准的,一个是标准模型,一个是IE模型。
在标准模型中,盒模型的宽高只是内容(content)的宽高,
IE模型中盒模型的宽高是**内容(content)+填充(padding)+边框(border)**的总宽高。

标准模型 box-sizing:content-box;
IE模型 box-sizing:border-box;

2.6 水平居中的方式

1)通过margin: 0 auto; text-align: center实现CSS水平居中

.parent{width: 600px;height: 200px;}
.child{width: 100px;height: 100px;margin: 0 auto;text-align: center;}

2)通过display:flex实现CSS水平居中

justify-content属性定义了项目在主轴上的对齐方式。
align-items属性定义项目在交叉轴上如何对齐

.parent{width: 600px;height: 200px;display: flex;flex-direction: column;}

3)通过position:absolute实现CSS水平居中

2.7 垂直居中的方式

1)通过display:flex实现CSS垂直居中

.parent{width:300px;height:300px;border: 1px solid red;
    display:flex;justify-content:center;align-items:center}

2)通过position:absolute实现CSS水平居中

3)inline-block+vertical-aligin

.wrap {width: 300px;height: 300px;background-color: pink;text-align: center;line-height: 300px;}
.box {
   width: 100px;
   height: 100px;
   /* 重新设置子元素的行高,否则会继承父元素的行高*/
   line-height: 100px;
   background-color: plum;
   display: inline-block;
   /* middle   把此元素放置在父元素的中部。 */
   vertical-align: middle;
}

2.8 如何绘制一个三角形

    .main {
      width: 100%;min-height: 100vh;
      background-color: #f5f5f5;
    }
    .content {
      width: 0;
      height: 0;
      border: 100px solid #000;
      border-top-color: red;
      border-bottom-color: transparent;
      border-left-color: transparent;
      border-right-color: transparent;
    }


三、JS

3.1 数组

请到我的另一个博客学习,JS数组概览(汇总)

3.2 set 和map 的区别

在JS中的默认对象的表示方式为{},即一组键值对,但是键必须是字符串。
为了使用Number或者其他数据类型作为键,ES6规范引入了新的数据类型Map。
Map(字典):是一组键值对的结构,具有极快的查找速度
键和值可以是任何的值,如下:

const m = new Map()
const o = {k: 'val'}
m.set(o,"content") // 向字典中添加新元素
m.get(o) // 会输出content

m.has(o)	// true 判断字典中是否存在键key。
m.delete(o)	// true 通过键 key 从字典中移除对应的数据
m.has(o)	// false
// m.clear(): 将这个字典中的所有元素删除。

Set: es6新增的一种新的数据结构,常用作数组去重
如下:

// 去重数组的重复对象
let arr = [1, 2, 3, 3, 2, 1]
[... new Set(arr)]	// [1, 2, 3]
let set = new Set();
set.add(1); // 新增
set.add('1')
set.has('1') // 是否存在value
console.log([...set])  // [1,"1"]
// set.clear(): 清空集合

两者都能使用的遍历方法:

keys()
values()
forEach
entries()

WeakSet和WeakMap

WeakSet :只能储存对象引用,不能存放值
WeakSet: 成员都是弱引用,可以被垃圾回收机制回收,可以用来保存DOM节点,不容易造成内存泄漏。
WeakMap:只接受对象作为键名(null除外),键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的。
WeakSet和WeakMap:不能遍历

3.3 for of用法

示例代码如下:

// 定义一个数组
var arr = ['1', '2', '3', '4', '5', '6'];
// 循环遍历数组中的每个元素
for (var value of arr) {
  // console.log(value); // 1,2,3,4,5,6
}

// 定义一个字符串
var str = "zyzhang";
// 循环遍历字符串中的每个字符
for (var value of str) {
  // console.log(value) // z y z h a n g
}
// 定义一个对象 虽然可以遍历对象但并不推荐,推荐使用 for in
var obj = {"name": "zyzhang", "age": "20"};
// 循环遍历对象中的所有属性(是属性而不是值) 
for(var value in obj) {
  console.log(value) // name age
}

3.4 forEach、for of 与 for in的区别

forEach 不能使用break return 结束并退出循环
for in 和 for of 可以使用break return;
for of 适合遍历数组或者类数组。
for in 适合遍历对象

3.5 实现深拷贝的方式

浅拷贝 : 拷贝的对象只是一个引用,指向同一个地址,修改数据会影响原数据。
深拷贝: 复制出来的每个对象都有属于自己的内存空间,不会互相干扰。

1)Json.stringify和Json.parse

如果对象中包含function或RegExp这些就不能用这种方法了

2)函数库lodash的_.cloneDeep方法
3)使用递归的方式实现深拷贝:(如下:)

function deepClone(obj){
	// 定义一个变量用于存储拷贝对象
	let objClone = Array.isArray(obj)?[]:{}; 
	if(obj && typeof obj==="object"){
		// 变量这个对象(或数组) for in
		for(key in obj) {
			// hasOwnProperty表示是否有自己的属性。这个方法会查找一个对象是否有某个属性,但是不会去查找它的原型链。
			if(obj.hasOwnProperty(key)){
				//判断obj子元素是否为对象,如果是,递归复制
				if(obj[key] && typeof obj[key] ==="object") {
					objClone[key] = deepClone(obj[key]);
				} else {
					// 如果不是 直接复制
					obClone[key] = obj[key]
				}
			}
		}
	}
	return objClone;
}

4)ES6解构

只能深度拷贝对象的第一层,如果对象中的属性也是对象的话,没有办法进行深度拷贝的。

var obj = {name:'123',age:1};
var obj2 = {...obj}

5) Object.assign() 对象的合并
只能深度拷贝对象的第一层,如果对象中的属性也是对象的话,没有办法进行深度拷贝的

// 利用Object.assign(), 第一个参数必须是空对象**
var obj = {name:'123',age:13};
var obj2 = Object.assign({},obj1);

3.6 localStorage和sessionStorage

都是用来存储临时信息,生命周期一个是永久的,一个为当前窗口或标签页。
sessionStorage 在同一个页面中数据共享
localStorage 可以在多个页面同一浏览器共享

3.7 private、protect、public关键字

private关键字:只在本类中可以使用 默认值
protected关键字:在本类及子类中可以使用
public关键字:在所有的类中可以使用


四、前端框架

4.1 Vue概述及特点

Vue是一个构建用户界面的渐进式的Javastrap框架

底层是由JavaScript实现
渐进式:即逐渐做加法的一种模式,例如vue中的双向绑定的特性,vue中的路由,vue中的vuex等都是选择性加入的而不是必须的。

Vue特点:

组件化模式
声明式编码,让编码人员无需直接操作DOM,提高开发效率

4.2 Angular

Angular 应用是模块化的,它拥有自己的模块化系统,称作 NgModule。

Angular特点:

Angula+Typescript,具有较强的模块化思想,代码结构较为清晰。
标准化的开发方式,后期能极大的提高开发生产力,提高开发效率。
依赖注入(DI):是当类需要执行其功能时,所需要的服务或对象

其它

vue与angular是数据双向绑定,而react由于是单向数据流
angular中的双向数据绑定是基于脏检查机制
vue的双向数据绑定是基于ES5的getter和setter来实现

4.3 MVVM

M : model层
VM:视图模型层(负责View和Model的交互和协作)
V:view层
VM层通过接口从后台M层请求数据,VM层继而和V层实现数据双向数据绑定(业务逻辑层)

我们清楚知道在mvvm架构中,数据层和视图层是不能直接通信的,所以通过ViewModel来通信,而ViewModel就是定义了一个Observe观察者。

监听数据变化,对视图内容进行更新
监听视图变化,通知数据改变


五、Vue知识点总结

5.1 vue生命周期

钩子描述
beforeCreate: 创建前el和data都没有初始化,不能访问data、method
created :创建后vue实例中的data、method已被初始化,属性也被绑定,但是此时还是虚拟dom,真正dom还没生成,$el 还不可用。一般进行数据的初始化
beforeMount: 挂载前模板已经编辑完成,但还没有被渲染至页面中(即为虚拟dom加载为真实dom)
Mounted:挂载后模板已经被渲染成真实DOM,用户已经可以看到渲染完成的页面
beforeUpdate:更新前状态view层数据发生变化才会触发
updated数据已经更改完成,dom也重新render完成。
activatedkeep-alive 组件激活(显示)时调用。
deactivatedkeep-alive 组件停用(隐藏)时调用。
beforeDestroy销毁前执行 一般在这清除计时器、清除非指令绑定的事件等等
destroyed销毁后 (Dom元素存在,只是不再受vue控制),卸载watcher,事件监听,子组件。

5.2 keep-alive的作用是什么?

顾名思义:保持活跃
vue是组件化变成,有着自己的生命周期从创建到销毁,如果使用keep-alive的作用就是使组件保持活跃,不会别销毁掉。

这在实际开发中是非常常见的,比如:

在页面中可能存在输入框,选择框等信息,跳转路由返回后这些内容不能再清空啊,所以这个时候keep-alive起到非常关键的作用。

补充:include和exclude指定是否缓存某些组件 非常灵活根据实际需要使用。

<!-- 指定home组件和about组件被缓存 -->
<keep-alive include="home,about" >
    <router-view></router-view>
</keep-alive>

5.3 父子组件之间通信方式

父子组件之间的通信

props 和 $emit 最常用的一种方式
ref 通过refs拿到子组件的实例
$children 和 $parent 不方便维护
provide/inject 多用于高阶组件库,平常开发一般不使用,不利于代码维护
vuex 常用于多个组件需要共享同一状态时。

举例:

 <!--ref主动寻找子组件组件-->
 <one ref="child"></one>
mounted(){
     //用法:this.$refs['child'].xxx()
    console.log(this.$refs['child']);
}

Vuex跨级组件之间传递

vuex:单项数据流,在全局通过state存放数据,通过mutation修改state中的数据,如果存在异步操作,需要先通过action再通过mutaion修改state数据。

5.4 Vue中双向数据绑定

用法: <表单元素 v-model=“变量” >
vue双向数据绑定是通过数据劫持,结合发布订阅模式方式来实现的。
核心:Object.defineProperty方法

Object.defineProperty()

语法:Object.defineProperty(obj,prop,descriptor)
obj——要在其上定义属性的对象。
prop——要定义或修改的属性的名称。
descriptor——将被定义或修改的属性描述符。

let obj = {}
Object.defineProperty(obj, 'name', {
  get: function() {
    console.log('调用了get方法')
  },
  set: function(newVal) { 
    console.log('调用了set方法,方法的值是:' + newVal)
  }
})
obj.name // 打印:调用了get方法
obj.name = 'xxx' // 打印:调用了set方法,方法的值是:xxx

不难发现当改变数据的时候会调用set方法 vue中的双向绑定就是据此实现的。

5.5 自定义组件的双向数据绑定实现

父组件写法:

<Child v-model:num="num"></Child>
<h1>父组件值:{{num}}</h1>

子组件写法:

<template>
  <div>
    <div>{{ `子组件值: ${num}` }}</div>
    <button @click="click">点击此处修改值</button>
  </div>
</template>

<script>
export default {
  name: "",
  data() {
    return {};
  },
  props: {
    num: {
      type: Number
    }
  },
  created() {},
  mounted() {
    this.valueData = this.num;
  },
  methods: {
    click() {
      this.valueData++;
      this.$emit("update:num", this.valueData);
    }
  }
};
</script>

扩展:vue2.3之后提供了sync方式,也能实现双向绑定 此时子组件中就不需要model的定义了

5.6 $nextTick的使用

官方解释:将回调延迟到下次DOM更新循环之后执行。

Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新

在数据变化后执行的某个操作,而这个操作需要使用随数据变化而变化的DOM结构的时候,这个操作就需要方法在nextTick()的回调函数中。
在vue生命周期中,如果在created()钩子进行DOM操作,也一定要放在nextTick()的回调函数中。

5.7 computed 和 watch 的区别和运用的场景?

computed: 计算属性。依赖其它属性值(一般没有计算属性,通过methods也能实现,但是他们之前的区别就是计算属性是基于它的依赖缓存的,一个计算属性所依赖的数据发生变化时,它才会重新取值,大大提高了性能)

watch: 监听数据的变化。更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;

运用场景:

computed - 需要进行数值计算,并且依赖于其它数据时
例如:购物车计算价格(只要购买数量,购买价格,优惠券,折扣券等任意一个发生变化,总价都会自动跟踪变化).

watch擅长处理的场景:一个数据影响多个数据
当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch。
应用场景:1、监听父组件接收子组件传过来的值,因为该操作是异步的,子组渲染之后才会被传。2、监听路由变化,3,搜索栏

使用watch需要注意的点:

watch有两个参数;
immediate:组件加载立即触发回调函数执行,
deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变
watch中的函数名称必须要和data中的属性名一致,watch依赖于data中的属性,data中的属性发生变化的时候,watch中的函数就会发生变化。
watch不支持缓存;

补充:此处参考网上博客
原文链接:https://blog.csdn.net/weixin_44718974/article/details/116201240

使用:
 data: {
      firstName: 'Dawei',
      lastName: 'Lou',
      fullName: ''
  },
  <div>
      <p>FullName: {{fullName}}</p>
      <p>FirstName: <input type="text" v-model="firstName"></p>
  </div>
  情景一:基本用法,当firstName值变化时,watch监听到并且执行
  watch: {
          firstName(newName, oldName) {
              this.fullName = newName + ' ' + this.lastName;
          }
      } 

  情景二:handler方法和immediate属性,最初的时候就执行,不用等到值变化在执行
  watch: {
      firstName: {
          handler(newName, oldName) {
              this.fullName = newName + ' ' + this.lastName;
          },
          // 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法,如果设置了false,那么效果和上边例子一样
          immediate: true
      }
  }

  情景三:deep属性(深度监听,常用语对象下面属性的改变)
  <p>obj.a: {{obj.a}}</p>
   <p>obj.a: <input type="text" v-model="obj.a"></p>

       data: {
           obj: {
               a: 123
           }
       },
       
       watch: {            -----------不推荐
               obj: {
                   handler(newName, oldName) {
                       console.log('obj.a changed');
                   },
                   immediate: true,
                   deep: true // 不加deep监听不到 obj的变化
               }
           } 
       这个方法对性能影响很大,修改obj中任何一个属性都会触发这个监听器内的handler,可做如下操作

       watch: {
           'obj.a': {
               handler(newName, oldName) {
                   console.log('obj.a changed');
               },
               immediate: true,
               // deep: true
           }
       }

5.8 vuex(状态管理)

属性介绍:

state: 基本数据(数据源存放地)
getters: 可以读取state中的数据
mutations : 提交更改数据的方法,同步!
actions : 像一个装饰器,包裹mutations,使之可以异步。
modules : 模块化Vuex,每个模块中都有自己的state、getter、mutations、actions

定义

// 引用 import store from './store'

 //定义基础的数据
state: {num: 99},

//getter为state的计算属性
getters: {
  getNum: (state) => state.num,//获取num
},

//mutations可更改状态的逻辑,同步操作
mutations: {
  setNum: (state, data) => state.num = data
},

//提交mutation,异步操作
  actions: {
    acSetNum(context, age) {
      setTimeout(() => {
        //延时1秒提交至mutations中的方法
        context.commit("setNum", age);
      }, 1000);
    }

使用

1)直接使用如下
this.$store.commit("setNum", 999); // mutations

this.$store.dispatch("acSetNnum"); // actions

2)vuex中的辅助函数
import { mapState, mapGetters } from "vuex"; //导入vuex的辅助函数
import { mapMutations, mapActions } from "vuex"; //导入vuex的辅助函数

computed: {
  // 映射 state 中的数据为计算属性
  ...mapState(["age"]),
  // 映射 getters 中的数据为计算属性
  ...mapGetters(["getNum"]),
},

methods: {
  //用于生成与 mutations 对话的方法,即:包含 $store.commit(xx) 的函数
  ...mapMutations(["setNum"]),
  //用于生成与 actions 对话的方法,即:包含 $store.dispatch(xx) 的函数
  ...mapActions(["acSetNum"]),
},

5.9 v-if与v-show的区别

v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果;
v-show指令是通过修改元素的CSS属性(display)让其显示或者隐藏;
使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。

v-for优先级比v-if

在vue2中v-for优先级比v-if
在vue3中v-if优先级更高
v-for和v-if在同一标签中使用也会报错,解决办法可以在外面套一个template标签,或者使用computed来对数组进行过滤然后渲染


六、Vue3.0

6.1 生命周期的变化

Vue3.0中取消了beforeCreate 和 created 两个阶段,同样的新增了一个 setup
其它变化不大只是名字变了,具体如下:

beforeMount 挂载之前 改名 onBeforeMount
mounted 挂载之后 改名 onMounted
beforeUpdate 数据更新之前 改名 onBeforeUpdate
updated 数据更新之后 改名 onUpdated
beforeDestroy 销毁前 改名 onBeforeUnmount
destoryed 销毁后 改名 onUnmounted

6.2 setup函数

setup函数是 Composition API(组合API)的入口
在setup函数中定义的变量和方法最后都是需要 return 出去的不然无法在模板中使用
注意点

setup 函数中,无法使用 data 和 methods 的变量和方法
setup函数中this还不是组件实例,即this就是undefined
setup函数只能是同步的不能是异步的

setup 参数 props

<HelloWorld :msg="msg" state='111' @handle='handleEvent' />
<template v-slot:header>
   张三
</template>
export default {
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
}

因为 props 是响应式的,你不能使用 ES6 解构,它会消除 prop 的响应性。
如果需要解构 props,可以在 setup 函数中使用 toRefs 函数来完成此操作:

import { toRefs } from 'vue'
setup(props) {
  const { title } = toRefs(props) 
}

如果 title 是可选的 prop,则传入的 props 中可能没有 title 。在这种情况下,toRefs 将不会为 title 创建一个 ref 。你需要使用 toRef 替代它:

import { toRef } from 'vue'
setup(props) {
  const title = toRef(props, 'title')
}

setup 参数 context

<slot name="header"></slot>
export default {
  setup(props, context) {
    // context.attrs  context.slots context.emit context.expose
    console.log(context.attrs) // {msg: '张三', state: '111'}
    
	const handleClick = function() {
       context.emit('handle', '子级数据传递')
    }
	return { handleClick }
  }
}

context是一个普通的JavaScript对象,不是响应式的因此可以使用ES6解构

export default {
  setup(props, { attrs, slots, emit, expose }) {
    ...
  }
}

注意点:

attrs(获取当前标签上的所有属性的对象) 但是该属性是props中没有声明接收的所有的对象。
如果你使用props去获取值,同时props中你声明了你要获取的值 则:获取的值是undefined

6.3 组件之间的通信

与vue2.0唯一的区别就是写法上了,如下子组件写法:

<script setup lang="ts">
	import { ref } from 'vue'
	const emit = defineEmits(['changeItem'])
	
	const props = defineProps({
		type: Number,
		children: Array
	})
	
	const changeChild = (stuId) => {
		 emit('changeItem', stuId)
	}
	
</script>

七、常见要点分析

7.1 SPA(单页应用)首屏加载速度慢

首屏加载:浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间。

  • 加载慢的原因

    网络问题;资源文件过大;请求过多;渲染内容阻塞等。

  • 解决方案

    减小入口文件体积 (常用手段路由懒加载)
    静态资源本地缓存(前端合理使用localStorage;后端采用http缓存,设置Cache-Control,Last-Modified,Etag等响应头)
    图片资源的压缩 (适当压缩、在线字体图标,或者雪碧图来减轻http请求压力)
    使用SSR(服务端渲染)

7.2 如何实现路由懒加载

vue组件异步加载

{
	path: '/xxx',
	name: 'cName',
	component: resolve => require(['./components/xxx.vue'], resolve)
}
// 实现懒加载,一个组件会生成一个js文件

ES6标准语法import() (推荐使用)

routes:[ 
    path: 'xxx',
    name: 'cName',
    component: () => import('./components/xxx.vue')
]

webpack的require,ensure()

const HelloWorld = resolve =>{
    require.ensure([],()=>{
        resolve(require('@/components/HelloWorld'))
    })
}
    
routes:[{
   {path: './', name: 'HelloWorld',component: HelloWorld}
}]

7.3 前端如何理解面向对象

在理解面向对象之前先理解一下面向过程编程:
即按步骤编程(函数和变量)
而面向对象呢?是将我们的需求分析成一个一个对象,利用对象中的属性和方法最后按照步骤编程。
面向对象特点:
1)抽象
核心的东西抽出来,把与我们要解决的问题有关的东西拿出来摆在面前。
比如我们熟知的date对象,我们知道它的一个方法getFullYear,我们不需要知道它的原理,而是会用就行。
2)封装
把一个具有相同的特征和行为的客观事物封装成抽象的类。
3)继承
让某一个类型的对象获得另一个类型对象的属性和方法。
4)多态
一个类实例中的相同方法和属性在不同场景有不同的表现形式。

7.4 如何理解构造函数

构造函数:可以理解为把对象里的一下属性和方法抽象出来封装到函数里面
构造函数主要用来在创建对象时完成对对象属性的一些初始化等操作, 当创建对象时, 对象会自动调用它的构造函数。

function Person(name) {
	this.name = name;
	this.eat = function(name,num,fruit) {
		console.log(this.name + "吃了" + num + "个" + fruit)
	}
};
let p1 = new Person('zyzhang');
// p1.name 
p1.eat("小明", 1, "苹果")

构造函数和对象的区别:

对象是一个具体事物,构造函数实际上是一个泛类
利用构造函数创建对象的过程也称为对象的实例化

7.5 prototype(原型)的理解(可以先看7.6再看7.5)

prototype属性是函数独有的,从一个函数指向一个对象,它的含义是函数的原型对象,也就是这个函数所创建的实例的原型对象。

分析: 举例如下代码(看注释)

let arr = [1,2,3,4,5]; // 字面量写法
// 实际是是使用了内置内Array 
let arr = new Array(1,2,3,4,5)
// 此时我们可以使用arr.push(6) 向数组中添加一个元素
// 但是此时arr这个对象是没有push方法的 它又是如何做到的呢?
// 这个时候 Array.prototype 出来了。
// 系统会默认基于 __proto__进行查找,第一个查找的就是 Array.prototype,发现存在即开始执行push方法。

7.6 __proto__的理解

__proto__和constructor属性是对象所独有的;
proto__属性都是由一个对象指向一个对象(指向它们的原型对象,也可以理解为父对象)
每一个对象(除null)都会有的属性__proto
,这个属性指向该对象的原型

分析

由此可见上文中的arr这个对象的原型即arr__proto__ == Array.prototype 两者完全一样。
这么理解下来上文就更加清晰了

7.6 constructor介绍

constructor属性也是对象才拥有的,它是从一个对象指向一个函数,含义就是指向该对象的构造函数

举例分析

function Person(){}   
var person1 = new Person()  
person1.name = "zyzhang" 
// true
console.log(Person === Person.prototype.constructor);

7.7 微任务与宏任务

JavaScript的一大特点就是单线程, 同一时间只能做一件事情,主要和它的用途有关, JavaScript主要是控制和用户的交互以及操作DOM。注定它是单线程。

所以如果全部代码都是同步执行的,这会引发很严重的问题,比方说我们要从远端获取一些数据,难道要一直循环代码去判断是否拿到了返回结果么?就像去饭店点餐,肯定不能说点完了以后就去后厨催着人炒菜的,会被揍的。
于是就有了异步事件的概念,注册一个回调函数,比如说发一个网络请求,我们告诉主程序等到接收到数据后通知我,然后我们就可以去做其他的事情了。

任务队列与事件循环:

1、所有的同步任务都在主线程上执行,行成一个执行栈。
2、主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
3、 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
4、主线程不断重复上面的第三步。

JavaScript 把异步任务又做了进一步的划分,异步任务又分为:微任务和宏任务
宏任务:

setTimeout、setInterval
异步 Ajax 请求
文件操作
script中整体的代码
UI渲染
DOM事件

微任务:

Promise 、 async/await

执行顺序如何?看懂下面两张图就基本OK了

在这里插入图片描述

7.8 async 与 await

1、async 告诉程序这是一个异步,awiat 会暂停执行async中的代码,等待await 表达式后面的结果,跳过async 函数,继续执行后面代码
2、async 函数会返回一个Promise 对象,那么当 async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值;当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值
3、await 操作符用于等待一个Promise 对象,并且返回 Promise 对象的处理结果(成功把resolve 函数参数作为await 表达式的值),如果等待的不是 Promise 对象,则用 Promise.resolve(xx) 转化

async function test(){
  await readFile('a'); 
  console.log('b');
  console.log('c')
}
test();   //a b c
function aaa() {
	return "aaa"
}

async function bbb() {
	return Promise.resolve("bbb")
}

async function test() {
	const v1 = await aaa()
	const v2 = await bbb()
	console.log(v1,v2)
}

test()
// 返回结果 aaa bbb

7.9 JS当中的防抖(debounce)与节流(throttle)

防抖只会在最后一次事件后执行触发函数,节流不管事件多么的频繁,都会保证在规定时间段内触发事件函数。

防抖

指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

节流

判断是否达到一定的时间来触发事件。某个时间段内只能触发一次函数。

函数防抖(debounce)

  • search搜索联想,用户在不断输入值时,用防抖来节约请求资源;
  • window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次

函数节流(throttle)

  • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
  • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断

举例分析:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>防抖与节流</title>
    <style>
      .input {width: 300px;height: 45px;border: 1px solid #ddd;
        border-radius: 5px;text-indent: 6px;font-size: 18px;}
    </style>
  </head>
  <body>
    <input class="input" oninput="change(event)" onporpertychange="change(event)" />

    <input class="input" oninput="change2(event)" onporpertychange="change2(event)" />
  </body>

  <script>
    change = debounce((e)=>{
      console.log("防抖======",e.target.value)
    },500, true) // true: 立即执行  false: 延迟

    change2 = throttle((e)=>{
      console.log("节流======",e.target.value)
    },500, 1) // 1: 时间戳 2: 定时

    // 防抖
    function debounce(func,delay,immediate) {
      let timer, context, args;
      return function() {
        context = this;
        args = arguments;
        if (timer) clearTimeout(timer);
        if(immediate) {
          let callNow = !timer;
          timer = setTimeout(()=>{
            timer = null;
          },delay)
          if(callNow) func.apply(context,args)
        } else {
          timer = setTimeout(()=>{
            func.apply(context,args)
          },delay)
        }
      }
    }

    // 节流
    function throttle(func,delay,type) {
      let timer, context, args, previous = 0;
      return function() {
        context = this;
        args = arguments;
        if(type == 1) { // 时间戳
          let now = Date.now();
          if (now - previous > delay) { 
            func.apply(context,args);
            previous = now;
          }
        } else { // 定时
          if(!timer) {
            timer = setTimeout(()=>{
              timer = null;
              func.apply(context,args)
            },delay);
          }
        }
      }
    }
  </script>
</html>

7.10 JS当中的this

定义:当前执行上下文(global、function或eval)的一个属性, 在非严格模式下,总指向一个对象;在严格模式下可以是任意值。

在全局上下文中,函数调用中直接使用this,this指向window
通过对象调用,this指向调用方法的对象
箭头函数——this与所在上下文this指向相同
构造函数——this指向构造出的对象

//  函数独立调用下 this指向window
function foo() {
  console.log(this)   //window
}
foo()
var a = 0;
var obj = {
    a: 2,
    foo: function(){
        console.log(this);   //obj
        function test(){
            console.log(this); //window
        }
        test(); // test() 函数执行, 此时是函数的独立调用,因此this指向window
    }
}
obj.foo() // 属于对象调用

案例分析,请问如下代码中的this指向什么:

var a = 0;
var obj = {
    a: 2,
    foo: function(){
        function test(){
            console.log(this); 
        }
        return test;
    }
}
obj.foo()()

分析:obj.foo()执行完毕返回test,然后变成了test()所以属于函数的独立调用。

巩固练习-如下代码请分析:

var a = 0;
function foo(){
    console.log(this);
}
var obj = { a: 2, foo: foo }
obj.foo()  //  

var bar = obj.foo;   // 
bar()

上述等价于

var obj = { 
	a: 2, 
	foo: function() {
		console.log(this);
	}
}
obj.foo()  // 所以此处属于对象方法调用 因此this指向obj

var bar = obj.foo 等价于

var bar = function() {
	console.log(this)
}
// 此时 bar() 很明显属于函数的独立调用 因此指向 window

7.11 JS当中的call()、apply()

先看如下代码,请分析console.log打印结果:

var obj = {
  myFun: function(...agreement){
    console.log(this.name + ":" + this.age); 
 }
}
var db = {name: "德玛",age: 99}
obj.myFun(db,'a','b','c'); // 属于对象方法的调用 this指向obj
obj.myFun(db,[1,2,3]); // 属于对象方法的调用 this指向obj

输出结果undefined,因为obj对象中并没有name属性和age属性
再看如下代码:

var obj = {
  myFun: function(...agreement){
    // 这里的this指向db对象
    console.log(this.name + ":" + this.age); 
 }
}
var db = {name: "德玛",age: 99}
obj.myFun.call(db,'a','b','c'); // 输出 德玛:99
obj.myFun.apply(db,[1,2,3]); // // 输出 德玛:99

由此可见call方法和apply方法能够改变this指向。
补充说明:还有另外一个作用:借用别的对象的方法(用一个对象替换掉另一个对象(this))

var Person1 = function(){
  this.name = 'LiLi';
}

var Person2 = function(){
 // 作用:使用 Person1 对象代替 this 对象,此时Person2 就有了 Person1 中的所有属性和方法了
  Person1.call(this);  
} 

var person = new Person2();
console.log(person.name) // LiLi

7.12 事件冒泡和事件捕获

事件冒泡:从下至上,当给父子元素的同一事件绑定方法的时候(比如click点击事件),触发子元素身上的事件,执行完毕之后,也会触发父级元素相同的事件。
事件捕获:从上至下到指定元素,当出发子元素身上到事件的时候,先触发父元素,然后再传递给子元素。

阻止事件冒泡

e.stopPropagation()
vue中直接使用.stop

补充:(vue事件修饰符)

.prevent -------等于javascript的event.preventDefault() 阻止默认程序的运行
capture 作用:打乱冒泡顺序
.self 作用:不让子元素的事件触发自己绑定的事件,但是不会阻止冒泡!
.once 顾名思义,事件只会触发一次

7.13 cookie、session与token

cookie 存储在客户端
当访问一个网站,客户端发送一个请求到服务器,服务器会返回set-cookie头部;
客户端保存cookie,之后向服务器发送请求时,httpRequest请求都会包含一个cookie头部;
最后服务端返回响应数据

session: 会话,保存于服务端
服务器为每个用户浏览器创建一个会话对象(session对象)

token令牌;当客户端登录后服务器端收到请求后去验证,验证成功后服务器会返回一个token发送给客户端;
客户端将token存储起来;后面每次请求时带上token,服务器端收到请求先验证token,验证成功返回请求数据。

区别:

token更适用于移动应该;cookie不支持手机端访问;
token支持跨域访问;cookie不支持跨域访问;
Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。而 Token 是令牌,访问资源接口(API)时所需要的资源凭证。Token 使服务端无状态化,不会存储会话信息。


八、微信小程序

8.1 应用的生命周期函数

onLaunch:小程序初始化完成后调用。
onShow:初始化后或者切回前台时会触发。
onHide:切到后台时触发

8.2 Page页面的生命周期

onLoad:页面加载的时触发,一个页面只调用1次
onShow:页面的显示。
onReady:监听页面初次渲染完成,一个页面只调用1次
onHide:页面隐藏但未卸载的时候触发的,如 wx.navigateTo 或底部tab切换到其他页面,小程序切入后台等。
onUnload:页面卸载时触发,如wx.redirectTo或wx.navigateBack到其他页面时。

8.3 Component的生命周期

created 当组件实例刚被创建时
attached 在组件完全初始化完毕并且进入页面节点树后, attached生命周期被触发。
detached 组件离开页面节点树后, detached生命周期被触发。
ready 视图层布局完成。


九、UniApp

8.1 应用的生命周期函数

onLaunch:当uni-app 初始化完成时触发(全局只触发一次)
onShow:当 uni-app 启动,或从后台进入前台显示
onHide:当 uni-app 从前台进入后台
onError: 当 uni-app 报错时触发

8.2 页面的生命周期

onInit:监听页面初始化
onLoad: 监听页面的加载
onShow:页面的显示。
onReady:监听页面初次渲染完成。
onHide:监听页面隐藏
onUnload:监听页面隐藏
onResize:监听窗口尺寸变化
onPullDownRefresh
onReachBottom

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作为前端程序员,以下是一些你需要掌握的关键知识: 1. HTML(超文本标记语言):了解 HTML 的基本结构、标签和属性,能够创建语义化的网页内容。 2. CSS(层叠样式表):掌握 CSS 的选择器、盒模型、布局、样式属性等,能够实现网页的样式和布局。 3. JavaScript:作为前端开发的核心语言,你需要熟悉 JavaScript 的语法、数据类型、函数、DOM 操作等,能够实现交互效果和动态内容。 4. 前端框架和库:掌握至少一个主流的前端框架(如React、Vue或Angular)以及相关的库,能够利用它们来构建复杂的用户界面和应用。 5. 响应式设计:了解响应式设计的原理和技术,能够创建适应不同设备和屏幕尺寸的网页。 6. 浏览器开发工具:熟练使用浏览器的开发工具(如Chrome DevTools)进行调试、性能优化和页面分析。 7. 版本控制系统:掌握使用版本控制系统(如Git)管理代码,进行分支管理和团队协作。 8. 前端构建工具:了解常用的前端构建工具(如Webpack、Gulp或Parcel),能够优化和打包前端资源。 9. HTTP 和网络基础知识:了解 HTTP 协议的基本原理、状态码、请求和响应,以及网络安全相关的知识。 10. 跨浏览器兼容性:了解不同浏览器之间的差异,编写兼容性良好的代码,确保网页在各种浏览器中正确显示和运行。 除了上述知识外,了解设计原则、UI/UX、性能优化、移动端开发和测试等领域的知识也会对你的前端开发能力有所帮助。不断学习和保持对新技术的关注也是成为一名优秀前端程序员的关键。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值