1、v-model默认的触发条件是input事件,加了.lazy修饰符之后,v-model会在change事件触发的时候去监听
2、:class 绑定变量 绑定对象 绑定一个数组 绑定三元表达式
:style 绑定变量 绑定对象 绑定函数返回值 绑定三元表达式
3、 组件中写name选项有什么作用
- 项目使用keep-alive时,可搭配组件name进行缓存过滤
- DOM做递归组件时需要调用自身name
- vue-devtools调试工具里显示的组见名称是由vue中组件name决定的
4、diff算法
(key的体现:不设key,newCh和oldCh只会进行头尾两端的相互比较,设key后,除了头尾两端的比较外,还会从用key生成的对象oldKeyToIdx中查找匹配的节点,所以为节点设置key可以更高效的利用dom。)
diff的过程就是调用patch函数,就像打补丁一样修改真实dom。
function patch (oldVnode, vnode) {
if (sameVnode(oldVnode, vnode)) {
patchVnode(oldVnode, vnode)
} else {
const oEl = oldVnode.el
let parentEle = api.parentNode(oEl) //取得oldvnode.el的父节点,parentEle是真实dom
createEle(vnode) //createEle(vnode)会为vnode创建它的真实dom,令vnode.el =真实dom
if (parentEle !== null) {
api.insertBefore(parentEle, vnode.el, api.nextSibling(oEl)) //parentEle将新的dom插入,移除旧的dom
api.removeChild(parentEle, oldVnode.el)
oldVnode = null
}
}
return vnode
function sameVnode (a, b) {
return (
a.key === b.key && // key值
a.tag === b.tag && // 标签名
a.isComment === b.isComment && // 是否为注释节点
// 是否都定义了data,data包含一些具体信息,例如onclick , style
isDef(a.data) === isDef(b.data) &&
sameInputType(a, b) // 当标签是<input>的时候,type必须相同
)
}
如果两个节点是一样的,那么就深入检查他们的子节点。如果两个节点不一样那就可以直接替换oldVnode:
当我们确定两个节点相同之后我们会对两个节点执行patchVnode方法:
当两个节点值得比较时
function patchVnode (oldVnode, vnode) {
const el = vnode.el = oldVnode.el
let i, oldCh = oldVnode.children, ch = vnode.children
if (oldVnode === vnode) return
if (oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text) {
api.setTextContent(el, vnode.text)
}else {
updateEle(el, vnode, oldVnode)
if (oldCh && ch && oldCh !== ch) {
updateChildren(el, oldCh, ch)
}else if (ch){
createEle(vnode) //create el's children dom
}else if (oldCh){
api.removeChildren(el)
}
}
}
这个函数做了以下事情:
找到对应的真实dom,称为el
判断Vnode和oldVnode是否指向同一个对象,如果是,那么直接return
如果他们都有文本节点并且不相等,那么将el的文本节点设置为Vnode的文本节点。
如果oldVnode有子节点而Vnode没有,则删除el的子节点
如果oldVnode没有子节点而Vnode有,则将Vnode的子节点真实化之后添加到el
如果两者都有子节点,则执行updateChildren函数比较子节点,这一步很重要
对比当前真实的DOM和虚拟DOM,在对比过程中直接更新真实DOM
只对比同一层级的变化
节点比较时有5中情况
- if (oldVnode === vnode),他们的引用一致,可以认为没有变化。
- if(oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text),文本节点的比较,需要修改,则会调用Node.textContent = vnode.text。
- if( oldCh && ch && oldCh !== ch ), 两个节点都有子节点,而且它们不一样,这样我们会调用updateChildren函数比较子节点,这是diff的核心,后边会讲到。
- else if (ch),只有新的节点有子节点,调用createEle(vnode),vnode.el已经引用了老的dom节点,createEle函数会在老dom节点上添加子节点。
- else if (oldCh),新节点没有子节点,老节点有子节点,直接删除老节点。
首屏加载优化
- 异步路由和异步加载
- 还有分屏加载, 按需加载, 延时加载图片等, cdn, 域名拆分
- webpack压缩HTML/CSS/JS,
- 首屏css单独提取内联,
- 关键资源Proload,
- 图片:不缩放,使用webp、小图片base64(3k大小,太大的话会增加css文件大小,Base64 跟 CSS 混在一起,大大增加了浏览器需要解析CSS树的耗时。),iconfont,
- gzip,
dns-prefetch, - 静态资源单独域名,去掉cookie
- 将资源放到不同的域下:浏览器同时从一个域下载资源的数目有限(chrome为6个),增加域可以提高并行下载量
- 减少回流重绘
事件捕获和事件冒泡
https://www.jianshu.com/p/c88c15c6074c
封装axios主要封装
封装处理配置(路径、时间、token)、统一管理接口、错误处理、不同形式的请求、消息提示、loading等。
div水平垂直居中
- 使用flex布局
div.parent {
display: flex;
justify-content: center;
align-items: center;
}
}
- 子元素绝对定位
div.parent {
position: relative;
}
}
div.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
- 知道子元素高度的情况下
/* 或者 */
div.child {
width: 50px;
height: 10px;
position: absolute;
top: 50%;
left: 50%;
margin-left: -25px;
margin-top: -5px;
}
}
/* 或 */
div.child {
width: 50px;
height: 10px;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
}
div.parent {
display: grid;
}
}
div.child {
justify-self: center;
align-self: center;
}
}
div.parent {
font-size: 0;
text-align: center;
&::before {
content: "";
display: inline-block;
width: 0;
height: 100%;
vertical-align: middle;
}
}
}
div.child{
display: inline-block;
vertical-align: middle;
}
}
5
div.parent{
display:flex;
}
}
div.child{
margin:auto;
}
}
computed原理
在initComputed中遍历每一个computed属性,创建对应的Watcher。在Watcher实例化过程中,计算computed属性结果,会对依赖的data进行取值,从而触发data的getter进行依赖收集,将当前Watcher加入到订阅者数组中。当computed属性依赖的data改变时,会触发data的setter通知订阅者更新,这个computed会重新计算。
浅拷贝是拷贝一层,深层次的对象级别的就拷贝引用;深拷贝是拷贝多层,每一级别的数据都会拷贝出来;
箭头函数和普通函数的区别
1、箭头函数是匿名函数,不能作为构造函数,即不能使用new来创建对象
2、箭头函数不能绑定arguments,需要用类似语法来实现 (...a)=>{拿到的是一个数组}
3、箭头函数没有原型属性
4、箭头函数没有自己的this
flex布局
flex-container有6个属性,包括flex-direction、flex-wrap、flex-flow、justify-content、align-items、align-content
其中
1、flex-direction主要来定义主轴的方向(默认我为row,还有row-reverse、column、column-reverse)
2、flex-wrap主要定义是否换行(默认nowrap、wrap、wrap-reverse)
3、flex-flow是flex-direction和flex-wrap的集合
4、justify-content用来定义项目在主轴上的对齐方式(flex-start,flex-end,center,space-between,space-around(2倍),space-evenly(均分))
5、align-items用来定义项目在交叉轴上如何对齐(flex-start,flex-end,center,baseline,stretch(默认值,如果item没有高度则会拉伸至整个container高度))
baseline是以文本基线来对齐的(项目的第一行文字的基线对齐)
6、align-content决定了多行的flex-items在交叉轴上的对齐方式。
和justify-content类似,不过轴换成了交叉轴
每一个item上也有6个属性,分别为order、flex-grow、flex-shrink、flex-basis、flex、align-self
(1)其中order定义每个item的排列顺序,数值越小排列越靠前
(2)flex-grow定义项目的放大比例,默认为0,即如果存在剩余空间也不放大。
flex-grow决定了items如何扩展,当flex container在主轴方向上有剩余size的时候flex-grow才会生效。
----若所有items的flex-grow总和sum超过1,每个flex item扩展的size为剩余的sizeflex-grow/num
----若总和不超过1,每个item扩展的size为剩余的sizeflex-grow
前端安全:
xss攻击,sql注入,CSRF攻击
前端性能优化
(1)资源的合并于压缩html压缩,css压缩,js压缩与混乱,公共文件合并
(2)服务端开启gzip
(3)懒加载 预加载
(4)缓存,分级缓存
200(from cache): 由expires / cache-control 控制。expires(http1.0有效)是绝对时间;cache-control(http1.1有效)是相对时间。两者都存在时,cache-control 覆盖 expires,只要没有失效,浏览器只访问自己的缓存。
304 : 由 last-modified / etag 控制。当上一层失效时或用户点击refresh,F5时,浏览器就会发送请求给服务器,如果服务器端没有变化,则返回304给浏览器。
200 :当浏览器本身没有缓存或者上一层失效时,或者用户点击了CTL + F5 时,浏览器直接去服务器下载最新数据。
url从输入到呈现经历的步骤。(性能优化)
1、浏览器查缓存,有直接返回,没有则从服务器取。
2、解析协议,主机,端口,path,开启网络线程
(每一个tab页面可以看作是浏览器内核进程,然后这个进程是多线程的,它有几大类子线程)
- GUI线程
- JS引擎线程
- 事件触发线程
- 定时器线程
- 网络请求线程
3、组装http报文
4、浏览器获取主机ip地址(dns 浏览器、本机、hosts)
DNS Prefetch 是让具有此属性的域名不需要用户点击链接就在后台解析,而域名解析和内容载入是串行的网络操作,所以这个方式能减少用户的等待时间,提升用户体验 。
5、拿到主机地址后,打开一个socket与主机建立三次握手
6、建立成功后发送http请求
7、服务器接收请求报文并解析。(若请求头中包含缓存验证,如果命中则返回304状态码)
8、服务器将相应报文返回浏览器
9、浏览器检查报文头中缓存信息,确认是否缓存
10、如果是gzip则先解码,后根据资源类型决定如何处理
11、解析html文档。
构建dom树,
解析过程中遇到图片、样式表、js文件则启动下载
构建cssom树
根据dom和cssom树构建渲染树(从dom树的根节点遍历所有可见节点)
for in和for of
for ... in 循环返回的值都是数据结构的 键值名。
遍历对象返回的对象的key值,遍历数组返回的数组的下标(key)。
for ... in 循环不仅可以遍历数字键名,还会遍历原型上的值和手动添加的其他键。如——例3
特别情况下, for ... in 循环会以任意的顺序遍历键名
总结一句: for in 循环特别适合遍历对象。
for of 循环用来获取一对键值对中的值,而 for in 获取的是 键名
一个数据结构只要部署了 Symbol.iterator 属性, 就被视为具有 iterator接口, 就可以使用 for of循环。
例1这个对象,没有 Symbol.iterator这个属性,所以使用 for of会报 obj is not iterable
for of 不同与 forEach, 它可以与 break、continue和return 配合使用,也就是说 for of 循环可以随时退出循环。
提供了遍历所有数据结构的统一接口
html全局属性
clas contenteditable (h5新加) dir(元素中文字的方向) id hidden spellcheck (表明浏览器是否应该对元素的内容进行拼写检查) style title
meta中viewpoint的作用
如果不定义viewpoint的话,页面宽度以屏幕分辨率为基准,而设置以后可以根据设备宽度来调整页面,达到适配终端大小的效果
css加载方式
1、外部样式表 style link
2、内部样式style里写样式
3、@import引入
4、内联样式,即直接在标签里写
inline元素特点
inline元素的margin和padding属性,水平方向的padding-left, padding-right, margin-left, margin-right都产生边距效果;但竖直方向的padding-top, padding-bottom, margin-top, margin-bottom不会产生边距效果。
Object.create()方法创建一个新对象,使用现有对象来提供新创建的对象的proto
document
document.ready 和 window.onload 的区别是:上面定义的document.ready方法在DOM树加载完成后就会执行,而window.onload是在页面资源(比如图片和媒体资源,它们的加载速度远慢于DOM的加载速度)加载完成之后才执行。也就是说$(document).ready要比window.onload先执行。
js继承的6种方式
- 原型链继承
function Person(name){
this.name = name
}
function Son(){
this.name = "son"
}
Son.prototype = new Person()
重点:让新实例的原型等于父类的实例。
特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
- 借用构造函数继承
func Son(){
Person.call(this,'son2')
}
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
- 组合继承(组合原型链继承和借用构造函数继承)(常用)
function Son(name){
Person.call(this, name)
}
Son.prototype = new Person()
重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
- 最完美的继承
function Parent4(){
this.name = "parent4";
this.colors = ["red","blue","yellow"];
}
Parent4.prototype.sex = "男";
Parent4.prototype.say = function(){console.log("Oh, My God!")}
function Child4(){
Parent4.call(this);
this.type = "child4";
}
Child4.prototype = Object.create(Parent4.prototype);
Child4.prototype.constructor = Child4;
//Object.create是一种创建对象的方式,它会创建一个中间对象
清除浮动
.clearfix:after,.clearfix:before{
content: "";
display: table;
}
.clearfix:after{
clear: both;
}
.clearfix:after{/伪元素是行内元素 正常浏览器清除浮动方法/
content: "";
display: block;
height: 0;
clear:both;
visibility: hidden;
}
.clearfix{
zoom: 1;/ie6清除浮动的方式 号只有IE6-IE7执行,其他浏览器不执行/
}
typeof除了null以外都可以显示正确的类型,对象和数组都返回object
instanceof主要来判断引用类型,原理是根据原型链来查找。
除了undefined、null、false、NaN、''、0、-0以外的值都会被转为true,包括所有的引用类型,即使是空的。
promise构造函数内的代码是同步执行的,之后的then或catch方式是异步执行的。构造函数接收两个参数,resolve和reject。
eventloop的理解
js的执行机制简单来说就是先执行同步代码,然后执行异步代码,而异步代码里又分为宏任务代码和微任务代码,先执行微任务,然后执行宏任务。
- 将所有js作为一个宏任务,遇到同步代码就执行,然后开始分配任务,遇到宏任务就把他们的回调分配到宏任务的队列里,遇到微任务就把他们的回调分配到微任务的队列里,然后开始执行所有的微任务。
- 执行微任务的过程还是遵循先同步然后分配异步任务的顺序,微任务执行完毕之后,一次eventloop的tick就完成了。接着挨个去执行分配好的宏任务,在每个宏任务里又先同步后异步分配任务,完成下一次tick,循环往复
34、浏览器或元素的各种距离参数。
解决跨域
- jsonp
- 设置头部Access-Control-Allow-Origin
===运算符判断相等的流程是怎样的
- 如果两个值不是相同类型,它们不相等
- 如果两个值都是 null 或者都是 undefined,它们相等
- 如果两个值都是布尔类型 true 或者都是 false,它们相等
- 如果其中有一个是NaN,它们不相等
- 如果都是数值型并且数值相等,他们相等, -0 等于 0
- 如果他们都是字符串并且在相同位置包含相同的 16 位值,他它们相等;如果在长度或者内容上不等,它们不相等;两个字符串显示结果相同但是编码不同==和===都认为他们不相等
如果他们指向相同对象、数组、函数,它们相等;如果指向不同对象,他们不相等
==运算符判断相等的流程是怎样的
- 如果两个值类型相同,按照===比较方法进行比较
- 如果类型不同,使用如下规则进行比较
- 如果其中一个值是 null,另一个是 undefined,它们相等
- 如果一个值是数字另一个是字符串,将字符串转换为数字进行比较
- 如果有布尔类型,将true 转换为 1,false 转换为 0,然后用==规则继续比较
- 如果一个值是对象,另一个是数字或字符串,将对象转换为原始值然后用==规则继续比较
其他所有情况都认为不相等(例如a = {} , a=="[object Object]"就返回true)
38、cookie 属性有名,值,max-age,path, domain,secure;
进行网站性能优化
dns方面
1、减少dns查询
2、DNS Prefetch 是让具有此属性的域名不需要用户点击链接就在后台解析,而域名解析和内容载入是串行的网络操作,所以这个方式能减少用户的等待时间,提升用户体验 。content 方面
1.减少http请求(雪碧图,小图片base64)
2.组件懒加载
3.前后端进行数据交互时尽量使用json格式,数据处理方便,资源偏小。server方面
1.添加 Expires 或者 Cache-Control(max-age、no-store、no-cache、public、private) 响应头
2.开启gzip
3.避免空 src 的 img 标签(当 <link> 标签的 href 属性为空,或 <script>、<img>、<iframe> 标签的 src 属性为空时,浏览器在渲染的过程中仍会将 href 属性或 src 属性中的空内容进行加载,直至加载失败,这样就阻塞了页面中其他资源的下载进程,而且最终加载到的内容是无效的,因此要尽量避免。)cookie方面
1、去除没有必要的cookie,如果网页不需要cookie就完全禁掉。
静态资源和主页面不同域,加载静态资源的HTTP请求就不会带上主页面中的cookie等数据,减少了数据传输量,节省流量,提升上传效率。
2、将cookie的大小减到最小。
由于cookie在访问对应域名下的资源时都会通过HTTP请求发送到服务器,因此,减小cookie的大小,能减小HTTP请求报文的大小,提高响应速度。
3、设置合适的过期时间,较长的过期时间可以提高响应速度。
给cookie添加一个过期时间,则cookie信息将存储到硬盘上,即使浏览器退出Cookie还会存在。只要Cookie未被清除且还在过期时间内,该Cookie就会在访问对应域名时发送给服务器。
4、通过使用不同的domain减少cookie的使用。
cookie在访问对应域名下的资源时都会通过HTTP请求发送到服务器,但在访问一些资源,如js,css和图片时,大多数情况下cookie是多余的,可以使用不同的domain来存储这些静态资源,这样访问这些资源时就不会发送多余的cookie,从而提高响应速度。css
1.将样式表放到页面顶部
原理:
CSS的下载是按照其在文档中出现的顺序进行的,所以很容易想到将不需立即使用的CSS,如弹出框CSS,放在底部,这似乎可以得到一个加载很快的页面。然而这其实是错误的,IE8及以下浏览器的工作方式是:为了避免样式变化导致页面重绘or重排,会阻塞内容呈现,在所有CSS加载并解析完之前不会呈现内容,导致整个浏览器显示空白,出现“白屏”(浏览器呈现过程:先出现白屏,后出现文字,图片,最后出现样式),直到CSS加载完毕。若在网速非常慢的情况下,CSS下载时间会特别长,导致浏览器“白屏”的时间很长,用户体验会非常差。
将CSS放在底部,页面可以逐步呈现,但在CSS下载并解析完毕后,已经呈现的文字和图片就要需要根据新的样式重绘,这是一种不好的用户体验。
2.不使用表达式
3.不使用@import
4.尽量避免回流。
引起回流包括
1).页面渲染初始化
2).DOM结构改变,比如删除了某个节点
3).render树变化,比如减少了padding
4).窗口resize
5).改变字体大小
优化方案:
减少逐项更改样式,最好一次性更改style,或者将样式定义为class并一次性更新
避免循环操作dom,创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添加到window.document
避免多次读取offset等属性。无法避免则将它们缓存到变量
将复杂的元素绝对定位或固定定位,使得它脱离文档流,否则回流代价会很高js
1.将脚本放到页面底部
script全部放在head中会出现的问题:
在需要操作body中的某元素时,可能找不到该元素,因此,若要放在head中,一般需要绑定一个监听windows.οnlοad=function(){ ... },当文档全部解析完之后再执行script代码。
2.将 javascript 和 css 从外部引入
3.压缩图片方面
1.保证 favicon.ico 小并且可缓存
css
1.transform可以设置的属性translate,translate3的,scale,rotate,skewX
2.CSS3新增了三个边框属性,分别是border-radius、box-shadow和border-image。border-radius可以创建圆角边框,box-shadow可以为元素添加阴影,border-image可以使用图片来绘制边框。IE9+支持border-radius和box-shadow属性。Firefox、Chrome以及Safari支持所有新的边框属性。
3.css优先级内联样式 > ID 选择器 > 类选择器 = 属性选择器 = 伪类选择器 > 元素(类型)选择器 = 伪元素选择器 !important 权重最高
4.字体单位
- px
px就是pixel像素的缩写,相对长度单位,网页设计常用的基本单位。像素px是相对于显示器屏幕分辨率而言的 - em
em是相对长度单位。相对于当前对象内文本的字体尺寸(参考物是父元素的font-size)
如当前父元素的字体尺寸未设置,则相对于浏览器的默认字体尺寸
特点:
1. em的值并不是固定的;
2. em会继承父级元素的字体大小 - rem(移动端)
rem是CSS3新增的一个相对单位,rem是相对于HTML根元素的字体大小(font-size)来计算的长度单位
如果你没有设置html的字体大小,就会以浏览器默认字体大小,一般是16px - vw、vh
vw、vh、vmax、vmin这四个单位都是基于视口
vw是相对视口(viewport)的宽度而定的,长度等于视口宽度的1/100
假如浏览器的宽度为200px,那么1vw就等于2px(200px/100)
vh是相对视口(viewport)的高度而定的,长度等于视口高度的1/100
假如浏览器的高度为500px,那么1vh就等于5px(500px/100)
vmin和vmax是相对于视口的高度和宽度两者之间的最小值或最大值
5.box-sizing属性用来控制元素的盒子模型的解析模式,默认为content-box。
context-box:W3C的标准盒子模型,设置元素的height/width属性指的是content部分的高/宽;border-box:IE传统盒子模型。设置元素的height/width属性指的是border + padding + content部分的高/宽。
6.伪类和伪元素
伪类:用于已有元素处于某种状态时为其添加对应的样式,这个状态是根据用户行为而动态变化的。例如:当用户悬停在指定元素时,可以通过:hover来描述这个元素的状态,虽然它和一般css相似,可以为已有元素添加样式,但是它只有处于DOM树无法描述的状态下才能为元素添加样式,所以称为伪类。
状态伪类:
1 :link
选择未访问的链接
2 :visited
选择已访问的链接
3 :hover
选择鼠标指针浮动在其上的元素
4 :active
选择活动的链接
5 :focus
选择获取焦点的输入字段
伪元素:用于创建一些不在DOM树中的元素,并为其添加样式。例如,我们可以通过:before来在一个元素之前添加一些文本,并为这些文本添加样式,虽然用户可以看见这些文本,但是它实际上并不在DOM文档中。
6::checked
其他:
遇到有defer属性的script标签,浏览器继续往下面解析页面,且会并行下载script标签的外部js文件,解析完HTML页面,再执行刚下载的js脚本(在DOMContentLoaded事件触发前执行,即刚刚解析完</html>,且可保证执行顺序就是他们在页面上的先后顺序)
遇到有sync属性的script标签,会继续往下解析,并且同时另开进程下载脚本,脚本下载完毕,浏览器停止解析,开始执行脚本,执行完毕后继续往下解析
为什么移动端会产生1px问题呢?
因为UI设计师在最初设计的时候使用的尺寸是按照640x960设计的,前端写的时候是按照320x480写的,写1px(css),浏览器自动变成2px(真实像素)。
那么前端工程师为什么不能直接写0.5px(css)呢?
因为在老版本的系统里写0.5px(css)的话,会被浏览器解读为0px(css),就没有边框了。不过在新版的系统里,已经开始逐渐支持0.5px(css)这种写法。所以如果设计师在大图上设计了一个1px(真实像素)的线的话,前端工程师直接除以2,写0.5px(css)就好了。
设置viewpoint来解决<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
webpack常用loader和插件
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
这么说loaders负责的是处理源文件的如css、jsx,一次处理一个文件。而plugins并不是直接操作单个文件,它直接对整个构建过程起作用
1、样式解析
2、file-loader、url-loader
file-loader可以解析项目中的url引入(不仅限于css),根据我们的配置,将图片拷贝到相应的路径,再根据我们的配置,修改打包后文件引用路径,使之指向正确的文件。
url-loader 功能与 file-loader 相似,但是如果文件小于一个 指定的大小他可以返回一个 DataURL。
3、mini-css-extract-plugin将css提取为单独的文件
4、uglify-webpack-plugin压缩代码
5、optimize-css-assets-webpack-plugin优化压缩css资源
6、HTMLWebpackPlugin,将style插入到html
其他:
vue大概流程
一、主要步骤
1.初始化
vue初始化init的过程包含生命周期、事件、props、methods、data、computed与watch等的初始化
其中最主要的两个步骤是watch的初始化和data属性的observer过程,两个过程是实现响应式和依赖收集
2.编译
编译是将template转变为render function 的过程,包括:解析/优化/生成三个步骤
解析:template->AST(抽象语法树)
优化:标记AST中的静态(static)节点
生成:AST->render function
3.render function 执行
render function 执行后生成虚拟节点树(VNode DOM Tree)
4.渲染展现页面
二、依赖收集过程
整体的流程图中render function 执行开始的绿色箭头指向的流程为依赖收集过程
1.render function 执行中会依此调用使用到的data.attr的get方法
2.get方法调用Dep.add将Vue对象中的watch加入到attr.Dep数组里
3.整个页面渲染完毕后,所有需要使用attr的组件Vue对象的watch都收集到attr.Dep,attr.Dep内容即为template与data的依赖关系(attr是随便起的一个组件名)
三、响应式原理
整体流程图中attr.set()执行开始的红色箭头指向的流程为响应式原理
1.对data.attr赋值即调用attr.set方法
2.attr.set会调用Dep.notify(),notify方法是依次执行attr.Dep数组中watch对象的update方法
3.update()是重新渲染视图的过程,中间生成的Vnode DOM Tree,供patch使用 (利用diff算法)
四、update中的patch
patch,是将update产生的New Vnode节点与上一次渲染的Old Vnode进行对比的过程,最终只有对比后的差异节点才会被更新到视图上,从而达到提高update性能的目的
hash router和history的区别:
hash模式url里面永远带着#号,我们在开发当中默认使用这个模式。window.location.href
如果用户考虑url的规范那么就需要使用history模式,因为history模式没有#号,是个正常的url适合推广宣传 history.pushState
功能也有区别,比如我们在开发app的时候有分享页面,那么这个分享出去的页面就是用vue或是react做的,
咱们把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式
但是使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上就ok啦。
伪类和伪元素
伪类的受体是文档树中已有的元素,而伪元素则创建了一个DOM外的元素
伪类用于添加元素的特殊效果,而伪元素则是添加元素的内容
伪类使用的一个冒号,为元素使用两个冒号
伪类更常用一些简单的动画或者交互的样式,例如滑入滑出,而为伪元素更常用语字体图标,清除浮动等
BFC
满足下列条件之一就可以触发BFC
1:根元素,即html元素
2:float的值不为none
3:overflow的值不为visible
4:display的值为inline-block、table-cell、table-caption
5:position的值为absolute或者fixed
CSS选择器有哪些?哪些属性可以继承?CSS优先级算法如何计算?
- id选择器( # myid)
- 类选择器(.myclassname)
- 标签(元素)选择器(div, h1, p)
- 相邻选择器(h1 + p)
- 子选择器(ul > li)
- 后代选择器(li a)
- 通配符选择器( * )
- 属性选择器(a[rel = "external"])
- 伪类选择器(a:hover, li:nth-child)
伪元素选择器、分组选择器。
继承性:
可继承的样式:font-size, font-family, color,ul,li,dl,dt,dd;
不可继承的样式:border, padding, margin, width, height
优先级(就近原则):!important > [ id > class > tag ]
!important 比内联优先级高
优先级算法计算
优先级就近原则,同权重情况下样式定义最近者为准
!important>id >class>tag
important比内联优先级高
元素选择符的权值:元素标签(派生选择器):1,class选择符:10,id选择符:100,内联样式权值最大,为1000
!important声明的样式优先级最高,如果冲突再进行计算。
如果优先级相同,则选择最后出现的样式。
继承得到的样式的优先级最低。
position
absolute
生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。
元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。
fixed
生成固定定位的元素,相对于浏览器窗口进行定位。(老IE不支持)
元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。
relative
生成相对定位的元素,相对于其正常位置进行定位,不脱离文档流。
因此,"left:20" 会向元素的 LEFT 位置添加 20 像素。
static 默认值。没有定位,元素出现在正常的文档流中(忽略 top, bottom, left, right 或者 z-index 声明)。
inherit 规定应该从父元素继承 position 属性的值。
vue和react区别
设计思想
react
1 函数式思想,all in js ,jsx语法,js操控css
2 单项数据流
3 setState重新渲染
4 每当应用的状态被改变时,全部子组件都会重新渲染。当然,这可以通过shouldComponentUpdate这个生命周期方法来进行控制,如果为true继续渲染、false不渲染,但Vue将此视为默认的优化。
vue
1 响应式思想,也就是基于数据可变的。把html、js、css、组合到一起,也可以通过标签引擎组合到一个页面中
2 双向绑定,每一个属性都需要建立watch监听(页面不用,涉及到组件更新的话需要)
3 Vue宣称可以更快地计算出Virtual DOM的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树
两者本质的区别:模板和组件化的区别
Vue本质是MVVM框架,由MVC发展而来;
React是前端组件化框架,由后端组件化发展而来;
Vue使用模板
React使用JSX
React本身就是组件化
Vue是在MVVM上扩展的
共同点:
都支持组件化,都是数据驱动视图
ES6相关
let 声明变量 (推荐)
特性
1、支持 块作用域
2、不支持 JS预解析
3、不支持 重复声明 (同域同名变量)
const 声明常量
特性
1、let所有特性
2、声明时必须赋值,否则报错
3、定义常量后,再也不能更改值
解构赋值
箭头函数
导出语法
模板字符串(${name}
)
...展开运算符,react大量用到
promise
浏览器缓存
强缓存通过Expires和Cache-Control两种响应头实现
1、Expires
Expires是http1.0提出的一个表示资源过期时间的header,它描述的是一个绝对时间,由服务器返回。
Expires 受限于本地时间,如果修改了本地时间,可能会造成缓存失效
2、Cache-Control
Cache-Control 出现于 HTTP / 1.1,优先级高于 Expires ,表示的是相对时间
Cache-Control: no-store才是真正的不缓存数据到本地
Cache-Control: no-cache代表使用协商缓存
Cache-Control: public可以被所有用户缓存(多用户共享),包括终端和CDN等中间代理服务器
Cache-Control: private只能被终端浏览器缓存(而且是私有缓存),不允许中继缓存服务器进行缓存
当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304并且会显示一个Not Modified的字符串
协商缓存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对Header来管理的
Last-Modified 表示本地文件最后修改日期,浏览器会在request header加上If-Modified-Since(上次返回的Last-Modified的值),询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来
但是如果在本地打开缓存文件,就会造成 Last-Modified 被修改,所以在 HTTP / 1.1 出现了 ETag
Max-Age相比Expires?
Expires使用的是服务器端的时间
但是有时候会有这样一种情况-客户端时间和服务端不同步
那这样,可能就会出问题了,造成了浏览器本地的缓存无用或者一直无法过期
所以一般http1.1后不推荐使用Expires
而Max-Age使用的是客户端本地时间的计算,因此不会有这个问题
因此推荐使用Max-Age。
注意,如果同时启用了Cache-Control与Expires,Cache-Control优先级高。
使用闭包的注意点
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
防抖节流(函数防抖是某一段时间内只执行一次,而函数节流是间隔时间执行。)
防抖:任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行。
应用:
-输入框联想,以防不停的发http请求
节流:
可以将一些事件降低触发频率。比如懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,而不必去浪费资源;另外还有做商品预览图的放大镜效果时,不必每次鼠标移动都计算位置。