1. px、rem 和 em的区别?
- em是相对于父元素的font-size的大小,一单位的em的值根据父元素font-size的改变而改变
- rem是相对于根元素( html )的font-size的大小
盒子模型
所有的页面的元素都可以看成是一个盒子,占据一定的页面空间。
盒子模型是由内容、边框、内边距间隙(padding)、外边距(margin)组成。
- 标准盒模型:width = content,不包含 border + padding
- 怪异盒模型 width = border + padding + content
什么是BFC
BFC是一个独立的布局环境,我们可以理解为一个箱子(实际上是看不见摸不着的),箱子内部的元素无论如何翻江倒海,都不会影响到外部。转换为BFC的理解则是:BFC中的元素的布局是不受外界的影响(我们往往利用这个特性来消除浮动元素对其非浮动的兄弟元素和其子元素带来的影响。比如清除浮动)并且在一个BFC中,块元素与行元素都会垂直的沿着其父元素的边框排列。
div垂直居中方案
1.子元素设置position: absolute;left:50%;top:50%;transform: translate(-50%,-50%);
2.子元素设置position:absolute;left:0;top:0;right:0;bottom:0;margin:auto;
3.父元素设置display:table-cell;vertical-algin:middle;text-algin:center;子元素设置display:inline-block
4.父元素设置display:flex;justity-content:center;align-center:center;
两边固定中间自适应方案
- flex布局,左右两边固定宽,中间设置flex:1
- float浮动,左边右边分别左浮动和右浮动,中间左浮动
- 绝对定位,左边右边设置position:absolute,固定宽,中间设置margin为左右两边宽
css实现多行多列布局
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HuzlCilf-1587110065630)(/img/bVbEzJd)]
- calc()
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
<div class="item">E</div>
</div>
.container {
width: 100%;
background: yellow;
}
.item {
display: inline-block;
width: 30%;
height: 44px;
line-height: 44px;
text-align: center;
background: red;
margin: 0 0 calc(10%/4) calc(10%/4);
}
- flex
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
<div class="item">E</div>
</div>
.container {
width: 100%;
background: yellow;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.item {
width: 30%;
height: 44px;
line-height: 44px;
text-align: center;
background: red;
margin-bottom: calc(10%/3);
}
清除浮动方案
- 在尾部添加一个标签,css样式写clear:both
- 父元素添加overflow:hidden
- 父元素添加伪元素after,css样式写clear:both,display:block,content:""
伪类元素有哪些?
伪类元素before,after
伪类选择器first-child,last-child,nth-of-child(从前面开始算),nth-last-of-child(从后面开始算)
伪类选择器first-type,last-type,nth-of-type(从前面开始算),nth-last-of-type(从后面开始算)
伪类选择器not(),参数包括一些基本选择器,但是不支持伪类选择器
:link 用这个可以设置未被访问的链接的样式
:visited 用这个设置已经被访问的链接的样式
:hover 用于设置将鼠标悬浮在链接上的样式
:active 用于设置鼠标点击链接时到鼠标松开时的样式
:focus 用于设置用键盘将焦点放在链接上时的样式
html5有哪些新特性、移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?
- html5的新特性
语义化标签:article、header,footer,section,nav,aside
表单元素:calendar,date,time,number,url,search;
多媒体:video,audio;
控件元素: websockt,webwork
绘画:canvas;
存储:localStorage;sessionStorage
定位:Geolocation用于定位用户信息
- 移除的元素
big font basefont,s,tt,u,frame.iframe
- 兼容性处理
1. IE6/IE7/IE8支持通过document.createElement方法产生的标签,利用这一特性让这些浏览器支持HTML5新标签。浏览器支持新标签后,还需要添加标签默认的样式;
2. 使用是html5shim框架
Doctype作用?
声明文档的解析类型,避免浏览器的怪异模式。如果你的页面不声明,将会解析类型默认是怪异模式。
标准模式与兼容模式各有什么区别?
标准模式的排版 和JS运作模式都是以该浏览器支持的最高标准运行。在兼容模式中,页面以宽松的向后兼容的方式显示,模拟老式浏览器的行为以防止站点无法工作。
HTML5 为什么只需要写
HTML5 不基于 SGML,因此不需要对DTD进行引用,但是需要doctype来规范浏览器的行为(让浏览器按照它们应该的方式来运行);
而HTML4.01基于SGML,所以需要对DTD进行引用,才能告知浏览器文档所使用的文档类型。
link和@import有什么区别?
1. link属于html标签,而@import是css提供的
2. 页面加载时,link会同时被加载,而@import引用的css会等到页面加载完成后加载
3. link没有兼容性问题,@import有兼容性问题
4. link方式样式的权重高于@import
移动端适配方案
Viewport
Flex
vw/vh
position现在有五个属性值
1.static:静态定位,没有特殊的定位规则,遵循正常的文档流对象
2.relative:相对定位,相对于元素自身进行定位
3.absolute:绝对定位,相对于最近的有定位的父元素进行定位
4.fixed:固定定位,相对于浏览器页面进行定位
5.sticky :粘性定位,基于用户的滚动位置来定位
import和require什么区别
1.
a.import是ES6的模块规范
b.require是commonjs的模块规范
2.
a.import是编译时调用,具有提升效果,会提升到模块的头部(编译时执行)
b.require是运行时加载整个模块(即模块中所有方法)
3.
a.require是赋值过程,export的一个对象,赋给某个变量;
b.import是解构过程(需要谁,加载谁)
new发生了什么?
1.创建一个空的新对象;
2.将构造函数中的this指针指向新对象;
3.执行构造函数中的代码;
4.返回新对象。
0.1+0.2!=0.3吗?请说出为什么?
浮点数运算的精度问题 计算机在进行运算时会将其他进制的数值转换成二进制在进行计算。
方法一:(换成整数计算)
(0.1*10+0.2*10)/10
方法二:
parseFloat((0.1+0.2).toFixed(10))
js的数据类型,以及区别
- 基本数据类型: Number、String、Boolean、Null、 Undefined、Symbol(ES6)
特点:数据存贮在栈内存中,复制的时候是值传递 - 引用数据类型:Object(Array,Date,RegExp,Function)
特点:存储的是该对象在栈中引用,复制的时候是地址的引用
js数据类型的检测
1.typeof
typeof操作符只可以对除null以外的基本类型做出正确的判断,但是对于引用数据类型,检测出来都是object
2.instanceof
instanceof是用来判断 A 是否为 B 的实例,表达式为:A instanceof B
,如果 A 属于 B 的实例,则返回true,否则返回false
console.log([] instanceof Array); //true
console.log({} instanceof Object); //true
console.log(new Date() instanceof Date); //true
3.constructor
constructor可以打印出实例所属的类,表达式为:实例.constructor
。
console.log([].constructor == Array) //true
console.log({}.constructor == Object) //true
console.log("string".constructor == String) //true
console.log((1).constructor == Number) //true
console.log(true.constructor == Boolean) //true
js求数组中的最大值和最小值的方法?
1.排序法(先把数组从小到大排序,数组第一个即为最小值,最后一个即为最大值)
ary.sort(function(a,b){return a-b;})
var minN = ary[0]
var maxN = ary[ary.length-1]
2.使用Math.max以及apply或者结构…来实现
apply(null,arr) apply会将传入的数组结构成一个一个的数值
… 展开运算符会将数组中的值提取成一个个的数值
var maxN = Math.max.apply(null,ary)
var minN = Math.min.apply(null,ary)
或者
var maxN = Math.max(...ary)
var minN = Math.min(...ary)
JavaScript原型,原型链 ? 有什么特点
1.JS中每个函数都存在有一个原型对象属性prototype。并且所有函数的默认原型都是Object的实例。
2.每个继承父函数的子函数的对象都包含一个内部属性_proto_。该属性包含一个指针(就像链表一样),指向父函数的prototype。若父函数的原型对象的_proto_属性为再上一层函数。在此过程中就形成了原型链。
3.原型链实现了继承。原型链存在两个问题:a 包含引用类型值的原型属性会被所有实例共享。b 在创建子类型时,无法向超类型的构造函数中传递参数。js在当初设计过程中,并没有设计继承,是利用原型继承,es6新增特性支持class类就解决了这些问题。
谈谈This对象的理解
框架中的this不一样。vue中this指向当前vue实例,angular中this指向当前类。
this表示当前对象,this的指向是根据调用的上下文来决定的,默认指向window对象
1. 如果在全局环境下直接调用函数,this指向就是window。
2. 对象函数调用,哪个对象调用就指向哪个对象。
3. 构造函数中的this,指向new实例化的对象。
4. 可以使用call和apply改变this的指向。
5. es6中箭头函数没有上下文环境,this直接指向上一级。
jQuery链式调用的原理
每次调用都返回this,this指向调用者
谈谈对闭包的理解以及闭包的形成
闭包就是能够读取其他函数内部变量的函数(函数 A 内部有一个函数 B,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包。)。闭包保护了一些私有变量,支持在函数作用域外调用,避免了全局污染。使用闭包会导致内存泄漏。
当某个函数的作用域链还引用着其他函数的活动对象时,就会形成闭包。(外层函数和内层函数)
闭包的优缺点
优点:避免全局变量的污染
缺点:常驻内存 会增大内存的使用量 使用不当会造成内存泄露
什么是内存泄漏
内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
浏览器是如何渲染页面的?
1.解析HTML,构建DOM树
2.解析CSS,生成CSS规则树
3.合并DOM树和CSS规则,生成render树
4.布局render树(Layout/reflow),负责各元素尺寸、位置的计算
5.绘制render树(paint),绘制页面像素信息
6.浏览器会将各层的信息发送给GPU,GPU会将各层合成(composite),显示在屏幕上
1.在浏览器的地址栏输入url地址,
2.浏览器会在浏览器缓存,系统缓存,路由缓存里查看,如果路由缓存有数据就显示在页面上,如果没有,就继续第三步。
3.在发起http请求前,需要域名解析,解析获取ip地址。
4.浏览器向服务器发起tcp请求(传输控制协议),与浏览器建立tcp三次握手
5.握手成功后,浏览器向服务器发起http请求,请求数据包。
6.服务器处理请求,发送数据给浏览器。
7.浏览器收到http响应。
8.读取页面数据,浏览器渲染,解析html源码。
9.生成DOM树,解析css样式,js交互。
10.客户端和服务器交互。
11.ajax查询。
从输入url到显示页面,都经历了什么?
1.在浏览器的地址栏输入url地址,
2.浏览器会在浏览器缓存,系统缓存,路由缓存里查看,如果路由缓存有数据就显示在页面上,如果没有,就继续第三步。
3.在发起http请求前,需要域名解析,解析获取ip地址。
4.浏览器向服务器发起tcp请求(传输控制协议),与浏览器建立tcp三次握手
5.握手成功后,浏览器向服务器发起http请求,请求数据包。
6.服务器处理请求,发送数据给浏览器。
7.浏览器收到http响应。
8.读取页面数据,浏览器渲染,解析html源码。
9.生成DOM树,解析css样式,js交互。
10.客户端和服务器交互。
11.ajax查询。
http和https的区别
1.https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2.http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3.http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4.http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
http是怎么进行缓存的
什么是跨域
当一个请求url的**协议、域名、端口**三者之间任意一个与当前页面url不同即为跨域
同源策略
同源策略是指协议,域名,端口都要相同,其中有一个不同都会产生跨域
跨域是怎么解决的
- JSONP script标签不受同源策略的限制,只支持get方法
网页通过添加一个<script>元素
,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。
<script src="http://test.com/data.php?callback=dosomething"></script>
// 向服务器test.com发出请求,该请求的查询字符串有一个callback参数,用来指定回调函数的名字
// 处理服务器返回回调函数的数据
<script type="text/javascript">
function dosomething(res){
// 处理获得的数据
console.log(res.data)~~~~
}
</script>
服务端返回时即执行全局函数
2.CORS
服务器设置HTTP响应头中Access-Control-Allow-Origin值,解除跨域限制
3. nginx代理跨域
4. nodejs中间件代理跨域
前端上传图片到服务器的格式是什么?
- base64格式
- new FormData (ios,andorid只支持FormData 却不支持base64)
创建一个空的FormData对象,然后再用append方法逐个添加键值对
var formdata = new FormData()
formdata.append("name", "xiaomei")
深拷贝和浅拷贝的区别,以及实现方式
- 区别:
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象 - 深拷贝的实现方式
1. 通过json方式实现
function deepClone (obj){
return JSON.parse(JSON.stringify(obj))
}
2. 通过递归实现
function deepClone (obj){
let result = {}
for(let key in obj){
if(Object.prototype.hasOwnProperty.call(obj, key)){
if(typeof obj[key] === 'object'){
result[key] = deepClone(obj[key])
}else{
result[key] = obj[key]
}
}
}
}
- 浅拷贝的实现方式
1. ... 解构赋值
2. Object.assign(target, …sources)
Cookie,session,sessionStorage和localStorage的之间的区别
- cookie
1、Cookie由服务端生成,保存在客户端。
2、存储大小只有4kb,存储内容只接受String类型,若没有设置过期时间,保存在内存中,浏览器关闭消失;若设置了过期时间,则保存在系统硬盘中,直到过期时间结束才消失(即使关闭浏览器) - session
1、sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除
2、存放数据大小为一般为5MB
3、它仅在客户端(即浏览器)中保存,不参与和服务器的通信 - sessionStorage
1、生命期为只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
2、存放数据大小为4K左右
3、有个数限制(各浏览器不同),一般不能超过50个
4、与服务器端通信:每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 - localStorage
1、localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在
2、存放数据大小为一般为5MB
3、它仅在客户端(即浏览器)中保存不参与和服务器的通信 - 区别
1、存放数据的大小:localStorage、sessionStorage的可以存放的数据大小明显大于cookie的可以存放数据大小
2、与服务器端通信:cookie会被携带在请求头中,而localStorage/sessionStorage不会参与与服务器的通信
3、会话级别:localStorage永久会话级别,sessionStorage浏览器关闭会话结束,cookie是根据他自身参数expires所设置的时间来决定会话级别
4、个数限制:localStorage/sessionStorage无限制,cookie根据浏览器的不同,个数稍有区别,一般不会超过50个
什么防抖与节流,它们的区别是什么?应用什么场景如何实现
一.函数防抖(高频事件触发时使用):
在第一次触发事件时,不立即执行函数,而是给出一个期限值比如100ms后执行
应用场景:
- 用户在输入框中连续输入一串字符后,只会在输入完后去执行最后一次的查询ajax请求,这样可以有效减少请求次数,节约请求资源;
- window的resize、scroll事件,不断地调整浏览器的窗口大小、或者滚动时会触发对应事件,防抖让其只触发一次;
(可以传参 不能用箭头函数)
function debounce(fn,delay = 100){
let timer = null
return function (){
if(timer){
clearTimer(timer)
}
timer = setTimeOut(() => {
fn.apply(this,arguments)
timer = null
},delay)
}
}
二.函数节流
让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活 (类似于技能冷却时间)
应用场景:
连续不断地触发某事件(如点击),只在单位时间内只触发一次。
function throttle(fn,delay = 100){
let timer = null
return function(){
if(timer) return
timer = setTimeOut(() => {
fn.apply(this,arguments)
timer = null
},delay)
}
}
es6使用过吗?说说你常用的(谈谈var、let、const它们的区别)
1. let const
var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。
let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,基本类型数据不可修改,对象和数组等引用类型数据只要地址不变,可改变其中的属性和内容。
2. ``模板字符串。
3. ...运算符,可以合并数组,合并对象。
let bar = { a: 1, b: 2 };
let baz = { ...bar }; // { a: 1, b: 2 }
实际上和使用Object.assign
4. Object.assign(targer,...resource)
5. 解构赋值
6. 函数参数默认值
7. Promise
8. 箭头函数
9. class类
10. set和map数据结构
promise原理
promise内部有一个状态管理器,有三种状态:pending,fulfilled,rejected。一旦状态修改成功后,promise状态就不能在次改变。
1.promise对象初始化状态为pending
2.当调用resolve时,会由pending => fulfilled。当你调用then方法时,then方法是放在promise原型中的一个方法,每个实例都会有,然后向then的成功的回调函数传值。
3.当调用reject时,会由pending => rejected。然后向then的成功的回调函数传值。
async/await的使用
- async 是一个修饰符,async 定义的函数会默认的返回一个Promise对象resolve的值,因此对async函数可以直接进行then操作,返回的值即为then方法的传入函数
- await 关键字 只能放在 async 函数内部, await关键字的作用 就是获取 Promise中返回的内容, 获取的是Promise函数中resolve或者reject的值
什么是单线程?和异步有何关系?
程序的执行顺序就是从上到下依次执行。同步阻塞,异步非阻塞。
一个js程序的单线程用来执行栈中的同步任务,异步任务会存放到一个任务队列中,当所有同步任务执行完毕后,栈被清空,然后会读取任务队列中的一个待处理任务,并把相关回调函数压入栈中,单线程开始执行新的同步任务,执行完毕。
什么是事件循环
因为javascript是单线程的,js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务。当一个异步事件返回结果后,js会将这个事件加入与当前执行栈不同的另一个队列,我们称之为事件队列。被放入事件队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码…,如此反复,这样就形成了一个无限的循环。这就是这个过程被称为“事件循环(Event Loop)”的原因。
字符串和数组排序以及去重
- 字符串去重
1. indexOf()方法
function removeRepeatStr (str) {
var newStr = ''
var len = str.length
for (var i = 0; i < len; i++) {
if (newStr.indexOf(str[i]) == -1) {
newStr = newStr + str[i]
}
}
return newStr
}
2. search()方法
function removeRepeatStr(str){
var newStr = ''
var len = str.length
for(var i=0; i<len; i++){
if(newStr.search(str[i])==-1){
newStr = newStr + str[i]
}
}
return newStr
}
3. includes()方法
function repetition(str) {
let newStr=""
for (let i=0; i<str.length; i++) {
if (!newStr.includes(str[i])) {
newStr += str[i]
}
}
return newStr
}
4. set()方法
function repetition(str) {
return [...new Set(str)].join('')
}
5. filter()方法
function repetition(str) {
return [].filter.call(str,(s,i,o)=>o.indexOf(s)==i).join()
}
- 数组去重
1. indexOf()去重
function unique(arr){
let newArr=[]
for(let item of arr){
if(newArr.indexOf(item)==-1){
newArr.push(item)
}
}
return newArr
}
2. includes()去重
function unique(arr){
let newArr=[]
for(let i = 0; i < arr.length; i++) {
if(!newArr.includes(arr[i])){
newArr.push(arr[i])
}
}
return newArr
}
3. new Set()去重
function unique(arr){
return [...new Set(arr)]
}
MVC 和 MVVM的区别
- MVC
View :视图层
Model:管理数据
Controller :控制器,数据模型和视图之间通信的桥梁(把Model的数据赋值给View)
- MVVM
MVVM的特点: 在MVVM的框架下,视图和模型是不能直接通信的,它们通过ViewModal来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。
vuex 和 本地存储(localstorage)什么区别
- vuex是存储在内存中,localstorage是以文件的方式存储在本地
- vuex是用于组件之间的传值,localstorage主要用于不同页面的传值
- 当页面刷新时vuex存储的值会丢失, localstorage则不会
谈谈对组件化的理解
抽离公共层,高度复用,简化结构,优化代码。
说说你了解的前端性能优化?
----网络方面----
一.减少http请求
1.合并js文件
2.合并css文件
3.尽量图片替换为svg或者字体图标
4.使用base64表示简单图片
二.减少资源体积
1.gzip压缩
2.js混淆
3.css压缩
4.图片压缩
三.缓存
1.DNS缓存
2.CDN部署和缓存
3.http缓存
四.移动端优化
1.使用长cache,减少重定向
2.首屏优化,保证首屏加载数据小于14kb
3不滥用web字体
----渲染和DOM操作方面----
一.优化网页渲染
1.css文件放在头部,js文件放在尾部或者异步
2.尽量避免内联样式
二.DOM操作优化
1.避免在doucument上直接进行频繁的DOM操作。
2.使用classname代替大量的内联样式修改。
3.对于复杂的UI元素,设置position为absolute或者fixed。
4,尽量使用css3动画
5. 适当使用canvas
6. 尽量减少css表达式的使用
7. 使用事件代理
三.操作细节注意
1.css属性为0时,去掉单位。
2.避免图片或者frame使用空src。
3.移除空的css。
4.对于css可继承的属性,尽量使用继承,少一点设置。
5.缩短css选择器
四.移动端优化
1.长列表滚动优化(给body添加上-webkit-overflow-scrolling: touch来优化移动端的滚动)
2.函数防抖和函数节流
3.使用touchstart和touchend代替click
4.html的viewport设置
5.开启GPU渲染加速
什么是AJAX?
异步javaScript和XML。
依赖是浏览器提供的XMLHttpRequest对象,是这个对象使得浏览器可以发出HTTP请求与接收HTTP响应。实现了在页面不刷新个情况下和服务器进行数据交互。
var xhr = new XMLHttpRequest()
xhr.open('GET', URL, true)
xhr.onreadystatechange = function(){
if(xhr.readyState === 4) {
if(xhr.status == 200){
//成功了
console.log(xhr.responseText)~~~~
} else {
console.log('服务器异常')
}
}
}
xhr.onerror = function(){
console.log('服务器异常')
}
xhr.send()
说说你所知道的web安全及防护措施 ?
1.CSRF跨站点请求伪造,冒充用户发起请求(在用户不知情的情况下), 完成一些违背用户意愿的事情(如修改用户信息,删除评论等)。
使用token,一般登陆时后端会随机产生一个token,并且存放在session中,并且也会回传给前端。前端页面发起请求时,会把这个token加入到请求头中,后端会验证前端传来的token与session中是否一致,一致则合法,不一致就是非法。
2.xss: 跨站脚本攻击(Cross Site Scripting)是最常见和基本的攻击 WEB 网站方法,攻击者通过注入非法的 html 标签或者 javascript 代码,从而当用户浏览该网页时,控制用户浏览器。前端对一些标签字符进行过滤,后端在接收参数时也要对这些参数进行过滤。
说下jquery和Vue的区别?
- 1.数据和视图的分离
1.dom 和 js没有分离,真正的内容会混合在js中由js创建
2.不符合开放封闭原则。对扩展开放,对修改封闭
- 2.以数据驱动视图
1.jquery直接修改视图
2.vue只需要修改数据,框架自动修改视图,Dom操作被封装
什么是MVVM?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tTAbptzZ-1587110065634)(/img/bVbfWxq)]
mvvm:数据层,视图层,vm层
vm是数据层和视图层的桥梁,数据与视图分离
在MVVM的框架下视图和模型是不能直接通信的,它们通过ViewModel来通信。当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动。
vue的虚拟dom
传统的直接操作dom浪费巨大的性能。(dom结构是一颗树)
Vue在监测到多次dom操作时,并不会直接操作dom,而是把多次更新的diff内容保存在一个本地js对象中,这个js对象就是虚拟dom,对dom的更新都体现在这个对象上,最终将这个js对象一次性放在dom树上
什么是vue的生命周期?
Vue实例从创建到销毁的过程,就是生命周期。
开始创建、初始化数据、编译模板、挂载DOM->渲染、更新->渲染、卸载等一系列过程,我们称这是Vue的生命周期。
Vue的生命周期(创建前/后, 载入前/后,更新前/后,销毁前/销毁后)
BeforeCreate:实例初始化后,无法访问方法和数据;
Created:实例创建完成,可访问数据和方法,注意,假如有某些数据必须获取才允许进入页面的话,并不适合;
beforeMonut:挂载DOM之前
Mounted:el被新创建的vm.$el替换,可获取dom,改变data,注意,beforeRouterEnter的next的钩子比mountend触发靠后;
beforeUpdate:数据更新时调用,发生在虚拟DOM重新渲染前;
Updated:数据更改后,可以执行依赖于DOM的操作,注意,应该避免在此期间更改状态,可能会导致更新无限循环;
beforeDestroy:实例销毁之前,这一步还可以用this获取实例,一般在这一步做重置操作,比如清定时器监听dom事件;
Destroyed:实例销毁后,会解除绑定,移除监听。
Vue 的单向数据流
父级 prop 的更新会向下流动到子组件中,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值;子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改
vue的实现流程
vue双向数据的原理?
Vue采用数据劫持结合发布者-订阅者模式的方法,通过Object.defineProperty()来劫持各个属性的setter,getter属性,同时每个组件都是一个watcher实例,在数据变动话,通知watcher实例,重新渲染视图。
实现双向绑定Proxy和defineproperty区别
- Object.defineProperty缺点
- 对数组的支持不好,无法监听到数组的变化,在Vue官方文档说明了可以监听到数组的变动,但只限于push、pop、shift、unshift、splice、sort、reverse方法
- Object.defineProperty监听的是对象的属性,当一个对象为深层嵌套的时候,必须进行递归遍历
- Proxy对比Object.defineProperty:
- Proxy可以劫持整个对象,这样以来操作便利程度远远优于Object.defineProperty。
- Proxy可以直接监听数组的变化,无需进行数组方法重写。
- 缺点:_Proxy的兼容性不是太好,不兼容IE,且无法通过polyfill提供兼容
v-if与v-show的区别,它们的哪个优先级更高?
父组件调用子组件的方法该怎么实现?
引入子组件后,this.$refs.子组件在父组件中自定义的ref属性名称.子组件里面的名称~~~~
Vue的$nextTick的作用?
在某个动作有可能改变DOM元素结构的时候,对DOM一系列的js操作都要放进Vue.nextTick()的回调函数中。
v-if会移除dom元素,v-show会给dom添加display:none来控制隐藏和展示。
父组件可以监听到子组件的生命周期吗?
例:父组件 Parent 和子组件 Child,如果父组件监听到子组件挂载 mounted 就做一些逻辑处理,可以通过以下写法实现:
方法一
// Parent.vue
<Child @mounted="doSomething"/>
// Child.vue
mounted() {
this.$emit("mounted");
}
以上需要手动通过 $emit 触发父组件的事件,更简单的方式可以在父组件引用子组件时通过 @hook 来监听即可,如下所示:
方法二
// Parent.vue
<Child @hook:mounted="doSomething" ></Child>
doSomething() {
console.log('父组件监听到 mounted 钩子函数 ...');
}
// Child.vue
mounted(){
console.log('子组件触发 mounted 钩子函数 ...');
},
// 以上输出顺序为:
// 子组件触发 mounted 钩子函数 …
// 父组件监听到 mounted 钩子函数 …
@hook 方法不仅仅是可以监听 mounted,其它的生命周期事件,例如:created,updated 等都可以监听
vue $set $forceupdate 应用场景
$set设置响应式数据,数据改变页面自动渲染。
f
o
r
c
e
u
p
d
a
t
e
强
制
更
新
页
面
数
据
,
如
果
用
o
b
j
.
某
个
属
性
,
该
属
性
非
响
应
式
,
需
要
用
forceupdate强制更新页面数据,如果用obj.某个属性,该属性非响应式,需要用
forceupdate强制更新页面数据,如果用obj.某个属性,该属性非响应式,需要用foreupdate强制更新页面数据。
vue 如何获取dom元素,$el如何使用?
1.给dom添加ref属性,给属性名称ref=“xxx”。通过this. r e f . x x x 来 获 取 此 d o m 元 素 。 2. t h i s . ref.xxx来获取此dom元素。 2.this. ref.xxx来获取此dom元素。2.this.el.querySelector返回第一个子元素 this.$el.querySelectorAll返回所有元素
Vue 计算属性(computed)、方法(methods)和侦听属性(watch)的区别与使用场景?
computed 是基于他的依赖进行缓存的,computed 只有在他的的相关依赖发生改变的时候才会重新计算。( 例如购物车计算总价,受它的单价和数量影响,只要这两个值不变,就不会重新计算,会缓存,而methods不会。
methods则是每次触发重新渲染之后,调用方法会再次执行函数。)
watch一般是监听一个数据,从而影响多个数据
computed 计算属性, 一般是计算一个属性,这个属性受多个数据影响
一般使用computed,但是如果需要异步,或者数据开销太大的情况下,使用watch.
vue中的作用(如何缓存又是如何清除缓存的,应用在什么情况下)
能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
1.Keep-alive组件接受两个props:
include: 字符串或正则表达式。只有匹配的组件会被缓存。
exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。
可以设置这两个属性来控制缓存或者不缓存。
也可以结合routers页面对象中元信息meta的keepAlive(布尔值)属性来配置是否缓存。
利用路由守卫动态配置路由元信息meta的keepAlive属性实现一些动态缓存业务逻辑。
2.列表页面 =>点击进入详情页=> 后退到列表页 要缓存列表原来数据
重新进入列表页面 => 获取最新的数据
vue组件之间传参的方式
父组件到子组件 通过子组件的props属性,抛出子组件自定义标签属性,来接收父组件中的数据
子组件到父组件 子组件绑定自定义事件,来处理父组件的方法函数,通过.
e
m
i
t
(
‘
自
定
义
事
件
’
,
[
参
数
]
)
来
触
发
属
于
自
己
的
自
定
义
事
件
。
非
父
子
组
件
通
过
创
建
一
个
中
间
V
u
e
实
例
,
注
册
一
个
事
件
,
一
个
组
件
中
通
过
emit(‘自定义事件’,[参数])来触发属于自己的自定义事件。 非父子组件 通过创建一个中间Vue实例,注册一个事件,一个组件中通过
emit(‘自定义事件’,[参数])来触发属于自己的自定义事件。非父子组件通过创建一个中间Vue实例,注册一个事件,一个组件中通过emit发送事件,另外个组件中通过$on来订阅发送的事件,通过这个事件订阅,来作出相应的操作。
vue如何注册全局组件,自定义指令
在一个component.js中引入所有组件,并且用Vue.component全局注册并且导出component.js,然后在app.js中引入这个component.js,Vue.use注册这个components。
在一个directive.js中引入所有组件,并且用Vue.component全局注册并且导出directive.js,然后在app.js中引入这个directive.js,Vue.use注册这个directive。
vue组件通讯vue中8种组件通信方式
(1)props / $emit适用 父子组件通信
(2)ref parent与children适用 父子组件通信
**(3)EventBus (emit/on)**适用于 父子、隔代、兄弟组件通信
(4)attrs listeners适用于 隔代组件通信
(5)provide / inject适用于 隔代组件通信
(6)Vuex适用于 父子、隔代、兄弟组件通信
Vuex是什么
Vuex是专门为Vuejs应用程序设计的**状态管理工具**。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
Vue生命周期是异步还是同步? 同步
Vuex中getter主要用来做什么操作?
主要作用是对state属性进行计算,可以理解类似于Vue中computed。
muation和action的区别
action就是异步提交mutations。action用dispatch来触发。mutations用commit来触发。
vuex的使用
1.state:定义初始化状态
2.getters:类似vue的计算属性,主要用来过滤一些数据
3.mutations: mutations提交更改数据,使用store.commit方法更改state存储的状态。(mutations同步函数)
4.actions: actions提交mutation,而不是直接变更状态。(actions可以包含任何异步操作)
5.module: Module是store分割的模块,每个模块拥有自己的state、getters、mutations、actions。
- vuex module的使用
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
this.$store.state.a // -> moduleA 的状态
this.$store.state.b // -> moduleB 的状态
单页面首屏加载优化?
- Vue-Router路由懒加载
require方式
{
path: '/goods',
name: 'goods',
component: resolve => require(['@/components/page/goods/Goods.vue'], resolve),
meta: {
title: '商品管理'
}
}
ES6 提出的import方法
{
path: '/goods',
name: 'goods',
component: () => import('@/components/page/goods/Goods.vue')
meta: {
title: '商品管理'
}
}
- 使用CDN资源,减小服务器带宽压力
- 按需加载三方资源,如iview,建议按需引入iview中的组件
- Vue动态加载异步组件
<script>
const AsyncComponent = () => import('./async-component')
或者
const AsyncComponent = resolve=>(\['./async-component',resolve\])
export default {
components: {
AsyncComponent
}
}
</script>
路由和组件的常用两种懒加载方式
1、vue异步组件实现路由懒加载
component:resolve => (['需要加载的路由的地址',resolve])
2、es6提出的import(推荐使用这种方式)
const HelloWorld = () =>import('需要加载的模块地址')
vue混入Mixins的理解
抽离组件中公共部分,抽离一些props,data,function, computed,钩子函数等,可以在注册组件时有个mixins属性导入。
mixin的data数据对象和组件的数据发生冲突时以组件数据优先.
Mixin和组件同名钩子函数将会混合为一个数组,都将被调用到,但是混入对象的钩子将在组件自身钩子之前调用。
值为对象的选项,例如 methods, components 和 directives,将被混合为同一个对象。两个对象键名冲突时,取组件对象的键值对。即取组件优先。
有没有配置过vue脚手架?尽量说多少是多少
webpack配置过吗?有了解过4.0的吗?
webpack loader原理 ?
vue-loader的作用
`vue-loader`:解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理
css-loade
:加载由 vue-loader 提取出的 CSS 代码。vue-template-compiler
:把 vue-loader 提取出的 HTML 模版编译成对应的可执行的 JavaScript 代码。
webpack的api使用过哪些?
active-class是哪个组件的属性?
Router-link
链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项 linkActiveClass 来全局配置。
嵌套路由怎么定义?
每个路由对象的children属性可以定义嵌套路由
怎么定义vue-router的动态路由?
routes: [
// 动态路径参数 以冒号开头
{ path: '/user/:id', component: User }
]
})
vue路由跳转怎么获取传过来的动态参数?params和query有什么区别?
this.$route.params
this.$route.query
区别:
- query的参数会在地址栏显示(路由未配置参数情况),刷新当前页面依旧能获取
- params路由未配置参数情况,参数不会在地址栏显示,在页面能获取,但如果刷新页面就没了
vue传参有哪几种方式?
1.通过path属性来匹配this.KaTeX parse error: Expected '}', got 'EOF' at end of input: …th: `/describe/{id}`,需要对应的路由下配置{path: ‘/describe/:id’…},添加冒号说明是动态的。
2.通过name属性来匹配this.
r
o
u
t
e
r
.
p
u
s
h
(
n
a
m
e
:
′
D
e
s
c
r
i
b
e
′
,
p
a
r
a
m
s
:
i
d
:
i
d
)
,
利
用
p
a
r
a
m
s
属
性
来
携
带
参
数
。
对
应
路
由
可
以
不
用
添
加
动
态
参
数
,
即
冒
号
后
面
的
参
数
名
称
。
3.
通
过
p
a
t
h
来
匹
配
路
由
,
t
h
i
s
.
router.push({name: 'Describe',params: {id: id}}),利用params属性来携带参数。对应路由可以不用添加动态参数,即冒号后面的参数名称。 3.通过path来匹配路由,this.
router.push(name:′Describe′,params:id:id),利用params属性来携带参数。对应路由可以不用添加动态参数,即冒号后面的参数名称。3.通过path来匹配路由,this.router.push({path: ‘/describe’,query: {id: id}}),利用query属性来携带参数,对应路由不用写动态参数。
路由导航有几个钩子函数?谈谈它们的区别
1.全局钩子
全局前置钩子beforeEach,接收三个参数,to即将要进入的目标,from当前正要离开的路由,next参数是一个方法,一定要调用,next()进入下一个钩子,next(false)中断当前导航,next(’’)或者next({path:’/’})可以使用router.push中的任何属性,next(error),error为Error实例,中止导航,而且错误会被传递给router.onError()注册过的回调。
全局解析钩子beforeResolve。
全局后置钩子afterEach,不接收next。
2.路由独享的守卫 beforeEnter,在路由配置的属性中直接定义
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
3.组件内的守卫
beforeRouteEnter 进入该组件对应路由时调用,不能访问this,但是可以通过给next里面添加回调来访问组件实例。
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 vm
访问组件实例
})
}
beforeRouteUpdate 在当前路由改变,但是该组件被复用时调用,即带有动态参数的路径
beforeRouteLeave 离开该组件对应路由时调用