HTTP篇
1. 怎么跨域?JSONP 是什么?CORS 是什么?postMessage 是什么?
因为浏览器出于安全考虑,有同源策略,如果协议、域名或者端口有一个不同就是跨域。
1.JSONP
JSONP 的原理很简单,就是利用 <script> 标签没有跨域限制的漏洞。当需要通讯时,通过 <script> 标签指向一个需要访问的地址并提供一个回调函数来接收数据。
<script src="http://domain/api?param1=a¶m2=b&callback=jsonp"></script>
<script>
function jsonp(data) {
console.log(data)
}
</script>
JSONP 使用简单且兼容性不错,但是只限于 get 请求。
2.CORS
CORS 需要浏览器和后端同时支持,需要设置 Access-Control-Allow-Origin:foo.example
IE 8 和 9 需要通过 XDomainRequest 来实现。
3.postMessage
这种方式通常用于获取嵌入页面中的第三方页面数据。一个页面发送消息,另一个页面判断来源并接收消息
JSONP和AJAX相比的优缺点?
1.JSONP可以跨域
2.因为JSONP是通过script标签发送的GET请求,所以读不到AJAX那么精确的状态码
2. 请尽可能详尽的解释AJAX的工作原理
ajax简单来说是通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。
ajax的优点
- 最大的一点是页面无刷新,在页面内与服务器通信,给用户的体验非常好。
- 使用异步方式与服务器通信,不需要打断用户的操作,具有更加迅速的响应能力。
- 可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本,ajax的原则是“按需取数据”,可以最大程度的减少冗余请求。
- 基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。
ajax的缺点
- ajax对浏览器后退机制造成了破坏,也就是说用户无法通过浏览器的后退按钮回到前一次操作的页面。虽然有些浏览器解决了这个问题,比如Gmail,但它也并不能改变ajax的机制,它所带来的开发成本是非常高的,和ajax框架所要求的快速开发是相背离的。这是ajax所带来的一个非常严重的问题。
- 安全问题。技术同时也对IT企业带来了新的安全威胁,ajax技术就如同对企业数据建立了一个直接通道。这使得开发者在不经意间会暴露比以前更多的数据和服务器逻辑。
- 对搜索引擎的支持比较弱。
- 破坏了程序的异常机制。至少从目前看来,像ajax.dll,ajaxpro.dll这些ajax框架是会破坏程序的异常机制的。关于这个问题,我曾经在开发过程中遇到过,但是查了一下网上几乎没有相关的介绍。后来我自己做了一次试验,分别采用ajax和传统的form提交的模式来删除一条数据……给我们的调试带来了很大的困难。
- 另外,像其他方面的一些问题,比如说违背了url和资源定位的初衷。例如,我给你一个url地址,如果采用了ajax技术,也许你在该url地址下面看到的和我在这个url地址下看到的内容是不同的。这个和资源定位的初衷是相背离的。
- 一些手持设备(如手机、PDA等)现在还不能很好的支持ajax,比如说我们在手机的浏览器上打开采用ajax技术的网站时,它目前是不支持的,当然,这个问题和我们没太多关系。
3. ajax的四个步骤
- 创建一个异步对象
let xmlhttp = new XMLHttpRequest();
- 设置请求方式和请求地址
open(method,url,async) 规定请求的类型、URL 以及是否异步处理请求。
method:请求的类型;GET 或 POST
url:文件在服务器上的位置
async:true(异步)或 false(同步)
xmlhttp.open("GET","04-ajax-get.php",true);
- 发送请求
xmlhttp.send();
- 监听状态的变化
xmlhttp.onreadystatechange = function(ev2){
/*
0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪
*/
if (xmlhttp.readyState === 4){
// 判断是否请求成功
if (xmlhttp.status >= 200 && xmlhttp.status < 300 || xmlhttp.status === 304){
// 5.处理返回的结果
console.log("接收到服务器返回的数据");
}else {
console.log("没有接收到服务器返回的数据");
}
}
}
4. 说说get和post的区别
-
提交数据存储位置不同
GET请求会将数据放到URL后面
POST请求会将数据放到请求头中 -
对提交的数据大小限制不同
GET请求对所发信息量的限制是2000 个字符
POST请求对信息量没有限制 -
对提交的数据编码不同
GET请求的参数只能是ASCII码,所以中文需要URI编码
POST请求传参没有这个限制 -
应用场景不同
GET请求用于提交非敏感数据和小数据
POST请求用于提交敏感数据和大数据 -
get请求可以被缓存,post不可以被缓存
-
get后退不会有影响,post后退会重新进行提交
-
get请求的记录会留在历史记录中,post请求不会留在历史记录
5. HTTP的特性和状态码说一下
特性:
HTTP 是无连接无状态的
HTTP 一般构建于 TCP/IP 协议之上,默认端口号是 80
HTTP 可以分为两个部分,即请求和响应。
区分状态码
1××开头 - 信息提示
2××开头 - 请求成功
3××开头 - 请求被重定向
4××开头 - 请求错误
5××开头 - 服务器错误
1xx(临时响应)
100: 请求者应当继续提出请求。
101(切换协议) 请求者已要求服务器切换协议,服务器已确认并准备进行切换。
2xx(成功)
200:正确的请求返回正确的结果
201:表示资源被正确的创建。比如说,我们 POST 用户名、密码正确创建了一个用户就可以返回 201。
202:请求是正确的,但是结果正在处理中,这时候客户端可以通过轮询等机制继续请求。
3xx(已重定向)
300:请求成功,但结果有多种选择。
301:请求成功,但是资源被永久转移。
302 请求成功,但是资源被临时转移。
303:使用 GET 来访问新的地址来获取资源。
304:请求的资源并没有被修改过
4xx(请求错误)
400:请求出现错误,比如请求头不对等。
401:没有提供认证信息。请求的时候没有带上 Token 等。
402:为以后需要所保留的状态码。
403:请求的资源不允许访问。就是说没有权限。
404:请求的内容不存在。
5xx(服务器错误)
500:服务器错误。
501:请求还没有被实现。
6. Cookie、 SessionStorage、LocalStorage的区别
-
生命周期不同(同一浏览器下)
Cookie生命周期: 默认是关闭浏览器后失效, 但是也可以设置过期时间
SessionStorage生命周期: 仅在当前会话(窗口)下有效,关闭窗口或浏览器后被清除, 不能设置过期时间
LocalStorage生命周期: 除非被清除,否则永久保存 -
容量不同
Cookie容量: 有大小(4KB左右)和个数(20~50)限制
SessionStorage容量: 有大小限制(5M左右) dev-test.nemikor.com/web-storage…
LocalStorage容量: 有大小限制(5M左右) dev-test.nemikor.com/web-storage… -
网络请求不同
Cookie网络请求: 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题
SessionStorage网络请求: 仅在浏览器中保存,不参与和服务器的通信
LocalStorage网络请求: 仅在浏览器中保存,不参与和服务器的通信 -
应用场景不同
Cookie: 判断用户是否登录
sessionStorage: 表单数据
LocalStorage: 购物车
无论通过以上那种方式存储的数据, 切记不能将敏感数据直接存储到本地
7. JSON和XML的区别
1. 数据体积方面
JSON相对于XML来讲,数据的体积小,传递的速度更快些。
2. 数据交互方面
JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互。
3. 数据描述方面;
JSON对数据的描述性比XML较差。
4. 传输速度方面:
JSON的速度要远远快于XML。
补充:
1.JSON转XML:用json2xml
var xml_content = $.json2xml(json);
console.log(xml_content);
2.XML转JSON:用xml2json
var json_obj = $.xml2json(xmlstr);
console.log(json_obj);
8. 前端对后端返回的数据如何处理?
前端通过javascript对后端返回的json或者xml进行格式化处理
JSON:
var jsonObj = JSON.parse(后端返回的json字符串);
var result = JSON.stringify(jsonObj, null, 2);//格式化
XML:
简单一点就先使用 xml2json转化为JSON格式,然后再JSON.parse再JSON.stringfy进行格式化
9. 从输入URL到页面展示中间发生了什么
1.读取缓存:
搜索自身的 DNS 缓存。(如果 DNS 缓存中找到IP 地址就跳过了接下来查找 IP 地址步骤,直接访问该 IP 地址。)
2.DNS 解析:将域名解析成 IP 地址
3.TCP 连接:TCP 三次握手,简易描述三次握手
客户端:服务端你在么?
服务端:客户端我在,你要连接我么?
客户端:是的服务端,我要链接。
连接打通,可以开始请求
4.发送 HTTP 请求
5.服务器处理请求并返回 HTTP 报文
6.浏览器解析渲染页面
7.断开连接:TCP 四次挥手
关于第六步浏览器解析渲染页面又可以聊聊如果返回的是html页面
根据 HTML 解析出 DOM 树
根据 CSS 解析生成 CSS 规则树
结合 DOM 树和 CSS 规则树,生成渲染树
根据渲染树计算每一个节点的信息
根据计算好的信息绘制页面
10. Http与Https的区别
HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头
HTTP 是不安全的,而 HTTPS 是安全的
HTTP 标准端口是80 ,而 HTTPS 的标准端口是443
在OSI 网络模型中,HTTP工作于应用层,而HTTPS 的安全传输机制工作在传输层
HTTP 无法加密,而HTTPS 对传输的数据进行加密
HTTP无需证书,而HTTPS 需要CA机构wosign的颁发的SSL证书
11. 什么是Http协议无状态协议?怎么解决Http协议无状态协议?
无状态协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息也就是说,
当客户端一次HTTP请求完成以后,客户端再发送一次HTTP请求,HTTP并不知道当前客户端是一个”老用户“。
可以使用Cookie来解决无状态的问题,Cookie就相当于一个通行证,第一次访问的时候给客户端发送一个Cookie,
当客户端再次来的时候,拿着Cookie(通行证),那么服务器就知道这个是”老用户“。
12. Ajax和Fetch区别
- ajax是使用XMLHttpRequest对象发起的,但是用起来很麻烦,所以ES6新规范就有了fetch,fetch发一个请求不用像ajax那样写一大堆代码。
- 使用fetch无法取消一个请求,这是因为fetch基于Promise,而Promise无法做到这一点。
- 在默认情况下,fetch不会接受或者发送cookies
- fetch没有办法原生监测请求的进度,而XMLHttpRequest可以
- fetch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
- fetch由于是ES6规范,兼容性上比不上XMLHttpRequest
13. Promise相关
什么是Promise? Promise的作用是什么?
Promise是ES6中新增的一个对象
通过Promise就可以实现用同步的流程来表示异步的操作
通过Promise就可以避免回调函数层层嵌套(回调地狱)问题
如何创建Promise对象?
promise对象不是异步的, 只要创建promise对象就会立即执行存放的代码
new Promise(function(resolve, reject){});
Promise是如何实现 通过同步的流程来表示异步的操作的?
promise对象是通过状态的改变来实现的, 只要状态发生改变就会自动触发对应的函数
Promise对象三种状态
状态一旦改变既不可逆, 从pending变为fulfilled, 那么永远都是fulfilled,从pending变为rejected, 那么永远都是rejected
pending: 默认状态,只要没有告诉promise任务是成功还是失败就是pending状态
fulfilled(resolved): 只要调用resolve函数, 状态就会变为fulfilled, 表示操作成功
rejected: 只要调用rejected函数, 状态就会变为rejected, 表示操作失败
如何监听Promise状态改变
可以通过函数来监听状态的变化
resolved --> then()
rejected --> catch()
Promise的then方法
then方法接收两个参数,
第一个参数是状态切换为成功时的回调,
第二个参数是状态切换为失败时的回调
let promise = new Promise(function (resolve, reject) {
// resolve(); // 将状态修改为成功
reject(); // 将状态修改为失败
});
promise.then(function () {
console.log("成功");
}, function () {
console.log("失败");
});
Promise的catch方法
catch 其实是 then(undefined, () => {}) 的语法糖
let promise = new Promise(function (resolve, reject) {
// resolve(); // 将状态修改为成功
reject(); // 将状态修改为失败
});
promise.catch(function () {
console.log("abc");
});
Promise的all静态方法:
1.all方法接收一个数组,
2.如果数组中有多个Promise对象,只有都成功才会执行then方法, 并且会按照添加的顺序, 将所有成功的结果重新打包到一个数组中返回给我们
3.如果数组中不是Promise对象, 那么会直接执行then方法
应用场景: 批量加载, 要么一起成功, 要么一起失败
Promise的race静态方法:
1.all方法接收一个数组,
2.如果数组中有多个Promise对象, 谁先返回状态就听谁的, 后返回的会被抛弃
3.如果数组中不是Promise对象, 那么会直接执行then方法
应用场景: 接口调试, 超时处理
14. 什么是axios?
Axios 是一个基于 promise 的 HTTP 库网络请求插件
axios特点
可以用在浏览器和 node.js 中
支持 Promise API
自动转换 JSON 数据
客户端支持防御 XSRF
// axios.get("http://127.0.0.1/jQuery/Ajax/41.php?teacher=lnj&age=34")
axios.post("http://127.0.0.1/jQuery/Ajax/41.php", {
teacher: "lnj",
age: 666
})
.then(function (res) {
console.log(res.data);
})
.catch(function (e) {
console.log(e);
});
全局的 axios 默认值
在开发中项目分为: 开发阶段和部署阶段, 这两个阶段项目存储的位置是不同的
项目上线前存储在企业内部测试服务器上, 项目上线后存储在企业正式服务器上
所以如果每次请求都将请求的地址写在请求中, 那么项目上线时需要大量修改请求地址
为了解决这个问题, 我们可以配置一个全局URL根地址, 项目上线时只需要修改根地址即可
例如: 上线前地址是: http://127.0.0.1/jQuery/Ajax/41.php
上线后地址是: http://192.199.13.14/jQuery/Ajax/41.php
axios.defaults.timeout = 2000;
axios.defaults.baseURL = "http://127.0.0.1";
axios.post("/jQuery/Ajax/41.php", {
teacher: "lnj",
age: 666
})
.then(function (res) {
console.log(res.data);
})
.catch(function (e) {
console.log(e);
});
15. XSS是什么
XSS是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。
比如这些代码包括HTML代码和客户端脚本。攻击者利用XSS漏洞旁路掉访问控制——例如同源策略(same origin policy)。
这种类型的漏洞由于被黑客用来编写危害性更大的网络钓鱼(Phishing)攻击而变得广为人知。
对于跨站脚本攻击,黑客界共识是:跨站脚本攻击是新型的“缓冲区溢出攻击“,而JavaScript是新型的“ShellCode”。
示例:
<script>alert(document.cookie)</script>
特点
能注入恶意的HTML/JavaScript代码到用户浏览的网页上,从而达到Cookie资料窃取、会话劫持、钓鱼欺骗等攻击。
<攻击代码不一定(非要)在 <script></script> 中>
原因
-
Web浏览器本身的设计不安全。浏览器能解析和执行JS等代码,但是不会判断该数据和程序代码是否恶意。
-
输入和输出是Web应用程序最基本的交互,而且网站的交互功能越来越丰富。如果在这过程中没有做好安全防护,很容易会出现XSS漏洞。
-
程序员水平参差不齐,而且大都没有过正规的安全培训,没有相关的安全意识。
-
XSS攻击手段灵活多变。
危害
- 盗取各类用户帐号,如机器登录帐号、用户网银帐号、各类管理员帐号
- 控制企业数据,包括读取、篡改、添加、删除企业敏感数据的能力
- 盗窃企业重要的具有商业价值的资料
- 非法转账
- 强制发送电子邮件
- 网站挂马
- 控制受害者机器向其它网站发起攻击
如何防范
- 将重要的cookie标记为http only, 这样的话Javascript 中的document.cookie语句就不能获取到cookie了.
- 表单数据规定值的类型,例如:年龄应为只能为int、name只能为字母数字组合。。。。
- 对数据进行Html Encode 处理
- 过滤或移除特殊的Html标签, 例如:
<script>, <iframe> , < for <, > for >, " for - 过滤JavaScript 事件的标签。例如 "onclick=", "onfocus" 等等。
16. CSRF是什么
CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
特点
- 依靠用户标识危害网站
- 利用网站对用户标识的信任
- 欺骗用户的浏览器发送HTTP请求给目标站点
- 另外可以通过IMG标签会触发一个GET请求,可以利用它来实现CSRF攻击。
防御
- 通过referer、token或者验证码来检测用户提交。
- 尽量不要在页面的链接中暴露用户隐私信息。
- 对于用户修改删除等操作最好都使用post操作 。
- 避免全站通用的cookie,严格设置cookie的域。
浏览器篇
1. 浏览器渲染机制
- 浏览器采用流式布局模型(
Flow Based Layout) - 浏览器会把
HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就产生了渲染树(Render Tree)。 - 有了
RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。 - 由于浏览器使用流式布局,对
Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。
2. 重绘
由于节点的几何属性发生改变或者由于样式发生改变而不会影响布局的,称为重绘,例如outline, visibility, color、background-color等,重绘的代价,因为浏览器必须验证DOM树上其他节点元素的可见性。
3. 回流
回流是布局或者几何属性需要改变就称为回流。回流是影响浏览器性能的关键因素,因为其变化涉及到部分页面(或是整个页面)的布局更新。一个元素的回流可能会导致了其所有子元素以及DOM中紧随其后的节点、祖先节点元素的随后的回流。
<body>
<div class="error">
<h4>我的组件</h4>
<p><strong>错误:</strong>错误的描述…</p>
<h5>错误纠正</h5>
<ol>
<li>第一步</li>
<li>第二步</li>
</ol>
</div>
</body>
在上面的HTML片段中,对该段落(标签)回流将会引发强烈的回流,因为它是一个子节点。这也导致了祖先的回流(div.error和body – 视浏览器而定)。此外,h5和ol也会有简单的回流,因为其在DOM中在回流元素之后。
大部分的回流将导致页面的重新渲染。
回流必定会发生重绘,重绘不一定会引发回流。
4. 浏览器优化
现代浏览器大多都是通过队列机制来批量更新布局,浏览器会把修改操作放在队列中,至少一个浏览器刷新(即16.6ms)才会清空队列,但当你获取布局信息的时候,队列中可能有会影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流与重绘来确保返回正确的值。
主要包括以下属性或方法:
offsetTop、offsetLeft、offsetWidth、offsetHeightscrollTop、scrollLeft、scrollWidth、scrollHeightclientTop、clientLeft、clientWidth、clientHeightwidth、heightgetComputedStyle()getBoundingClientRect()
所以,我们应该避免频繁的使用上述的属性,他们都会强制渲染刷新队列。
5. 减少重绘与回流
-
CSS
-
使用
transform替代top -
使用
visibility替换display: none,因为前者只会引起重绘,后者会引发回流(改变了布局 -
避免使用
table布局,可能很小的一个小改动会造成整个table的重新布局。 -
尽可能在
DOM树的最末端改变class,回流是不可避免的,但可以减少其影响。尽可能在DOM树的最末端改变class,可以限制了回流的范围,使其影响尽可能少的节点。 -
避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多。
<div> <a> <span></span> </a> </div> <style> span { color: red; } div > a > span { color: red; } </style>对于第一种设置样式的方式来说,浏览器只需要找到页面中所有的
span标签然后设置颜色,但是对于第二种设置样式的方式来说,浏览器首先需要找到所有的span标签,然后找到span标签上的a标签,最后再去找到div标签,然后给符合这种条件的span标签设置颜色,这样的递归过程就很复杂。所以我们应该尽可能的避免写过于具体的 CSS 选择器,然后对于 HTML 来说也尽量少的添加无意义标签,保证层级扁平。 -
将动画效果应用到
position属性为absolute或fixed的元素上,避免影响其他元素的布局,这样只是一个重绘,而不是回流,同时,控制动画速度可以选择requestAnimationFrame,详见探讨 requestAnimationFrame。 -
避免使用
CSS表达式,可能会引发回流。 -
将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点,例如
will-change、video、iframe等标签,浏览器会自动将该节点变为图层。 -
CSS3 硬件加速(GPU加速),使用css3硬件加速,可以让
transform、opacity、filters这些动画不会引起回流重绘 。但是对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。
-
-
JavaScript
- 避免频繁操作样式,最好一次性重写
style属性,或者将样式列表定义为class并一次性更改class属性。 - 避免频繁操作
DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。 - 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
- 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
- 避免频繁操作样式,最好一次性重写
6. 说说浏览器和Node事件循环的区别
浏览器环境下,microtask的任务队列是每个macrotask执行完之后执行。而在Node.js中,microtask会在事件循环的各个阶段之间执行,也就是一个阶段执行完毕,就会去执行microtask队列的任务。

setTimeout(()=>{
console.log('timer1')
Promise.resolve().then(function() {
console.log('promise1')
})
}, 0)
setTimeout(()=>{
console.log('timer2')
Promise.resolve().then(function() {
console.log('promise2')
})
}, 0)
浏览器端运行结果:timer1=>promise1=>timer2=>promise2
浏览器端的处理过程如下:

Node端运行结果分两种情况:
- 如果是node11版本一旦执行一个阶段里的一个宏任务(setTimeout,setInterval和setImmediate)就立刻执行微任务队列,这就跟浏览器端运行一致,最后的结果为
timer1=>promise1=>timer2=>promise2 - 如果是node10及其之前版本:要看第一个定时器执行完,第二个定时器是否在完成队列中。
- 如果是第二个定时器还未在完成队列中,最后的结果为
timer1=>promise1=>timer2=>promise2 - 如果是第二个定时器已经在完成队列中,则最后的结果为
timer1=>timer2=>promise1=>promise2(下文过程解释基于这种情况下)
- 如果是第二个定时器还未在完成队列中,最后的结果为
1.全局脚本(main())执行,将2个timer依次放入timer队列,main()执行完毕,调用栈空闲,任务队列开始执行;
2.首先进入timers阶段,执行timer1的回调函数,打印timer1,并将promise1.then回调放入microtask队列,同样的步骤执行timer2,打印timer2;
3.至此,timer阶段执行结束,event loop进入下一个阶段之前,执行microtask队列的所有任务,依次打印promise1、promise2
Node端的处理过程如下:

总结
浏览器和Node 环境下,microtask 任务队列的执行时机不同
- Node端,microtask 在事件循环的各个阶段之间执行
- 浏览器端,microtask 在事件循环的 macrotask 执行完之后执行
Vue篇
1. Vue.js 对比 Angular.js 、 React
-
vue.js,更轻量,gzip后只有26k,Angular(56k),react(44k) vue.js 更容易上手,学习曲线平稳。Angular难学,颠覆了学习前端的思想,因为之初是由写java的人写的。这点react与Angular比起来稍微好一些,有一套js 语法,但是这些的学习也是一个挑战,而且react学习也会复制一些react全家桶,也是比较难学的。vue是最好学习的。 vue吸取了两者之长,借鉴了angular的指令和react的组件化。vue还有很多自己的特点,是这两家没有的。
-
Vue可能有些方面是不如React,不如Angular,但它是渐进的,没有强主张,你可以在原有大系统的上面,把一两个组件改用它实现,当jQuery用;也可以整个用它全家桶开发,当Angular用;还可以用它的视图,搭配你自己设计的整个下层用。你可以在底层数据逻辑的地方用OO和设计模式的那套理念,也可以函数式,都可以,它只是个轻量视图而已,只做了自己该做的事,没有做不该做的事,仅此而已。
-
我们没必要一上来就搞懂Vue的每一个部件和功能,先从核心功能开始学习,逐渐扩展。 同时,在使用中,我们也没有必要把全部件能都拿出来,需要什么用什么就是了,而且也可以把Vue很方便的与其它已有项目或框架相结合。
2. 什么是生命周期,生命周期的作用是什么?
生命周期:Vue 实例从创建到销毁的过程,就是生命周期。
也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期
作用:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑
3. 生命周期有几个阶段?
它可以总共分为8个阶段:
创建前/后:beforeCreate created
载入前/后:beforeMount mounted
更新前/后:beforeUpdate updated
销毁前/后:beforeDestroy destroyed
4. DOM渲染在哪个周期中就已经完成?
DOM 渲染在 mounted 中就已经完成了
5. 每个生命周期适合哪些场景?
beforeCreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
beforeMount:无操作
mounted : 挂载元素,获取到DOM节点,一般在这个钩子请求数据
beforeUpdate:可在更新前访问现有的DOM,如手动移除添加的事件监听器
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框,可用于销毁定时器,解绑全局时间 销毁插件对象
destroyed:当前组件已被删除,销毁监听事件。 组件 事件 子实例也被销毁
这时组件已经没有了,你无法操作里面的任何东西了。
6. v-show与v-if区别
v-show 指令是通过修改元素的 display 的 CSS 属性让其显示或者隐藏
v-if 指令是直接销毁和重建 DOM 达到让元素显示和隐藏的效果
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用v-if 较好。
7. vue 中子组件调用父组件的方法
- 第一种方法是直接在子组件中通过 this.$parent.event 来调用父组件的方法
- 第二种方法是在子组件里用$emit 向父组件触发一个事件,父组件监听这个事件就行了
- 第三种是父组件把方法传入子组件中,在子组件里直接调用这个方法
8. vue 中父组件调用子组件的方法
使用$refs
父组件
<template>
<div>
<button @click="clickParent">点击</button>
<child ref="mychild"></child>
</div>
</template>
<script>
import Child from "./child";
export default {
name: "parent",
components: {
child: Child
},
methods: {
clickParent() {
this.$refs.mychild.parentHandleclick("嘿嘿嘿"); // 划重点!!!!
}
}
};
</script>
子组件
<template>
<div>
child
</div>
</template>
<script>
export default {
name: "child",
props: "someprops",
methods: {
parentHandleclick(e) {
console.log(e);
}
}
};
</script>
9. Vue 如何实现组件通信?
方法一、props/$emit
在父组件中通过v-bind传递数据,在子组件中通过props接收数据
在父组件中通过 v-on 传递方法,在子组件的自定义方法中通过 this.$emit('自定义接收名称'); 触发传递过来的方法
方法二、$emit/$on
这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。
- 定义一个空的Vue实例
var Event = new Vue();
- 传递数据
Event.$emit(事件名,数据);
- 获取数据
Event.$on(事件名,data => {});
方法三、vuex
vuex 是 Vue 配套的 公共数据管理工具,我们可以将共享的数据保存到 vuex 中,
方便整个程序中的任何组件都可以获取和修改vuex中保存的公共数据
- 创建Vuex对象
const store = new Vuex.Store({
// 这里的state就相当于组件中的data, 就是专门用于保存共享数据的
state: {
msg: "共享数据"
}
});
- 在祖先组件中添加 store 的 key 保存Vuex对象
只要祖先组件中保存了Vuex对象 , 那么祖先组件和所有的后代组件就可以使用Vuex中保存的共享数据了
store: store,
- 在使用Vuex中保存的共享数据的时候, 必须通过如下的格式来使用
<p>{{this.$store.state.msg}}</p>
10. 实现通信方式
方式1: props
1) 通过一般属性实现父向子通信
2) 通过函数属性实现子向父通信
3) 缺点: 隔代组件和兄弟组件间通信比较麻烦
方式2: vue自定义事件
1) vue内置实现, 可以代替函数类型的props
a. 绑定监听: <MyComp @eventName="callback"
b. 触发(分发)事件: this.$emit("eventName", data)
2) 缺点: 只适合于子向父通信
方式3: 消息订阅与发布
1) 需要引入消息订阅与发布的实现库, 如: pubsub-js
a. 订阅消息: PubSub.subscribe('msg', (msg, data)=>{})
b. 发布消息: PubSub.publish(‘msg’, data)
2) 优点: 此方式可用于任意关系组件间通信
方式4: vuex
1) 是什么: vuex是vue官方提供的集中式管理vue多组件共享状态数据的vue插件
2) 优点: 对组件间关系没有限制, 且相比于pubsub库管理更集中, 更方便
方式5: slot
1) 是什么: 专门用来实现父向子传递带数据的标签
a. 子组件
b. 父组件
2) 注意: 通信的标签模板是在父组件中解析好后再传递给子组件的
11. 说说VueRouter
1.Vue Router 是 Vue.js 官方的路由管理器,说出核心概念的名字和作用:Hash 模式/History 模式/路由守卫/路由懒加载
Hash模式:由于 hash 发生变化的url都会被浏览器记录下来,所以浏览器的前进后退可以使用,
尽管浏览器没有请求服务器,但是页面状态和 url 关联起来。后来人们称其为前端路由,成为单页应用标配。
History模式:页面刷新的时候不重新加载数据
2.常用 API:router-link/router-view/this.$router.push/this.$router.replace/this.$route.params
12. vue-router原理
说简单点,vue-router的原理就是通过对URL地址变化的监听,继而对不同的组件进行渲染。
每当URL地址改变时,就对相应的组件进行渲染。原理是很简单,实现方式可能有点复杂,主要有hash模式和history模式。
#hash不会触发浏览器页面请求,不需要用服务器配合
history是使用history.pushstate(),修改url不会触发浏览器页面请求,需要服务器配合
13. $route和$router的区别
$route 是路由信息对象,包括path,params,hash,query,fullPath,matched,name 等路由信息参数。
而 $router 是路由实例对象,包括了路由的跳转方法,钩子函数等
14. 知道路由守卫吗
常用的两个路由守卫:router.beforeEach 和 router.afterEach
每个守卫方法接收三个参数:
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子。
在项目中,一般在beforeEach这个钩子函数中进行路由跳转的一些信息判断。
判断是否登录,是否拿到对应的路由权限等等。
15. 单页应用和多页应用的区别
单页应用(SPA):只有一个主页的应用,一开始只需要加载一次JS、CSS资源,单页应用的跳转其实就是组件切换,仅刷新局部资源。
多页应用(MPA):多个独立页面的应用,每个页面必须要重复加载JS、CSS资源,多页应用的跳转页面整体资源会刷新。
16. 单页应用怎么实现多个路由
先在router.js中配置好各个路由,当路由显示时展示出对应的组件(这里可以使用hidden:true;判断路由是否展示)
补充:怎么动态渲染路由?
1.对配置好的路由进行遍历,有一个子路由遍历一遍,多个子路由的需要重新遍历一遍
2.然后在菜单组件比如添加上router属性,地址栏就会动态渲染
17. Vue怎么实现页面的权限控制
利用 vue-router 的 beforeEach 事件,可以在跳转页面前判断用户的权限(利用 cookie 或 token,sessionid),是否能够进入此页面,如果不能则提示错误或重定向到其他页面,在后台管理系统中这种场景经常能遇到。
18. vue 等单页面应用及其优缺点
优点:
1、用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染。
2、前后端职责业分离(前端负责view,后端负责model),架构清晰
3、减轻服务器的压力
缺点:
1、SEO(搜索引擎优化)难度高
2、初次加载页面更耗时
3、前进、后退、地址栏等,需要程序进行管理,所以会大大提高页面的复杂性和逻辑的难度
19. 什么是mvvm
MVVM最早由微软提出来,它借鉴了桌面应用程序的MVC思想,在前端页面中,把Model用纯JavaScript对象表示,View负责显示,两者做到了最大限度的分离,把Model和View关联起来的就是ViewModel。
ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回Model
View 和 Model 之间的同步工作完全是自动的,无需人为干涉(由viewModel完成,在这里指VUE)
因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理
MVVM的设计思想:关注Model的变化,让MVVM框架去自动更新DOM的状态,从而把开发者从操作DOM的繁琐步骤中解脱出来!
20. MVVM 与 MVC
M - Model,Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑
V - View,View 代表 UI 组件,它负责将数据模型转化为 UI 展现出来
C - Control 控制器,对数据进行一些操作
VM - ViewModel,ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,
简单理解就是一个同步 View 和 Model 的对象,连接 Model 和 View
区别
MVC:m是保存数据的地方,v是视图,c是对数据进行一些操作的过程,基本上是c对m数据操作,然后更新v视图。
MVVM:m是保存数据的地方,v是视图,vm相当于把v和m结合起来取代了c。
可以进行数据响应式,v视图变化会影响m数据,m数据变化会影响v视图,这中间就是通过vm来实现的。
21. MVC、MVP 与 MVVM 模式
一、MVC

-
视图(View):用户界面。 传送指令到 Controller
-
控制器(Controller):业务逻辑 完成业务逻辑后,要求 Model 改变状态
-
模型(Model):数据保存 将新的数据发送到 View,用户得到反馈
所有通信都是单向的。
二、MVP

-
各部分之间的通信,都是双向的。
-
View 与 Model 不发生联系,都通过 Presenter 传递。
-
View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter 非常厚,所有逻辑都部署在那里。
三、MVVM
MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。

22. mvvm 和 mvc 区别?它和其它框架(jquery)的区别是什么?哪些场景适合?
mvc 和 mvvm 其实区别并不大。都是一种设计思想。主要就是 mvc 中 Controller 演变成 mvvm 中的 viewModel。mvvm 主要解决了 mvc 中大量的 DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
区别:vue 数据驱动,通过数据来显示视图层而不是节点操作。
场景:数据操作比较多的场景,更加便捷
23. 说说Vue的MVVM实现原理
1) Vue作为MVVM模式的实现库的2种技术
a. 模板解析
b. 数据绑定
2) 模板解析: 实现初始化显示
a. 解析大括号表达式
b. 解析指令
3) 数据绑定: 实现更新显示
a. 通过数据劫持实现
24. Vue的优点是什么
mvvm的优点即是vue的优点,在这里再总结一下:
数据和UI 组件之间的同步工作完全是自动的,无需人为干涉,所以开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题, 复杂的数据状态维护完全由 MVVM 来统一管理,节省了很多精力。
低耦合。视图(View)可以独立于 Model 变化和修改,一个 ViewModel 可以绑定到不同的"View"上,当 View 变化的时候 Model 可以不变,当 Model 变化的时候 View 也可以不变。
可重用性。你可以把一些视图逻辑放在一个 ViewModel 里面,让很多 view 重用这段视图逻辑。
独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
可测试。界面素来是比较难于测试的,而现在测试可以针对 ViewModel 来写。
25. watch的作用是什么
watch 主要作用是监听某个数据值的变化。和计算属性相比除了没有缓存,作用是一样的。
借助 watch 还可以做一些特别的事情,例如监听页面路由,当页面跳转时,我们可以做相应的权限控制,拒绝没有权限的用户访问页面。
26. watch 和 computed 和 methods 区别是什么?
1.computed 和 methods 相比,最大区别是 computed 有缓存:如果 computed 属性依赖的属性没有变化,
那么 computed属性就不会重新计算。methods 则是看到一次计算一次。
2.watch 和 computed 相比,computed 是计算出一个属性,而 watch 则可能是做别的事情(如上报数据)
总结:
1. 当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为computed
2. 如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化
27. 为什么需要用到key?
需要使用 key 来给每个节点做一个唯一标识,Diff 算法就可以正确的识别此节点,找到正确的位置区插入新的节点
所以一句话,key 的作用主要是为了高效的更新虚拟 DOM
比如渲染一堆input框,中间删除一个就会产生问题,下面的input会被顶上来,
vue会选择复用节点(Vue的就地更新策略),导致之前节点的状态被保留,从而产生一系列的bug
28. 知道keep-alive吗?
在 Vue 中,每次切换组件时,都会重新渲染。如果有多个组件切换,又想让它们保持原来的状态,避免重新渲染,这个时候就可以使用 keep-alive。 keep-alive 可以使被包含的组件保留状态,或避免重新渲染。
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 ,其有以下特性:
1.一般结合路由和动态组件一起使用,用于缓存组件;
2.提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,
exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;
3.对应两个钩子函数 activated 和 deactivated ,
当组件被激活时,触发钩子函数 activated,
当组件被移除时,触发钩子函数 deactivated。
29. 说说nextTick()
在下次DOM更新循环结束之后执行延迟回调。在修改数据之后,立即使用的这个回调函数,获取更新后的DOM
// 修改数据
vm.msg = 'Hello'
// DOM 还未更新
Vue.nextTick(function () {
// DOM 更新
})
30. 说说Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式;或者说就是一个仓库,仓库里放了很多对象。
Vuex有5种属性: 分别是 state、getter、mutation、action、module;
1.state
Vuex 使用单一状态树,即每个应用将仅仅包含一个store实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据
2.mutations
mutations定义的方法动态修改Vuex 的 store 中的状态或数据
3.getters
类似vue的计算属性,主要用来过滤一些数据
4.action
actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action
5.module
当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter
总结
1.vuex 一般用于中大型 web 单页应用中对应用的状态进行管理,
2.对于一些组件间关系较为简单的小型应用,使用vuex的必要性不是很大,因为完全可以用组件prop属性或者事件来完成父子组件之间的通信
3.vuex 更多地用于解决跨组件通信以及作为数据中心集中式存储数据
31. Vuex原理
vuex的原理其实非常简单,它为什么能实现所有的组件共享同一份数据?
因为vuex生成了一个store实例,并且把这个实例挂在了所有的组件上,所有的组件引用的都是同一个store实例。
store实例上有数据,有方法,方法改变的都是store实例上的数据。由于其他组件引用的是同样的实例,所以一个组件改变了store上的数据, 导致另一个组件上的数据也会改变,就像是一个对象的引用。
32. v-model的原理知道吗?
vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
1.text 和 textarea 元素使用 value 属性和 input 事件;
2.checkbox 和 radio 使用 checked 属性和 change 事件;
3.select 字段将 value 作为 prop 并将 change 作为事件;
以 input 表单元素为例:
<input v-model='something'>
相当于
<input v-bind:value="something" v-on:input="something = $event.target.value">
如果在自定义组件中,v-model 默认会利用名为 value 的 prop 和名为 input 的事件,如下所示:
父组件:
<ModelChild v-model="message"></ModelChild>
子组件:
<div>{{value}}</div>
props:{
value: String
},
methods: {
test1(){
this.$emit('input', '小红')
},
}
33. 说说Vue数据响应式的原理
Vue通过数据劫持配合发布者-订阅者的设计模式,内部通过调用object.defineProperty()来劫持各个属性的getter和setter,在数据变化的时候通知订阅者,并触发相应的回调
34. Vue是如何实现数据双向绑定的?
Vue数据双向绑定是指:数据变化更新视图,视图变化更新数据,例如输入框输入内容变化时,data中的数据同步变化;data中的数据变化时,文本节点的内容同步变化
Vue主要通过以下4个步骤实现数据双向绑定:
- 实现一个监听器「Observer」:
对数据对象进行遍历,包括子属性对象的属性,利用Object.defineProperty()在属性上都加上getter和setter,这样后,给对象的某个值赋值,就会触发setter,那么就能监听到数据变化 - 实现一个解析器「Compile」:
解析Vue模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新 - 实现一个订阅者「Watcher」:
Watcher订阅者是Observer和Compile之间通信的桥梁,主要任务是订阅Observer中的属性值变化的消息,当收到属性值变化的消息时,触发解析器Compile中对应的更新函数 - 实现一个订阅器「Dep」:
订阅器采用发布-订阅设计模式,用来收集订阅者Watcher,对监听器Observer和订阅者Watcher进行统一管理
35. 计算属性有什么作用
先来看一下计算属性的定义:
当其依赖的属性的值发生变化的时,计算属性会重新计算。反之则使用缓存中的属性值。
计算属性和vue中的其它数据一样,都是响应式的,只不过它必须依赖某一个数据实现,并且只有它依赖的数据的值改变了,它才会更新。
36. v-for 和 v-if 区别,优先级?
v-for表示遍历渲染,v-if表示是否展示
v-for的优先级比v-if高
37. 为什么避免 v-if 和 v-for 用在一起
当 Vue 处理指令时,v-for 比 v-if 具有更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中。通过 v-if 移动到容器元素,不会再重复遍历列表中的每个值。取而代之的是,我们只检查它一次,且不会在 v-if 为否的时候运算 v-for。
38. 你有对 Vue 项目进行哪些优化?
1.不要在模板里面写过多表达式
2.循环调用子组件时添加key
3.频繁切换的使用v-show,不频繁切换的使用v-if
4.尽量少用float,可以用flex
5.按需加载,可以用require或者import()按需加载需要的组件
6.路由懒加载
39. vue操作虚拟DOM的原理?
vue使用虚拟DOM对DOM进行了一些修改与调整。
比如一次操作中需要更新10次dom,虚拟dom不会立即操作dom,而是将这10次的更新内容diff保存早本地一个js对象中 最终将这个js对象一次性attch到DOM树上再进行操作,可以避免不必要的计算。
40. VUE的全局属性有哪些
$ref / $data / $router / $route / $data / $el / $props / $root / $parent / $children / $slots ...
补充:
$route 是“路由信息对象”,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数。
$router 是“路由实例”对象,即使用 new VueRouter创建的实例,包括了路由的跳转方法,钩子函数等。
41. vue-loader是什么?使用它的用途有哪些?
vue-loader 是解析 .vue 文件的一个加载器,将 template/js/style 转换成 js 模块。
用途:js 可以写 es6、style 样式可以 scss 或 less;template 可以加 jade 等。
42. 假设定义了一个数组a=[1,2,3],相应的,页面上显示的值为1,2,3,现设a[0]=5,页面上的值会变成5,2,3吗?为什么?
不会
因为 Vue 是使用 Object.defineProperty 来监听数值变化的,而直接修改数组的值的这种操作无法监听。
例如:vm.items[indexOfItem] = newValue 这种操作是无法监听的。
如果需要直接修改数组元素的值,可以使用 Vue.set
Vue.set(vm.items, indexOfItem, newValue)
43. vue 中的性能优化
Vue 应用运行时性能优化措施
引入生产环境的 Vue 文件
使用单文件组件预编译模板
提取组件的 CSS 到单独到文件
利用 Object.freeze()提升性能
扁平化 Store 数据结构
合理使用持久化 Store 数据
组件懒加载
Vue 应用加载性能优化措施
服务端渲染 / 预渲染
减少 http 请求,合理设置 HTTP 缓存
使用浏览器缓存
启用压缩
CSS Sprites
LazyLoad Images
尽量避免使用 eval 和 Function
44. 为什么要替换 Object.defineProperty?(Proxy 相比于 defineProperty 的优势)
-
在 Vue 中,Object.defineProperty 无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。
-
Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue 2.x里,是通过 递归 + 遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象是才是更好的选择。
而要取代它的Proxy有以下两个优点:
- 可以劫持整个对象,并返回一个新对象
- 有13种劫持操作
既然Proxy能解决以上两个问题,而且Proxy作为es6的新属性在vue2.x之前就有了,为什么vue2.x不使用Proxy呢?一个很重要的原因就是:
Proxy是es6提供的新特性,兼容性不好,最主要的是这个属性无法用polyfill来兼容
45. 什么是 Proxy?
1.含义:
Proxy 是 ES6 中新增的一个特性,翻译过来意思是"代理",用在这里表示由它来“代理”某些操作。 Proxy 让我们能够以简洁易懂的方式控制外部对对象的访问。其功能非常类似于设计模式中的代理模式。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
使用 Proxy 的核心优点是可以交由它来处理一些非核心逻辑(如:读取或设置对象的某些属性前记录日志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)。 从而可以让对象只需关注于核心逻辑,达到关注点分离,降低对象复杂度等目的。
2.基本用法:
let p = new Proxy(target, handler);
参数:
- target 是用Proxy包装的被代理对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
- handler 是一个对象,其声明了代理target 的一些操作,其属性是当执行一个操作时定义代理的行为的函数。
- p 是代理后的对象。当外界每次对 p 进行操作时,就会执行 handler 对象上的一些方法。Proxy共有13种劫持操作,handler代理的一些常用的方法有如下几个:
get:读取
set:修改
has:判断对象是否有该属性
construct:构造函数
46. Vue 中如何实现 proxy 代理?
webpack 自带的 devServer 中集成了 http-proxy-middleware。配置 devServer 的 proxy 选项即可
proxyTable: {
'/api': {
target: 'http://192.168.149.90:8080/', // 设置你调用的接口域名和端口号
changeOrigin: true, // 跨域
pathRewrite: {
'^/api': '/'
}
}
}
47. 组件的设计原则
(1)页面上每个独立的可视/可交互区域视为一个组件(比如页面的头部,尾部,可复用的区块)
(2)每个组件对应一个工程目录,组件所需要的各种资源在这个目录下就近维护(组件的就近维护思想体现了前端的工程化思想,为前端开发提供了很好的分治策略,在vue.js中,通过.vue文件将组件依赖的模板,js,样式写在一个文件中)
(每个开发者清楚开发维护的功能单元,它的代码必然存在在对应的组件目录中,在该目录下,可以找到功能单元所有的内部逻辑)
(3)页面不过是组件的容器,组件可以嵌套自由组合成完整的页面
48. 对于 Vue 是一套渐进式框架的理解
渐进式代表的含义是:主张最少。每个框架都不可避免会有自己的一些特点,从而会对使用者有一定的要求,这些要求就是主张,主张有强有弱,它的强势程度会影响在业务开发中的使用方式。
我个人理解渐进式就是阶梯式向前。
渐进式就是指我们可以由浅入深、由简单到复杂的方式去使用Vue.js。“Progressive(渐进式的)”——这个词在英文中定义是渐进,一步一步,不是说你必须一竿子把所有的东西都用上。就像是搭积木,我们可以根据需求,利用社区良好的生态,借助已有的工具和库搭建我们的项目,用最小、最快的成本一步步搭建。
49. vue.js 的两个核心是什么?
数据驱动和组件化
50. 构建的 vue-cli 工程都到了哪些技术,它们的作用分别是什么?
1、vue.js:vue-cli 工程的核心,主要特点是 双向数据绑定 和 组件系统。
2、vue-router:vue 官方推荐使用的路由框架。
3、vuex:专为 Vue.js 应用项目开发的状态管理器,主要用于维护 vue 组件间共用的一些 变量 和 方法。
4、axios( 或者 fetch 、ajax ):用于发起 GET 、或 POST 等 http 请求,基于 Promise 设计。
5、vux 等:一个专为 vue 设计的移动端 UI 组件库。
6、创建一个 emit.js 文件,用于 vue 事件机制的管理。
7、webpack:模块加载和 vue-cli 工程打包器。
51. vue.cli 中怎样使用自定义的组件?有遇到过哪些问题吗?
第一步:在 components 目录新建你的组件文件(如:indexPage.vue),script 一定要 export default {}
第二步:在需要用的页面(组件)中导入:import indexPage from '@/components/indexPage.vue'
第三步:注入到 vue 的子组件的 components 属性上面,components:{indexPage}
第四步:在 template 视图 view 中使用
遇到的问题: 例如有 indexPage 命名,使用的时候则 index-page
52. vue 如何优化首页的加载速度?vue 首页白屏是什么问题引起的?如何解决呢?
vue 如何优化首页的加载速度?
- 路由懒加载
- ui框架按需加载
- gzip压缩
vue 首页白屏是什么问题引起的?
- 第一种,打包后文件引用路径不对,导致找不到文件报错白屏
解决办法:修改一下config下面的index.js中bulid模块导出的路径。因为index.html里边的内容都是通过script标签引入的,而你的路径不对,打开肯定是空白的。先看一下默认的路径。
- 第二种,由于把路由模式mode设置影响
解决方法:路由里边router/index.js路由配置里边默认模式是hash,如果你改成了history模式的话,打开也会是一片空白。所以改为hash或者直接把模式配置删除,让它默认的就行 。如果非要使用history模式的话,需要你在服务端加一个覆盖所有的情况的候选资源:如果URL匹配不到任何静态资源,则应该返回一个index.html,这个页面就是你app依赖页面。
所以只要删除mode或者把mode改成hash就OK了。
- 第三种,项目中使用了es6的语法,一些浏览器不支持es6,造成编译错误不能解析而造成白屏
解决方法:
安装 npm install --save-dev babel-preset-es2015
安装 npm install --save-dev babel-preset-stage-3
在项目根目录创建一个.babelrc文件 里面内容 最基本配置是:
{
// 此项指明,转码的规则
"presets": [
// env项是借助插件babel-preset-env,下面这个配置说的是babel对es6,es7,es8进行转码,
// 并且设置amd,commonjs这样的模块化文件,不进行转码
["env", {
"modules": false
}],
// 下面这个是不同阶段出现的es语法,包含不同的转码插件
"stage-2"
],
// 下面这个选项是引用插件来处理代码的转换,transform-runtime用来处理全局函数和优化babel编译
"plugins": ["transform-runtime"],
// 下面指的是在生成的文件中,不产生注释
"comments": false,
// 下面这段是在特定的环境中所执行的转码规则,当环境变量是下面的test就会覆盖上面的设置
"env": {
// test 是提前设置的环境变量,如果没有设置BABEL_ENV则使用NODE_ENV,如果都没有设置默认就是development
"test": {
"presets": ["env", "stage-2"],
// instanbul是一个用来测试转码后代码的工具
"plugins": ["istanbul"]
}
}
}
53. Vue 的父组件和子组件生命周期钩子执行顺序是什么
-
加载渲染过程
- 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
-
子组件更新过程
- 父beforeUpdate->子beforeUpdate->子updated->父updated
-
父组件更新过程
- 父beforeUpdate->父updated
-
销毁过程
- 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
54. vue如何实现按需加载配合webpack设置
webpack中提供了require.ensure()来实现按需加载。以前引入路由是通过import 这样的方式引入,改为const定义的方式进行引入。
不进行页面按需加载引入方式:
import home from ‘…/…/common/home.vue’
进行页面按需加载的引入方式:
const home = r => require.ensure( [], () => r (require(’…/…/common/home.vue’)))