(1)、 声明位于文档中的最前面,处于 标签之前。告知浏览器以何种模式来渲染文档。
(2)、严格模式的排版和 JS 运作模式是 以该浏览器支持的最高标准运行。
(3)、在混杂模式中,页面以宽松的向后兼容的方式显示。模拟老式浏览器的行为以防止站点无法工作。
(4)、DOCTYPE不存在或格式不正确会导致文档以混杂模式呈现。
该标签可声明三种 DTD 类型,分别表示严格版本、过渡版本以及基于框架的 HTML 文档。
HTML 4.01 规定了三种文档类型:Strict、Transitional 以及 Frameset。
XHTML 1.0 规定了三种 XML 文档类型:Strict、Transitional 以及 Frameset。
Standards (标准)模式(也就是严格呈现模式)用于呈现遵循最新标准的网页,而 Quirks
(包容)模式(也就是松散呈现模式或者兼容模式)用于呈现为传统浏览器而设计的网页。
区别:
1.所有的标记都必须要有一个相应的结束标记
2.所有标签的元素和属性的名字都必须使用小写
3.所有的XML标记都必须合理嵌套
4.所有的属性必须用引号""括起来
5.把所有<和&特殊符号用编码表示
6.给所有属性赋一个值
7.不要在注释内容中使“--”
8.图片必须有说明文字
行内元素:a、b、strong、span、em、img、input、textarea、select button ...
块级元素:div、footer、header、section、p、ul、ol、li、dl、dt、dd、table、h1-h6...
行内块元素:img、input、td
a、span、em、strong、b、i、u、label、br
空元素:br、hr、link、meta、col...
元素之间的转换问题:
display: inline; 把某元素转换成了行内元素 ===>不独占一行的,并且不能设置宽高
display: inline-block; 把某元素转换成了行内块元素 ===>不独占一行的,可以设置宽高
display: block; 把某元素转换成了块元素 ===>独占一行,并且可以设置宽高
link 属于 html 标签,而@import 是 css 提供的
页面被加载时,link 会同时被加载,而@import 引用的 css 会等到页面加载结束后加载。
link 是 html 标签,因此没有兼容性,而@import 只有 IE5 以上才能识别。
link 方式样式的权重高于@import 的。(@import 是将引⽤的样式导⼊到当前的⻚⾯中)
区别一:link先有,后有@import(兼容性link比@import兼容);
区别二:加载顺序差别,浏览器先加载的标签link,后加载@import
link:link是HTML提供的标签,不仅可以加载CSS,还可以定义rel等属性
@import:@import是css提供的语法,只有导入样式表的作用
link:link在页面加载时CSS同时被加载
@import:引入的CSS要等页面加载完毕后再加载
link是HTML提供的语法,不存在兼容性问题
@import是css2.1提供的语法,ie5以上才兼容
js控制DOM时,可以通过插入link标签来改变样式,不能通过@import改变
link标签引入的样式权重大于@import标签
title与h1的区别:
定义:
title:概括了网站信息,可以告诉搜索引擎或者用户关于这个网站的内容主题是什么
h1:文章主题内容,告诉蜘蛛我们的网站内容最主要是什么
区别:
title他是显示在网页标题上、h1是显示在网页内容上
title比h1添加的重要 (title > h1 ) ==》对于seo的了解
场景:
网站的logo都是用h1标签包裹的
b与strong的区别:
定义:
b:实体标签,用来给文字加粗的。
strong:逻辑标签,用来加强字符语气的。
区别:
b标签只有加粗的样式,没有实际含义。
strong表示标签内字符比较重要,用以强调的。
题外话:为了符合css3的规范,b尽量少用该用strong就行了。
i与em的区别:
定义:
i:实体标签,用来做文字倾斜的。
em:是逻辑标签,用来强调文字内容的
区别:
i只是一个倾斜标签,没有实际含义。
em表示标签内字符重要,用以强调的。
场景:
i更多的用在字体图标,em术语上(医药,生物)。
meta标签有下面的作用:
1.搜索引擎优化(SEO)
2.定义页面使用编码
3.自动刷新并指向新的页面
4.实现网页转换时的动态效果
5.控制页面缓冲
6.网页定级评价
7.控制网页显示的窗口
name属性
name属性主要用于描述网页,与之对应的属性值为content,content中的内容主要是便于搜索引擎机器人查找信息和分类信息用的。
Keywords(关键字)
说明:keywords用来告诉搜索引擎你网页的关键字是什么。
description(网站内容描述)
description用来告诉搜索引擎你的网站主要内容。
author(作者)
标注网页的作者
icon
区别一:
title : 鼠标移入到图片显示的值
alt : 图片无法加载时显示的值
区别二:
在seo的层面上,蜘蛛抓取不到图片的内容,所以前端在写img标签的时候为了增加seo效果要加入alt属性来描述这张图是什么内容或者关键词。
png:无损压缩,尺寸体积要比jpg/jpeg的大,适合做小图标。
jpg:采用压缩算法,有一点失真,比png体积要小,适合做中大图片。
gif:一般是做动图的。
webp:同时支持有损或者无损压缩,相同质量的图片,webp具有更小的体积。兼容性不是特别好。
1. 易读性和维护性更好。
2. seo成分会好,蜘蛛抓取更好。
3. IE8不兼容HTML5标签的。解决:可以通过html5shiv.js去处理。
好处
语义类标签对开发者更为友好,使用语义类标签增强了可读性,即便是在没有 CSS 的时候,开发者也能够清晰地看出网页的结构,也更为便于团队的开发和维护。
除了对人类友好之外,语义类标签也十分适宜机器阅读。它的文字表现力丰富,更适合搜索引擎检索(SEO),也可以让搜索引擎爬虫更好地获取到更多有效信息,有效提升网页的搜索量,并且语义类还可以支持读屏软件,根据文章可以自动生成目录等等。
坏处
不恰当地使用语义标签,反而会造成负面作用。这里我们举一个常见的误区作为例子。我们都知道 ul 是无序列表,ol 是有序列表,所以很多接触过语义这个概念,半懂不懂的前端工程师,特别喜欢给所有并列关系的元素都套上 ul
Trident内核:IE,MaxThon,TT,The World,360,搜狗浏览器等。[又称MSHTML]
Gecko内核:Netscape6及以上版本,FF,MozillaSuite/SeaMonkey等
Presto内核:Opera7及以上。 [Opera内核原为:Presto,现为:Blink;]
Webkit内核:Safari,Chrome等。 [ Chrome的:Blink(WebKit的分支)]
CSS的盒子模型有哪些:标准盒子模型、IE盒子模型
CSS的盒子模型区别:
标准盒子模型:margin、border、padding、content
IE盒子模型 :margin、content( border + padding + content )
通过CSS如何转换盒子模型:
box-sizing: content-box; /*标准盒子模型*/
box-sizing: border-box; /*IE盒子模型*/
line-height是每一行文字的高,如果文字换行则整个盒子高度会增大(行数*行高)。
height是一个死值,就是这个盒子的高度。
CSS选择符:
通配(*)
id选择器(#)
类选择器(.)
标签选择器(div、p、h1...)
相邻选择器(+)
后代选择器(ul li)
子元素选择器( > )
属性选择器(a[href])
CSS属性哪些可以继承:
文字系列:
font-size
color
line-height
text-align
word-break
letter-spacing
text-rendering
word-spacing
white-space
text-indent
text-transform
text-shadow
visibility
cursor
***不可继承属性:border、padding、margin...
优先级比较:!important > 内联样式 > id > class > 标签 > 通配
CSS权重计算:
第一:内联样式(style) 权重值:1000
第二:id选择器 权重值:100
第三:类选择器 权重值:10
第四:标签&伪元素选择器 权重值:1
第五:通配、>、+ 权重值:0
新增各种CSS选择器 (: not(.input):所有 class 不是“input”的节点)
圆角 (border-radius:8px)
多列布局 (multi-column layout)
阴影和反射 (Shadow\Reflect)
文字特效 (text-shadow、)
文字渲染 (Text-decoration)
线性渐变 (gradient)
旋转 (transform)
缩放,定位,倾斜,动画,多背景
例如:transform:\scale(0.85,0.90)\ translate(0px,-30px)\ skew(-9deg,0deg)\Animation:
触发条件
包含结构,所有的子元素浮动,且父元素没有设置高度,就会触发父元素高度塌陷。
解决方法一:
给父元素添加固定高度。
缺点:不适合高度自适应的布局。
解决方法二:
给父元素添加overflow:hidden;
缺点:不适合和定位定出去的页面布局使用
解决方法三:
给所有的浮动盒子最后添加一个空的标签,例如 div,且添加声明 clear:both;
缺点:多了很多空的标签,造成代码冗余。
解决方法四:
万能清除浮动法。
给塌陷的父元素:after{content:"";display:block;clear:both; visibility:hidden;}
p{
width:100px;
word-break:keep-all;
white-space:nowrap;
}
p{
width:100px;
word-break:keep-all;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
}
说明:
word-break:keep-all; /* 不换行 / => 只能在半角空格或连字符处换行
white-space:nowrap; / 不换行 / => 规定段落中的文本不进行换行
overflow:hidden; / 内容超出宽度时隐藏超出部分的内容 /
text-overflow:ellipsis;
/ 当对象内文本溢出时显示省略标记(…) ; 需与 overflow:hidden; 一起使用 */
/* 单行文字省略号 */
.ellipsis{
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 多行文字省略号 */
.ellipsis{
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
line-clamp: 3;
-webkit-box-orient: vertical;
}
display: flex;
flex-direction
值:row 主轴为水平方向,起点在左端
row-reverse 主轴为水平方向,起点在右端
column 主轴为垂直方向,起点在上面
column-reverse 主轴为处置方向,起点在下沿
justify- content 定义了项目在主轴上的对齐
flex - start 左对齐
flex - end 右对齐
center 居中
space - around 盒子两侧间隔相等
space - between 两端对齐,中间间隔相等
它能取5个值。具体的对齐方式与交叉轴的方向有关
flex-start:交叉轴的起点对齐,垂直方向最上端。
flex-end: 交叉轴的终点对齐,垂直方向最下端。
center: 交叉轴的中点对齐,垂直方向中间。
baseline: 项目的第一行文字的基线对齐。
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。
Internet Explorer 和 Safari 浏览器不支持 align-self 属性)
说明:
align-self 属性规定灵活容器内被选中项目的对齐方式。
注意:align-self 属性可重写灵活容器的 align-items 属性。
属性值
auto 默认值。元素继承了它的父容器的 align-items 属性。如果没有父容器则为 "stretch"。
Stretch 元素被拉伸以适应容器。
Center 元素位于容器的中心。
flex-start 元素位于容器的开头。
flex-end 元素位于容器的结尾。
flex-wrap: nowrap(不换行) | wrap(换行) | wrap-reverse;(反向换行)
none 隐藏元素
block 把某某元素转换成块元素
inline 把某某元素转换成内联元素
inline-block 把某某元素转换成行内块元素
block 块类型。默认宽度为父元素宽度,可设置宽高,换行显示。
none 元素不显示,并从文档流中移除。
inline 行内元素类型。默认宽度为内容宽度,不可设置宽高,同行显示。
inline-block 默认宽度为内容宽度,可以设置宽高,同行显示。
list-item 象块类型元素一样显示,并添加样式列表标记。
table 此元素会作为块级表格来显示。
inherit 规定应该从父元素继承 display 属性的值。
BFC就是页面上一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。
1. 了解BFC : 块级格式化上下文。
2. BFC的原则:如果一个元素具有BFC,那么内部元素再怎么弄,都不会影响到外面的元素。
3. 如何触发BFC:
float的值非none
overflow的值非visible
display的值为:inline-block、table-cell...
position的值为:absoute、fixed
1. 触发BFC
2. 多创建一个盒子,添加样式:clear: both;
3. after方式
ul:after{
content: '';
display: block;
clear: both;·
}
使⽤空标签清除浮动 clear:both (缺点,增加⽆意义的标签)
使⽤ overflow:auto (使⽤ zoom:1 ⽤于兼容 IE ,缺点:内部宽⾼超过⽗级 div 时,会出现滚动条)
⽤ afert 伪元素清除浮动( IE8 以上和⾮ IE 浏览器才⽀持,⽬前:⼤型⽹站都有使⽤
偶数 : 让文字在浏览器上表现更好看。偶数字号相对更容易和 web 设计的其他部分构成⽐例关系
另外说明:ui给前端一般设计图都是偶数的,这样不管是布局也好,转换px也好,方便一点。
static [默认] 没有定位
fixed 固定定位,相对于浏览器窗口进行定位。
relative 相对于自身定位,不脱离文档流。
absolute 相对于第一个有relative的父元素,脱离文档流
sticky 粘性定位的元素是依赖于用户的滚动,在 position:relative 与 position:fixed 定位之间切换
relative和absolute区别
1. relative不脱离文档流 、absolute脱离文档流
2. relative相对于自身 、 absolute相对于第一个有relative的父元素
3. relative如果有left、right、top、bottom ==》left、top
absolute如果有left、right、top、bottom ==》left、right、top、bottom
因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对CSS初始化往往会出现浏览器之间的页面显示差异。
当然,初始化样式会对SEO有一定的影响,但鱼和熊掌不可兼得,但力求影响最小的情况下初始化。
最简单的初始化方法: * {padding: 0; margin: 0;} (强烈不建议)
reset.css 是一个css文件,用来重置css样式的。
normalize.css 为了增强跨浏览器渲染的一致性,一个CSS 重置样式库。
1. 是什么
把多个小图标合并成一张大图片。
2. 优缺点
优点:减少了http请求的次数,提升了性能。
缺点:维护比较差(例如图片位置进行修改或者内容宽高修改)
1. 占用位置的区别
display: none; 是不占用位置的
visibility: hidden; 虽然隐藏了,但是占用位置
2. 重绘和回流的问题
visibility: hidden; 、 display: none; 产生重绘
display: none; 还会产生一次回流
产生回流一定会造成重绘,但是重绘不一定会造成回流。
产生回流的情况:改变元素的位置(left、top...)、显示隐藏元素....
产生重绘的情况:样式改变、换皮肤
联系:它们都能让元素不可见
区别:
display:none;会让元素完全从渲染树中消失,渲染的时候不占据任何空间;visibility: hidden;不会让元素从渲染树消失,渲染师元素继续占据空间,只是内容不可见
display: none;是非继承属性,子孙节点消失由于元素从渲染树消失造成,通过修改子孙节点属性无法显示;visibility:hidden;是继承属性,子孙节点消失由于继承了hidden,通过设置visibility: visible;可以让子孙节点显式
修改常规流中元素的display通常会造成文档重排。修改visibility属性只会造成本元素的重绘
读屏器不会读取display: none;元素内容;会读取visibility: hidden元素内容
当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。
每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树。
完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘
共同性:实现透明效果
1. opacity 取值范围0到1之间,0表示完全透明,1表示不透明
2. rgba R表示红色,G表示绿色,B表示蓝色,取值可以在正整数或者百分数。A表示透明度取值0到1之间
区别:继承的区别
opacity会继承父元素的opacity属性,而RGBA设置的元素的后代元素不会继承不透明属性。
1. 区别
:是伪类、::伪元素 ===》是为了做区分
2.是什么?作用
元素before之前 、 元素after之后
作用:清除浮动、样式布局上也有作用
Chrome默认字体大小是:16px
**每个浏览器默认字体大小可能都不一样
相对于font-size
em针对于父元素的font-size
rem针对于根(html)元素的font-size
禁止ios 长按时触发系统的菜单,禁止ios&android长按时下载图片
html,body{
touch-callout: none;
-webkit-touch-callout: none;
user-select:none;
-webkit-user-select:none;
}
html,body{
user-select:none;
-webkit-user-select:none;
}
延迟加载:async、defer
例如:
defer : 等html全部解析完成,才会执行js代码,顺次执行js脚本。
async : async是和html解析同步的(一起的),不是顺次执行js脚本(谁先加载完谁先执行)。
1.异步加载的方案: 动态插入script标签
2.通过ajax去获取js代码,然后通过eval执行
3.script标签上添加defer或者async属性
4.创建并插入iframe,让它异步执行js
5.延迟加载:有些 js 代码并不是页面初始化的时候就立刻需要的,而稍后的某些情况才需要的。
基本类型:string、number、boolean、undefined、null、symbol、bigint
引用类型:object
NaN是一个数值类型,但是不是一个具体的数字。
基本数据类型:String,Boolean,number,undefined,object,Null
引⽤数据类型:Object(Array,Date,RegExp,Function)
push
pop
unshift
shift
splice
join
concat
forEach
filter
map
sort
some
every
例如:
let arrInfo=[4,6,6,8,5,7,87]
arrInfo.forEach((item,index,arr)=>{
//遍历逻辑
})
其中:
item代码遍历的每一项,
index:代表遍历的每项的索引,
arr代表数组本身
let arrInfo=[4,16,6,8,45,7,87]
let resultArr=arrInfo.filter((item,index,arr)=>{
//例如返回数组每项值大于9的数组
return item>9
})
console.log(resultArr)
map() 方法返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组
区别一:返回的内容不同
filter 返回是新数组
find 返回具体的内容
区别二:
find :匹配到第一个即返回
filter : 返回整体(没一个匹配到的都返回)
some ==》 如果有一项匹配则返回true
every ==》 全部匹配才会返回true
console.log( true + 1 ); //2
console.log( NAN + 1 ); //NAN
console.log( 'name'+true ); //nametrue
console.log( undefined + 1 ); //NaN
console.log( typeof undefined ); //undefined
console.log( typeof(NaN) ); //number
console.log( typeof(null) ); //object
1. 作者在设计js的都是先设计的null(为什么设计了null:最初设计js的时候借鉴了java的语言)
2. null会被隐式转换成0,很不容易发现错误。
3. 先有null后有undefined,出来undefined是为了填补之前的坑。
具体区别:JavaScript的最初版本是这样区分的:null是一个表示"无"的对象(空对象指针),转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。
我原先看过一些资料 据我所知 作者最先设计出来null 他是借鉴了java语言 但是null有一些问题
比如说:作者会觉得表示”无”的值最好不要是对象,是一个基本类型是最好的 而且null会被隐式转换成0,很不容易发现错误 所有说作者有设计出undefined
因为undefined首先不会隐式转换成0 而且undefined还有一个比较好的点就是它是一个基本类型
document.write只能重绘整个页面
innerHTML可以重绘页面的一部分
es6 之前,存在两种
全局作用域
局部作用域(函数作用域)
es6之后,引入一种新的作用域
块级作用域
== : 比较的是值
string == number || boolean || number ....都会隐式转换
通过valueOf转换(valueOf() 方法通常由 JavaScript 在后台自动调用,并不显式地出现在代码中。)
=== : 除了比较值,还比较类型
从输入URL到页面加载的主干流程如下:
1、浏览器的地址栏输入URL并按下回车。
2、浏览器查找当前URL的DNS缓存记录。
3、DNS解析URL对应的IP。
4、根据IP建立TCP连接(三次握手)。
5、HTTP发起请求。
6、服务器处理请求,浏览器接收HTTP响应。
7、渲染页面,构建DOM树。
8、关闭TCP连接(四次挥手)。
http的三次握手和四次挥手:
浏览器在给服,务器传输数据之前,有三次握手,握手成功之后,才可以传输数据
浏览器需要先发送SYN码,客户端请求和服务器建立连接;
服务器接收到SYN码,再发送给客户端SYN+ACK码,我可以建立连接;
客户端接收到ACK码,验证这个ACK是否正确,如果正确则客户端和服务端则建立起数据连接;双方的数据发送通道都将开启;
四次挥手:
当客户端无数据要传输了,会发送FIN码告诉服务器,我发送完毕了;
当服务器接收完毕后,告诉客户端ACK码,告诉客户端你可以把数据通道关闭了;
当服务器发送完毕之后,也会发送FIN码,告诉浏览器,数据发送完毕;
当客户端接收完毕 之后,同样发送ACK码,告诉服务器,数据接收 完毕,
js代码执行时,先按代码顺序将同步任务压入主执行栈中执行
遇到异步任务则先将异步任务压入对应的任务队列中(宏队列或微队列)
同步任务执行完毕后,查看微队列,将微任务一一取出进入主执行栈中执行
微任务队列清空后,再查看宏队列,只取出第一个宏任务执行,执行完一个宏任务后,回到第三步的操作 这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)
1. js是单线程的语言。
2. js代码执行流程:同步执行完==》事件循环
同步的任务都执行完了,才会执行事件循环的内容
进入事件循环:请求、定时器、事件....
3. 事件循环中包含:【微任务、宏任务】
微任务:promise.then
宏任务:setTimeout..
要执行宏任务的前提是清空了所有的微任务
流程:同步==》事件循环【微任务和宏任务】==》微任务==》宏任务=》微任务...
宏任务可以被理解为每次"执⾏栈"中所执⾏的代码,⽽浏览器会在每次宏任务执⾏结束后,在下⼀个宏任务执⾏开始前,对页⾯进⾏渲染,
⽽宏任务包括:
script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate
UI rendering
微任务,可以理解是在当前"执⾏栈"中的任务执⾏结束后⽴即执⾏的任务。⽽且早于页⾯渲染和取任务队列中的任务。
微任务包括:
Promise.then
Object.observe
MutaionObserver
process.nextTick
他们的运⾏机制是这样的:
执⾏⼀个宏任务(栈中没有就从事件队列中获取)
执⾏过程中如果遇到微任务,就将它添加到微任务的任务队列中
宏任务执⾏完毕后,⽴即执⾏当前微任务队列中的所有微任务(依次执⾏)
当前宏任务执⾏完毕,开始检查渲染,然后GUI线程接管渲染
渲染完毕后,js线程继续接管,开始下⼀个宏任务(从事件队列中获取)
1. 除了函数外,js是没有块级作用域。
2. 作用域链:内部可以访问外部的变量,但是外部不能访问内部的变量。
注意:如果内部有,优先查找到内部,如果内部没有就查找外部的。
3. 注意声明变量是用var还是没有写(window.)
4. 注意:js有变量提升的机制【变量悬挂声明】
5. 优先级:声明变量 > 声明普通函数 > 参数 > 变量提升
1. 本层作用域有没有此变量【注意变量提升】
2. 注意:js除了函数外没有块级作用域
3. 普通声明函数是不看写函数的时候顺序
1. 对象是通过new操作符构建出来的,所以对象之间不想等(除了引用外);
2. 对象注意:引用类型(共同一个地址);
3. 对象的key都是字符串类型;
4. 对象如何找属性|方法;
查找规则:先在对象本身找 ===> 构造函数中找 ===> 对象原型中找 ===> 构造函数原型中找 ===> 对象上一层原型查找
var arr = [1,2,3];
console.log( Array.isArray( arr ) );
var arr = [1,2,3];
console.log( arr instanceof Array );
var arr = [1,2,3];
console.log( Object.prototype.toString.call(arr).indexOf('Array') > -1 );
var arr = [1,2,3];
console.log( Array.prototype.isPrototypeOf(arr) )
var arr = [1,2,3];
console.log( arr.constructor.toString().indexOf('Array') > -1 )
1. slice是来截取的
参数可以写slice(3)、slice(1,3)、slice(-3)
返回的是一个新的数组
2. splice 功能有:插入、删除、替换
返回:删除的元素
该方法会改变原数组
1. 创建了一个空的对象
2. 将空对象的原型,指向于构造函数的原型
3. 将空对象作为构造函数的上下文(改变this指向)
4. 对构造函数有返回值的处理判断
function Fun( age,name ){
this.age = age;
this.name = name;
}
function create( fn , ...args ){
//1. 创建了一个空的对象
var obj = {}; //var obj = Object.create({})
//2. 将空对象的原型,指向于构造函数的原型
Object.setPrototypeOf(obj,fn.prototype);
//3. 将空对象作为构造函数的上下文(改变this指向)
var result = fn.apply(obj,args);
//4. 对构造函数有返回值的处理判断
return result instanceof Object ? result : obj;
}
console.log( create(Fun,18,'张三') )
JS事件代理就是通过给父级元素(例如:ul)绑定事件,不给子级元素(例如:li)绑定事件,然后当点击子级元素时,通过事件冒泡机制在其绑定的父元素上触发事件处理函数,主要目的是为了提升性能,因为我不用给每个子级元素绑定事件,只给父级元素绑定一次就好了,在原生js里面是通过event对象的targe属性实现
var ul = document.querySelector("ul");
ul.onclick = function(e){//e指event,事件对象
var target = e.target || e.srcElement; //target获取触发事件的目标(li)
if(target.nodeName.toLowerCase() == 'li'){//目标(li)节点名转小写字母,不转的话是大写字母
alert(target.innerHTML)
}
}
jq方式实现相对而言简单 $(“ul”).on(“click”,“li”,function(){//事件逻辑}) 其中第二个参数指的是触发事件的具体目标,特别是给动态添加的元素绑定事件,这个特别起作用
this总是指向函数的直接调用者(而非间接调用者)
如果有new关键字,this指向new出来的那个对象
在事件中,this指向目标元素,特殊的是IE的attachEvent中的this总是指向全局对象window。
前者是在一定时间过后将函数添加至执行队列,执行时间=延迟时间+之前函数代码执行时间+执行函数时间。
后者是不管前一次是否执行完毕,每隔一定时间重复执行,用于精准执行互相没有影响的重复操作。
1. 闭包是什么
闭包是一个函数加上到创建函数的作用域的连接,闭包“关闭”了函数的自由变量。
2. 闭包可以解决什么问题【闭包的优点】
2.1 内部函数可以访问到外部函数的局部变量
2.2 闭包可以解决的问题
var lis = document.getElementsByTagName('li');
for(var i=0;i 可说可不说,如果说一定要提到ie
闭包说的通俗一点就是打通了一条在函数外部访问函数内部作用域的通道。正常情况下函数外部是访问不到函数内部作用域变量的,
表象判断是不是闭包:函数嵌套函数,内部函数被return 内部函数调用外层函数的局部变量
优点:可以隔离作用域,不造成全局污染
缺点:由于闭包长期驻留内存,则长期这样会导致内存泄露
如何解决内存泄露:将暴露全外部的闭包变量置为null
适用场景:封装组件,for循环和定时器结合使用,for循环和dom事件结合.可以在性能优化的过程中,节流防抖函数的使用,导航栏获取下标的使用
定义:程序不需要的内存,由于某些原因其不会返回到操作系统或者可用内存池中。 内存泄露会导致(运行缓慢 ,高延迟,崩溃)的问题
常见的导致内存泄露的原因有:
意外的全局变量
被遗忘的计时器或回调函数
脱离文档的DOM的引用
闭包
内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。
垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。
setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
全局变量、闭包、DOM清空或删除时,事件未清除、子元素存在引用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kZnm9Qdn-1662000025339)(/Users/hbc/Library/Application Support/typora-user-images/image-20220607105846298.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GEZLMiSR-1662000025340)(/Users/hbc/Library/Application Support/typora-user-images/image-20220607105905169.png)]
1. 原型可以解决什么问题
对象共享属性和共享方法
2. 谁有原型
函数拥有:prototype
对象拥有:__proto__
3. 对象查找属性或者方法的顺序
先在对象本身查找 --> 构造函数中查找 --> 对象的原型 --> 构造函数的原型中 --> 当前原型的原型中查找
4. 原型链
4.1 是什么?:就是把原型串联起来
4.2 原型链的最顶端是null
原型对象也是普通的对象,是对象一个自带隐式的 __proto__ 属性,原型也有可能有自己的原型,如果一个原型对象的原型不为null的话,我们就称之为原型链。
原型链是由一些用来继承和共享属性的对象组成的(有限的)对象链。
prototype是函数特有的, __proto__是对象有的
prototype
和——proto——
区别与作用
prototype把共有属性预先定义好,给之后对象使用
prototype的存在实现了继承,节省内存空间
__proto__是对象的,prototype是函数的,因为函数也是对象,所以函数也有__proto__ ;
__proto__的作用是就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会沿着它的**__proto__**属性所指向的那个对象(父对象)里找,也就是原型链
prototype的作用是就是让该函数所实例化的对象们都可以找到公用的属性和方法
class Parent{
constructor(){
this.age = 18;
}
}
class Child extends Parent{
constructor(){
super();
this.name = '张三';
}
}
let o1 = new Child();
console.log( o1,o1.name,o1.age );
function Parent(){
this.age = 20;
}
function Child(){
this.name = '张三'
}
Child.prototype = new Parent();
let o2 = new Child();
console.log( o2,o2.name,o2.age );
function Parent(){
this.age = 22;
}
function Child(){
this.name = '张三'
Parent.call(this);
}
let o3 = new Child();
console.log( o3,o3.name,o3.age );
function Parent(){
this.age = 100;
}
function Child(){
Parent.call(this);
this.name = '张三'
}
Child.prototype = new Parent();
let o4 = new Child();
console.log( o4,o4.name,o4.age );
可以改变this指向
语法: 函数.call()、函数.apply()、函数.bind()
1. call、apply可以立即执行。bind不会立即执行,因为bind返回的是一个函数需要加入()执行。
2. 参数不同:apply第二个参数是数组。call和bind有多个参数需要挨个写。
面试时候说:
call、apply、bind功能都是改变函数体内的this指向的
他们的区别是
1.call、apply可以立即执行 bind不会立即执行,因为bind返回的是一个函数需要加入()执行
2.参数不同:apply第二个参数是数组 call和bind有多个参数 可能又三四个 五六个 需要挨个写
3.使用场景:一般情况用call就可以了 但是在特定情况下 可能我会用apply 比如: Math.max.apply 因为max后面是一个一个值 但是可能取最大值 他是一个数组,正好apply第二参数是数组 这就没问题 用call就不行 用bind 情况下我们可能是用函数 比如你要给某一个dom元素加入一个onclick事件 但是你希望赋值的元素体指向某一个元素 这时候就可以用bind
1. 用apply的情况
var arr1 = [1,2,4,5,7,3,321];
console.log( Math.max.apply(null,arr1) )
2. 用bind的情况
var btn = document.getElementById('btn');
var h1s = document.getElementById('h1s');
btn.onclick = function(){
console.log( this.id );
}.bind(h1s)
V8 引擎 sort 函数只给出了两种排序 InsertionSort 和 QuickSort,数量小于10的数组使用 InsertionSort,比10大的数组则使用 QuickSort。
之前的版本是:插入排序和快排,现在是冒泡
原理实现链接:https://github.com/v8/v8/blob/ad82a40509c5b5b4680d4299c8f08d6c6d31af3c/src/js/array.js
***710行代码开始***
共同点:复制
1. 浅拷贝:只复制引用,而未复制真正的值。
var arr1 = ['a','b','c','d'];
var arr2 = arr1;
var obj1 = {a:1,b:2}
var obj2 = Object.assign(obj1);
2. 深拷贝:是复制真正的值 (不同引用)
var obj3 = {
a:1,
b:2
}
var obj4 = JSON.parse(JSON.stringify( obj3 ));
//递归的形式
function copyObj( obj ){
if( Array.isArray(obj) ){
var newObj = [];
}else{
var newObj = {};
}
for( var key in obj ){
if( typeof obj[key] == 'object' ){
newObj[key] = copyObj(obj[key]);
}else{
newObj[key] = obj[key];
}
}
return newObj;
}
console.log( copyObj(obj5) );
1.如果json里面有时间对象,则序列化后会将时间对象转换为字符串格式
2.如果json里有 function,undefined,则序列化后会将 function,undefined 丢失
3.如果json里有NaN、Infinity和-Infinity,则序列化后会变成null
4.如果json里有对象是由构造函数生成的,则序列化的结果会丢弃对象的 constructor
5.如果对象中存在循环引用的情况将抛出错误
6.当json里有RegExp、Error对象时,序列化的结果将只得到一个空对象;
公共点:在客户端存放数据
区别:
1. 数据存放有效期
sessionStorage : 仅在当前浏览器窗口关闭之前有效。【关闭浏览器就没了】
localStorage : 始终有效,窗口或者浏览器关闭也一直保存,所以叫持久化存储。
cookie: 只在设置的cookie过期时间之前有效,即使窗口或者浏览器关闭也有效。
2. localStorage、sessionStorage不可以设置过期时间
cookie 有过期时间,可以设置过期(把时间调整到之前的时间,就过期了)
3. 存储大小的限制
cookie存储量不能超过4k
localStorage、sessionStorage不能超过5M
****根据不同的浏览器存储的大小是不同的。
(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.
(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
(3)设置响应HTTP请求状态变化的函数.
(4)发送HTTP请求.
(5)获取异步调用返回的数据.
(6)使用JavaScript和DOM实现局部刷新.
GET:一般用于信息获取,使用URL传递参数,对所发送信息的数量也有限制,一般在2000个字符
POST:一般用于修改服务器上的资源,对所发送的信息没有限制。
GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值,也就是说Get是通过地址栏来传值,而Post是通过提交表单来传值。
然而,在以下情况中,请使用 POST 请求:
无法使用缓存文件(更新服务器上的文件或数据库)
向服务器发送大量数据(POST 没有数据量限制)
发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
当用户在浏览网页的时候,浏览器会返回一个htttp状态码,主要是用来响应浏览器的请求。
200 OK 请求正常处理完毕
204 No Content 请求成功处理,没有实体的主体返回
301 Moved Permanently 永久重定向,资源已永久分配新URI
302 Found 临时重定向,资源已临时分配新URI
400 Bad Request 请求报文语法错误或参数错误
401 Unauthorized 要通过HTTP认证,或认证失败
403 Forbidden 请求资源被拒绝
404 Not Found 无法找到请求资源(服务器无理由拒绝)
500 Internal Server Error 服务器故障或Web应用故障
503 Service Unavailable 服务器超负载或停机维护你可以关闭;
map和object区别是
object对象存储的key都是字符串类型
map的key可以接受任何类型
map和哈希表区别是
哈希表又叫散列表
区别:如果要找到对象的某一个值,哈希表省去了遍历的过程和操作
1.Map是键值对,Set是值的集合,键和值可以是任何的值;
2.Map可以通过get方法获取值,而set不能因为它只有值,set只能用has来判断,返回一个布尔值;
3.Set的值是唯一的可以做数组去重,Map由于没有格式限制,可以做数据存储
浏览器对象模型
BOM是浏览器对象模型,用来获取或设置浏览器的属性、行为,例如:新建窗口、获取屏幕分辨率、浏览器版本号等。
DOM是文档对象模型,用来获取或设置文档中标签的属性,例如获取或者设置input表单的value值。
BOM的内容不多,主要还是DOM。
由于DOM的操作对象是文档(Document),所以dom和浏览器没有直接关系
```
弹窗
window.alert
window.confirm
window.prompt
```
```
定时器
只执行一次 - setTimeout
重复执行 - setInterval
```
```
location 对象
端口: ${location.port}
协议: ${location.protocol}
主机地址(带端口): ${location.host}
主机地址(不带端口): ${location.hostname}
访问的主机内路径: ${location.pathname}
地址栏的完整地址: ${location.href}
查询参数: ${location.search}
常用方法
页面跳转(会保存历史记录) location.href
页面跳转(不保存历史记录) location.replace
页面重载 location.reload
```
```
navigator 对象
对象内存储了用户浏览器信息和系统信息。但不是很准确具有一定误导性
用户浏览器是否开启cookies: navigator.cookieEnabled
用户浏览器本地语言:navigator.language
用户代理(浏览器信息, 系统信息等):navigator.userAgent
```
```
history 对象
back: 对应浏览器中的回退按钮 history.back();
forward: 对应浏览器中的前进按钮 history.forward();
go: 参数为正数时等同于 back 效果, 为负数时等同于 forward 效果
后退 history.go(-1);
前进 history.go(1);
```
navigator.userAgent
var、let、const 共同点都是可以声明变量的
区别一:
var 具有变量提升的机制
let和const没有变量提升的机制
区别二:
var 可以多次声明同一个变量
let和const不可以多次声明同一个变量
区别三:
var、let声明变量的
const声明常量
var和let声明的变量可以再次赋值,但是const不可以再次赋值了。
区别四:
var声明的变量没有自身作用域
let和const声明的变量有自身的作用域
console.log( str );//undefined
var str = '你好';
console.log( num );//报错
let num = 10;
function demo(){
var n = 2;
if( true ){
var n = 1;
}
console.log( n );//1
}
demo();
function demo(){
let n = 2;
if( true ){
let n = 1;
}
console.log( n );//2
}
demo();
const obj = {
a:1
}
obj.a = 11111;
console.log( obj )
const arr = ['a','b','c'];
arr[0]= 'aaaaa';
console.log( arr );
const a = {a:1,b:4};
const b = {b:2,c:3};
let obj1 = Object.assign(a,b);
console.log( obj1 );
let obj2 = {...a,...b};
console.log( obj2 );
function extend( target, source ){
for(var key in source){
target[key] = source[key];
}
return target;
}
console.log( extend(a,b) );
1. this指向的问题
箭头函数中的this只在箭头函数定义时就决定的,而且不可修改的(call、apply、bind)
****箭头函数的this指向定义时候、外层第一个普通函数的this
2. 箭头函数不能new(不能当作构造函数)
3. 箭头函数prototype
4. 箭头函数arguments
面试时候说:
1. this指向的问题
首先this指向的箭头函数是不可通过(call、apply、bind)修改的 它的this就在定义时就决定的 而且取决于他外层第一个普通函数的this 其次箭头函数不能new操作符进行实力话 也就说不能当作一个构造函数 其次箭头函数没有原型 还有箭头函数没有arguments对象
相同点:
JavaScript 中 typeof 和 instanceof 常用来判断一个变量是否为空, 或者是什么类型的。
不同点:
typeof:
1、返回值是一个字符串, 用来说明变量的数据类型。
2、typeof 一般只能返回如下几个结果: number, boolean, string, function, object, undefined。
对于 Array, Null 等特殊对象使用 typeof 一律返回 object, 这正是 typeof 的局限性
instanceof:
1、返回值为布尔值
2、instanceof 用于判断一个变量是否属于某个对象的实例。
isNaN会将参数做类型转换后再判断
Number.isNaN 不会做类型转换,判断不是数字类型即返回false
防抖动和节流本质是不一样的。防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。
指在时间n内,函数被触发多次,但是只执行一次,执行最新的触发。也就是在时间n内,碰到新的触发,就清除之前的,重新计时。
function debounce(func, ms = 1000) {
let timer;
return function (...args) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
func.apply(this, args)
}, ms)
}
}
// 测试
const task = () => { console.log('run task') }
const debounceTask = debounce(task, 1000)
window.addEventListener('scroll', debounceTask)
当持续触发某个事件时,会有规律的每隔时间n就执行一次函数。
function throttle(func, ms = 1000) {
let canRun = true
return function (...args) {
if (!canRun) return
canRun = false
setTimeout(() => {
func.apply(this, args)
canRun = true
}, ms)
}
}
// 测试
const task = () => { console.log('run task') }
const throttleTask = throttle(task, 1000)
window.addEventListener('scroll', throttleTask)
有三种状态:
pending(进行中)
fulfilled(已成功)
rejected(已失败)
在Promise的内部,有一个状态管理器的存在,有三种状态:pending、fulfilled、rejected。
(1) promise 对象初始化状态为 pending。
(2) 当调用resolve(成功),会由pending => fulfilled。
(3) 当调用reject(失败),会由pending => rejected。
需要记住的是注意promsie状态 只能由 pending => fulfilled/rejected, 一旦修改就不能再变。
resolve 返回一个由参数决定的Promise对象,简单来说就是返回一个Promise对象,且是成功的时候调用该方法,会将信息传递给下一个then方法。
reject 返回一个状态为失败的Promise对象,并将失败信息传递给对应的catch方法
all 把封装好的Promise方法进行链式调用
Promise.all方法必须是所有的对象都是调用成功的resolve方法,否则会走catch方法。然后得到的结果会按顺序输出一个数组。如果参数不是Promise对象,这些值会被忽略,但是结果放入数组。在对于页面一些必须所有数据得到才渲染的场景下,all方法非常有用
race 第一个执行完毕的结果,无论结果是成功还是失败
Promise.finally是无论Promise最后是fulfilled还是rejected都会执行的操作。
import和require都是被模块化使用
require是运行时调用,所以可以随处引入
import是编译时调用,必须放在文件开头引入,目前部分浏览器不支持,需要用babel把es6转成es5再执行说
现在的前端网页功能丰富,特别是SPA(single page web application 单页应用)技术流行后,JavaScript的复杂度增加和需要一大堆依赖包,还需要解决Scss,Less……新增样式的扩展写法的编译工作。
所以现代化的前端已经完全依赖于webpack的辅助了。
现在最流行的三个前端框架,可以说和webpack已经紧密相连,框架官方都推出了和自身框架依赖的webpack构建工具。
react.js+WebPack
vue.js+WebPack
AngluarJS+WebPack
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Sass,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。在3.0出现后,Webpack还肩负起了优化项目的责任。
把一切都视为模块:不管是 css、JS、Image 还是 html 都可以互相引用,通过定义 entry.js,对所有依赖的文件进行跟踪,将各个模块通过 loader 和 plugins 处理,然后打包在一起。
按需加载:打包过程中 Webpack 通过 Code Splitting 功能将文件分为多个 chunks,还可以将重复的部分单独提取出来作为 commonChunk,从而实现按需加载。把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元片段并按需加载
Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。告诉webpack要使用哪个模块作为构建项目的起点,默认为./src/index.js
output :出口,告诉webpack在哪里输出它打包好的代码以及如何命名,默认为./dist
Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。
Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
Plugin:扩展插件,在 Webpack 构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。
代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等等
文件优化:压缩 JavaScript、CSS、html 代码,压缩合并图片等
代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
模块合并:在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件
自动刷新:监听本地源代码的变化,自动构建,刷新浏览器
代码校验:在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过
自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。
如果像以前开发时一个html文件可能会引用十几个js文件,而且顺序还不能乱,因为它们存在依赖关系,同时对于ES6+等新的语法,less, sass等CSS预处理都不能很好的解决……,此时就需要一个处理这些问题的工具。
三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。
grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。
webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。
所以总结一下:
从构建思路来说
gulp和grunt需要开发者将整个前端构建过程拆分成多个`Task`,并合理控制所有`Task`的调用关系 webpack需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader做何种解析和加工
对于知识背景来说
gulp更像后端开发者的思路,需要对于整个流程了如指掌 webpack更倾向于前端开发者的思路
同样是基于入口的打包工具还有以下几个主流的:
webpack
rollup
parcel
从应用场景上来看:
webpack适用于大型复杂的前端站点构建
rollup适用于基础库的打包,如vue、react
parcel适用于简单的实验性项目,他可以满足低门槛的快速看到效果
由于parcel在打包过程中给出的调试信息十分有限,所以一旦打包出错难以调试,所以不建议复杂的项目使用parcel
file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
source-map-loader:加载额外的 Source Map 文件,以方便断点调试
image-loader:加载并且压缩图片文件
babel-loader:把 ES6 转换成 ES5
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
eslint-loader:通过 ESLint 检查 JavaScript 代码
css-loader读取 合并CSS 文件
style-loader把 CSS 内容注入到 JavaScript 里
sass-loader 解析sass文件(安装sass-loader,node-sass)
postcss-loader自动添加浏览器兼容前缀(postcss.config配置)
url-loader将文件转换为base64 URI。
vue-loader处理vue文件。
webpack默认只能打包js文件,配置里的module.rules数组配置了一组规则,告诉 Webpack 在遇到哪些文件时使用哪些 Loader 去加载和转换打包成js。
注意:
use属性的值需要是一个由 Loader 名称组成的数组,Loader 的执行顺序是由后到前的;
每一个 Loader 都可以通过 URL querystring 的方式传入参数,例如css-loader?minimize中的minimize告诉css-loader要开启 CSS 压缩。
define-plugin:定义环境变量
commons-chunk-plugin:提取公共代码
uglifyjs-webpack-plugin:插件用来缩小(压缩优化)js文件
HtmlWbpackPlugin自动在打包结束后生成html文件,并引入bundle.js
clearwebPackPlugin打包自动删除上次打包文件
mini-css-extract-plugin 提取CSS到一个单独的文件中
copy-webpack-plugin 复制文件或目录到执行区域,如vue的打包过程中,如果我们将一些文件放到public的目录下,那么这个目录会被复制到dist文件夹中
Plugin 是用来扩展 Webpack 功能的,通过在构建流程里注入钩子实现,它给 Webpack 带来了很大的灵活性。
Webpack 是通过plugins属性来配置需要使用的插件列表的。plugins属性是一个数组,里面的每一项都是插件的一个实例,在实例化一个组件时可以通过构造函数传入这个组件支持的配置属性。
ExtractTextPlugin插件的作用是提取出 JavaScript 代码里的 CSS 到一个单独的文件。
对此你可以通过插件的filename属性,告诉插件输出的 CSS 文件名称是通过[name]_[contenthash:8].css字符串模版生成的,里面的[name]代表文件名称,[contenthash:8]代表根据文件内容算出的8位 hash 值, 还有很多配置选项可以在ExtractTextPlugin的主页上查到。
Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。
bundle:是由webpack打包出来的文件
chunk:是指webpack在进行模块依赖分析的时候,代码分割出来的代码块
module:是开发中的单个模块
代码层面:
体积更小(Tree-shaking、压缩、合并),加载更快
编译高级语言和语法(TS、ES6、模块化、scss)
兼容性和错误检查(polyfill,postcss,eslint)
研发流程层面:
统一、高效的开发环境
统一的构建流程和产出标准
集成公司构建规范(提测、上线)
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
确定入口:根据配置中的 entry 找出所有的入口文件;
编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
单页应用可以理解为webpack的标准模式,直接在entry中指定单页应用的入口即可,这里不再赘述
多页应用的话,可以使用webpack的 AutoWebPlugin来完成简单自动化的构建,但是前提是项目的目录结构必须遵守他预设的规范。 多页应用中要注意的是:
每个页面都有公共的代码,可以将这些代码抽离出来,避免重复的加载。比如,每个页面都引用了同一套css样式表
随着业务的不断扩展,页面可能会不断的追加,所以一定要让入口的配置足够灵活,避免每次添加新页面还需要修改构建配置
Loader像一个"翻译官"把读到的源文件内容转义成新的文件内容,并且每个Loader通过链式操作,将源文件一步步翻译成想要的样子。
编写Loader时要遵循单一原则,每个Loader只做一种"转义"工作。 每个Loader的拿到的是源文件内容(source),可以通过返回值的方式将处理后的内容输出,也可以调用this.callback()方法,将内容返回给webpack。 还可以通过 this.async()生成一个callback函数,再用这个callback将处理后的内容输出出去。 此外webpack还为开发者准备了开发loader的工具函数集——loader-utils。
相对于Loader而言,Plugin的编写就灵活了许多。 webpack在运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。
压缩代码。删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用cssnano(css-loader?minimize)来压缩css
利用CDN加速。在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于output参数和各loader的publicPath参数来修改资源路径
删除死代码(Tree Shaking)。将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数--optimize-minimize来实现
提取公共代码。
多入口情况下,使用CommonsChunkPlugin来提取公共代码
通过externals配置来提取常用库
利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。
使用Happypack 实现多线程加速编译
使用webpack-uglify-parallel来提升uglifyPlugin的压缩速度。 原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度
使用Tree-shaking和Scope Hoisting来剔除多余代码
Npm是目前最大的 JavaScript 模块仓库,里面有来自全世界开发者上传的可复用模块。你可能只是JS模块的使用者,但是有些情况你也会去选择上传自己开发的模块。 关于NPM模块上传的方法可以去官网上进行学习,这里只讲解如何利用webpack来构建。
要支持CommonJS模块化规范,所以要求打包后的最后结果也遵守该规则。
Npm模块使用者的环境是不确定的,很有可能并不支持ES6,所以打包的最后结果应该是采用ES5编写的。并且如果ES5是经过转换的,请最好连同SourceMap一同上传。
Npm包大小应该是尽量小(有些仓库会限制包大小)
发布的模块不能将依赖的模块也一同打包,应该让用户选择性的去自行安装。这样可以避免模块应用者再次打包时出现底层模块被重复打包的情况。
UI组件类的模块应该将依赖的其它资源文件,例如.css文件也需要包含在发布的模块里。
CommonJS模块化规范的解决方案: 设置output.libraryTarget='commonjs2'使输出的代码符合CommonJS2 模块化规范,以供给其它模块导入使用
输出ES5代码的解决方案:使用babel-loader把 ES6 代码转换成 ES5 的代码。再通过开启devtool: 'source-map'输出SourceMap以发布调试。
Npm包大小尽量小的解决方案:Babel 在把 ES6 代码转换成 ES5 代码时会注入一些辅助函数,最终导致每个输出的文件中都包含这段辅助函数的代码,造成了代码的冗余。解决方法是修改.babelrc文件,为其加入transform-runtime插件
不能将依赖模块打包到NPM模块中的解决方案:使用externals配置项来告诉webpack哪些模块不需要打包。
对于依赖的资源文件打包的解决方案:通过css-loader和extract-text-webpack-plugin来实现,配置如下:
Vue UI组件库的按需加载 为了快速开发前端项目,经常会引入现成的UI组件库如ElementUI、iView等,但是他们的体积和他们所提供的功能一样,是很庞大的。 而通常情况下,我们仅仅需要少量的几个组件就足够了,但是我们却将庞大的组件库打包到我们的源码中,造成了不必要的开销。
不过很多组件库已经提供了现成的解决方案,如Element出品的babel-plugin-component和AntDesign出品的babel-plugin-import 安装以上插件后,在.babelrc配置中或babel-loader的参数中进行设置,即可实现组件按需加载了。
单页应用的按需加载 现在很多前端项目都是通过单页应用的方式开发的,但是随着业务的不断扩展,会面临一个严峻的问题——首次加载的代码量会越来越多,影响用户的体验。
通过import(*)语句来控制加载时机,webpack内置了对于import(*)的解析,会将import(*)中引入的模块作为一个新的入口在生成一个chunk。 当代码执行到import(*)语句时,会去加载Chunk对应生成的文件。import()会返回一个Promise对象,所以为了让浏览器支持,需要事先注入Promise polyfill
是一个映射关系,将打包后的文件隐射到源代码,用于定位报错位置
配置方式:
例如:devtool:‘source-map’
加不同前缀意义:
inline:不生成映射关系文件,打包进main.js
cheap: 1.只精确到行,不精确到列,打包速度快 2.只管业务代码,不管第三方模块
module:不仅管业务代码,而且管第三方代码
eval:执行效率最快,性能最好
最佳实践:
开发环境:cheap-module-eval-source-map
线上环境:cheap-mudole-source-map
借助webpack.HotModuleReplacementPlugin(),devServer开启hot
场景1:实现只刷新css,不影响js
场景2:js中实现热更新,只更新指定js模块
if (module.hot) {
module.hot.accept(’./library.js’, function() {
// Do something with the updated library module…
});
}
entry: {
home: resolve(__dirname, "src/home/index.js"),
about: resolve(__dirname, "src/about/index.js")
}
dependOn: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。
filename: 指定要输出的文件名称。
import: 启动时需加载的模块。
library: 指定 library 选项,为当前 entry 构建一个 library。
runtime: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为 false 以避免一个新的运行时 chunk。
publicPath: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址
模块热更新是webpack的一个功能,它可以使得代码修改之后,不用刷新浏览器就可以更新。
在应用过程中替换添加删出模块,无需重新加载整个页面,是高级版的自动刷新浏览器。
优点:只更新变更内容,以节省宝贵的开发时间。调整样式更加快速,几乎相当于在浏览器中更改样式
借助import()语法异步引入组件,实现文件懒加载:prefetch,preloading
webpack提倡多写异步代码,提升代码利用率,从而提升页面性能
先加载主业务文件,prefetch利用网络空闲时间,异步加载组件
import(/* webpackPrefetch: true / ‘LoginModal’);
preload和主业务文件一起加载,异步加载组件
import(/ webpackPreload: true */ ‘ChartingLibrary’);
浏览器在用户访问页面的时候,为了加快加载速度,会对用户访问的静态资源进行存储,但是每一次代码升级或者更新,都需要浏览器去下载新的代码,最方便和最简单的更新方式就是引入新的文件名称。
在webpack中,可以在output给出输出的文件制定chunkhash,并且分离经常更新的代码和框架代码,通过NameModulesPlugin或者HashedModulesPlugin使再次打包文件名不变。
指打包中去除那些引入了但在代码中没用到的死代码。在wepack中js treeshaking通过UglifyJsPlugin来进行,css中通过purify-CSS来进行。
webpack-dev-server使用内存来存储webpack开发环境下的打包文件,并且可以使用模块热更新,比传统的http服务对开发更加有效。
mode/–mode参数,新增了mode/–mode参数来表示是开发还是生产(development/production)production 侧重于打包后的文件大小,development侧重于goujiansud移除loaders,必须使用rules(在3版本的时候loaders和rules 是共存的但是到4的时候只允许使用rules)移除了CommonsChunkPlugin (提取公共代码),用optimization.splitChunks和optimization.runtimeChunk来代替支持es6的方式导入JSON文件,并且可以过滤无用的代码
git --version
git clone "地址"
git init
git config --global user.name "用户名"
git config --global user.email "邮箱"
git config user.name "用户名"
git config user.email "邮箱"
git config --global --list
git config -l
git status
红色的===》没有被git管理
绿色的===》存储在版本库暂缓区
git add .
****.代表所有文件
****指定某一个文件 git add index.js
git commit -m '注释内容'
git pull
git push
git diff
****查看某一个文件:git diff index.js
****查看所有文件 :git diff
git log
git reflog (简单形式)
回到上一个版本:git reset --hard HEAD^
回到指定版本 :git reset --hard 版本号
1、查看远程库
git remote -v
2 设置git远程库的用户名密码
git remote set-url origin [url]
如:git remote set-url origin http://username:[email protected]:3000/cb/ks.git
3、先删除再修改地址
git remote rm origin
git remote add origin [url]
例如: git remote add origin https://gitee.com/xxx/xxx.git
git branch 分支名称
git checkout 分支名称
git remote update origin --prune
git branch -r
git branch
git branch -vv
git push --set-upstream origin 分支名称
git branch -d 分支名称
git push origin --delete 分支名称
git merge 分支名称
注意:如果当前是在master分支下写入:git merge dev,那么master和dev会进行合并,相当于master + dev
终端运行:ssh-keygen -t rsa -C "邮箱"
cat ~/.ssh/id_rsa.pub //把运行后的代码复制粘贴到【SSH公钥】配置中
我们必须先把远程仓库的代码下拉,然后再push
gitflow (中、大型)
master 用于保存上线版本代码,创建了dev分支
develop 用于保存相对稳定版本的代码,所有的feature都是dev分支创建的
feature 用于开发某几个功能,不同的功能可能会创建不同的分支
***feature/login
***feature/list
release 用于代码上线前的准备(测试,bug修复),是dev创建的
***release/v1.0
bugfix 用于修复不紧急bug
hotfix 用于修复紧急bug
git有冲突 是两个人协商 找到冲突点 git里面有冲突提示 看看谁改 改完之后确保没有冲突 然后再次提交
当遇到多人协作修改同一个文件时出现冲突,我先将远程文件先git pull下来,手动修改冲突代码后,再git add ,git commit,git push再上传到远程仓库。如果pull也pull不下来提示冲突的话,可以先通过git stash暂存下来,然后再pull拉取,然后git stash pop,取出原来写的,手动修改,然后提交
规则表达式
表单验证
定义:
字面量 //
构造函数:new RegExp()
区别:
new RegExp()可以放变量
字面量不可以
test() 检测一个内容是否与正则匹配 匹配返回true 不匹配false
exec() 检测一个内容是否与正则匹配 匹配返回数组 不匹配null
g : 全文匹配
i : 不分区大小写
m : 换行(不常用)
^ 开始
$ 结束
() 把部分内容组合在一起
$1
$2
$3
...
运行前提 正则必须执行一次
例如:
var str = '2021-06-25';
var reg = /^(\d{4})-(\d{2})-(\d{2})$/;
console.log(str.replace(reg,'$1'))
//或者
reg.test(str)或者 reg.exec(str)
console.log(RegExp.$1,RegExp.$2,RegExp.$3)
* 重复最少0次 最多不限
\+ 重复最少一次 最多不限
?重复最少0次 最多一次
{n} 重复n次
{n,m} 最少重复n次 最多不限
{n,} 最少重复n次 最多不限
[] 匹配括号内任意一个
[^] 除了括号内任意字符
[0-9] 匹配0-9范围
[a-z] 匹配小写a-z
[A-Z] 匹配大写A-Z
[^a-z] 匹配任何不在指定范围内的任意字符
[a-zA-Z0-9] 匹配大小写 数字
\d 匹配数字
\D 匹配非数字
\w 匹配数字字母下划线
\W 匹配非数字字母下划线
\s 匹配空格
\S 匹配非空格
\b 匹配边界
\B 匹配非边界
\n 换行符
\0 查找 NUL字符
\f 查找换页符
\r 查找回车符
\t 查找制表符
\v 查找垂直制表符
. 除换行符以外的任意字符
? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。
| 替换,"或"操作
/ 转义
replace
match 类似于exec (查找返回对应的值[值是数组] 没有找到返回null)
**支持全局
贪婪模式 (/\d{3,6}/g) 取最大值
非贪婪模式(懒得模式) (/\d{3,6}?/g) 取最小值
var phone = /^1[345678]\d{9}$/g;
var phone =/^1\d{10}$/;
var email = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
vue中每个组件都是独立的,每个组件都有一个属于它的生命周期,
从一个组件创建、数据初始化、挂载、更新、销毁,这就是一个组件所谓的生命周期。
1. 有哪些生命周期
系统自带:
beforeCreate 组件创建之前
created 组件创建之后
beforeMount 组价挂载到页面之前执行
mounted 组件挂载到页面之后执行
beforeUpdate 组件更新之前
updated 组件更新之后
beforeDestroy 组件销毁之前
destroyed 组件销毁后
errorCaptured
2. 一旦进入到页面或者组件,会执行哪些生命周期,顺序。
beforeCreate
created
beforeMount
mounted
3. 在哪个阶段有$el,在哪个阶段有$data
beforeCreate 啥也没有
created 有data没有el
beforeMount 有data没有el
mounted 都有
4. 如果加入了keep-alive会多俩个生命周期
activated、deactivated
5. 如果加入了keep-alive,第一次进入组件会执行哪些生命?
beforeCreate
created
beforeMount
mounted
activated
6. 如果加入了keep-alive,第二次或者第N次进入组件会执行哪些生命周期?
只执行一个生命周期:activated
setup 开始创建组件
onBeforeMount 组价挂载到页面之前执行
onMounted 组件挂载到页面之后执行
onBeforeUpdate 组件更新之前
onUpdated 组件更新之后
onBeforeUnmount 组件销毁之前
onUnmounted 组件销毁后
onErrorCaptured
Vue2--------------vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
errorCaptured -> onErrorCaptured
渲染过程:
⽗组件挂载完成⼀定是等⼦组件都挂载完成后,才算是⽗组件挂载完,所以⽗组件的mounted在⼦组件mouted之后
⽗beforeCreate -> ⽗created -> ⽗beforeMount -> ⼦beforeCreate -> ⼦created -> ⼦beforeMount-> ⼦mounted -> ⽗mounted
⼦组件更新过程:
1. 影响到⽗组件: ⽗beforeUpdate -> ⼦beforeUpdate->⼦updated -> ⽗updted
2. 不影响⽗组件: ⼦beforeUpdate -> ⼦updated
⽗组件更新过程:
1. 影响到⼦组件: ⽗beforeUpdate -> ⼦beforeUpdate->⼦updated -> ⽗updted
2. 不影响⼦组件: ⽗beforeUpdate -> ⽗updated
销毁过程:
⽗beforeDestroy -> ⼦beforeDestroy -> ⼦destroyed -> ⽗destroyed
看起来很多好像很难记忆,其实只要理解了,不管是哪种情况,都⼀定是⽗组件等待⼦组件完成后,才
会执⾏⾃⼰对应完成的钩⼦,就可以很容易记住
DOM 渲染在 mounted 周期中就已经完成
组件化就是可以将页面和页面中可复用的元素都看做成组件,写页面的过程,就是写组件,然后页面是由这些组件“拼接“起来的组件树
数据驱动就是让我们只关注数据层,只要数据变化,页面(即视图层)会自动更新,至于如何操作dom,完全交由vue去完成,咱们只关注数据,数据变了,页面自动同步变化了,很方便
v-if:根据表达式的值的真假条件渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建
v-show:根据表达式之真假值,切换元素的 display CSS 属性。
v-for:循环指令,基于一个数组或者对象渲染一个列表,vue 2.0以上必须需配合 key值 使用。
v-bind:动态地绑定一个或多个特性,或一个组件 prop 到表达式。
v-on:用于监听指定元素的DOM事件,比如点击事件。绑定事件监听器。
v-model:实现表单输入和应用状态之间的双向绑定
v-pre:跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
v-once:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
1. 是什么
vue系统自带的一个组件,功能:是来缓存组件的。===》提升性能
2. 使用场景
就是来缓存组件,提升项目的性能。具体实现比如:首页进入到详情页,如果用户在首页每次点击都是相同的,那么详情页就没必要请求N次了,直接缓存起来就可以了,当然如果点击的不是同一个,那么就直接请求。
3.一旦使用keep-live会多出两个生命周期
activated
deactivated
4. 优势
在组件切换过程中,将状态保留在内存中,防止重复渲染DOM,减少了加载时间,提升了用户体验
1. 展示形式不同
v-if是 创建一个dom节点
v-show 是display:none 、 block
2. 使用场景不同
初次加载v-if要比v-show好,页面不会做加载盒子
频繁切换v-show要比v-if好,创建和删除的开销太大了,显示和隐藏开销较小
总结:v-if 会在切换过程中对条件块的事件监听器和⼦组件进⾏销毁和重建,如果初始条件是false,则什么 都不做,直到条件第⼀次为true时才开始渲染模块。
v-show 只是基于css进⾏切换,不管初始条件是什么,都会渲染。
所以, v-if 切换的开销更⼤,⽽ v-show 初始化渲染开销更⼤,在需要频繁切换,或者切换的部分 dom很复杂时,使⽤ v-show 更合适。
渲染后很少切换的则使⽤ v-if 更合适
v-for的优先级要比v-if高
证明这件事在vue源码11002行左右:
if (el.staticRoot && !el.staticProcessed) {
return genStatic(el, state)
} else if (el.once && !el.onceProcessed) {
return genOnce(el, state)
} else if (el.for && !el.forProcessed) {
return genFor(el, state)
} else if (el.if && !el.ifProcessed) {
return genIf(el, state)
} else if (el.tag === 'template' && !el.slotTarget && !state.pre) {
return genChildren(el, state) || 'void 0'
} else if (el.tag === 'slot') {
return genSlot(el, state)
注:v-if和v-for不要写在同一个节点上,要不性能很差(v-if写在父节点上)
首先不要把 v-if 与 v-for 用在同一个元素上,原因:v-for 比 v-if 优先,
如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染
很小一部分的时候
当 v-for 和 v-if 处于同⼀个节点时, v-for 的优先级⽐ v-if 更⾼,这意味着 v-if 将分别重复
运⾏于每个 v-for 循环中。如果要遍历的数组很⼤,⽽真正要展示的数据很少时,这将造成很⼤的性能浪费。
这种场景建议使⽤ computed ,先对数据进⾏过滤
key 是给每个 vnode 指定的唯⼀ id ,在同级的 vnode diff 过程中,可以根据 key 快速的对⽐,
来判断是否为相同节点,并且利⽤ key 的唯⼀性可以⽣成 map 来更快的获取相应的节点。
另外指定 key 后,就不再采⽤“就地复⽤”策略了,可以保证渲染的准确性
它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
当以数组的下标index作为index值时,其中一个元素(如增删改查)发生了变化就有可能导致所有元素的key值发生变化
为什么不用index作为key呢,是因为,如果在一个v-for list里面,删除中间的一个item,这个时候这个item后面所有的index都会变化,那么diff就会计算出后面的item的key-index映射都发生了变化,就会全部重新渲染,大大影响了性能。而且这也会导致一些bug,比如当删除了item2的时候,再选中item3就会变成选中item4
是什么?
用来获取dom
场景?
如果项目中使用插件,并且插件是要获取dom的,就可以使用ref
作用
ref 被用来给 DOM 元素或子组件注册引用信息。引用信息会根据父组件的 $refs 对象进行注册。
如果在普 通的 DOM 元素上使用,引用信息就是元素; 如果用在子组件上,引用信息就是组件实例
注意:只要想要在 Vue 中直接操作 DOM 元素,就必须用 ref 属性进行注册
是什么?
当dom更新完毕执行内部代码
场景?
使用插件时候会用到,例如:new Swiper这个插件可能会获取到当前元素的宽度或者高度,等dom加载完毕再去获取宽度或者高度就不会有问题了
插槽就是子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的 标签。
描述:
默认插槽就是指没有名字的插槽,子组件未定义的名字的插槽,父级将会把 未指定插槽的填充的内容填充到默认插槽中。
描述:
具名插槽其实就是给插槽娶个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中。
描述:
作用域插槽其实就是带数据的插槽,即带参数的插槽,简单的来说就是子组件提供给父组件的参数,该参数仅限于插槽中使用,父组件可根据子组件传过来的插槽数据来进行不同的方式展现和填充插槽内容。
1. 作用:让样式在本组件中生效,不影响其他组件。
2. 原理:给节点新增自定义属性,然后css根据属性选择器添加样式。
在Vue文件中的style标签上有一个特殊的属性,scoped。当一个style标签拥有scoped属性时候,它的css样式只能用于当前的Vue组件,可以使组件的样式不相互污染。如果一个项目的所有style标签都加上了scoped属性,相当于实现了样式的模块化
stylus样式穿透使用:>>>
sass和less使用:/deep/
通用使用: :v-deep
1.props/$emit:可以实现父子组件的双向通信,在日常的父子组件通信中一般会作为我们的最常用选择。
2.v-slot:可以实现父子组件单向通信(父向子传值),在实现可复用组件,向组件中传入DOM节点、html等内容以及某些组件库的表格值二次处理等情况时,可以优先考虑v-slot。
3.$refs/$parent/$children/$root:可以实现父子组件双向通信,其中 $root可以实现根组件实例向子孙组件跨级单向传值。在父组件没有传递值或通过v-on绑定监听时,父子间想要获取彼此的属性或方法可以考虑使用这些api。
4.$attrs/$listeners:能够实现跨级双向通信,能够让你简单的获取传入的属性和绑定的监听,并且方便地向下级子组件传递,在构建高级组件时十分好用。
5.provide/inject:可以实现跨级单向通信,轻量地向子孙组件注入依赖,这是你在实现高级组件、创建组件库时的不二之选。
6.eventBus:可以实现全局通信,在项目规模不大的情况下,可以利用eventBus实现全局的事件监听。但是eventBus要慎用,避免全局污染和内存泄漏等情况。
7.Vuex:可以实现全局通信,是vue项目全局状态管理的最佳实践。在项目比较庞大,想要集中式管理全局组件状态时,那么安装Vuex准没错
因为一个组件是可以共享的,但他们的data是私有的,所以每个组件都要return一个新的data对象,返回一个唯一的对象,不要和其他组件共用一个对象
当data定义为对象后,这就表示所有的组件实例共⽤了⼀份data数据,因此,⽆论在哪个组件实例中修改了data,都会影响到所有的组件实例。组件中的data写成⼀个函数,数据以函数返回值形式定义,这样每复⽤⼀次组件,就会返回⼀份新的data,类似于给每个组件实例创建⼀个私有的数据空间,让各个组件实例维护各⾃的数据。⽽单纯的写成对象形式,就使得所有组件实例共⽤了⼀份data,就会造成⼀个变了全都会变的结果
watch: {
obj: {
handler () { // 执行回调
// do something
},
deep: true, // 是否进行深度监听
immediate: true // 是否初始执行handler函数
}
}
computed:计算属性
可以监听某些数据的变化,并且有缓存。
如果一进入页面调用,就会触发
methods : 可以放入函数
没有缓存
如果一进入页面调用,就会触发
watch :监听(路由和数据)
当数据发生改变时,才会触发
可以得到现在的值和过去的值
1. computed vs methods区别
computed是有缓存的
methods没有缓存
2. computed vs watch区别
watch是监听,数据或者路由发生了改变才可以响应(执行)
computed计算某一个属性的改变,如果某一个值改变了,计算属性会监听到进行返回
watch是当前监听到数据改变了,才会执行内部代码
methods中都是封装好的函数,无论是否有变化只要触发就会执行
computed:是vue独有的特性计算属性,可以对data中的依赖项再重新计算,得到一个新值,应用到视图中
和methods本质区别是computed是可缓存的,也就是说computed中的依赖项没有变化,则computed中的值就不会重新计算,而methods中的函数是没有缓存的。
Watch是监听data和计算属性中的新旧变化。
自定义指令也像组件那样存在钩子函数:
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用
unbind:只调用一次,指令与元素解绑时调用
所有的钩子函数的参数都有以下:
el:指令所绑定的元素,可以用来直接操作 DOM
binding:一个对象,包含以下 property
`name`:指令名,不包括 v- 前缀。
`value`:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
`oldValue`:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
`expression`:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
`arg`:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
`modifiers`:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
`vnode`:Vue 编译生成的虚拟节点
`oldVnode`:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用
vue
中说说你知道的自定义指令自定义指令两种:一种全局自定义指令,vue.js对象提供了directive方法,可以用来自定义指令,directive方法接收两个参数,一个是指令名称,另一个是函数;
第二种是局部自定义指令,通过组件的directives属性定义。
Vue 的 Observer 对数组做了单独的处理,对数组的⽅法进⾏编译,并赋值给数组属性的 __proto__
属性上,因为原型链的机制,找到对应的⽅法就不会继续往上找了。编译⽅法中会对⼀些会增加索引的
⽅法( push , unshift , splice )进⾏⼿动 observe。
props ===> methods ===> data ===> computed ===>watch
state、getters、mutations、actions、modules
state 类似于组件中data,存放数据
getters 类型于组件中computed
mutations 类似于组件中methods
actions 提交mutations的
modules 把以上4个属性再细分,让仓库更好管理
什么场景用Vuex:共享、方便管理、方便维护、组件传值......
项目:购物车数据,订单数据,用户的登录信息....
vuex是一个状态管理工具,主要解决大中型复杂项目的数据共享问题,主要包括state,actions,mutations,getters和modules 5个要素,主要流程:组件通过dispatch到 actions,actions是异步操作,再actions中通过commit到mutations,mutations再通过逻辑操作改变state,从而同步到组件,更新其数据状态,而getters相当于组件的计算属性对,组件中获取到的数据做提前处理的.再说到辅助函数的作用
Vuex是单向数据流
单向数据流主要是vue 组件间传递数据是单向的,即数据总是由父组件传递给子组件,子组件在其内部维护自己的数据,但它无权修改父组件传递给它的数据,当开发者尝试这样做的时候,vue 将会报错。这样做是为了组件间更好的维护。
在开发中可能有多个子组件依赖于父组件的某个数据,假如子组件可以修改父组件数据的话,一个子组件变化会引发所有依赖这个数据的子组件发生变化,所以 vue 不推荐子组件修改父组件的数据
mutaitons : 都是同步事物
actions : 可以包含任意异步操作
***在调试中就看出来
Vuex本身不是持久化存储
1. 使用localStorage自己写
2. 使用vuex-persist插件
vue.config.js
module.exports = {
publicPath:'./',
devServer: {
proxy: 'http://localhost:3000'
}
}
1. 自测==>修改路由模式
2. 代理不生效,使用ENV
3. 修改路径
路由模式有俩种:history、hash
区别:
1. 表现形态不同
history:http://localhost:8080/about
hash:http://localhost:8080/#/about
2. 跳转请求
history : http://localhost:8080/id ===>发送请求
hash : 不会发送请求
3. 打包后前端自测要使用hash,如果使用history会出现空白页
1. url 展示上,hash 模式有“#”,history 模式没有
const code = generate(ast, options)
2. 刷新⻚⾯时,hash 模式可以正常加载到 hash 值对应的⻚⾯,⽽ history 没有处理的话,会返回
404,⼀般需要后端将所有⻚⾯都配置重定向到⾸⻚路由。
3. 兼容性。hash 可以⽀持低版本浏览器和 IE。
hash 模式:
# 后⾯ hash 值的变化,不会导致浏览器向服务器发出请求,浏览器不发出请求,就不会刷新⻚
⾯。同时通过监听 hashchange 事件可以知道 hash 发⽣了哪些变化,然后根据 hash 变化来实现
更新⻚⾯部分内容的操作。
history 模式:
history 模式的实现,主要是 HTML5 标准发布的两个 API, pushState 和 replaceState ,这
两个 API 可以在改变 url,但是不会发送请求。这样就可以监听 url 变化来实现更新⻚⾯部分内容
的操作
SPA跳转是一个页面进行切换
传统页面跳转就是跳转不同的html了
SPA对于seo部分不是特别好,只能收录一个
传统的页面对于seo比较好,多个html文件收录
SPA是什么?单页面应用
缺点:
1. SEO优化不好
2. 性能不是特别好
1. 显式
http://localhost:8080/about?a=1
1.1 传:this.$router.push({
path:'/about',
query:{
a:1
}
})
1.2 接:this.$route.query.a
2. 隐式
http://localhost:8080/about
2.1 传:this.$router.push({
name:'About',
params:{
a:1
}
})
2.2 接:this.$route.params.a
全局、路由独享、组件内
1. 全局
beforeEach、beforeResolve、afterEach
2. 路由独享
beforeEnter
3. 组件内
beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
使用场景:判断是否登录,如果登录就next否则就跳转到登录页面
场景:要去拦截,判断用户是否是登录状态。功能:进入地址管理,用户如果没有登录是进入不了地址管理(在进入之前判断拦截),需要先登录
场景:详情页(文章、商品)
router.js配置:
{
path: "/list",
name: "List",
children:[
{
path:"/list/:id",
name:'Details',
component: () =>
import("../views/Details.vue"),
}
],
component: () =>
import("../views/List.vue"),
},
接:this.$route.params.id
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。
通过Object.defineProperty()来实现数据劫持的。
1.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
2.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
3.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
Vue 的响应式是通过 Object.defineProperty 对数据进⾏劫持,并结合观察者模式实现。 Vue 利⽤Object.defineProperty 创建⼀个 observe 来劫持监听所有的属性,把这些属性全部转为 getter和 setter 。
Vue 中每个组件实例都会对应⼀个 watcher 实例,它会在组件渲染的过程中把使⽤过的数据属性通过 getter 收集为依赖。之后当依赖项的setter 触发时,会通知 watcher ,从⽽使它关联的组件重新渲染。
Vue3.x改⽤ Proxy 替代Object.defineProperty。因为Proxy可以直接监听对象和数组的变化,并且有多达13种拦截⽅法。并且作为新标准将受到浏览器⼚商重点持续的性能优化。
判断当前Reflect.get的返回值是否为Object,如果是则再通过 reactive ⽅法做代理, 这样就实现了深度观测。
我们可以判断key是否为当前被代理对象target⾃身属性,也可以判断旧值与新值是否相等,只有满⾜以上两个条件之⼀时,才有可能执⾏trigger
监测机制的改变(Object.defineProperty —> Proxy)
模板
对象式的组件声明⽅式 (class)
使⽤ts
其它⽅⾯的更改:⽀持⾃定义渲染器、 ⽀持 Fragment(多个根节点)和 Protal(在 dom 其他部
分渲染组建内容)组件、基于 treeshaking 优化,提供了更多的内置功能
MVVM是 Model-View-ViewModel 缩写,也就是把 MVC 中的 Controller 演变成 ViewModel 。
Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并⾃动将数据渲染到⻚⾯中,视图变化的时候会通知viewModel层更新数据
1. 响应式:vue如何监听data的属性变化
2. 模板解析:vue的模板是如何被解析的
3. 渲染:vue模板是如何被渲染成HTML的
1、build:应用依赖第三方模块
2、cache:该配置项让你开启组件缓存策略以提升渲染性能。
3、css:该配置项用于定义应用的全局(所有页面均需引用的)样式文件、模块或第三方库。
4、dev:该配置项用于配置 Nuxt.js 应用是开发还是生产模式。
5、env:该配置项用于定义应用客户端和服务端的环境变量。
6、generate:该配置项用于定义每个动态路由的参数,Nuxt.js 依据这些路由配置生成对应目录结构的静态文件。
7、head:该配置项用于配置应用默认的meta标签。
8、loading:该配置项用于个性化定制 Nuxt.js 使用的加载组件。
9、modules:该配置项允许您将Nuxt模块添加到项目中。
10、modulesDir:该配置项允许您定义Nuxt.js应用程序的node_modules文件夹
11、plugins:该配置项用于配置那些需要在 根vue.js应用 实例化之前需要运行的 Javascript 插件。
12、rootDir:该配置项用于配置 Nuxt.js 应用的根目录。
13、router:该配置项可用于覆盖 Nuxt.js 默认的 vue-router 配置。
14、srcDir:该配置项用于配置应用的源码目录路径。
15、transition:该配置项用于个性化配置应用过渡效果属性的默认值。
其实就是数据,把dom变成数据结构。
vue的虚拟DOM有什么好处?
⾸先了解浏览器显⽰⽹页经历的5个过程
1、解析标签,⽣成元素树(DOM树)
2、解析样式,⽣成样式树
3、⽣成元素与样式的关系
4、⽣成元素的显⽰坐标
5、显⽰页⾯
修改真实DOM
每修改⼀个元素,那么这5个过程都要重新⾛⼀次。修改10个元素就⾛10遍。
修改虚拟DOM
虚拟DOM存储在内存中,对10个元素的修改是在虚拟DOM中进⾏,修改完后,⽐较虚拟DOM和真实DOM的差异,当有差异时,再⼀次过
去更新⽹页的显⽰,⽽不是⾛10遍过程。
虚拟 DOM 好处
速度快,减⼩了页⾯渲染过程的次数
虚拟DOM具有批处理和高效的Diff算法,最终表现在DOM上的修改只是变更的部分,可以保证非常高效的渲染,优化性能.
缺点:
首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。
利用diff算法可以更多提升dom之间对比的性能(采用虚拟dom数据进行对比)。
搭建环境
npm init -y
cnpm install webpack@5 webpack-cli@3 webpack-dev-server@3 -S
cnpm install snabbdom -S
新建webpack.config.js
配置webpack.config.js
M就是data的model层
V就是view视图层
VM就是理解为v-model原理实现,通过view更新model
微信小程序采用 JavaScript、WXML、WXSS 三种技术进行开发,本质就是一个单页面应用,所有的页面渲染和事件处理,都在一个页面内进行,但又可以通过微信客户端调用原生的各种接口
微信的架构,是数据驱动的架构模式,它的 UI 和数据是分离的,所有的页面更新,都需要通过对数据的更改来实现
小程序分为两个部分 webview 和 appService 。其中 webview 主要用来展现 UI ,appService 有来处理业务逻辑、数据及接口调用。它们在两个进程中运行,通过系统层 JSBridge 实现通信,实现 UI 的渲染、事件的处理
小程序直接 this.data 的属性是不可以同步到视图的,必须调用:
this.setData({
// 这里设置
})
WXSS 和 CSS 类似,不过在 CSS 的基础上做了一些补充和修改
rpx
rpx 是响应式像素,可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx。如在 iPhone6 上,屏幕宽度为 375px,共有 750 个物理像素,则 750rpx = 375px = 750 物理像素
@import
标识符来导入外联样式。@import
后跟需要导入的外联样式表的相对路径,用;表示语句结束/** index.wxss **/
@import './base.wxss';
.container{
color: red;
}
尺寸单位
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
设备 rpx换算px (屏幕宽度/750) px换算rpx (750/屏幕宽度)
iPhone5 1rpx = 0.42px 1px = 2.34rpx
iPhone6 1rpx = 0.5px 1px = 2rpx
iPhone6 Plus 1rpx = 0.552px 1px = 1.81rpx
建议: 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。
注意: 在较小的屏幕上不可避免的会有一些毛刺,请在开发时尽量避免这种情况
onLoad 页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数
onShow() 页面显示/切入前台时触发
onReady() 页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互
onHide() 页面隐藏/切入后台时触发。 如 navigateTo 或底部 tab 切换到其他页面,小程序切入后台等
onUnload() 页面卸载时触发。如 redirectTo 或 navigateBack 到其他页面时
onPullDownRefresh() 触发下拉刷新时执行
onReachBottom() 页面触底时执行
onShareAppMessage() 页面被用户分享时执行
onPageScroll() 页面滚动时执行
onResize() 页面尺寸变化时执行
wx.navigateTo()
, wx.redirectTo()
, wx.switchTab()
, wx.navigateBack()
, wx.reLaunch()
的区别wx.navigateTo():保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面
wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
wx.switchTab():跳转到 abBar 页面,并关闭其他所有非 tabBar 页面
wx.navigateBack()关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层
wx.reLaunch():关闭所有页面,打开到应用内的某个页面
app.js
文件中定义全局变量 globalData
, 将需要存储的信息存放在里面// app.js
App({
// 全局变量
globalData: {
userInfo: null
}
})
使用的时候,直接使用 getApp()
拿到存储的信息
wx.navigateTo
与 wx.redirectTo
的时候,可以将部分数据放在 url
里面,并在新页面 onLoad
的时候初始化/pageA.js
// Navigate
wx.navigateTo({
url: '../pageD/pageD?name=raymond&gender=male',
})
// Redirect
wx.redirectTo({
url: '../pageD/pageD?name=raymond&gender=male',
})
// pageB.js
...
onLoad: function(option){
console.log(option.name + 'is' + option.gender)
this.setData({
option: option
})
}
需要注意的问题:
`wx.navigateTo` 和 `wx.redirectTo` 不允许跳转到 `tab` 所包含的页面
`onLoad` 只执行一次
Storage
相关wx.setStorageSync('name','xxxx')
wx.getStorageSync(name)
子组件在js中获取父组件中传过来的值
// child.js
properties: { // 在这里拿到了数据之后可以直接使用了(在wxml模板渲染,或者js中使用this.data.fatherName/this.properties.fatherName 都能获取到),不要直接修改properties属性中的数据
fatherName: {
type: String
},
fatherAge: Number
}
子组件触发自定义事件,传递数据给父组件
tab
子组件在点击事件中主动触发自定义事件
// child.js
onChangeAnchor(e) {
var index = e.target.dataset.index
//子组件传值给父组件
let myEventDetail = { // 需要传递什么数据就在这个对象中写
val: index
}
// myEventDetail 对象,提供给事件监听函数的参数数据
// changeNaviIndex 是自定义名称事件,父组件中监听使用
this.triggerEvent('changeNaviIndex', myEventDetail)
}
父组件wxml中监听子组件的自定义事件
父组件的js中书写事件函数,获取子组件传递过来的数据
// parents.js
onGetIndex( paramData) { // paramData参数就是子组件的this.triggerEvent()
console.log(paramData.detail.val) // 0
}
app.json进行配置
"window":{
"navigationStyle":"custom",
}
1、提高页面加载速度
2、用户行为预测
3、减少默认 data 的大小
4、组件化方案
即用即走,不用安装,省流量,省安装时间,不占用桌面
依托微信流量,天生推广传播优势
开发成本比 App 低
用户留存,即用即走是优势,也存在一些问题
入口相对传统 App 要深很多
限制较多,页面大小不能超过1M。不能打开超过5个层级的页面
小程序支持 ES6 语法
在返回成功的回调里面处理逻辑
Promise 异步
async/await
首先在全局 config 中的 window 配置 enablePullDownRefresh
在 Page 中定义 onPullDownRefresh 钩子函数,到达下拉刷新条件后,该钩子函数执行,发起请求方法
请求返回后,调用 wx.stopPullDownRefresh 停止下拉刷新
相同点:首先他们都是作为点击事件函数,就是点击时触发。在这个作用上他们是一样的,可以不做区分
不同点:他们的不同点主要是bindtap是不会阻止冒泡事件的,catchtap是阻值冒泡的
如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过 unionid 来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的 unionid 是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid 是相同的
工具==》详情==》本地设置==》不校验合法域名 : 项目上线前URL一定要请求到(不勾选也可以请求到数据)
应用生命周期、页面生命周期、组件生命周期
在工具中,打if出现的条件编译
例如:
这是h5端
1. http请求
能不能减少(能不能合并)
2. 图片的雪碧图
3. script标签位置
4. link标签(css引入)
1. 图片懒加载
2. 响应式图片
3. webp代替其他格式
4. 小图标可以改用字体图标
1. 减少重绘和回流
2. 改变位置使用transform
3. 动画尽量用requestAnimationFrame,不要用定时器
1. 长列表
2. 项目的html文件、css文件、图片、js文件压缩打包
1. keep-alive 缓存组件
2. 路由懒加载
3. 内容使用
v-if和v-show
computed、watch、methods
4. Object.freeze :冻结对象
5. 使用ui组件按需引入
(1) 减少http请求次数:CSS Sprites, JS、CSS源码压缩、图片大小控制合适;网页Gzip,CDN托管,data缓存 ,图片服务器。
(2) 前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数
(3) 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。
(4) 当需要设置的样式很多时设置className而不是直接操作style。
(5) 少用全局变量、缓存DOM节点查找的结果。减少IO读取操作。
(6) 避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)。
(7) 图片预加载,将样式表放在顶部,将脚本放在底部 加上时间戳。
1. 在ios键盘中首字母大写的问题?
2. ios日期转换NAN问题
具体就是,new Date('2020-11-12 00:00:00')在ios中会为NAN
解决方案:用new Date('2020/11/12 00:00:00')的日期格式,或者写个正则转换
3. 在移动端使用click事件有300ms延迟的问题
禁止双击缩放===》meta:user-scalabel=no
4. 移动端touch事件有穿透(点透)的问题,怎么解决?
4.1 阻止默认行为 : e.preventDefault();
4.2 fastclick.js
5. 安卓部分版本input的placeholder偏上
input{
line-height:normal;
}
前端:jsonp、vue的项目可以设置代理(打包后无效。解决:.ENV文件)
后端:CORS
1. 端口不同
http :80端口
https :443端口
2. https比http更加安全
***https就是证书
用户输入的文本框,需要替换某些特殊字符( <> ... )
用户输入的文本框中不可以有特殊符号( 引号、空格 )
token是后端生成的
token + cookie : 前端判断是否过期
token + localStorage : 后端判断是否过期给前端返回code码,前端判断code码等于多少
1. 网站一定要多页面
2. title、描述、关键字
3. 图片、音频、视频、的标签属性特别关键
4. 网站不能出现死链接
优点:
1. seo会特别好
2. 人员成本下降(后端就可以做了)
3. 无需请求接口,压力在服务器,如果服务器比较好,用户打开网页速度比分离的要快。( 但是有一个问题,是整个网页打开或者不打开 )
缺点:
1. 项目不好维护(项目大)
2. 如果网页没出来,后端是不可以套数据的
优点:
1. 项目好维护( 分责任 )
缺点:
1. 人员成本会高
2. seo不好 ===>有对应解决方案的 【预渲染和服务端渲染】
3. 如果接口请求次数特别多,并且没办法优化合并请求,用户打开网页速度就会慢
本身:
1. 网页先出来
2. 请求接口
3. 接口数据放在页面上
预渲染:
1. 请求接口
2. 接口数据放在页面上
3. 网页先出来
服务端渲染:
1. nodejs服务 请求接口
2. 后端服务给nodejs返回数据
3. nodejs服务,把数据给client
4. 打开页面
1. 预渲染(prerender-spa-plugin)
实现原理:相当于html预备加载,但是要等数据完成后
1. 请求接口数据
2. 打开页面
场景:
1. 如果一个网站,不是所有页面都做 seo,可以用。
2. 他不支持动态路由
3. 动态的title描述关键词
2. 服务端渲染 : SSR
实现原理:相当于多了一个后端服务
1. nodejs服务 请求接口
2. 后端服务给nodejs返回数据
3. nodejs服务,把数据给client
4. 打开页面
场景:
1. 整个网站都做seo,可以实现动态title
2. 多页面
3. 可以数据爬去
缺点 : 不支持localStorage、cookie
SSR:服务端渲染,指的是服务端直接吐出具有数据的HTML页面,而不是在客户端拼接的HTML。相对的则是CSR(客户端渲染),客户端渲染指的是在客户端通过Ajax请求来拼装数据,此时所有页面是在客户端拼接好的
角色管理
我们那个角色是分两大模块的
一个是根据角色划分权限的
一个是自定义权限
角色是指普通员工 经理级之类的 我需要做的就是角色管理 可以增加的就是副经理之类的岗位 可以做增删改查,然后每一个角色根据类型不同是需要划分菜单的,然后有做一个用户管理,商品管理 供应商管理 地图管理之类的,这个菜单是动态路由,动态加载进来的 在角色管理有个权限分配,比如说分配一个经理 它具有商品管理 订单管理的权限 那这几块选上以后他登录进去就有这三块管理的功能
自定义管理就是一些特殊的权限 比如张三的角色是一个经理 ,可能它具有商品管理 订单管理等但他还需要地图管理之类的 这时候就需要单独的勾选了
面试官问怎么学前端的,这种问题考察什么?总结四个字:学习能力
面试官想知道以下内容:
1.1 学习能力
12 总结能力
1.3动手能力(这个也是面试官最想知道的,毕竟学以致用)
可以这样回答:
一开始学习前端,主要靠视频以及书籍,主要是总结很多知识点,但是发现学习过程中理论大于实操,所以自己把知识点总结后就开始找项目实操,这样一步一步成长起来的,那么在公司中也会碰到很多问题值得学习,一般都是自己查找原因或者和同事交流进行解决,然后自己总结出文档,方便日后查看和积攒经验。所以我感觉我的学习都是实操加总结。
1. http请求
能不能减少(能不能合并)
2. 图片的雪碧图
3. script标签位置
4. link标签(css引入)
1. 图片懒加载
2. 响应式图片
3. webp代替其他格式
4. 小图标可以改用字体图标
1. 减少重绘和回流
2. 改变位置使用transform
3. 动画尽量用requestAnimationFrame,不要用定时器
1. 长列表
2. 项目的html文件、css文件、图片、js文件压缩打包
1. keep-alive 缓存组件
2. 路由懒加载
3. 内容使用
v-if和v-show
computed、watch、methods
4. Object.freeze :冻结对象
纯å
5. 使用ui组件按需引入
(1) 减少http请求次数:CSS Sprites, JS、CSS源码压缩、图片大小控制合适;网页Gzip,CDN托管,data缓存 ,图片服务器。
(2) 前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数
(3) 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。
(4) 当需要设置的样式很多时设置className而不是直接操作style。
(5) 少用全局变量、缓存DOM节点查找的结果。减少IO读取操作。
(6) 避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)。
(7) 图片预加载,将样式表放在顶部,将脚本放在底部 加上时间戳。
1. 在ios键盘中首字母大写的问题?
2. ios日期转换NAN问题
具体就是,new Date('2020-11-12 00:00:00')在ios中会为NAN
解决方案:用new Date('2020/11/12 00:00:00')的日期格式,或者写个正则转换
3. 在移动端使用click事件有300ms延迟的问题
禁止双击缩放===》meta:user-scalabel=no
4. 移动端touch事件有穿透(点透)的问题,怎么解决?
4.1 阻止默认行为 : e.preventDefault();
4.2 fastclick.js
5. 安卓部分版本input的placeholder偏上
input{
line-height:normal;
}
前端:jsonp、vue的项目可以设置代理(打包后无效。解决:.ENV文件)
后端:CORS
1. 端口不同
http :80端口
https :443端口
2. https比http更加安全
***https就是证书
用户输入的文本框,需要替换某些特殊字符( <> ... )
用户输入的文本框中不可以有特殊符号( 引号、空格 )
token是后端生成的
token + cookie : 前端判断是否过期
token + localStorage : 后端判断是否过期给前端返回code码,前端判断code码等于多少
1. 网站一定要多页面
2. title、描述、关键字
3. 图片、音频、视频、的标签属性特别关键
4. 网站不能出现死链接
优点:
1. seo会特别好
2. 人员成本下降(后端就可以做了)
3. 无需请求接口,压力在服务器,如果服务器比较好,用户打开网页速度比分离的要快。( 但是有一个问题,是整个网页打开或者不打开 )
缺点:
1. 项目不好维护(项目大)
2. 如果网页没出来,后端是不可以套数据的
优点:
1. 项目好维护( 分责任 )
缺点:
1. 人员成本会高
2. seo不好 ===>有对应解决方案的 【预渲染和服务端渲染】
3. 如果接口请求次数特别多,并且没办法优化合并请求,用户打开网页速度就会慢
本身:
1. 网页先出来
2. 请求接口
3. 接口数据放在页面上
预渲染:
1. 请求接口
2. 接口数据放在页面上
3. 网页先出来
服务端渲染:
1. nodejs服务 请求接口
2. 后端服务给nodejs返回数据
3. nodejs服务,把数据给client
4. 打开页面
1. 预渲染(prerender-spa-plugin)
实现原理:相当于html预备加载,但是要等数据完成后
1. 请求接口数据
2. 打开页面
场景:
1. 如果一个网站,不是所有页面都做 seo,可以用。
2. 他不支持动态路由
3. 动态的title描述关键词
2. 服务端渲染 : SSR
实现原理:相当于多了一个后端服务
1. nodejs服务 请求接口
2. 后端服务给nodejs返回数据
3. nodejs服务,把数据给client
4. 打开页面
场景:
1. 整个网站都做seo,可以实现动态title
2. 多页面
3. 可以数据爬去
缺点 : 不支持localStorage、cookie
SSR:服务端渲染,指的是服务端直接吐出具有数据的HTML页面,而不是在客户端拼接的HTML。相对的则是CSR(客户端渲染),客户端渲染指的是在客户端通过Ajax请求来拼装数据,此时所有页面是在客户端拼接好的
角色管理
我们那个角色是分两大模块的
一个是根据角色划分权限的
一个是自定义权限
角色是指普通员工 经理级之类的 我需要做的就是角色管理 可以增加的就是副经理之类的岗位 可以做增删改查,然后每一个角色根据类型不同是需要划分菜单的,然后有做一个用户管理,商品管理 供应商管理 地图管理之类的,这个菜单是动态路由,动态加载进来的 在角色管理有个权限分配,比如说分配一个经理 它具有商品管理 订单管理的权限 那这几块选上以后他登录进去就有这三块管理的功能
自定义管理就是一些特殊的权限 比如张三的角色是一个经理 ,可能它具有商品管理 订单管理等但他还需要地图管理之类的 这时候就需要单独的勾选了
面试官问怎么学前端的,这种问题考察什么?总结四个字:学习能力
面试官想知道以下内容:
1.1 学习能力
12 总结能力
1.3动手能力(这个也是面试官最想知道的,毕竟学以致用)
可以这样回答:
一开始学习前端,主要靠视频以及书籍,主要是总结很多知识点,但是发现学习过程中理论大于实操,所以自己把知识点总结后就开始找项目实操,这样一步一步成长起来的,那么在公司中也会碰到很多问题值得学习,一般都是自己查找原因或者和同事交流进行解决,然后自己总结出文档,方便日后查看和积攒经验。所以我感觉我的学习都是实操加总结。