css部分
如何水平垂直居中一个盒子?
- 已知高度可以使用 line-height 等于 高度实现垂直居中;使用 text-align:center实现水平居中
- display:flex; align-items:center;justify-content:center;
- 绝对定位的话,给父元素 设置定位属性 relative,子元素设置 absolute,然后设置 子元素 top:0;left:0;right:0;bottom:0;margin:auto;
px、rem、em、vw的区别?
- px是相对于显示器屏幕分辨率而言的,固定的一种单位。
- em是相对于父元素的字体大小而言的,譬如父元素字体大小为16px,那么1em=16px,2em=32px。
- rem是相对于根元素(html)字体大小而言的,浏览器默认的字体大小都是16px,那么1rem=16px,2rem=32px,可以根据设备的宽度,结合媒体查询(@media)来进行自适应的布局。
- vw是窗口的实际宽度,1vw=1% 窗口的实际宽度。
- 对于只需要适配少部分手机设备,且分辨率对页面影响不大的,使用px即可 。
- 对于需要适配各种移动设备,使用rem,例如只需要适配iPhone和iPad等分辨率差别比较挺大的设备。
- 为什么给font-size设置为62.5%: 方便换算!
1. 因为绝大多数浏览器的默认字体大小为 16px ,而将font-size设置为 62.5% 则等价于字体大小的font-size:10px;
2. 随之在其他的换算单位,如 rem 的字体换算时,则可以表示为 1rem = 10px, 整数值对于单位的换算会比较方便
3. 但是在Chrome(谷歌浏览器)中,支持最小字体的大小为 12px ,解决办法就是 将html根字体设置为 font-size: 625%; 意:1rem = 100px ,以此单位换算
CSS中的定位方式?
- 绝对定位,参照离自己的最近的,有定位属性的父元素定位。
- 相对定位,参照自己本身的位置进行定位。
- 固定定位,基于浏览器窗口定位。
- 默认定位,,由左到右,从上往下流式布局。
都有哪些方式实现回到顶部功能?
1. 使用锚点,页面顶部放置一个锚点链接,然后在页面下方放置一个返回到该锚点的链接,用户点击该链接即可返回到该锚点所在的顶部位置。
//锚点方式
<body style="height:2000px;">
<div id="topAnchor"></div>
<a href="#topAnchor" style="position:fixed;right:0;bottom:0">回到顶部</a>
</body>
2. 监听浏览器的scollTop事件,当用户滚动到页面底部时,出现回到顶部按钮,点击之后重置浏览器滚动条的高度.
//兼容性获取并监听浏览器滚动条
var osTop=document.documentElement.scrollTop|| document.body.scrollTop;
document.documentElement.scrollTop=document.body.scrollTop = 0;
3.第三方插件,例如jquery中:
$('html,body').animate({srollTop:0},500);
flex布局
flex布局即为弹性布局,也就是弹性盒模型,给元素开启弹性盒之后,子元素的float、clear、 vertical-align等失效
flex-direction:决定主轴方向
- row(默认值):主轴为水平,起点在左端
- row-reverse:主轴为水平,起点在右端
- column:主轴为垂直方向,起点在上沿
- column-reverse:起点在下沿
flex-wrap:是否换行
- nowrap(默认) 不换行
- wrap 换行 首行在上
- wrap-reverse 换行 首行在下
justify-content:子元素在主轴上的对齐方式
- flex-start(默认):左对齐
- flex-end:右对齐
- center:居中
- space-between:两端对齐,子元素之间的间隔都相等
- space-around:两端对齐(但子元素不与父元素边框贴合),子元素两侧的间隔相等;故子元素之间的间隔比子元素与父元素边框的间隔大一倍
align-item:子元素在交叉轴上对齐方式
- flex-start:交叉轴的起点对齐
- flex-end:交叉轴的终点对齐
- center:中点对齐
- baseline:子元素的第一行
- stretch(默认):若项目为设置高度或设置为auto,将占满整个父元素
设置在子元素的属性
- order:定义子元素的排列顺序,数值越小,排列越靠前,默认为0
- flex-grow:定义子元素的放大比例,默认为0,即如果存在剩余空间,也不放大;如果所有子元素的flex-grow属性为1,则它们将等分剩余空间
- flex-shrink:定义子元素的缩小比例,默认为1,如果空间不足,该子元素将缩小;如果所有子元素的flex-shrink属性都为1,当空间不足时,都将等比例缩小
- flex-basis:定义了在分配多余空间之前,子元素占据的主轴空间,默认值为auto
- flex:前三者的缩写,默认值为 0 1 auto。
flex:1代表着什么?
- flex:1 是 flex-grow、flex-shrink、flex-basis三个属性的缩写,一般默认为flex:1 1 auto(存在剩余空间就放大,空间不足就缩小);
- flex-grow:元素的放大比例,默认为1,即使存在剩余空间,也不会放大;
- flex-shrink:元素的缩小比例,默认为1,即如果空间不足,该元素将缩小;
- flex-basis:项目占据的主轴空间,默认为auto,即项目原本的大小。
http三次握手以及常见的状态码?
- 第一次握手是客户端给服务端发送请求,请求建立连接。
- 第二次握手是服务端给客户端发送请求,表示已经收到客户端的请求,并且同意建立连接。
- 第三次握手是客户端向服务端发送请求,表示确认收到服务端发送的信息。
- 三次握手的原因是为了确认客户端和服务端都有收发信息的能力,少一次确认不了,多一次浪费资源。
常见状态码:
- 200:服务器已经成功处理了请求。
- 3XX:表示重定向。
- 401:未授权,服务器请求身份验证。
- 404:服务器找不到请求的网页。
- 500:服务器内部错误,无法完成请求。
- 503:服务器目前无法使用。
简述四次挥手
什么是四次挥手:
由于TCP连接是全双工的,断开一个TCP连接,需要客户端与服务器发送四个包来确认连接的断开
简述四次挥手的过程:
因为TCP是全双工的,因此,每个方向都要单独关闭当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着一方向不会再收到数据了,但是这个TCP连接上仍然能够发送数据,直到这一方也发送了FIN.首先进行关闭的一方执行主动关闭,另一方执行被动关闭.第一个关闭的最后等待2MSL
第一次挥手:
- Client将FIN置为1,序号seq=M,发送给Server,进入FIN_WAIT_1状态第二次挥手
- Server收到后,将ACK置为1,ack=M+1,响应给Client,进入CLOSE_WAIT状态
- Client收到响应后,进入FIN_WAIT_2状态第三次挥手
- Server在结束所有数据传输后,将Fin置为1,seq=N+1,发送给Client,进入
- LAST_ACK状态第四次挥手
- Client收到后,将ACK置为1,ack=N+1,响应给Server,进入TIME_WAIT状态,等待2MSL后,进入CLOSED状态
- Server收到后,进入CLOSED状态
如何实现页面自适应?
- 使用rem单位
- 使用媒体查询
- 使用flex结合百分比布局
CSS常见的布局方式?
- 流式布局,盒子自上而下排列。
- 弹性布局,flex弹性盒。
- grid网格布局。
- 自适应(响应式布局),使用rem单位。
自适应布局 @media
通过判断当前窗口的大小,来决定使用什么样的布局
<meta name="viewport" content="width=device-width, initial-scale=1" />
@media screen (max-width: 1000px){} //窗口超过1000px时
注:使用自适应布局,不能使用绝对单位 如 px
标准盒模型和怪异)盒模型:
- W3C 标准盒模型: 属性width,height只包含内容content,不包含border和padding。
- IE (怪异)盒模型: 属性width,height包含border和padding,指的是content+padding+border。
html中元素的margin是否会叠加(合并)?如何解决?
/* 会叠加 */
问题详解1: flex布局对子元素的影响
1.子元素的float、clear和vertical-align属性将会失效
2.解决了margin传递、重叠(叠加)问题
问题详解2:flex布局的margin传递叠加问题主要有以下两种
1.父子间的margin,会由子级传递到父级
—— 解决方法: margin传递的产生的原因是父级的高度没有被自动撑开,所以在父级父级增加属性:overflow: auto 即可解决
2.兄弟间的margin值会重复叠加
—— 解决方法: 浏览器为了保证列表的整齐,上下margin产生了叠加,不能直接解决。只能通过减少一个margin的方式。如只定义margin-top:100px; margin-bottom:0px。的方式解决。
什么叫做优雅降级和渐进增强?
渐进增强 progressive enhancement:
1. 针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
2. 渐进增强观点则认为应关注于内容本身。内容是我们建立网站的诱因。有的网站展示它,有的则收集它,有的寻求,有的操作,还有的网站甚至会包含以上的种种,但相同点是它们全都涉及到内容。这使得“渐进增强”成为一种更为合理的设计范例。这也是它立即被 Yahoo! 所采纳并用以构建其“分级式浏览器支持 (Graded Browser Support)”策略的原因所在。
优雅降级 graceful degradation:
1. 一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
2. 优雅降级观点认为应该针对那些最高级、最完善的浏览器来设计网站。而将那些被认为“过时”或有功能缺失的浏览器下的测试工作安排在开发周期的最后阶段,并把测试对象限定为主流浏览器(如 IE、Mozilla 等)的前一个版本。
区别:
1. 优雅降级是从复杂的现状开始,并试图减少用户体验的供给
2. 渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要
3. 降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带
CSS清除浮动的方法
1. 在标签尾部添加空块级标签,设置样式属性为:clear:both;缺点:如果页面浮动布局多,就要增加很多空div,不利于页面的优化。
2. 父级定义伪类after和zoom,.box:after{display:block; clear:both; content:""; visibility:hidden; height:0;} .box{ zoom: 1 }
3. 简单粗暴,父级设置overflow:hidden,缺点是不能和position配合使用
4. 直接给父元素单独设置高度(height);缺点:只适合高度固定的布局,要给出精确的高度,如果高度和父级div不一样时,会产生问题。对于响应式布局会有很大影响。
移动端1px问题
原因:Retine屏的分辨率始终是普通屏幕的2倍,1px的边框在devicePixelRatio=2的retina屏下会显示成2px,在手机上缩小呈现时,导致边框太粗的效果
解决方式: .scale-1px{ position: relative; border:none; }
.scale-1px:after{ content: ''; position: absolute; bottom: 0; background: #000; width: 100%; height: 1px; -webkit-transform: scaleY(0.5); transform: scaleY(0.5); -webkit-transform-origin: 0 0; transform-origin: 0 0; }
BFC 原理 怎么清除 怎么创建bfc
BFC是块级格式化上下文;
原理:个人感觉只需要回答:BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会穿透去影响到外面的元素;属于同一个BFC的两个相邻Box的margin会发生重叠
注:1)内部的Box会在垂直方向,一个接一个地放置。 2)Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠 3)每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。 4)BFC的区域不会与float box重叠。 5)BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。 6)计算BFC的高度时,浮动元素也参与计算)
清除: 1)在父元素中添加一个属性:overflow:hidden 2)在浮动的盒子之下再放一个标签,在这个标签中使用clear:both
创建一个BFC: 1)根元素 2)float属性不为none 3)position不为static和relative 4)overflow不为visible 5)display为inline-block, table-cell, table-caption, flex, inline-flex
http请求的完全过程
- 浏览器根据域名解析IP地址
- 浏览器于web服务器建立一个TCP连接
- 浏览器给web服务器发送一个http请求(请求行、请求方法、get post url 协议版本)
- 服务器端响应HTTP请求,浏览器得到html代码 (状态行、响应头部、响应数据)
- 浏览器解析HTML代码 并请求 HTML代码中的资源
- 关闭TCP连接,浏览器对页面进行渲染呈现给用户
http协议和https协议
超文本传输协议,是一个基于请求与响应,无状态的,应用层的协议,常基于TCP/IP协议传输数据,互联网上应用最为广泛的一种网络协议
基于HTTP协议,通过SSL或TLS提供 加密处理数据、验证对方身份以及数据完整性保护
CSS优化主要是4个方面
1、加载性能
- css压缩:将写好的css进行打包,可以减少很多的体积。
- css单一样式:在需要下边距和左边距的时候,很多时候选择:margin:top 0 bottom 0,但是margin-bottom:bot tom;margin-left:left;执行效率更高。
- 减少@import,而建议使用link,因为后者在页面加载时一起加载,前者是等待页面加载完成之后再进行加载。
2、选择器性能
- 关键选择器:选择器的最后面的部分为关键选择器。css选择器是从右向左进行匹配的。当使用后代选择器的时候,浏览器会遍历所有子元素来确定是否是指定的元素等等。
- 如果规则拥有ID选择器作为其关键选择器,则不要为规则增加标签。过滤掉无关的规则。
- 避免使用通配符规则,如果*{},计算次数惊人,只对需要用到的元素进行选择。
- 尽量少的区队标签进行选择,而使用class。
- 了解哪些属性是可以通过继承而来的,然后避免对这些属性重复指定规则。
3、渲染性能
- 慎重使用高性能属性:浮动,定位。
- 尽量减少页面的重排和重绘。
- 去除控规则,{}。空规则的产生的原因一般来说是为了预留样式。去除这些空规则则无疑能减少css文档体积。
- 属性值为0时,不加单位。
- 属性值为浮动小数0.,可以省略小数点之前的0。
- 标准化各种浏览器前缀,带浏览器前缀的在前。标准属性在后。
- 不使用@import前缀,它会影响css的加载速度。
- 选择器优先嵌套,尽量避免层级过深。
- css雪碧图:同一页面相近部分的小图标,方便使用,减少页面的请求次数,但是同时图片本身不变大,使用时,优劣考虑清楚使用。
- 正确使用display的属性,由于display的作用,某一些样式组合会无效,徒增样式体积的同时也影响性能。
4、可维护性和健壮性
- 将具有相同内容的样式抽离出来,整合并通过class在页面中进行使用,提高css的可维护性。
- 样式和内容分离,将css代码定义到外部css中。
html5的新增特性.
语义标签 header nav footer section main
视频和音频 video audio
canvas 绘图
SVG绘图
新增表单元素:
progress //进度条
meter //刻度值
新增input输入特性:
color: 选取颜色
date: 选取日期
datetime: 选取日期
month: 选取月份
week 选取年
但其不支持ie8及ie8以下版本的浏览器
Js部分
js中数据类型
1、基本数据类型。
基本数据类型共有6种。字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined),还有在 ES6 中新增的 Symbol 类型。
2、引用数据类型
引用数据类型统称object对象,主要包括对象(Object)、数组(Array)、函数(Function)、日期(Date)、正则(RegExp)等等
this指向
- 普通函数调用,此时this指向window
- 构造函数调用,this指向实例对象
- 对象方法调用,this指向该方法所属对象
- 事件绑定时,this指向绑定事件的对象
- 定时器函数,this指向window
- 箭头函数,this指向上下文
更改this指向的三个方法
- call()方法
- apply()方法
- bind()方法
三者区别
- bind 会有一个返回值,返回值是个函数,因此要加上()才能调用;call,apply是没有返回值,当改变函数this指向的时候,不需要加()就会执行
- call 传递参数的时候是一个一个传递的, apply是传递一个数组
介绍箭头函数的 this
由于箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值
1. 所以 call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的 this 毫无影响。
2. 考虑到 this 是词法层面上的,严格模式中与 this 相关的规则都将被忽略
作为方法的箭头函数this指向全局window对象,而普通函数则指向调用它的对象
使用箭头函数应该注意什么?
1. 不要在对象里面定义函数,对象里面的行数应该用传统的函数方法
2. 不要在对原型对象上定义函数,在对象原型上定义函数也是遵循着一样的规则
3. 不要用箭头定义构造函数
4. 不要用箭头定义事件回调函数
ES6 箭头函数和普通函数有什么差异?
1. 相比普通函数更简洁的语法
2. 没有this,捕获其所在上下文的 this 值,作为自己的 this 值
3. 不能使用new,箭头函数作为匿名函数,是不能作为构造函数的,不能使用new
4. 不绑定arguments,用rest参数...解决
let test3=(...a)=>{console.log(a[1])} //22
5. 使用call()和apply()调用:由于 this 已经在词法层面完成了绑定,通过 call() 或 apply() 方法调用一个函数时,只是传入了参数而已,对 this 并没有什么影响:
6. 箭头函数没有原型属性
7. 不能简单返回对象字面量
let fun5 = ()=>({ foo: x }) //如果x => { foo: x } //则语法出错
8. 箭头函数不能当做Generator函数,不能使用yield关键字
9. 箭头函数不能换行
let a = ()
=>1; //SyntaxError: Unexpected token =>
解释下 let 和 const 的块级作用域
/*------------let-----------*/
1. let声明的仅在块级作用域内有效,
2. let不会发生变量提升的现象,所以一定要在定义后使用,否则报错。
3. 暂时性死区:只要块级作用域内存在let命令,它所声明的变量就绑定这个区域,不再受外部影响。
4. 不允许重复声明,let不允许在相同作用域内,重复声明同一个变量:
/*-----------const----------*/
1. 声明一个只读的常量。一旦声明,常量的值就不能改变。
2. 一旦声明,就要立即初始化,否则也报错。
3. const命令声明的常量也不提升,同样存在暂时性死区,只能在声明的位置后使用。
4. 也不可以重复声明。
谈一下你对原型链的理解
原型链:
因为每个对象和原型都有原型,对象的原型指向原型对象,
而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。
节流防抖
防抖
防抖即短时间内大量触发同一事件,只会执行一次函数*,防抖常用于搜索框/滚动条的监听事件处理,如果 不做防抖,每输入一个字/滚动屏幕,都会触发事件处理,造成性能浪费;实现原理为设置一个定时器, 约定在xx毫秒后再触发事件处理,每次触发事件都会重新设置计时器,直到xx毫秒内无第二次操作,。 // func是用户传入需要防抖的函数 // wait是等待时间
节流
防抖是延迟执行,而节流是间隔执行,和防抖的区别在于,防抖每次触发事件都重置定时器,而节流在 定时器到时间后再清空定时器,*函数节流即每隔一段时间就执行一次,实现原理为设置一个定时器,约定xx* *毫秒后执行事件,如果时间到了,那么执行函数并重置定时器* // func是用户传入需要防抖的函数 // wait是等待时间
对闭包的看法,为什么要用闭包?说一下闭包的原理以及应用场景?闭包的 this 指向问题?
闭包的作用:
1. 在外部访问函数内部的变量
2. 让函数内的局部变量可以一直保存下去
3. 模块化私有属性和公共属性
闭包的原理:
全局变量生存周期是永久,局部变量生存周期随着函数的调用介绍而销毁。
闭包就是 在函数中定义且成为该函数内部返回的函数的自由变量 的变量,该变量不会随着外部函数调用结束而销毁。
(注:不光是变量,函数内声明的函数也可以形成闭包)
当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时就产生了闭包。
闭包的应用场景:
// 1. 返回值 最常见的一种形式
var fun_1 = function () {
var name = "limo";
return function () {
return name;
}
}
var fun_1 = function () {
var name = "limo";
return name;
}
var fu_1 = fun_1();
console.log("fu_1():" + fu_1());
// 2. 函数赋值 一种变形的形式是将内部函数赋值给一个外部变量
var f2;
var fun_2 = function () {
var name = "limop"
var a = function () {
return name;
}
f2 = a;
}
f2();
console.log(f2);
// 3. 函数参数 通过函数参数引用内部函数产生闭包
var fn_3 = function (f3) {
console.log(f3);
}
function fun_3() {
var name = "limo";
var a = function () {
return name;
}
fn_3(a)
}
fun_3();
// 4. IIFE(自执行函数)
// 5. 循环赋值
function foo(){
var arr = [];
for(var i = 0; i < 10; i++){
arr[i] = (function(n){
return function(){
return n;
}
})(i)
}
return arr;
}
var bar = foo();
console.log(bar[3]());
.触发事件
window.onload = function (){
var btn = document.querySelector('.btn')
btn.onclick = function (){//事件相当于在全局触发
btn.style.color = 'red'//保持对上层作用域的引用 btn
console.log('abc')
// this
}
}
闭包的this指向问题:
var myNumber = {
value: 1,
add: function(i){
var helper = function(i){
console.log(this);
this.value += i;
}
helper(i);
}
}
myNumber.add(1);
1.this指向window对象(因为匿名函数的执行具有全局性,所以其this对象指向window);
2.不能实现value加1(每个函数在被调用时都会自动取得两个特殊变量,this和arguments,内部函数在搜索这两个对象时,只会搜索到其活动对象为止,所以不能实现访问外部函数的this对象);
3.修改代码实现正确功能
第一种解决方法:
var myNumber={
value:1,
add:function(i){
var that=this;//定义变量that用于保存上层函数的this对象
var helper=function(i){
console.log(that);
that.value+=i;
}
helper(i);
}
}
myNumber.add(1);
第二种解决方法:
var myNumber={
value:1,
add:function(i){
var helper=function(i){
this.value+=i;
}
helper.apply(this,[i]);//使用apply改变helper的this对象指向,使其指向myNumber对象
}
}
myNumber.add(1);
第三种解决方法
var myNumber={
value:1,
add:function(i){
var helper=function(i){
this.value+=i;
}.bind(this,i);//使用bind绑定,和apply相似,只是它返回的是对函数的引用,不会立即执行
helper(i);
}
}
myNumber.add(1);
简述闭包的问题以及优化
闭包的缺点:占用内层空间 大量使用闭包会造成 栈溢出
由于闭包会一直占用内存空间,直到页面销毁,我们可以主动将已使用的闭包销毁:
将闭包函数赋值为null 可以销毁闭包
async 和 await 、promise的区别 和 这两个的本质
/*---------Promise概念:---------*/
是用来解决回调地狱的,他接受一个function作为参数。function中有两个形参,一个成功的回调函数一个失败的回调函数。
.then在成功的时候触发
.catch在失败的时候触发
promise的状态不可逆,三个状态:pending、fulfilled、rejected
有两个很重要的api:
.all,表示所有的Promise数组中的方法都成功之后触发
.race,表示数组中只要有一个完成就结束
Promise对象有三种状态,他们分别是:
pending: 等待中,或者进行中,表示还没有得到结果
resolved(Fulfilled): 已经完成,表示得到了我们想要的结果,可以继续往下执行
rejected: 也表示得到结果,但是由于结果并非我们所愿,因此拒绝执行
这三种状态不受外界影响,而且状态只能从pending改变为resolved或者rejected,并且不可逆。在Promise对象的构造函数中,将一个函数作为第一个参数。而这个函数,就是用来处理Promise的状态变化。
Promise对象中的then方法,可以接收构造函数中处理的状态变化,并分别对应执行。then方法有2个参数,第一个函数接收resolved状态的执行,第二个参数接收reject状态的执行。
promise的实现原理,如果我现在向服务器发送一个请求,但是我后悔了,不想让服务器返回数据,去实现一个delay
取消结束Promise的方法?
1. 返回一个pending状态的Promise,原Promise链会终止
Promise.resolve().then(() => {
console.log('ok1')
return new Promise(()=>{}) // 返回“pending”状态的Promise对象
}).then(() => {
// 后续的函数不会被调用
console.log('ok2')
}).catch(err => {
console.log('err->', err)
})
对象方法
Promise.all()同时处理多个异步函数,当所有任务都执行完成后才得到结果
Promise.race()同时处理多个异步函数,只要有一个任务执行完成就能得到结果
/*---------async await概念:---------*/
async await也是异步编程的一种解决方案,他遵循的是Generator 函数的语法糖,他拥有内置执行器,不需要额外的调用直接会自动执行并输出结果,它返回的是一个Promise对象。
两者的区别:
Promise的出现解决了传统callback函数导致的“地域回调”问题,但它的语法导致了它向纵向发展行成了一个回调链,遇到复杂的业务场景,这样的语法显然也是不美观的。而async await代码看起来会简洁些,使得异步代码看起来像同步代码,await的本质是可以提供等同于”同步效果“的等待异步返回能力的语法糖,只有这一句代码执行完,才会执行下一句。
async await与Promise一样,是非阻塞的。
async await是基于Promise实现的,可以说是改良版的Promise,它不能用于普通的回调函数。
简述 aync await 的好处
async/await最重要的好处是同步编程风格
2. async/await有本地浏览器支持。截至今天,所有主流浏览器 查看都完全支持异步功能。
3. async关键字。它声明 getBooksByAuthorWithAwait()函数返回值确保是一个 promise,以便调用者可以安全调用 getBooksByAuthorWithAwait().then(...)或 await getBooksByAuthorWithAwait()
ES6新特性
- 箭头函数
- class类的继承
- const、let变量定义
- 模板字符串
- 结构赋值
- Promise对象
- 字面量简写(当属性值与属性名一样时)
- 拓展运算符
- import和export,之前是commonJS的规范
数组中常见方法
- find 查找符合条件的项
- findIndex 查找符合条件项目的下标
- filter过滤数组,返回符合条件的项
- map遍历数组,映射并返回一个新数组
- forEach循环数组,无返回值
- reduce数组的累加方法
- splice截取数组
- concat数组合并
- join数组转字符串
js数组主要有哪些方法?主要参数你了解吗?
- shift():删除数组的第一个元素,返回删除的值。这里是0
- unshift(3,4):把参数加载数组的前面,返回数组的长度。现在list:中是3,4,0,1,2
- pop():删除数组的最后一个元素,返回删除的值。这里是2.
- push(3):将参数加载到数组的最后,返回数组的长度,现在List中时:0,1,2,3
- concat(3,4):把两个数组拼接起来。
- splice(start,deleteCount,val1,val2,...):从start位置开始删除deleteCount项,并从该位置起插入val1,val2,...
- reverse:将数组反序 var a = [1,2,3,4,5]; var b = a.reverse(); //a:[5,4,3,2,1] b:[5,4,3,2,1]
- sort(orderfunction):按指定的参数对数组进行排序 var a = [1,2,3,4,5]; var b = a.sort(); //a:[1,2,3,4,5] b:[1,2,3,4,5]
- slice(start,end):返回从原数组中指定开始下标到结束下标之间的项组成的新数组 var a = [1,2,3,4,5]; var b = a.slice(2,5); //a:[1,2,3,4,5] b:[3,4,5]
- js迭代的方法:every() 、fliter()、forEach()、map()、some()
.git经常用到的命令
git helper -a # 查看全部git子命令 git -version # 查看git版本 git checkout -b "新建分支名" # 创建一个分支并切换到新创建的分支
git branch "新建分支名" # 创建分支
git branch # 查看本地所有分支 git branch -r # 查看远程所有分支 git branch -a # 查看本地和远程分支 git branch -d "某分支名" # 删除某分支
git checkout "某分支名" # 切换到某分支
git switch "某分支名" # 切换到某分支 git status # 查看状态
git add "文件名" # 将某个文件存入暂存区
git add . # 将所有文件存入暂存区
git commit -m "备注信息" # 提交到仓库
git diff # 查看变更 工作区和暂存区的差别比对 git push <远程主机名><本地分支>:<远程分支> # 完整写法
git push origin master # 将本地的master分支推送到远程的master分支,如果master不存在 则会创建master分支
git push <新建分支名> # 将新建分支推送到远程分支 git push origin :master # 如果忽略本地分支,则推送了一个空分支,相当于删除了分支。
等同于git push origin --delete <要被删除的分支名>
git push # 将本地分支推送到远程分支,如果当前分支和远程分支之间存在追踪关系,则本地分支和远程分支都可以省略 git push origin --delete <要删除的分支名> # 删除远程分支 git fetch origin master # 将远程分支下拉到本地 git pull <远程分支地址> <远程分支名>:<本地分支名> # 完整写法
例如,git pull origin next : master .将远程分支与next分支合并。
git pull origin master # 获取远程分支,并于当前分支合并 git fetch origin master # 获取远程分支master到本地,不合并
git clone "远程地址" # 将远程分支克隆到本地
git merge "分支名" # 把现有分支合并到分支上
git reset HEAD file # 文件 add后,撤销修改
git remote add origin git项目地址 # 本地仓库和远程仓库建立连接
git remote -v # 查看远程关联的地址
git remote remove origin # 移除远程关联
深浅拷贝 优缺点 json.parse、 for循环递归方法拷贝
浅拷贝: ES6 为 Object 对象新增一个方法 Object.assign( target, source1, source2)。第一个参数是目标对象,后面的是源对象。这个方法会把源对象上面的可枚举属性拷贝到目标对象上。但是这种拷贝属于浅拷贝。 //展开运算符 ... 赋值运算符 =
深拷贝: 对象的深拷贝可以通过 JSON 对象的两个方法,一是将 js 对象转成字符串对象的 JSON.stringify 方法,另一个是将 js 字符串对象转换成 js 对象的 JSON.parse 方法。 //插件使用 lodash 的深拷贝函数。
弊端:1.如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式,而不是对象的形式 2.如果obj里有RegExp(正则表达式的缩写)、Error对象,则序列化的结果将只得到空对象;3.如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
宏任务微任务
宏任务包括 script , setTimeout , setInterval , setImmediate 。 微任务包括 process.nextTick , promise , MutationObserver 。
首先执行同步代码,这属于宏任务 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行 执行所有微任务 当执行完所有微任务后,如有必要会渲染页面 然后开始下一轮 Event Loop,执行宏任务中的异步代码,也就是 setTimeout 中的回调函数 //这里很多人会有个误区,认为微任务快于宏任务,其实是错误的。因为宏任务中包括了 script ,浏览器会先执行一个宏任务,接下来有异步代码的话才会先执行微任务
回流和重绘
回流:当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候,这时候是一定会发生回流的,因为要构建render tree。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。
重绘:当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
区别:他们的区别很大: 回流必将引起重绘,而重绘不一定会引起回流。比如:只有颜色改变的时候就只会发生重绘而不会引起回流 当页面布局和几何属性改变时就需要回流 比如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变以下几个动作可能会导致性能问题: 改变 window 大小 改变字体 添加或删除样式 文字改变 定位或者浮动 盒模型
判断两对象是否相等
1、通过JSON.stringify(obj)来判断两个对象转后的字符串是否相等
2、getOwnPropertyNames方法返回一个由指定对象的所有自身属性的属性名组成的数组。先进行长度的比较,然后进行遍历
3.Object.is(a,b)
手写: function diff(obj1,obj2){ var o1 = obj1 instanceof Object; var o2 = obj2 instanceof Object; // 判断是不是对象 if (!o1 || !o2) { return obj1 === obj2; }
//Object.keys() 返回一个由对象的自身可枚举属性(key值)组成的数组,
//例如:数组返回下表:let arr = ["a", "b", "c"];console.log(Object.keys(arr))->0,1,2;
if (Object.keys(obj1).length !== Object.keys(obj2).length) {
return false;
}
for (var o in obj1) {
var t1 = obj1[o] instanceof Object;
var t2 = obj2[o] instanceof Object;
if (t1 && t2) {
return diff(obj1[o], obj2[o]);
} else if (obj1[o] !== obj2[o]) {
return false;
}
}
return true;
}
简述同步和异步的区别
同步:
同步的思想是:所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。异步:
将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。同步和异步本身是相对的:
同步就相当于是 当客户端发送请求给服务端,在等待服务端响应的请求时,客户端不做其他的事情。当服务端做完了才返回到客户端。这样的话客户端需要一直等待。用户使用起来会有不友好。异步就是,当客户端发送给服务端请求时,在等待服务端响应的时候,客户端可以做其他的事情,这样节约了时间,提高了效率。
存在就有其道理 异步虽然好 但是有些问题是要用同步用来解决,比如有些东西我们需要的是拿到返回的数据在进行操作的。这些是异步所无法解决的。
异步的解决方案有哪些?
1.回调函数callback
2.事件发布订阅
3.Promise
4.Generator
5.async/await
请描述一下 cookies,sessionStorage 和 localStorage 的区别?
不同点:
1.存储大小
cookie数据大小不能超过4k。
sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
2.有效时间
localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
sessionStorage 数据在当前浏览器窗口关闭后自动删除。
cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
3. 数据与服务器之间的交互方式
cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
使用场景:
localStorage可以用来统计页面访问次数。
cookie一般存储用户名密码相关信息,一般使用escape转义编码后存储。
判断数据类型
1. typeof
- 可以判断数据类型,它返回表示数据类型的字符串(返回结果只能包括number,boolean,string,function,object,undefined);
- 可以使用typeof判断变量是否存在(如if(typeof a!="undefined"){...});
- Typeof 运算符的问题是无论引用的对象是什么类型 它都返回object
2.instanceof
原理 因为A instanceof B 可以判断A是不是B的实例,返回一个布尔值,由构造类型判断出数据类型
3.通过Object下的toString.call()方法来判断
Object.prototype.toString.call();
console.log(toString.call(123)); //[object Number]
console.log(toString.call('123')); //[object String]
4.根据对象的contructor判断
console.log('数据类型判断' - constructor);
console.log(arr.constructor === Array); //true
5.jq中判断数据类型的方法
jQuery提供了一系列工具方法,用来判断数据类型,以弥补JavaScript原生的typeof运算符的不足。以下方法对参数进行判断,返回一个布尔值。
jQuery.isArray();是否为数组
jQuery.isEmptyObject();是否为空对象 (不含可枚举属性)。
jQuery.isFunction():是否为函数
jQuery.isNumberic():是否为数字
jQuery.isPlainObject():是否为使用“{}”或“new Object”生成对象,而不是浏览器原生提供的对象。 jQuery.isWindow(): 是否为window对象;
jQuery.isXMLDoc(): 判断一个DOM节点是否处于XML文档中。
网页性能优化
1.减少http请求
2.压缩js和css,使用精灵图
3.将样式表放在页面上方
4.将脚本放在底部
5.将JavaScript和CSS独立成外部文件
6.减少DOM访问
7.不要使用@import 用link
解决跨域的方法性能
(1)通过jsonp解决跨域 (2)通过修改document.domain来跨子域 (3)使用window.name来进行跨域 (4)使用HTML5中新引进的window.postMessage方法来跨域
你的项目如何实现支付功能的?
网页上:
- 支付宝:后端返回我一个URL,我直接做跳转就行了。
- 微信:如果是小程序,调用微信的支付接口。
手机App:
- 支付宝:调用原生开发人员给我提供的方法就行了。
- 微信:使用微信小程序提供的支付接口。
Vue部分
vue优点?
- 轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb;
- 简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;
- 双向数据绑定:保留了angular的特点,在数据操作方面更为简单;
- 组件化:保留了react的优点,实现了html的封装和重用,在构建单页面应用方面有着独特的优势;
- 视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;
- 虚拟DOM:dom操作是非常耗费性能的, 不再使用原生的dom操作节点,极大解放dom操作,但具体操作的还是dom不过是换了另一种方式;
- 运行速度更快: 相比较与react而言,同样是操作虚拟dom,就性能而言,vue存在很大的优势。
如何获取dom?
答:ref="domName" 用法:this.$refs.domName
为什么使用key?
答:需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点。
作用主要是为了高效的更新虚拟DOM。
v-modal的使用。
答:v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:
v-bind绑定一个value属性;
v-on指令给当前元素绑定input事件。
$nextTick的使用
答:定义:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。所以就衍生出了这个获取更新后的DOM的Vue方法。所以放在Vue.nextTick()回调函数中的执行的应该是会对DOM进行操作的 js代码;
理解:`nextTick()`,是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数,
vue组件中data为什么必须是一个函数?
答:因为JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。
组建中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。
vue中怎么重置data
第一种,手动去给表单双向绑定的对象赋值为空
`this.$options.data()`调用它我们可以获取到页面data在刚初始化时的状态那么这样我们就可以将data中的某个数据重置到初始状态
如果我想把整个data都重置到初始化状态呢?
`Object.assign(this.$data, this.$options.data())`
那就用这个方法
`this.$data` 获取的是当前的data对象
`Object.assign`则可以将一个对象赋值给另一个对象
两个参数,可以将参数2 赋值给 参数1
#### 渐进式框架的理解
答:主张最少;可以根据不同的需求选择不同的层级;
Vue中双向数据绑定是如何实现的?
答:vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;
核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法。
单页面应用(spa)和多页面应用区别及优缺点
答:单页面应用(SPA),通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。多应用于pc端。
多页面(MPA),就是指一个应用中有多个页面,页面跳转时是整页刷新
单页面的优点:
用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小;前后端分离;页面效果会比较炫酷(比如切换页面内容时的专场动画)。
单页面的缺点:
不利于seo;导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理);初次加载时耗时多;页面复杂度提高很多。
v-if和v-for的优先级
答:当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中。所以,不推荐v-if和v-for同时使用。
如果v-if和v-for一起用的话,vue中的的会自动提示v-if应该放到外层去。
assets和static的区别
答:相同点:assets和static两个都是存放静态资源文件。项目中所需要的资源文件图片,字体图标,样式文件等都可以放在这两个文件下,这是相同点
不相同点:assets中存放的静态资源文件在项目打包时,也就是运行npm run build时会将assets中放置的静态资源文件进行打包上传,所谓打包简单点可以理解为压缩体积,代码格式化。而压缩后的静态资源文件最终也都会放置在static文件中跟着index.html一同上传至服务器。static中放置的静态资源文件就不会要走打包压缩格式化等流程,而是直接进入打包好的目录,直接上传至服务器。因为避免了压缩直接进行上传,在打包时会提高一定的效率,但是static中的资源文件由于没有进行压缩等操作,所以文件的体积也就相对于assets中打包后的文件提交较大点。在服务器中就会占据更大的空间。
建议:将项目中template需要的样式文件js文件等都可以放置在assets中,走打包这一流程。减少体积。而项目中引入的第三方的资源文件如iconfoont.css等文件可以放置在static中,因为这些引入的第三方文件已经经过处理,我们不再需要处理,直接上传。
vue常用的修饰符
答:.stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡;
.prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);
.capture:与事件冒泡的方向相反,事件捕获由外到内;
.self:只会触发自己范围内的事件,不包含子元素;
.once:只会触发一次。
Vue的修饰符分类
一、事件修饰符
vue为v-on提供了事件修饰符,可以通过(.)表示的指令后缀来调用修饰符。
- .stop:**阻止冒泡行为**。等同于e.stopPropagation()
- .prevent:**阻止默认行为**。等同于e.preventDefault()
- .self:只有点击自身的范围内才会触发,不包括子元素
- .once:只执行一次
- .capture:当元素发生冒泡时,先触发带有该修饰符的元素。若有多个该修饰符,则由外而内触发。就是**谁有该事件修饰符,就先触发谁。**
二、键盘修饰符
- .enter:回车键
- .tab:制表键
- .delete:删除键
- .esc:返回键
- .space:空格键
- .up:向上键
- .down:向下键
- .left:向左键
- .right:向右键
三、系统修饰键
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
- .ctrl
- .alt
- .shift
- .meta
- .exact修饰符:允许你控制由精确的系统修饰符组合触发事件
四、鼠标按钮修饰符
鼠标修饰符用来限制处理程序监听特定的滑鼠按键。常见的有:
- .left
- .right
- .middle
这些修饰符会限制处理函数仅响应特定的鼠标按钮。
五、input修饰符(例如:v-model.xxxx使用)
- .lazy:在改变后才触发(也就是只有input不聚焦的时候才会执行)
- .number:将输入的字符串转换为Number类型(但是如果输入字符串,输出的还是string,只是控制台会警告)
- .trim:自动过滤用户输入的首尾空格
vue的两个核心点
答:数据驱动、组件系统
数据驱动:ViewModel,保证数据和视图的一致性。
组件系统:应用类UI可以看作全部是由组件树构成的。
vue和jQuery的区别
答:jQuery是使用选择器`($)`选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的。比如需要获取label标签的内容:`$("lable").val()`;,它还是依赖DOM元素的值。
Vue则是通过Vue对象将数据和View完全分离开来了。对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的,他们通过Vue对象这个vm实现相互的绑定。这就是传说中的MVVM。
引进组件的步骤
答: 在template中引入组件;
在script的第一行用import引入路径;
用component中写上组件名称。
Vue中引入组件的步骤?
1.采用ES6的import ... from ...语法
或 CommonJS的require()方法引入组件
2.对组件进行注册,代码如下
注册 Vue.component('my-component', { template: '<div>A custom component!</div>'})
3.使用组件<my-component></my-component>
delete和Vue.delete删除数组的区别
答:delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。Vue.delete 直接删除了数组 改变了数组的键值。
SPA首屏加载慢如何解决
答:安装动态懒加载所需插件;使用CDN资源。
vue slot
答:简单来说,假如父组件需要在子组件内放一些DOM,那么这些DOM是显示、不显示、在哪个地方显示、如何显示,就是slot分发负责的活。
Vue2中注册在router-link上事件无效解决方法
答: 使用@click.native。原因:router-link会阻止click事件,.native指直接监听一个原生事件。
请说下封装 vue 组件的过程?
答:1. 建立组件的模板,先把架子搭起来,写写样式,考虑好组件的基本逻辑。(os:思考1小时,码码10分钟,程序猿的准则。)
2. 准备好组件的数据输入。即分析好逻辑,定好 props 里面的数据、类型。
2. 准备好组件的数据输出。即根据组件逻辑,做好要暴露出来的方法。
2. 封装完毕了,直接调用即可
params和query的区别
答:用法:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.$route.query.name和this.$route.params.name。
url地址显示:query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
注意点:query刷新不会丢失query里面的数据
params刷新 会 丢失 params里面的数据。
vue初始化页面闪动问题
答:使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。
首先:在css里加上[v-cloak] {
display: none;
}。
如果没有彻底解决问题,则在根元素加上style="display: none;" :style="{display: 'block'}"
vue更新数组时触发视图更新的方法
答:push();pop();shift();unshift();splice(); sort();reverse()
axios与ajax的区别及优缺点
区别:axios是通过Promise实现对ajax技术的一种封装,就像jquery对ajax的封装一样,简单来说就是ajax技术实现了局部数据的刷新,axios实现了对ajax的封装,axios有的ajax都有,ajax有的axios不一定有,总结一句话就是axios是ajax,ajax不止axios
优缺点:
ajax:
1、本身是针对MVC编程,不符合前端MVVM的浪潮
2、基于原生XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案,jquery整个项目太大,单纯使用ajax却要引入整个jquery非常不合理(采取个性化打包方案又不能享受cdn服务)
3、ajax不支持浏览器的back按钮
4、安全问题ajax暴露了与服务器交互的细节
5、对搜索引擎的支持比较弱
6、破坏程序的异常机制
7、不容易调试
axios:
1、从node.js创建http请求
2、支持Promise API
3、客户端防止CSRF(网站恶意利用)
4、提供了一些并发请求的接口
axios的特点有哪些
答:从浏览器中创建XMLHttpRequests;
node.js创建http请求;
支持Promise API;
拦截请求和响应;
转换请求数据和响应数据;
取消请求;
自动换成json。
axios中的发送字段的参数是data跟params两个,两者的区别在于params是跟请求地址一起发送的,data的作为一个请求体进行发送
params一般适用于get请求,data一般适用于post put 请求
axios是什么?怎么使用?描述使用它实现登录功能的流程?
答:请求后台资源的模块。
npm install axios -S装好,然后发送的是跨域,需在配置文件中config/index.js进行设置。后台如果是Tp5则定义一个资源路由。js中使用import进来,然后.get或.post。返回在.then函数中如果成功,失败则是在.catch函数中
get 和post的区别
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST么有。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
vue-cli 工程中常用的 npm 命令有哪些?
- npm install:下载 node_modules 资源包的命令
- npm run dev:启动 vue-cli 开发环境的 npm 命令
- npm run build:vue-cli 生成生产环境部署资源的 npm 命令
- npm run build--report: 用于查看 vue-cli 生产环境部署资源文件大小的 npm命令
- npm run lib: 用于生成 npm 发布的包
Vue 如何优化首屏加载速度?
- 异步路由加载
- 不打包库文件
- 代码分割
- 关闭 sourcemap
- 开启 gzip 压缩
- 公共代码抽取
- 图片懒加载
- 路由懒加载
- 多项目共享公共js(缓存)
指令v-el的作用是什么?
提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标.可以是 CSS 选择器,也可以是一个 HTMLElement 实例,
scss是什么?在vue.cli中的安装使用步骤是?有哪几大特性?
答:css的预编译。
使用步骤:
第一步:用npm 下三个loader(sass-loader、css-loader、node-sass)
第二步:在build目录找到webpack.base.config.js,在那个extends属性中加一个拓展.scss
第三步:还是在同一个文件,配置一个module属性
第四步:然后在组件的style标签加上lang属性 ,例如:lang=”scss”
有哪几大特性:
1、可以用变量,例如($变量名称=值);
2、可以用混合器,
3、可以嵌套
scss与less:
less也是动态样式语言,一样也比css多处很多功能(如变量,继承,运算, 函数), Less 既可以在客户端上运行,也可在服务端运行 ( Node.js)。
- `less`、`scss`的变量符不一样`less`是@、`scss`是$、`css`变量是两根连词线(- -)
- 变量作用域不一样
- 条件语句不一样`less`不支持条件语句\
`scss`语句支持if{}else{}、for{}循环语句
mint-ui是什么?怎么使用?说出至少三个组件使用方法?
答:基于vue的前端组件库。
npm安装,然后import样式和js,vue.use(mintUi)全局引入。在单个组件局部引入:import {Toast} from ‘mint-ui’。
组件一:Toast(‘登录成功’);
组件二:mint-header;
组件三:mint-swiper
请说下封装 vue 组件的过程?
答:首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性等问题。
然后,使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。
Vue中事件绑定的原理
Vue 的事件绑定分为两种一种是原生的事件绑定,还有一种是组件的事件绑定, 理解:
1.原生 dom 事件的绑定,采用的是 addEventListener 实现
2.组件绑定事件采用的是 $on 方法
ssr是什么
服务端渲染
keep-alive元素?
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
例如在创建时从 API 调用中引入数据的组件。你可能不希望每次动态切换这个组件进行渲染时都调用此 API。这时你可以将组件包含在 keep-alive 元素中。keep-alive 元素缓存该组件并从那里获取它,而不是每次都重新渲染它。
keepalive就是保证这个组件一直在不销毁,只要组件创建了就不会被销毁
- include
包含,为每一个组件设置一个name属性。在include的时候写上这个属性值,表示keep-alive的时候包含这个组件。include表示包含,多个用,隔开
- exclude
exclude表示不包含,多个用,隔开
在设置了keep-alive的时候,页面切换的场景下会触发这两个钩子函数:activated和deactivated
Vue组件中写 name 选项有什么作用?
当项目使用keep-alive时,可搭配组件name进行缓存过滤
DOM递归迭代时需要调用自身name
当你用vue-devtools调试工具里显示的组见名称是由vue中组件name决定的
computed 是一个对象时,它有哪些选项?
computed 和 methods 有什么区别? computed 是否能依赖其它组件的数据? watch 是一个对象时,它有哪些选项?
有get和set两个选项 methods是一个方法,它可以接受参数,而computed不能,computed是可以缓存的,methods不会。 computed可以依赖其他computed,甚至是其他组件的data watch 配置 handler deep 是否深度 immeditate 是否立即执行
描述下 vue 从初始化页面–修改数据–刷新页面 UI 的过程?
当 Vue 进入初始化阶段时,一方面 Vue 会遍历 data 中的属性,并用 Object.defineProperty 将它转化成 getter/setter 的形式,实现数据劫持;另一方面,Vue 的指令编译器 Compiler 对元素节点的各个指令进行解析,初始化视图,并订阅 Watcher 来更新试图,此时 Watcher 会将自己添加到消息订阅器 Dep 中,此时初始化完毕。
当数据发生变化时,触发 Observer 中 setter 方法,立即调用 Dep.notify(),Dep 这个数组开始遍历所有的订阅者,并调用其 update 方法,Vue 内部再通过 diff 算法,patch 相应的更新完成对订阅者视图的改变。
Vue中watch、methods 和 计算属性的区别是什么?
1、computed和methods
共同点:computed能现实的methods也能实现;
不同点:computed是基于它的依赖进行缓存的。computed只有在它的相关依赖发生变化才会重新计算求值。 而只要它的相关依赖没有发生变化,多次访问会立即返回之前的计算结果,而不必再次执行计算。相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。也就是说当我们不希望有缓存,用方法来替代。
2、watch和computed
共同点:都是以Vue的依赖追踪机制为基础的,都是希望在依赖数据发生改变的时候,被依赖的数据根据预先定义好的函数,发生“自动”的变化。
不同点:watch擅长处理的场景:一个数据影响多个数据;computed擅长处理的场景:一个数据受多个数据影响。虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器,当需要在数据变化时执行异步或开销较大的操作时,通过侦听器最有用。
计算属性computed :
1. 支持缓存,只有依赖数据发生改变,才会重新进行计算
2. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
3.computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
4. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
侦听属性watch:
1. 不支持缓存,数据变,直接会触发相应的操作;
2.watch支持异步;
3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
4. 当一个属性发生变化时,需要执行对应的操作;一对多;
5. 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
immediate:组件加载立即触发回调函数执行,
deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。
注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
watch工作原理:
watch在一开始初始化的时候,会读取一遍监听的数据的值,此时那个数据就收集到watch的watcher了然后你给watch设置的handler,watch 会放入watcher的更新函数中,当数据改变时,通知watch的watcher进行更新,于是你设置的handler就被调用了。
vue常用的UI组件库
答:Mint UI,element,VUX
如何给vue自定义组件添加点击事件?
需要在@click后面加上.native,官方对于native的解释为:.native -——监听组件根元素的原生事件
正确写法:<my-button @click.native="alert1()" names="删除" v-bind:item2="btdata"></my-button>
什么是异步组件?
当大型程序使用大量组件时,从服务器上同时加载所有组件可能是没有意义的。在这种情况下,Vue 允许我们在需要时定义从服务器异步加载的组件。在声明或注册组件时,Vue 接受提供 Promise 的工厂函数。然后可以在调用该组件时对其进行“解析”。
通过仅加载基本组件并把异步组件的加载推迟到未来的调用时间,可以节省带宽和程序加载时间。
vue组件之间的传参
父传子 props 子传父 `this.$emit` 非父子组件 eventHub 中转站 `this.$on vuex state` 存的变量,mutations改变的状态 actions 触发的行为(方法)
使用eventBus 事件总线 一种组件间相互通信的方式,适用于任意组件间通信。
- 创建一个空Vue对象
- $emit自定义事件
- $on接收事件
1、接受数据:A组件想接受数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
2、提供数据:`this.$bus.$emit('xxx',数据)` 最好在beforeDestroy钩子中,用`$off('xxx')`去解绑当前组件所用到的事件 vuex 状态管理 创建store对象 在组件中引入并使用
vue创建组件的时候data中为什么会被return出一个对象?
可以保证组件的每一次调用都是创建一个新对象,组件之间不会产生影响;
vue中有哪些内置组件:
component slot transtion fliters
谈谈对vue 组件化的理解。
组件是可复用的 Vue 实例,准确讲它们是VueComponent的实例,继承自Vue。可以增加代码的复用性、可维护性和可测试性。提高开发效率, 方便重复使用,简化调试步骤,提升整个项目的可维护性,便于协同开发,是高内聚、低耦合代码的实践。
Class 与 Style 如何动态绑定?
.绑定 class 的数组用法
对象方法 v-bind:class="{'orange': isRipe, 'green': isNotRipe}"
数组方法v-bind:class="[class1, class2]"
行内 v-bind:style="{color: color, fontSize: fontSize+'px' }"
Class 可以通过对象语法和数组语法进行动态绑定:
**对象语法:**
data: { isActive: true, hasError: false }
**数组语法:**
data: { activeClass: 'active', errorClass: 'text-danger' }
Style 也可以通过对象语法和数组语法进行动态绑定
**对象语法:**
data: { activeColor: 'red', fontSize: 30 }
**数组语法:**
data: { styleColor: { color: 'red' }, styleSize:{ fontSize:'23px' } }
生命周期函数面试题
什么是 vue 生命周期?有什么作用?
答:每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做 生命周期钩子 的函数,这给了用户在不同阶段添加自己的代码的机会。(ps:生命周期钩子就是生命周期函数)例如,如果要通过某些插件操作DOM节点,如想在页面渲染完后弹出广告窗, 那我们最早可在mounted 中进行。
第一次页面加载会触发哪几个钩子?
答:beforeCreate, created, beforeMount, mounted
简述每个周期具体适合哪些场景
答:beforeCreate:在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法
create:data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作
beforeMount:执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的
mounted:执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行
beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步
updated:页面显示的数据和data中的数据已经保持同步了,都是最新的
beforeDestory:Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁
destroyed: 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。
created和mounted的区别
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。 mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作
created
在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),
属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
mounted
el 被新创建的 `vm.$el` 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,
当 mounted 被调用时 `vm.$el` 也在文档内。
vue获取数据在哪个周期函数
答:一般 created/beforeMount/mounted 皆可.
比如如果你要操作 DOM , 那肯定 mounted 时候才能操作.
请详细说下你对vue生命周期的理解?
答:总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
创建前/后: 在beforeCreated阶段,vue实例的挂载元素`$el`和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,`$el`还没有。
载入前/后:在beforeMount阶段,vue实例的`$el`和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:当data变化时,会触发beforeUpdate和updated方法。
销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在。
生命周期钩子函数
分为四个阶段
- 创建
- beforeCreate
- created【重要】
组件创建成功之后执行,主要用来在这个钩子函数中调接口取数据
- 挂载
- beforeMount
- mounted【重要】
挂载成功之后执行,在这个钩子函数中可以获取组件的dom元素
可以使用$el属性获取当前组件的dom元素
- 更新
- beforeUpdate
- updated
- 销毁
- beforeDestroy
- destroyed
父子套件执行顺序
- 更新阶段的钩子函数是在组件存在的周期中重复执行的,其他六个都是只执行一次。在更新阶段不能改变数据,数据改变会引起死循环。因为数据或者属性改变的话组件会触发更新阶段的钩子函数
- 嵌套组件的生命周期函数执行顺序
在嵌套组件中,当执行到父组件的挂载之前的时候,会执行所有子组件的创建到挂载完成的钩子函数。当子组件都挂载完成之后会执行父组件的挂载完成函数
activated路由组件被激活时触发
deactivated路由切换时触发
vue路由面试题
RouterLink在IE和Firefox中不起作用(路由不跳转)的问题
答: 方法一:只用a标签,不适用button标签;方法二:使用button标签和Router.navigate方法
Vue里面router-link在电脑上有用,在安卓上没反应怎么解决?
答:Vue路由在Android机上有问题,babel问题,安装babel polypill插件解决。
Vue-router跳转和location.href有什么区别
答:使用location.href='/url'来跳转,简单方便,但是刷新了页面;
使用history.pushState('/url'),无刷新页面,静态跳转;
引进router,然后使用router.push('/url')来跳转,使用了diff算法,实现了按需加载,减少了dom的消耗。
其实使用router跳转和使用history.pushState()没什么差别的,因为vue-router就是用了history.pushState(),尤其是在history模式下。
谈谈对Vue 路由的理解。
根据不同的url展示不同的页面或者数据。
分类:路由分为前端路由和后端路由。
前端路由:主要用于单页面的开发,根据用户请求的地址来渲染不同的页面。前端路由不会经过后端,而是根据hash值的变化进行页面数据的渲染,所以不会刷新,不跳转。
原理:通过hashRouter(onhashchange)或者history路由(h5 historyAPI)进行页面的切换。
后端路由:根据用户请求的路径返回不同的页面或数据。
登录原理:
每次你在网站的登录页面中输入用户名和密码时,这些信息都会发送到服务器。服务器随后会将你的密码与服务器中的密码进行验证。如果两者不匹配,则你会得到一个错误密码的提示。如果两者匹配,则成功登录。
控制权限:
首先在我前端页面中我会配置好所有的路由节点,每一个节点都会添加一个自定义属性用来标识当前页面的访问权限。每一次用户登录成功之后,服务器端会返回当前用户的权限信息,然后我根据返回的权限信息动态设置我的管理系统的导航菜单 我们除了客户端验证之外还有会服务器端验证,每一次调用接口的时候服务器端都会验证用户的的权限信息,如果没有权限就会返回401状态码,我在页面中弹提示
mvvm 框架是什么?
答:vue是实现了双向数据绑定的mvvm框架,当视图改变更新模型层,当模型层改变更新视图层。在vue中,使用了双向绑定技术,就是View的变化能实时让Model发生变化,而Model的变化也能实时更新到View。
vue-router 是什么?它有哪些组件
答:vue用来写路由一个插件。router-link、router-view
active-class 是哪个组件的属性? 嵌套路由怎么定义?children
答:vue-router模块的router-link组件。children数组来定义子路由
怎么定义 vue-router 的动态路由? 怎么获取传过来的值?
答:在router目录下的index.js文件中,对path属性加上/:id。 使用router对象的params.id。
vue-router 有哪几种导航钩子?
答:三种,
第一种:是全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截。
第二种:组件内的钩子
- `beforeRouteEnter`
- `beforeRouteUpdate` (2.2 新增)
- `beforeRouteLeave`
第三种:单独路由独享组件
$route 和 $router 的区别
答:`$router`是VueRouter的实例,在script标签中想要导航到不同的URL,使用`$router.push`方法。返回上一个历史history用`$router.to(-1)`
$route为当前router跳转对象。里面可以获取当前路由的name,path,query,parmas等。
hash路由和history路由实现原理说一下
location.hash的值实际就是URL中#后面的东西。
history实际采用了HTML5中提供的API来实现,主要有history.pushState()和history.replaceState()。
答:hash模式:即地址栏 URL 中的 # 符号;
history模式:window.history对象打印出来可以看到里边提供的方法和记录长度。利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)。
vue-router实现路由懒加载( 动态加载路由 )
路由懒加载是通过异步的方式来加载对应的路由组件,提高页面相应速度
答:三种方式
第一种:vue异步组件技术 ==== 异步加载,vue-router配置路由 , 使用vue的异步组件技术 , 可以实现按需加载 .但是,这种情况下一个组件生成一个js文件。
第二种:路由懒加载(使用import)。
第三种:webpack提供的require.ensure(),vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
vuex是什么?怎么使用?哪种功能场景使用它?
答:vue框架中状态管理。在main.js引入store,注入。
新建了一个目录store.js,….. export 。
场景有:单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车
vuex有哪几种属性?
答:有五种,分别是 State、 Getter、Mutation 、Action、 Module
state => 基本数据(数据源存放地)
getters => 从基本数据派生出来的数据
mutations => 提交更改数据的方法,同步!
actions => 像一个装饰器,包裹mutations,使之可以异步。
modules => 模块化Vuex
vuex的State特性是?
stae就是存放数据的地方,类似一个仓库 , 特性就是当mutation修改了state的数据的时候,他会动态的去修改所有的调用这个变量的所有组件里面的值( 若是store中的数据发生改变,依赖这个数据的组件也会发生更新 )
vuex的Getter特性是?
getter用来获取数据,mapgetter经常在计算属性中被使用
vuex的Mutation特性是?
Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。 Action 可以包含任意异步操作
Vue.js中ajax请求代码应该写在组件的methods中还是vuex的actions中?
答:如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用
vuex 的 store 特性是什么
vuex 就是一个仓库,仓库里放了很多对象。其中 state 就是数据源存放地,对应于一般 vue 对象里面的 data
state 里面存放的数据是响应式的,vue 组件从 store 读取数据,若是 store 中的数据发生改变,依赖这相数据的组件也会发生更新 它通过 mapState 把全局的 state 和 getters 映射到当前组件的 computed 计算属性
Vuex 如何区分 state 是外部直接修改,还是通过 mutation 方法修改的?
Vuex中修改state的唯一渠道就是执行 commit(‘xx’, payload) 方法,其底层通过执行 this.*withCommit(fn) 设置*committing标志变量为true,然后才能修改state,修改完毕还需要还原*committing变量。外部修改虽然能够直接修改state,但是并没有修改*committing标志位,所以只要watch一下state,state change时判断是否_committing值为true,即可判断修改的合法性。
vuex 数据流向
在组件中通过dispatch派发一个action,在action中调接口获取数据,然后通过commit提交一个mutation改变数据,数据改变之后页面重新更新
vue中的其他API
https://cn.vuejs.org/v2/api/#%E5%85%A8%E5%B1%80-API
- $refs
获取所有设置了ref属性的标签
我们可以通过它获取子组件中的数据和方法
- $el
可以获取组件的dom元素
- $root
表示根组件
- $nextTick
dom元素更新成功之后的回调函数
vue中的dom更新是异步的
- replace和push路由跳转
push是追加历史记录, replace是替换当前路由记录