HTML篇
1、H5新增標(biāo)簽有哪些?
一、語義化標(biāo)簽
header、footer、nav、aside、section、article
語義化的意義?
1、更適合搜索引擎的爬蟲爬取有效的信息,利于SEO。
2、對(duì)開發(fā)團(tuán)隊(duì)很友好,增加了標(biāo)簽的可讀性,結(jié)構(gòu)更加的清晰,便于團(tuán)隊(duì)的開發(fā)和維護(hù)。
二、多媒體標(biāo)簽
視頻標(biāo)簽:video
屬性:src、 Poster(加載等待畫面的圖片)、muted(靜音)
音頻標(biāo)簽: audio
屬性:src、loop、controls(調(diào)出當(dāng)前控件)
三、表單元素、控件
輸入框input中新增 type,類型可為、email、url、data、number等
required、placeholder
2、src和href的區(qū)別
src和href都是對(duì)外部資源的引用,區(qū)別如下:
src: 表示對(duì)資源的引用,用在js腳本、img、frame等元素上,當(dāng)瀏覽器解析到該元素時(shí),會(huì)暫停其他資源的下載和處理,直到該資源加載、編譯、執(zhí)行完成,所以js腳本會(huì)放在頁面的底部,而不是頭部。
href:表示超文本引用,指向一些網(wǎng)絡(luò)資源,當(dāng)瀏覽器識(shí)別它指向的文件時(shí),就會(huì)并行下載資源,不會(huì)停止對(duì)當(dāng)前文件的處理,用在a、link上
3、defer和async
參考博文:
https://blog.csdn.net/weixin_42561383/article/details/86564715
默認(rèn)情況下,瀏覽器是同步加載js腳本的,即渲染引擎遇到 script標(biāo)簽就會(huì)停下來,等執(zhí)行完腳本,再去繼續(xù)向下渲染,如果是外部腳本,還必須加入腳本的下載時(shí)間。
加入腳本的很多而且體積很大的話,下載和 執(zhí)行 就會(huì)占用很大的時(shí)間,照成瀏覽器堵塞,用戶就會(huì)感覺卡死了,沒有任何響應(yīng),體驗(yàn)極差,所以瀏覽器允許腳本的異步加載,方式如下:
<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>
關(guān)鍵字就是defer和async,腳本會(huì)異步加載。渲染引擎遇到這行命令就會(huì)開始下載外部的腳本,但是并不會(huì)等待其腳本下載完成和執(zhí)行完成,而是直接執(zhí)行后面的命令。
defer和async的區(qū)別:
defer:需要等待整個(gè)頁面正常DOM渲染完成后,才會(huì)執(zhí)行下載好的js腳本,并且是按下載完后的順序執(zhí)行。
async:當(dāng)外部的js腳本下載完成后,渲染引擎會(huì)暫停DOM渲染,開始執(zhí)行下載好的JS腳本的內(nèi)容,在執(zhí)行完成后,再去渲染。
簡(jiǎn)單的說:
defer是需要等DOM元素都渲染完成后,才去執(zhí)行下載完成的js腳本
async是當(dāng)js腳本下載完成后,開始執(zhí)行的時(shí)候中斷DOM渲染,執(zhí)行js腳本的內(nèi)容,執(zhí)行完成再去渲染DOM元素
沒有defer
或async
屬性,瀏覽器會(huì)立即下載并執(zhí)行相應(yīng)的腳本,并且在下載和執(zhí)行時(shí)頁面的處理會(huì)停止??赡苄纬身撁娑氯?/p>
不用異步加載的話可以把外部引入的腳本放在</body>
前即可
4、行內(nèi)元素與塊級(jí)元素
塊級(jí)元素: 獨(dú)占一行,可以設(shè)置寬高,設(shè)置margin和padding都有效,代表如下:
div、p、h1…h(huán)6、table、tr、ol、li、ul
行內(nèi)元素元素: 可以排成一行,設(shè)置寬高無效,對(duì)margin設(shè)置左右方向有效,而上下無效,padding設(shè)置都無效,代表如下:
基本上都是文本標(biāo)簽
span、img、b、strong、font、br、a
5、title與h1、b與strong、i與em的區(qū)別
Strong表示的是重點(diǎn)內(nèi)容,有語氣加強(qiáng)的含義,,會(huì)重讀,而展示強(qiáng)調(diào)的內(nèi)容
b只是展示強(qiáng)調(diào)的內(nèi)容
title屬性沒有明確意義只表示是個(gè)標(biāo)題,H1則表示層次明確的標(biāo)題,對(duì)頁面信息的抓取也有很大的影響
i內(nèi)容展示為斜體,em表示強(qiáng)調(diào)的文本
6、回流(重拍)與重繪
先了解下HTML文文件渲染的過程
都發(fā)生在渲染DOM樹(Render Tree)后的過程中,其中Layout是回流,Painting是重繪
回流:瀏覽器中進(jìn)行布局的過程就是回流
重繪:瀏覽器進(jìn)行 渲染就是重繪
觸發(fā)回流的一些條件:
1、添加或者刪除可見的DOM元素;
2、元素位置改變;
3、元素尺寸改變——邊距、填充、邊框、寬度和高度
4、內(nèi)容改變——比如文本改變或者圖片大小改變而引起的計(jì)算值寬度和高度改變;
5、頁面渲染初始化;
6、瀏覽器窗口尺寸改變——resize事件發(fā)生時(shí);
觸發(fā)重繪的一些條件:
1、改變背景色
2、改變透明度
簡(jiǎn)單的說,就是不影響布局的情況下,改變的就是重繪
性能優(yōu)化方法:
減少瀏覽器的回流行為達(dá)到性能優(yōu)化。
1、用transform代替位移
2、用visibility:hidden透明度代替display:none
3、使用display:none技術(shù),只引發(fā)兩次回流和重繪;
4、使用cloneNode(true or false)和replaceChild技術(shù),引發(fā)一次回流和重繪;
5、讓元素脫離動(dòng)畫流,減少回流的Render tree的規(guī)模;
7、cookie、localStorage 和 sessionStorage的區(qū)別及應(yīng)用實(shí)例
詳解cookie
簡(jiǎn)單的理解是因?yàn)閔ttp協(xié)議的無狀態(tài)性,所以需要cookie去把特別的信息保存下來,當(dāng)然保存的是在瀏覽器中,下面簡(jiǎn)單的講解下邏輯
1、瀏覽器向服務(wù)器發(fā)送請(qǐng)求,傳輸一些信息
2、服務(wù)器收到請(qǐng)求,在響應(yīng)體中通過set-cookie返回字段,保存在瀏覽器中。
3、瀏覽器再次發(fā)送請(qǐng)求時(shí)會(huì)攜帶cookie,根據(jù)服務(wù)器中對(duì)比,做一個(gè)判斷。
在前端的js代碼中通過:
document.cookie = ‘name=value’
去設(shè)置cookie,其中cookie帶有如下屬性
max-age/expires:可設(shè)置cookie的有效時(shí)間,其中expires必須時(shí)GMT的時(shí)間格式,可用new Date().toGMTString()
去對(duì)時(shí)間進(jìn)行轉(zhuǎn)換。在沒有設(shè)置時(shí)間時(shí),cookie會(huì)隨著瀏覽器的關(guān)閉,而被刪除
domain:可設(shè)置訪問該cookie的域名
path:可設(shè)置訪問此cookie的頁面路徑
Size:設(shè)置cookie的大小
http:cookie的httponly屬性,如果為true。則只有在http請(qǐng)求頭中會(huì)有此cookie的信息,而不能通過document.cookie
來進(jìn)行訪問
刪除cookie
只需要把cookie的有效時(shí)間設(shè)置為當(dāng)前日期的前任何時(shí)間即可
下面是列子:
<body>
<form>
用戶名<input type="text" name="username1111" /> 密碼<input
type="password"
name="pwd"
id="pwd"
/>
提交<input id="submit" type="submit" /> 記住密碼<input type="checkbox" />
<button onclick="hand1()" id="delete">刪除cookie</button>
</form>
<script>
let lineTime = new Date("2022-7-20 19:7:30").toGMTString();
console.log("lineTime: ", lineTime);
let submit = document.getElementById("submit");
let username = document.querySelector('input[type="text"]');
let pwd = document.querySelector('input[type="password"]');
let check = document.querySelector('input[type="checkbox"]');
let arr = document.cookie.split(";");
console.log(arr);
let arr1 = [];
arr.forEach((item) => {
arr1.push(item.split("="));
});
let cookie = {};
for (let i = 0; i < arr1.length; i++) {
let name = arr1[i][0];
let value = arr1[i][1];
cookie[name] = value;
}
if (document.cookie) {
username.value = cookie.yourname;
check.checked = true;
}
submit.addEventListener("click", (e) => {
let value = username.value;
let key = "yourname";
if (check.checked && username.value !== "") {
document.cookie = `${key}=${value};expires=${lineTime}`;
e.preventDefault();
}
});
function hand1() {
let key = "yourname";
document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
console.log(document.cookie);
e.preventDefault();
}
</script>
localStorage 和sessionStorage
前面得cookie作為一個(gè)存儲(chǔ)手段進(jìn)行舉例,但是在H5中新增了兩種存儲(chǔ)方式,其中使用方法如下:
localStorage.key()
:拿到指定key得值
localStorage.setItem('名','值')
:設(shè)置相關(guān)的儲(chǔ)存值
localStorage.getItem('名')
:取出對(duì)應(yīng)名的值
localStorage.removeItem('名')
:移除掉相關(guān)的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<input type="text" />
<button onclick="hand1()" class="hand">搜索</button>
<ul id="one"></ul>
<script>
if (sessionStorage.length > 0) {
for (let i = 0; i < sessionStorage.length; i++) {
let key = sessionStorage.key(i);
let newLi = document.createElement("li");
newLi.innerHTML = `${sessionStorage.getItem(key)}`;
let ul = document.getElementById("one");
ul.append(newLi);
let close = document.createElement("span");
close.innerHTML = `刪除`;
newLi.appendChild(close);
close.addEventListener("click", (e) => {
sessionStorage.removeItem(key);
newLi.parentNode.removeChild(newLi);
});
}
}
let search = document.querySelector('input[type="text"]');
let hand = document.getElementsByClassName("hand")[0];
let temp = 0;
function hand1() {
if (search.value) {
console.log(111);
temp++;
sessionStorage.setItem(`${temp}`, search.value);
let newLi = document.createElement("li");
newLi.innerHTML = `${sessionStorage.getItem(temp)}`;
let ul = document.getElementById("one");
ul.append(newLi);
let close = document.createElement("span");
close.innerHTML = `刪除`;
newLi.appendChild(close);
close.addEventListener("click", (e) => {
console.log(temp);
sessionStorage.removeItem(temp);
newLi.parentNode.removeChild(newLi);
});
}
}
</script>
</body>
</html>
sessionStorage使用的方法和localStorage一致。
三者的區(qū)別
cookie具有時(shí)效性,可以手動(dòng)的去設(shè)置需要保存的時(shí)間,內(nèi)存大小大概為4KB,內(nèi)容保存在客戶端上,刪除的話把過期時(shí)間設(shè)置為前一天即可。
localStorage,除非手動(dòng)去刪除,不然一直會(huì)保存,內(nèi)存大小為5MB
sessionStorage,臨時(shí)會(huì)話保存,相關(guān)頁面關(guān)閉掉就自動(dòng)刪除,內(nèi)容大小為5MB
建議理解三者的基本使用再去理解這面試題,因?yàn)楣ぷ髦幸材苡玫?/p>
8、同源策略與跨域問題
什么是同源策略?
借用阮一峰老師的描述:
簡(jiǎn)單地說就是為了網(wǎng)頁之間的安全性,但是在平常的工作中,我們會(huì)遇到別的資源請(qǐng)求問題,也就是跨域問,下面給出幾種常見的跨域解決問題的方案
跨域解決方案
參考B站技術(shù)蛋老師的講解
1、JSONP
json with padding,也就是JSON的填充方法。在服務(wù)器與客戶端之間的格式我們常用的是JSON格式。
我們用script標(biāo)簽獲取數(shù)據(jù),其中的數(shù)據(jù)會(huì)被執(zhí)行,所以我們一般會(huì)給數(shù)據(jù)外包一個(gè)js函數(shù),然后再外包一層作為傳輸用的json格式。
我們知道通過script標(biāo)簽請(qǐng)求的資源中,并不會(huì)受到同源策略的限制,而jsonp方法就是通過這個(gè)方式去實(shí)現(xiàn)別的資源共享,簡(jiǎn)單原理如下:
原理可分為 客戶端與服務(wù)器
客戶端:客戶端上去寫一個(gè)函數(shù),專門用來處理跨域獲取服務(wù)器JSON數(shù)據(jù)的方法,在傳入的url上寫額外的參數(shù),傳到服務(wù)器,同時(shí)客戶端收到服務(wù)器傳過來的數(shù)據(jù)后,調(diào)用提前設(shè)定好的函數(shù),執(zhí)行服務(wù)器傳過來的數(shù)據(jù)。
服務(wù)器:數(shù)據(jù)源是在服務(wù)器上存在的,而我們需要再然后服務(wù)器對(duì)額外的參數(shù)進(jìn)行判斷,把數(shù)據(jù)外包一個(gè)js函數(shù),通過JSON的方式傳給客戶端。
2、CORS
當(dāng)瀏覽器向服務(wù)器發(fā)起請(qǐng)求的時(shí)候,會(huì)在請(qǐng)求頭中添加origin(協(xié)議+主機(jī)+端口),也就是表明自己的協(xié)議+主機(jī)+端口,當(dāng)服務(wù)器接收到這個(gè)origin的時(shí)候,就得添加頭部Access-Control-Allow-Origin到響應(yīng)里面,瀏覽器看到服務(wù)器傳回來的Access-Control-Allow-Origin,就可以進(jìn)行判斷是否進(jìn)行跨域請(qǐng)求
核心其實(shí)就是設(shè)置Access-Control-Allow-Origin
9、檢測(cè)數(shù)據(jù)類型的方法
1、typeof
typeof在檢測(cè)null、object、array、data的結(jié)果中都是object,所以無法用來區(qū)分這幾個(gè)類型的區(qū)別
<script>
let a = [
"123",
123,
false,
true,
Symbol(1),
new Date(),
null,
undefined,
function () {},
{},
[]
];
a.forEach((item) => {
console.log(item, "檢測(cè)出的值:", typeof item);
});
</script>
2、instanceof
缺點(diǎn)是只能檢測(cè)該對(duì)象是否存在目標(biāo)對(duì)象的原型上
[對(duì)象] instanceof [構(gòu)造函數(shù)]
<script>
function Foo() {}
var f1 = new Foo();
var d = new Number(1);
console.log(f1 instanceof Foo); // true
console.log(d instanceof Number); //true
console.log(123 instanceof Number); //false -->不能判斷字面量的基本數(shù)據(jù)類型
</script>
console.log(Number instanceof Number) // false
console.log(String instanceof String) // false
console.log(Fun instanceof Fun) // false,這里Fun指的是函數(shù)
console.log(null instanceof Object) // false,null不具有任何對(duì)象的特性,也沒有__proto__屬性
instanceof 用于判斷對(duì)象類型,但以上情況的結(jié)果都為false,請(qǐng)注意。
instanceof 的原理
因?yàn)闀?huì)一直往原型鏈上查找
L代表instanceof左邊,R代表右邊
function hand(L, R) {
let L = L._propto_;
while (true) {
if (L === null) {
return false;
}
if (L === R.propotype) {
return true;
}
L = L._propto_;
}
}
3、constructor
constructor 不能判斷null、undefind,因?yàn)樗麄儾皇菢?gòu)造對(duì)象
<script>
let a = [
"123",
123,
false,
true,
Symbol(1),
new Date(),
function () {},
{},
[],
null,
undefined,
];
try {
a.forEach((item) => {
console.log(item, "檢測(cè)出的值:", item.constructor.name);
});
} catch (e) {
console.log(e);
}
</script>
4、Object.prototype.toString.call
可以檢測(cè)出所有的數(shù)據(jù)類型
<script>
let a = [
"123",
123,
false,
true,
Symbol(1),
new Date(),
function () {},
{},
[],
null,
undefined,
];
try {
a.forEach((item) => {
console.log(
item,
"檢測(cè)出的值:",
Object.prototype.toString.call(item)
);
});
} catch (e) {
console.log(e);
}
</script>
在使用Array.prototype.toString.call的時(shí)候,遇到null、undefined會(huì)出現(xiàn)報(bào)錯(cuò)
10、阻止默認(rèn)事件
在面試中我們會(huì)被問到事件冒泡、默認(rèn)事件等概念,下面做一些簡(jiǎn)單的了解:
事件冒泡:
1.原理:元素自身的事件被觸發(fā)后,如果父元素有相同的事件,如click事件,那么元素本身的觸發(fā)狀態(tài)就會(huì)傳遞,也就是冒到父元素,父元素的相同事件也會(huì)一級(jí)一級(jí)根據(jù)嵌套關(guān)系向外觸發(fā),直到document/window,冒泡過程結(jié)束。
2.使用范圍:冒泡事件只是針對(duì)于click相關(guān)的事件,還有click的分支事件:mouseup、mousedown
默認(rèn)事件:
比如點(diǎn)擊a標(biāo)簽會(huì)默認(rèn)打開、input提交表單按鈕,都是默認(rèn)事件
阻止默認(rèn)事件但是不阻止事件冒泡
event.preventDefault()
阻止事件冒泡阻止默認(rèn)事件
event.stopPropagation();
在jquery中阻止事件冒泡和默認(rèn)行為,在原生js中只阻止事件冒泡
return false
11、文檔流,文本流清除浮動(dòng)
文檔流:
我理解的是頁面中的塊級(jí)元素等DOM元素按照默認(rèn)的方式去進(jìn)行排列
文本流:
網(wǎng)頁頁面上的一些文字的排列
清除浮動(dòng)的方法及原理:
原理:其實(shí)就是讓目標(biāo)元素脫離文檔流即可,手段有float:left
、position中的絕對(duì)定位和固定定位
等
方法:
1、用偽類去清除浮動(dòng)
2、在浮動(dòng)元素上添加一個(gè)空盒子,寫上clear:both的樣式
3、雙偽類清除浮動(dòng)
12、手寫call、apply、bind
1、call
想要手寫出就得知道它是怎么使用的,函數(shù).call(綁定this指向,參數(shù)一,參數(shù)二,…)
<script>
function person(a, b, c, d) {
console.log(this.name);
console.log(a, b, c, d);
}
let egg = {
name: "測(cè)試",
};
//js創(chuàng)建新函數(shù)是在函數(shù)原型上去添加
Function.prototype.newCall = function (params) {
//先做判斷,如果綁定的調(diào)用的this不是函數(shù),則拋出異常錯(cuò)誤
if (typeof this !== "function") {
throw new TypeError("不是函數(shù)");
}
//防止傳入null、undefinde,和window進(jìn)行綁定
params = params || window;
//先獲取傳入的參數(shù)
let arr = [...arguments].slice(1);
//把this指向指向形參的函數(shù),保存this
params.fn = this;
//帶入的參數(shù)傳入函數(shù)中
let result = params.fn(...arr);
//刪除用完的函數(shù)
delete params.fn;
return result;
};
person.newCall(egg,'1','2','3','4')
</script>
2、apply
apply和call的寫法基本一至,就是二者接受的參數(shù)不同,面試apply的寫法
函數(shù).apply(this指向?qū)ο?,[參數(shù)1,參數(shù)2,參數(shù)3…])
<script>
function person(a, b, c, d) {
console.log(this.name);
console.log(a, b, c, d);
}
egg = {
name: "tom",
};
Function.prototype.newApply = function (context) {
if (typeof this !== "function") {
throw TypeError("不是一個(gè)函數(shù)");
}
context = context || window;
context.fn = this;
let result
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
delete context.fn
return result
};
person.newApply(egg,[1,2,3,4])
</script>
3、bind
bind與前兩個(gè)的區(qū)別如下
1、bind返回的是一個(gè)函數(shù)
2、如果是new出來的 ,返回一個(gè)空對(duì)象,且使創(chuàng)建出來的實(shí)例的__proto__指向_this的prototype,且完成函數(shù)柯里化
<script>
function person(a, b, c, d) {
console.log(this.name);
console.log(a, b, c, d);
}
Function.prototype.newBind = function (content) {
if (typeof this !== "function") {
throw TypeError("不是一個(gè)函數(shù)");
}
let arr = Array.prototype.slice.call(arguments, 1);
const that = this;
return function fn() {
if (this instanceof fn) {
return new that(...arr, ...arguments);
} else {
return that.apply(content, arr.concat(...arguments));
}
};
};
egg = {
name: "tom",
};
person.newBind(egg, 1, 2, 3)(4);
</script>
13、new的過程中發(fā)生了什么
其實(shí)new的過程中就是this指向改變、新創(chuàng)建一個(gè)實(shí)列的過程,如下
<script>
function Mother(tip){
this.tip=tip
}
let son =new Mother()
// 1、創(chuàng)建一個(gè)son空對(duì)象
// 2、使空對(duì)象的隱式原型指向原函數(shù)的顯示原型
// son_proto_=Mother.prototype
// 3、原函數(shù)進(jìn)行this的綁定,指向空對(duì)象
// let result =Mother.call(son,tip)
// 4、判斷函數(shù)結(jié)果是不是null、undefined,是就返回之前新對(duì)象,不是就返回結(jié)果
// return result instanceof Object ? Object: result
</script>
14、js的繼承方式
1、原型鏈繼承
關(guān)鍵點(diǎn)就是: 繼承函數(shù).prototype =new 被繼承函數(shù)
<script>
function person() {
this.obj = {
age: 10,
};
this.speack=function(){
console.log('父元素');
}
}
person.prototype.name = "tom";
//子元素
function son() {
this.name = "son1";
}
son.prototype = new person(); //原型鏈繼承
let p1 = new son();
console.log(p1.obj.age); //10
console.log(p1 instanceof person); //true
console.log(p1.name); //son1
</script>
缺點(diǎn):
1、繼承單一
2、子類無法向父類的構(gòu)造函數(shù)傳參
3、所有新實(shí)列都會(huì)共享父類實(shí)列的屬性(原型上的屬性也是共享的,一個(gè)實(shí)列修改了原型屬性,另一個(gè)也會(huì)被修改)
2、原型繼承
<script>
var person ={
arr: ['a','b','c','d']
}
var p1 =Object.create(person)
p1.arr.push('aaa')
console.log(p1); //{}
console.log(person);
</script>
缺點(diǎn):子類實(shí)列共享了父類構(gòu)造函數(shù)的引用屬性,不能傳參
3、構(gòu)造函數(shù)繼承
<script>
var person = function (name) {
this.name = name;
};
person.prototype.age=10
var son = function () {
person.call(this, "tom");
};
var p1 =new son()
console.log(p1.name);//tom
console.log(p1.age);undefined
</script>
重點(diǎn):借用.call()和.apply()將父類構(gòu)造函數(shù)引入子類函數(shù)(在子類函數(shù)中做了父類函數(shù)的自執(zhí)行)
優(yōu)點(diǎn):1、可以繼承多個(gè)構(gòu)造函數(shù)屬性
? 2、在子實(shí)列中可以向父實(shí)列傳參
缺點(diǎn):1、只能繼承父實(shí)列的構(gòu)造函數(shù)屬性
? 2、每新實(shí)列都會(huì)有父類構(gòu)造函數(shù)的副本,臃腫
4、組合繼承
<script>
var person = function (name) {
this.name = name;
};
person.prototype.age=10
var son = function () {
person.call(this, "tom"); //構(gòu)造函數(shù)繼承
};
son.prototype=new person() //原型鏈繼承
var p1 =new son()
console.log(p1.name);//tom
console.log(p1.age);undefined
</script>
重點(diǎn):結(jié)合了兩種模式的優(yōu)點(diǎn),傳參和復(fù)用
特點(diǎn):1、可以繼承父類原型上的屬性,可以傳參,可復(fù)用。
2、每個(gè)新實(shí)例引入的構(gòu)造函數(shù)屬性是私有的。
缺點(diǎn):調(diào)用了兩次父類構(gòu)造函數(shù)(耗內(nèi)存),子類的構(gòu)造函數(shù)會(huì)代替原型上的那個(gè)父類構(gòu)造函數(shù)。
5、寄生組合繼承
<script>
var person = function (name) {
this.name = name;
};
person.prototype.age = 10;
var son = function () {
person.call(this, "tom"); //構(gòu)造函數(shù)繼承
};
son.prototype = Object.create(person.prototype); //寄生組合繼承
son.prototype.constructor = son;
var p1 = new son();
console.log(p1.name); //tom
console.log(p1.age); //10
</script>
優(yōu)點(diǎn)
- 只調(diào)用了一次父類構(gòu)造函數(shù),只創(chuàng)建了一份父類屬性
- 子類可以用到父類原型鏈上的屬性和方法
6、extends繼承
<script>
class person{
constructor(){
this.name ='tom'
this.speack =()=>{
console.log('我是爹');
}
}
}
class son extends person{
constructor(){
super()
this.age=12
}
}
let s1 =new son()
console.log(s1.age,s1.name);
</script>
ES6出來的
? 子類只要繼承父類,可以不寫 constructor ,一旦寫了,則在 constructor 中的第一句話必須是 super 。
15、箭頭函數(shù)和普通函數(shù)的區(qū)別
1、call、apply、bind不會(huì)改變箭頭函數(shù)this值,會(huì)改變普通函數(shù)this值
2、箭頭函數(shù)沒有原型屬性
3、箭頭函數(shù)不綁定arguments,取而代之用rest參數(shù)… 解決
4、箭頭函數(shù)不能作為構(gòu)造函數(shù)使用,不能使用new
5、箭頭函數(shù)中的 this 和調(diào)用時(shí)的上下文無關(guān),而是取決于定義時(shí)的上下文
16、移動(dòng)端1px像素解決辦法
先理解概念,物理像素、邏輯像素
物理像素:是不同手機(jī)型號(hào)出廠時(shí)攜帶的像素,也稱為硬件像素
邏輯像素:css中記錄的像素
問題描述:
在開發(fā)的時(shí)候ui設(shè)計(jì)師要求的1px是設(shè)備的物理像素,而css中的是邏輯像素,它們之間并不是直接等于的關(guān)系,存在著比列關(guān)系,通??梢杂?javascript 中的 window.devicePixelRatio
來獲取,也可以用媒體查詢的 -webkit-min-device-pixel-ratio
來獲取。當(dāng)然,比例多少與設(shè)備相關(guān)。
解決辦法:
1、媒體查詢利用設(shè)備像素比列縮放,設(shè)置小數(shù)像素
css可以這樣設(shè)置:
.border { border: 1px solid #999 }
@media screen and (-webkit-min-device-pixel-ratio: 2) {
.border { border: 0.5px solid #999 }
}
@media screen and (-webkit-min-device-pixel-ratio: 3) {
.border { border: 0.333333px solid #999 }
}
js可以這樣寫:
<body><div id="main" style="border: 1px solid #000000;"></div></body>
<script type="text/javascript">
if (window.devicePixelRatio && devicePixelRatio >= 2) {
var main = document.getElementById('main');
main.style.border = '.5px solid #000000';
}
</script>
2、媒體查詢 + transfrom 對(duì)方案1的優(yōu)化
/* 2倍屏 */
@media only screen and (-webkit-min-device-pixel-ratio: 2.0) {
.border-bottom::after {
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
}
}
/* 3倍屏 */
@media only screen and (-webkit-min-device-pixel-ratio: 3.0) {
.border-bottom::after {
-webkit-transform: scaleY(0.33);
transform: scaleY(0.33);
}
}
17、偽類與偽元素的區(qū)別
首先在知道這個(gè)概念之前先了解什么是偽類?偽元素?
1、偽元素
1、偽元素在DOM樹中創(chuàng)建了一些抽象元素,這些抽象元素并不存在與文檔語言中(邏輯上存在,不存在文檔樹中)
2、偽元素由兩個(gè)::開頭,接的是偽元素得名稱(使用兩個(gè)::是為了區(qū)分偽類和偽元素,在CSS2中依然可以用一個(gè):的語法,但是在CSS3中必須使用兩個(gè)冒號(hào)::)
3、一個(gè)選擇器只能使用一個(gè)偽元素,并且偽元素必須處于選擇器語句的最后
偽元素的種類:
2、偽類
1、偽類由一個(gè)冒號(hào)開頭:
2、獲取不存在與DOM樹中的信息。比如<a>
標(biāo)簽的:link
、visited
等,這些信息不存在與DOM樹結(jié)構(gòu)中,只能通過CSS選擇器來獲取
偽類的種類:
18、移動(dòng)端、瀏覽器字體小于12px的解決方案
font-size: 12px;
是瀏覽器字體設(shè)置最小的時(shí)候,12以下的數(shù)值不生效了,要是想實(shí)現(xiàn)小于12px,方法如下:
transform: scale(0.5);
這時(shí)候可能會(huì)遇到字體縮放和布局一起縮小了,只需要將字體與容器樣式分開寫就好了
<style>
*,
body {
padding: 0;
margin: 0;
}
.one {
font-size: 20px;
transform: scale(0.5);
}
.father {
width: 100px;
height: 100ox;
background-color: red;
}
</style>
</head>
<body>
<div class="father"><p class="one">這是一段話</p></div>
</body>
19、js浮點(diǎn)數(shù)精度計(jì)算問題解決
一般運(yùn)算中,我們會(huì)保留后兩位小數(shù),這里做點(diǎn)知識(shí)擴(kuò)展
1、.toFixed()
語法:
數(shù)字.toFixed(2)
括號(hào)中的數(shù)字是保留的位數(shù),該方法會(huì)四舍五入,返回的值類型是string型
2、Math.round()
語法:
Math.round(x)
x是數(shù)值
返回值: 給指定的數(shù)字值四舍五入到最接近的整數(shù)
解決精度運(yùn)算問題有如下方式:
1、 擴(kuò)大倍數(shù)法:有多少位小數(shù)就擴(kuò)大10的n次方
document.write((0.01*100+0.09*100)/100); //輸出結(jié)果為0.1
2、四舍五入法:
document.write((0.01+0.09).toFixed(2)); //保留2位小數(shù),輸出結(jié)果為0.10
document.write(Math.round((0.01+0.09)*100)/100); //輸出結(jié)果為0.1
20、移動(dòng)端的300毫秒延遲問題
問題描述:
移動(dòng)端瀏覽器在派發(fā)點(diǎn)擊事件的時(shí)候,通常會(huì)出現(xiàn)300ms左右的延遲。也就是說,當(dāng)我們點(diǎn)擊頁面的時(shí)候移動(dòng)端瀏覽器并不是立即作出反應(yīng),而是會(huì)等上一小會(huì)兒才會(huì)出現(xiàn)點(diǎn)擊的效果。
方案一:禁用縮放
<meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="initial-scale=1,maximum-scale=1">
方案二:更改默認(rèn)的視口寬度
<meta name="viewport" content="width=device-width">
方案三:fastclick,解決移動(dòng)端300ms延遲
FastClick 是 FT Labs 專門為解決移動(dòng)端瀏覽器 300 毫秒點(diǎn)擊延遲問題所開發(fā)的一個(gè)輕量級(jí)的庫。FastClick的實(shí)現(xiàn)原理是在檢測(cè)到touchend事件的時(shí)候,會(huì)通過DOM自定義事件立即出發(fā)模擬一個(gè)click事件,并把瀏覽器在300ms之后的click事件阻止掉。
直接安裝依賴按照官網(wǎng)的教程使用就好了
21、HTTP緩存
面試中我們常會(huì)被到,你知道http緩存的方式有幾種嗎?這樣的問題,下面我簡(jiǎn)單的介紹下,為什么會(huì)有HTTP緩存、緩存的方式
1、存在的意義
我們每一次的網(wǎng)絡(luò)請(qǐng)求中,在請(qǐng)求成功的前提下,服務(wù)器都會(huì)給我們返回對(duì)應(yīng)的資源,瀏覽器進(jìn)行下載,但是并不是所以的資源都會(huì)被下載,比如當(dāng)某些資源未改變時(shí),瀏覽器會(huì)在本地緩存中拿到它們,從而避免了重復(fù)下載的過程,這也算是一種性能上的優(yōu)化
可以被緩存的資源:JS文件、CSS文件、圖片、字體包等等
2、緩存的類型
我們可以知道,前端發(fā)起HTTP請(qǐng)求的時(shí)候,會(huì)在請(qǐng)求頭上攜帶相關(guān)的信息,瀏覽器就會(huì)根據(jù)我們攜帶的信息去判斷,本次請(qǐng)求的該資源是否有本地緩存
強(qiáng)緩存
以前的使用中,我們一直用的是expires,也就是當(dāng)服務(wù)器返回響應(yīng)時(shí),在響應(yīng)頭中將過期的時(shí)間寫入expires字段中,自己隨便找個(gè)網(wǎng)站F12打開調(diào)試臺(tái),找一條網(wǎng)絡(luò)請(qǐng)求即可
可以看到expires中寫入了過期的時(shí)間范圍,那整個(gè)流程是怎么樣的呢?
當(dāng)首次資源發(fā)送時(shí):
再次發(fā)送資源時(shí),瀏覽器會(huì)把expires中的時(shí)間戳和本地時(shí)間去進(jìn)行對(duì)比,如果本地時(shí)間小于expires中的時(shí)間,則在緩存中拿到這個(gè)資源,這里的時(shí)間戳由于是服務(wù)器上傳的,所以需要保證瀏覽器和服務(wù)器上的時(shí)間一致
expires是通過拿到時(shí)間戳去進(jìn)行比對(duì)的,在后面又增加了Cache-Control
中的max-age
字段也允許我們通過設(shè)定時(shí)間長度來達(dá)到同樣的目的。
max-age可以看作是對(duì)expires的補(bǔ)充,在日常工作中,我們可能用max-age較多,但是如果要實(shí)現(xiàn)向下兼容,expires也是必不可少的
cache-control: max-age=3600, s-maxage=31536000
這里可以看到max-age的值,它并不是一個(gè)時(shí)間戳,而是一個(gè)時(shí)間長度,單位是秒,意思是在3600秒內(nèi),該資源是有效的。max-age的機(jī)制就是對(duì)資源的判定有效不再受到服務(wù)器時(shí)間的限制,客戶端會(huì)記錄到請(qǐng)求資源的時(shí)間點(diǎn),以此時(shí)間點(diǎn)為起點(diǎn),從而確保兩個(gè)時(shí)間點(diǎn)都來自于客戶端,相對(duì)來說更加的精確,這里就不給出請(qǐng)求圖了,和上面原理一致
這里介紹下cache-control中的值
max-age:緩存保存的時(shí)間
no-cache:繞開了瀏覽器,每一次發(fā)起請(qǐng)求都不會(huì)再去詢問瀏覽器的緩存情況,而是直接向服務(wù)端去確認(rèn)該緩存是否過期
no-store:不使用任何的緩存策略,連服務(wù)器端的緩存確認(rèn)都繞開了,只允許直接向服務(wù)端發(fā)起請(qǐng)求,并下載完整的響應(yīng)
public:資源能被本地緩存、服務(wù)器代理
private:資源只能給本地緩存,其他服務(wù)器不能緩存
協(xié)商緩存
瀏覽器向服務(wù)器詢問是否需要重新下載資源,還是從本地上獲取到緩存的資源,值得一提的是,當(dāng)服務(wù)器提示資源未改動(dòng),資源就會(huì)被重定向到瀏覽器緩存,對(duì)應(yīng)的HTTP狀態(tài)碼是304
協(xié)商緩存的實(shí)現(xiàn)
Last-Modified:時(shí)間戳,當(dāng)我們第一次請(qǐng)求資源時(shí),會(huì)在響應(yīng)頭中返回
If-Modified-Since:時(shí)間戳,就是服務(wù)器返回的Last-Modified的值
過程就是,請(qǐng)求頭會(huì)攜帶If-Modified-Since,服務(wù)器會(huì)進(jìn)行判斷,若If-Modified-Since的時(shí)間戳是和last-modified不一致,服務(wù)器就會(huì)完整的返回響應(yīng)內(nèi)容,并且返回新的last-modified值,如果一致,就返回304,響應(yīng)頭也不會(huì)添加last-modified字段
第一次請(qǐng)求:
再次請(qǐng)求
但是last-modified有自己的缺陷
1、last-modified的值只精確到秒級(jí)
2、如果文件每隔一段時(shí)間重復(fù)生成,但內(nèi)容是一致的,last-modified會(huì)每次返回資源文件,即使內(nèi)容一致
所以etag對(duì)其進(jìn)行了補(bǔ)充
Etag是服務(wù)器對(duì)每個(gè)資源文件生成的唯一 標(biāo)識(shí)字符串 ,這個(gè)字符串基于文件內(nèi)容編碼,只要文件內(nèi)容不同,對(duì)應(yīng)的Etag也會(huì)不同
請(qǐng)求方式和上圖差不多,服務(wù)器返回Etag,下次請(qǐng)求請(qǐng)求頭會(huì)帶上名為if-None-Match的字符串為服務(wù)器做對(duì)比
這里其實(shí)可以看到,Etag會(huì)讓服務(wù)器多做事,也就是會(huì)影響到服務(wù)器的性能,所以我們使用的時(shí)候需要進(jìn)行考慮,Etag的感知文件變化上比Last-modified更為準(zhǔn)確,所以優(yōu)先級(jí)也更高,二者同時(shí)出現(xiàn)時(shí),以Etag為準(zhǔn)
上訴只是對(duì)HTTP緩存的一些簡(jiǎn)單介紹,基礎(chǔ)面試知識(shí)點(diǎn)可以應(yīng)付了,HTTP緩存有很多知識(shí),感興趣可以多百度看下
CSS篇
1、舉出讓元素居中的方法
個(gè)人總結(jié)出兩種情況,即需要居中的元素帶寬高、不帶寬高,如下:
帶寬高
一
<style>
.father {
width: 500px;
height: 500px;
background-color: red;
position: relative;
}
.son {
width: 100px;
height: 100px;
background-color: blue;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
</style>
<body>
<div class="father">
<div class="son"></div>
</div>
</body>
二
<style>
.father {
width: 500px;
height: 500px;
background-color: red;
position: relative;
}
.son {
width: 100px;
height: 100px;
background-color: blue;
position: absolute;
top: 50%;
left: 50%;
margin-top: -50px;
margin-left: -50px;
}
</style>
<body>
<div class="father">
<div class="son"></div>
</div>
</body>
不帶寬高
一
<style>
.father {
width: 500px;
height: 500px;
background-color: red;
position: relative;
}
.son {
background-color: blue;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
</style>
<body>
<div class="father">
<div class="son">son</div>
</div>
</body>
二
<style>
.father {
width: 500px;
height: 500px;
background-color: red;
display: flex;
justify-content: center;
align-items: center;
}
.son {
background-color: blue;
}
</style>
<body>
<div class="father">
<div class="son">son</div>
</div>
</body>
2、常見的布局方式
一、左邊(右邊)固定,右邊(左邊)自適應(yīng)
float布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.left {
width: 200px;
height: 200px;
background-color: red;
float: left;
}
.right {
height: 200px;
background-color: blue;
}
</style>
</head>
<body>
<div class="left"></div>
<div class="right"></div>
</body>
</html>
絕對(duì)定位
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.left {
width: 200px;
height: 200px;
background-color: red;
position: absolute;
}
.right {
height: 200px;
background-color: blue;
}
</style>
</head>
<body>
<div class="left"></div>
<div class="right"></div>
</body>
</html>
彈性布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.box {
display: flex;
}
.left {
width: 200px;
height: 200px;
background-color: red;
}
.right {
flex: 1;
background-color: blue;
}
</style>
</head>
<body>
<div class="box">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
</html>
彈性布局若是要實(shí)現(xiàn)右邊固定的效果,則加上如下代碼即可
.box {
display: flex;
flex-direction: row-reverse;
}
二、左中右(左右不變,中間自適應(yīng))
float布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.left {
width: 200px;
height: 200px;
background-color: red;
float: left;
}
.right {
width: 200px;
height: 200px;
background-color: red;
float: right;
}
.center {
background-color: blue;
height: 200px;
}
</style>
</head>
<body>
<div class="left"></div>
<div class="right"></div>
<div class="center"></div>
</body>
</html>
絕對(duì)定位
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.left {
width: 200px;
height: 200px;
background-color: red;
position: absolute;
left: 0;
}
.right {
width: 200px;
height: 200px;
background-color: red;
position: absolute;
right: 0;
}
.center {
background-color: blue;
height: 200px;
width: 100%;
}
</style>
</head>
<body>
<div class="left"></div>
<div class="right"></div>
<div class="center"></div>
</body>
</html>
彈性布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.box {
display: flex;
}
.left {
width: 200px;
height: 200px;
background-color: red;
}
.right {
width: 200px;
height: 200px;
background-color: red;
}
.center {
background-color: blue;
flex: 1;
}
</style>
</head>
<body>
<div class="box">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
</body>
</html>
三、上中下(上下不變,中間自適應(yīng))
在寫之前,首先說明一點(diǎn),關(guān)于元素的寬度,若是沒給出,在瀏覽器中會(huì)自動(dòng)給出寬度, 但是關(guān)于高度并不會(huì)自動(dòng)給出高度,所以上面的彈性布局列子中,沒給出高度但是還是顯示出了盒子是因?yàn)楹凶拥膬?nèi)容已經(jīng)被撐開了,但是高度并不會(huì)自動(dòng)分配
絕對(duì)定位
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.top {
height: 200px;
width: 100%;
background-color: red;
position: absolute;
top: 0;
}
.bottom {
height: 200px;
width: 100%;
background-color: red;
position: absolute;
bottom: 0;
}
.center {
position: absolute;
background-color: blue;
top: 200px;
bottom: 200px;
width: 100%;
}
</style>
</head>
<body>
<div class="top"></div>
<div class="center"></div>
<div class="bottom"></div>
</body>
</html>
彈性布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
html,
body {
height: 100%;
}
.box {
height: 100%;
display: flex;
flex-direction: column;
}
.top {
width: 100%;
height: 200px;
background-color: red;
}
.bottom {
width: 100%;
height: 200px;
background-color: red;
}
.center {
flex: 1;
background-color: blue;
}
</style>
</head>
<body>
<div class="box">
<div class="top"></div>
<div class="center"></div>
<div class="bottom"></div>
</div>
</body>
</html>
額外補(bǔ)充點(diǎn):
文檔流和文本流
個(gè)人對(duì)文檔流的理解就是盒模型中的概念。
文檔流就是在瀏覽器中的規(guī)則,塊狀元素的規(guī)則是從上到下排序的,行內(nèi)元素是從左到右排序的
文本流:適用于文字之間的規(guī)則
其中我們?cè)谏厦娴牧凶又衒loat、絕對(duì)定位、固定定位、display:flex,都會(huì)讓原本的元素脫離文檔流,在了解相關(guān)的規(guī)則后,我們可以按照自己的想法去布局。
vue篇
1、你怎么理解vue?它是屬于什么模式?
vue.js是一款漸進(jìn)式、多途徑、高性能JavaScript框架,易用、靈活、高效
屬于MVVM(Model-View-ViewModel)模式,也是就model(模型層)、ViewModel(視圖驅(qū)動(dòng)層)、view(視圖層),數(shù)據(jù)在傳遞的時(shí)候雙向傳遞
2、v-if和v-show的區(qū)別
相同點(diǎn):v-if與v-show都可以動(dòng)態(tài)控制dom元素顯示隱藏
不同點(diǎn):v-if顯示隱藏是將dom元素整個(gè)添加或刪除,而v-show隱藏則是為該元素添加css–display:none,dom元素還在。
性能角度上:v-if有更高的切換消耗;v-show有更高的初始渲染消耗;
使用場(chǎng)景:v-if適合運(yùn)營條件不大可能改變;v-show適合頻繁切換。
3、vue響應(yīng)式原理和雙向綁定原理
在了解該知識(shí)點(diǎn)前,先做一個(gè)只是鋪墊,詳細(xì)介紹下Object.defineProperty的用法
Object.defineProperty詳解
Object.defineProperty是es5的方法,作用是直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性,并返回這個(gè)對(duì)象(只能用在對(duì)象上,不能用在數(shù)組上)
1、語法
Object.defineProperty(obj, prop, descriptor)
2、參數(shù)
- obj:必需。目標(biāo)對(duì)象
- prop:必需。需定義或修改的屬性的名字
- descriptor:必需。目標(biāo)屬性所擁有的特性
3、屬性用法
修改某個(gè)屬性的值時(shí),給這個(gè)屬性添加一些特性。
let person = {};
Object.defineProperty(person, 'name',
writable: true || false,
configurable: true || false,
enumerable: true || false,
value:'gjf'
});
屬性詳解:
writable:是否可以被重寫,true可以重寫,false不能重寫,默認(rèn)為false。
enumerable:是否可以被枚舉(使用for…in或Object.keys())。設(shè)置為true可以被枚舉;設(shè)置為false,不能被枚舉。默認(rèn)為false。
value:值可以使任意類型的值,默認(rèn)為undefined
configurable:是否可以刪除目標(biāo)屬性或是否可以再次修改屬性的特性(writable, configurable, enumerable)。設(shè)置為true可以被刪除或可以重新設(shè)置特性;設(shè)置為false,不能被可以被刪除或不可以重新設(shè)置特性。默認(rèn)為false。
vue響應(yīng)式原理(vue雙向綁定的原理)
vue2.x中
object.defineProperty是屬性級(jí)別的攔截,會(huì)在set、get的方法中進(jìn)行攔截操作
當(dāng)把一個(gè)普通的js對(duì)象傳入vue實(shí)列作為data選項(xiàng)時(shí),vue會(huì)遍歷此對(duì)象的所有的property,并使用object.defineProperty
,把這些property全部轉(zhuǎn)換為getter/setter。然后watcher會(huì)監(jiān)聽setter的變化,每當(dāng)setter變化后,就會(huì)進(jìn)行視圖層的重新渲染,達(dá)到響應(yīng)式效果
在這里主要我改動(dòng)了data中的某一個(gè)值,那么整個(gè)響應(yīng)式的狀態(tài)又會(huì)重新開始進(jìn)行setter、監(jiān)聽,相對(duì)來說浪費(fèi)資源
<body>
<div id="app">
hellow
</div>
<script>
let data ={
name: 'tom',
age:123
}
let vm ={}
var id= document.getElementById('app')
Object.keys(data).forEach((k)=>{
Object.defineProperty(vm,k,{
get:function(){
id.textContent=data[k]
return data[k]
},
set:function(e){
data[k]=e
id.textContent=data[k]
}
})
})
</script>
若是data中有多個(gè)值,則會(huì)進(jìn)行循環(huán)輸出,來監(jiān)聽每一個(gè)值的變化
vue3.x中
Proxy(代理)
對(duì)象級(jí)別的攔截
改變語法原有的規(guī)則,可以自定義其規(guī)則(元編程)
target:代理處理的目標(biāo)對(duì)象
handler: 代理處理的方法
let obj =new Proxy(target,handler)
自定義對(duì)象屬性的獲取、賦值、枚舉、函數(shù)調(diào)用等功能
<body>
<div id="app">
hellow
</div>
<script>
let data ={
name: 'tom',
age:123
}
let vm ={}
var id= document.getElementById('app')
const vs =new Proxy(data,{
get(target,key){
id.textContent=target[key]
},
set(target,key,newValue){
if(target[key] === newValue){
return
}
target[key]=newValue
id.textContent=target[key]
}
})
</script>
這里去監(jiān)聽每一個(gè)屬性的時(shí)候不需要用到循環(huán)的方法,簡(jiǎn)單的說就是誰改變就去監(jiān)聽誰,在原用的基礎(chǔ)上提升了性能
4、虛擬DOM和diff算法
參考b站 https://www.bilibili.com/video/BV1dV411a7mT/
1、認(rèn)識(shí)虛擬DOM
沒有虛擬DOM之前: 數(shù)據(jù)改變=>操作DOM=>視圖更新
使用虛擬DOM后:數(shù)據(jù)改變=>虛擬DOM(計(jì)算出變更)=>操作DOM=>視圖更新
虛擬DOM:用js模擬DOM結(jié)構(gòu)
如下圖,左邊是實(shí)際DOM元素,而右邊是js模擬的DOM結(jié)構(gòu)
2、虛擬DOM的好處
每當(dāng)dom改變的時(shí)候,不會(huì)全部都進(jìn)行DOM改變,而是被改動(dòng)的地方進(jìn)行改變
這里就是用js代碼去模擬DOM結(jié)構(gòu)
用虛擬DOM計(jì)算出最小的變化,然后再去更新變化的實(shí)際DOM
3、認(rèn)識(shí)diff算法基本概念
是兩個(gè)虛擬DOM之間的一種比較
1、虛擬DOM之間會(huì)平級(jí)別對(duì)比 ,深度遍歷進(jìn)行對(duì)比
2、對(duì)比的同時(shí)會(huì)通過key值進(jìn)行判斷,判斷元素是僅僅位置發(fā)生改變還是需要整個(gè)替換或刪除
3、如果不是元素發(fā)生改變的話,再對(duì)內(nèi)容進(jìn)行對(duì)比,如果是內(nèi)容發(fā)生改變的話,就直接修改內(nèi)容
詳細(xì)的算法介紹就需要另外研究了
5、vue的生命周期與不同階段的作用
vue的生命周期有:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed
作用:
beforeCreate:可以加載loading事件,在加載實(shí)列的時(shí)候被觸發(fā)
created:初始化完成時(shí)的事件在這里,這里也結(jié)束loading事件,異步請(qǐng)求也適合在這里被調(diào)用
mounted:可以掛載元素,過去DOM節(jié)點(diǎn)
updated:對(duì)數(shù)據(jù)統(tǒng)一處理,這里寫上對(duì)應(yīng)的函數(shù)即可
beforeDestroy:可以確定一個(gè)停止事件的確認(rèn)框
nextTick:更新數(shù)據(jù)后,立即操作dom
6、vue組件之間的傳值方式
1、父子組件傳值方式
父組件向子組件傳值
1、傳值前現(xiàn)在父組件中導(dǎo)入需要的子組件,然后在父組件中傳入值、
2、子組件需要在props:{}中定義傳過來的值,以及類型,然后就可以在其他地方使用
父組件:
子組件:
子組件向父組件傳值
就是在子組件中通過$emit(傳向父組件事件,傳向父組件值)向父組件傳入值,父組件接受改變即可
子組件:
<template>
<div>
{{ sendData }}
<button @click="hand">點(diǎn)擊</button>
</div>
</template>
<script>
export default {
name: "Son",
props: ["sendData"],
data() {
return {
city: "上海",
};
},
methods: {
hand: function () {
console.log(this.city);
this.$emit("change", this.city);
},
},
};
父組件:
<template>
<div class="home">
<Son :sendData="msg" @change="changeFather" />
</div>
</template>
<script>
// @ is an alias to /src
import Son from "@/components/son.vue";
export default {
name: "Home",
components: {
Son,
},
data() {
return {
msg: "北京",
};
},
methods: {
changeFather: function (city) {
console.log(this.msg);
this.msg = city;
},
},
};
</script>
2、兄弟組件傳值方式
1、bus總線方法
1、定義一個(gè)bus.js ,內(nèi)容如下
import Vue from "vue";
const Bus = new Vue();
export default Bus;
2、然后在main.js中添加如下代碼
import bus from "./components/bus";
Vue.use(bus);
Vue.prototype.$bus = bus;
3、在需要傳值的兄弟組件中,通過 b u s . bus. bus.emit(傳入方法,傳入值),方式傳入
<template>
<div>
<p>child1</p>
<button @click="hand1">點(diǎn)擊</button>
</div>
</template>
<script>
export default {
name: "Child1",
data() {
return {
msg: "666",
};
},
methods: {
hand1: function () {
this.$bus.$emit('get',this.msg)
}
}
};
</script>
<style></style>
4、在接收的組件中在mouted生命周期中,用 b u s . bus. bus.on(傳過來的方法名,回調(diào)函數(shù)),來進(jìn)行接收
<template>
<div>
<p>child2</p>
<p>{{ cmsg }}</p>
</div>
</template>
<script>
export default {
name: "Child2",
data() {
return {
cmsg: "",
};
},
mounted: function () {
this.$bus.$on("get", (data) => {
console.log(data);
this.cmsg = data;
});
},
};
</script>
<style></style>
2、 可以子組件先傳入父組件,然后再由父組件再傳給另一個(gè)子組件
7、methods、computed 和 watch 的區(qū)別和運(yùn)用的場(chǎng)景?
1、methods、computed的區(qū)別
在頁面進(jìn)行渲染的時(shí)候,methos中所有的方法都會(huì)被重新調(diào)用,而computed,只會(huì)在其被依賴項(xiàng)改變的時(shí)候才會(huì)重新計(jì)算
2、computed和watch的區(qū)別
computed是計(jì)算屬性,有如下特點(diǎn):
1、計(jì)算屬性定義的屬性可以不用在data中定義,在DOM中直接使用。
2、支持緩存,只有在數(shù)據(jù)依賴項(xiàng)發(fā)生改變的時(shí)候,才會(huì)重新計(jì)算。
3、不支持異步操作,在computed中異步操作無效,無法監(jiān)聽數(shù)據(jù)的變化
使用方法如下:
watch是監(jiān)聽屬性,特點(diǎn)如下:
1、不支持緩存,只要數(shù)據(jù)變化,就會(huì)直接觸發(fā)響應(yīng)的操作
2、在watch內(nèi)支持異步操作
3、監(jiān)聽的函數(shù)接受兩個(gè)參數(shù),第一個(gè)是參數(shù)最新的值,第二個(gè)是參數(shù)輸入之前的值
使用方法如下:
總結(jié):
- 如果一個(gè)數(shù)據(jù)需要經(jīng)過復(fù)雜計(jì)算就用 computed
- 如果一個(gè)數(shù)據(jù)需要被監(jiān)聽并且對(duì)數(shù)據(jù)做一些操作就用 watch
8、在哪個(gè)生命周期內(nèi)調(diào)用異步請(qǐng)求?
在created、beforeMount、mounted都可以發(fā)送異步請(qǐng)求,因?yàn)榭梢詫⒎?wù)端端返回的數(shù)據(jù)進(jìn)行賦值。但是最常用的是在 created 鉤子函數(shù)中調(diào)用異步請(qǐng)求,因?yàn)樵?created 鉤子函數(shù)中調(diào)用異步請(qǐng)求
有兩個(gè)優(yōu)點(diǎn):
第一點(diǎn):能更快獲取到服務(wù)端數(shù)據(jù),減少頁面 loading 時(shí)間;
第二點(diǎn):放在 created 中有助于一致性,因?yàn)閟sr 不支持 beforeMount 、mounted 鉤子函數(shù)。
9、對(duì) keep-alive 的了解?
10、組件中 data 為什么是一個(gè)函數(shù)?
因?yàn)関ue的組件可能在不同的頁面中會(huì)被調(diào)用,是一個(gè)函數(shù)的話每一次的調(diào)用就會(huì)執(zhí)行data函數(shù)并返回新的數(shù)據(jù),這樣就可以避免多處調(diào)用之間的數(shù)據(jù)污染
11、Vue 中的 key 有什么作用?
我們可以知道,通常我們?cè)谑褂胿-for的時(shí)候會(huì)去標(biāo)明key值,但是不建議去使用其數(shù)組的下標(biāo)index作為key值。
在上面中已經(jīng)簡(jiǎn)單的介紹的虛擬DOM、diff算法,key值主要是為了diff算法服務(wù)的,給每一個(gè)循環(huán)出的item綁定一個(gè)key值,做唯一標(biāo)識(shí)
好處如下:
1、判斷新舊VDOM節(jié)點(diǎn)在邏輯上是不是同一個(gè)對(duì)象
2、準(zhǔn)確。因?yàn)閗ey的特性是唯一性。所以如果不加key,
采用index的標(biāo)記法,那么vue會(huì)選擇復(fù)用同類型節(jié)點(diǎn)(Vue的就地更新策略),導(dǎo)致之前節(jié)點(diǎn)的狀態(tài)被保留下來,會(huì)產(chǎn)生一系列的bug.
3、快速。在元素list一直變化的情況下,key值設(shè)置唯一時(shí),能很精確找到/找不到變更元素,若使用index標(biāo)記,要遍歷vnode,時(shí)間長。
- Vue的策略是不對(duì)dom直接更新,而是先比較oldDOM和VDOM 之間的區(qū)別,通過比較差別并且復(fù)用沒有改變的dom,來快速的構(gòu)建新的dom并渲染到頁面
12、vue中如何動(dòng)態(tài)的設(shè)置class、style?
//動(dòng)態(tài)class對(duì)象
<div :class="{ 'isActive': true, 'red': isRed }"></div>
//動(dòng)態(tài)style對(duì)象
<div :style="{ color: bgColor, fontSize: '18px' }"></div>
//動(dòng)態(tài)class數(shù)組
<div :class="['is-active', isRed ? 'red' : '' ]"></div>
//動(dòng)態(tài)style數(shù)組
<div :style="[{ color: bgColor, fontSize: '18px' }, { fontWeight: '500' }]"></div>
13、為什么v-if和v-for不建議用在同一標(biāo)簽?
因?yàn)関-for的優(yōu)先級(jí)高于v-if,程序會(huì)先執(zhí)行v-for的操作,然后再去執(zhí)行v-if,每次都會(huì)先去循環(huán)再進(jìn)行條件判斷,就會(huì)帶來性能上的浪費(fèi)
14、不需要響應(yīng)式的數(shù)據(jù)應(yīng)該怎么處理?
// 方法一:將數(shù)據(jù)定義在data之外
data () {
this.list1 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list2 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list3 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list4 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list5 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
return {}
}
// 方法二:Object.freeze()
data () {
return {
list1: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list2: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list3: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list4: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list5: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
}
}
15、watch有哪些屬性,分別有什么用?
1、正常監(jiān)聽
<div id="app">
<input tyoe="text" v-model="brand">
</div>
new Vue({
el:"#app",
data:{
brand:'nike',
},
watch:{
cityname(newbrand,oldbrand){
//...
}
}
})
2、immediate
watch時(shí)有一個(gè)特點(diǎn),就是當(dāng)值第一次綁定的時(shí)候,不會(huì)執(zhí)行監(jiān)聽函數(shù),只有值發(fā)生改變才會(huì)執(zhí)行。如果我們需要在最初綁定值的時(shí)候也執(zhí)行函數(shù),則就需要用到immediate屬性。
<body>
<div id="app">
<input type="text" v-model="num">
</div>
<script src="vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: 1
},
watch: {
num: {
// 數(shù)據(jù)發(fā)生變化就會(huì)調(diào)用這個(gè)函數(shù)
handler(newVal, oldVal) {
console.log('oldVal:', oldVal)
console.log('newVal:', newVal)
},
// 立即處理 進(jìn)入頁面就觸發(fā)
immediate: true
}
}
})
</script>
</body>
普通的監(jiān)聽時(shí)候?qū)懙恼?qǐng)示寫的函數(shù)其實(shí)就是在寫這個(gè)handler方法。
immediate表示在watch中首次綁定的時(shí)候,是否執(zhí)行handler,值為true則表示在watch中聲明的時(shí)候,就立即執(zhí)行handler方法,值為false,則和一般使用watch一樣,在數(shù)據(jù)發(fā)生變化的時(shí)候才執(zhí)行handler。
3、deep
深度監(jiān)聽,當(dāng)需要監(jiān)聽一個(gè)對(duì)象的改變時(shí),普通的watch方法無法監(jiān)聽到對(duì)象內(nèi)部屬性的改變,只有data中的數(shù)據(jù)才能夠監(jiān)聽到變化,此時(shí)就需要deep屬性對(duì)對(duì)象進(jìn)行深度監(jiān)聽。
<div id="app">
<input tyoe="text" v-model="brand">
</div>
new Vue({
el:"#app",
data:{
brand:(name:'nike',id:"no1"),
},
watch:{
cityname:{
handler:(newbrand,oldbrand){
//...
},
deep:true,
immediate:true
}
}
})
vue-router篇
1、this.$router和this.$route的區(qū)別
this.$router:是全局路由器的router的實(shí)列,可以在任何組件內(nèi)進(jìn)行訪問,就是跳轉(zhuǎn)路由的方法,里面有很多的方法比如
this.$router.push()
this.$router.replace()
this.$router.go()
his.$route:包含當(dāng)前激活的路由狀態(tài)信息、url解析得到的信息
**1.$route.path**
字符串,對(duì)應(yīng)當(dāng)前路由的路徑,總是解析為絕對(duì)路徑,如 "/foo/bar"。
**2.$route.params**
一個(gè) key/value 對(duì)象,包含了 動(dòng)態(tài)片段 和 全匹配片段,
如果沒有路由參數(shù),就是一個(gè)空對(duì)象。
**3.$route.query**
一個(gè) key/value 對(duì)象,表示 URL 查詢參數(shù)。
例如,對(duì)于路徑 /foo?user=1,則有 $route.query.user == 1,
如果沒有查詢參數(shù),則是個(gè)空對(duì)象。
**4.$route.hash**
當(dāng)前路由的 hash 值 (不帶 #) ,如果沒有 hash 值,則為空字符串。錨點(diǎn)
**5.$route.fullPath**
完成解析后的 URL,包含查詢參數(shù)和 hash 的完整路徑。
**6.$route.matched**
數(shù)組,包含當(dāng)前匹配的路徑中所包含的所有片段所對(duì)應(yīng)的配置參數(shù)對(duì)象。
**7.$route.name 當(dāng)前路徑名字**
**8.$route.meta 路由元信息
2、active-class 是哪個(gè)組件的屬性?
active-class是vue-router模塊的router-link組件中的屬性,用來做選中樣式的切換;
用法:
1、直接在路由js文件中配置linkActiveClass
export default new Router({
linkActiveClass: 'active'
})
2、在router-link中寫入active-class
<router-link to="/home" class="menu-home" active-class="active">首頁</router-link>
這里這個(gè)路由的樣式可以直接在style中去寫對(duì)應(yīng)的類名就好了
如果兩個(gè)路由都是用一樣的樣式,比如如下情況:
<div class="menu-btn">
<router-link to="/" class="menu-home" active-class="active">
首頁
</router-link>
</div>
<div class="menu-btn">
<router-link to="/my" class="menu-my" active-class="active">
我的
</router-link>
</div>
這樣跳轉(zhuǎn)后兩個(gè)router-link都會(huì)有顯示的樣式,可能是因?yàn)?to=“/” 引起的,active-class選擇樣式時(shí)根據(jù)路由中的路徑去匹配,然后顯示,例如在my頁面中,路由為localhost:8080/#/my,那么to=“/”和to=”/my"都可以匹配到,所有都會(huì)激活選中樣式
解決辦法
a.直接在路由js文件中配置linkActiveClass
export default new Router({
linkExactActiveClass: 'active',
})
b.在router-link中寫入exact
<router-link to="/" class="menu-home" active-class="active" exact>首頁</router-link>
3、路由傳參的方式與動(dòng)態(tài)路由匹配
介紹前我們先了路由的兩中形式
-
編程式的導(dǎo)航 router.push
-
聲明式的導(dǎo)航
<router-link>
對(duì)于參數(shù)的傳遞主要是用對(duì)象的方式去寫的,可分為命名路由、查詢參數(shù)
命名路由
使用前提:在注冊(cè)路由的地方需要給路由命名
{
path: "/",
name: "Home",
component: Home,
},
命名路由搭配著params來進(jìn)行傳遞,如下
this.$router.push({ name: 'Home', params: { userId: 123 }})
<router-link :to="{ name: 'Home', params: { userId: 1111}}">click to news page</router-link>
在目標(biāo)頁面接收
this。$route.params.userId
查詢參數(shù)
查詢參數(shù)其實(shí)就是在路由地址后面帶上參數(shù)和傳統(tǒng)的url參數(shù)一致的,也就是傳遞的參數(shù)會(huì)出現(xiàn)在url地址欄上
注意:name、path可以和query搭配,params只能和name搭配
用法:
this.$router.push({ path: 'Home', query: { userId: 123 }});
<router-link :to="{ path: 'Home', query: { userId: 1111}}">click to news page</router-link>
接收:
this.$route.query.userId
動(dòng)態(tài)路由匹配
常見場(chǎng)景:當(dāng)我們有一個(gè)通用組件,對(duì)應(yīng)不同ID共和不相同的客戶,都要使用這個(gè)組件來渲染,我們就可以使用路由中的 動(dòng)態(tài)路參數(shù)來達(dá)到這個(gè)效果,一個(gè)路徑參數(shù)使用:進(jìn)行標(biāo)記,每當(dāng)匹配到一個(gè)路由,參數(shù)值就會(huì)被設(shè)置
可以用this.$route.params
去接收參數(shù)的值
注意:當(dāng)使用該方法時(shí),原組件的實(shí)列會(huì)被復(fù)用,但是組件的生命周期鉤子不會(huì)被調(diào)用,簡(jiǎn)單列子如下
寫跳轉(zhuǎn)的組件:
<div>
<p><router-link to="/about/1">user1</router-link></p>
<p><router-link to="/about/2">user2</router-link></p>
<p><router-link to="/about/3">user3</router-link></p>
</div>
路由寫法:
{
path: "/about/:id",
name: "About",
component: () => import("../views/About.vue"),
},
在目標(biāo)組件用 {{ this.$route.params.id }}
進(jìn)行參數(shù)接收即可
關(guān)于在watch中$route(to, from)不生效
這里我想監(jiān)聽組件的路由變化,使用watch去監(jiān)聽$route(to, from)發(fā)現(xiàn)不生效,解決辦法參考這篇文章
https://blog.csdn.net/u010227042/article/details/107961248
路由組件傳參
當(dāng)組件中使用 $route
會(huì)與路由緊密耦合,這限制了組件的靈活性,因?yàn)樗荒苡糜谔囟ǖ?URL。雖然這不一定是件壞事,但我們可以通過 props
配置來解除這種行為:
1、如果 props 被設(shè)置為 true,route.params 將會(huì)被設(shè)置為組件屬性
這里用動(dòng)態(tài)路由匹配做列子,同樣傳入的是id
在目標(biāo)跳轉(zhuǎn)的路由中:
{
path: "/about/:id",
name: "About",
props: true,
component: () => import("../views/About.vue"),
},
目標(biāo)路由中props接收然后直接用:
export default {
name: "About",
props: ["id"],
};
2、對(duì)象模式
{
//對(duì)象模式
path:'/about/chilrenRoute2/:id',
component:chilrenRoute2,
props: { userName: 'userName'}
}
export default {
props:['userName']
}
獲?。?/p>
<p> 通過 props傳遞——對(duì)象 , 獲取路由組件傳遞參數(shù)值 /about/chilrenRoute2/:id 路由的id值: {{ this.userName }}</p>
3、函數(shù)模式
函數(shù)模式的路由配置中,props屬性是函數(shù),這個(gè)函數(shù)返回一個(gè)對(duì)象。
在函數(shù)模式中,可以有一個(gè)參數(shù),這個(gè)參數(shù)就是route對(duì)象,里面存儲(chǔ)的是路由的相關(guān)攜帶信息。
{
//函數(shù)模式
path:'/about/chilrenRoute2/:id',
component:chilrenRoute2,
props: function (route){
//route 是 $route對(duì)象
return {
userName:'userName',
querys: route.params.id
}
}
}
js代碼:
export default {
// props:['id']
// props:['userName']
props:['userName','querys']
}
獲取:
<p> 通過 props傳遞——函數(shù)模式 , 獲取路由組件傳遞參數(shù)值 /about/chilrenRoute2/:id 路由的id值: {{ this.userName }} , {{ this.querys }} , {{ $route.params }}</p>
4、vue-router 有哪幾種導(dǎo)航鉤子(導(dǎo)航守衛(wèi))?
1、全局守衛(wèi): router.beforeEach
2、全局解析守衛(wèi): router.beforeResolve
3、全局后置鉤子: router.afterEach
4、路由獨(dú)享的守衛(wèi): beforeEnter
5、組件內(nèi)的守衛(wèi): beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave
beforeRouteEnter
// 在渲染該組件的對(duì)應(yīng)路由被 confirm 前調(diào)用
// 不!能!獲取組件實(shí)例 `this`
// 因?yàn)楫?dāng)守衛(wèi)執(zhí)行前,組件實(shí)例還沒被創(chuàng)建
雖然無法直接獲取組件實(shí)力
但是我們可以通過next參數(shù)的回調(diào)函數(shù)獲取到當(dāng)前實(shí)例進(jìn)行操作
beforeRouteEnter: (to, from, next) => {
next((vm) => {
//vm就是當(dāng)前組件實(shí)例
});
}
beforeRouteUpdate
// 在當(dāng)前路由改變,但是該組件被復(fù)用時(shí)調(diào)用
// 舉例來說,對(duì)于一個(gè)帶有動(dòng)態(tài)參數(shù)的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉(zhuǎn)的時(shí)候,
// 由于會(huì)渲染同樣的 Foo 組件,因此組件實(shí)例會(huì)被復(fù)用。而這個(gè)鉤子就會(huì)在這個(gè)情況下被調(diào)用。
// 可以訪問組件實(shí)例 `this`
beforeRouteLeave
// 導(dǎo)航離開該組件的對(duì)應(yīng)路由時(shí)調(diào)用
// 可以訪問組件實(shí)例 `this`
詳細(xì)介紹:
https://zhuanlan.zhihu.com/p/54112006
5、vue-router歷史模式和hash模式的區(qū)別?
hash模式:
url里面帶有#號(hào),開發(fā)中默認(rèn)的就是hash模式,hash雖然出現(xiàn)在URL中,但是不會(huì)被包括在HTTP請(qǐng)求中,所以改變hash不會(huì)重新刷新頁面
路由的哈希模式就是利用了window.onhashchange事件,也就是url中的hash值(#號(hào)后面的值)如果有變化,就會(huì)自動(dòng)調(diào)用hashchange的監(jiān)聽事件,在hashchange的監(jiān)聽事件內(nèi)可以得到改變后的url,這樣就能找到對(duì)應(yīng)頁面進(jìn)行加載
window.addEventListener('hashchange', () => {
// 把改變后的url地址欄的url賦值給data的響應(yīng)式數(shù)據(jù)current,調(diào)用router-view去加載對(duì)應(yīng)的頁面
this.data.current = window.location.hash.substr(1)
})
歷史模式:
利用了H5新增的pushState()、replaceState()方法。當(dāng)這兩個(gè)方法執(zhí)行時(shí),只能改變當(dāng)前地址欄的URL,但是瀏覽器不會(huì)像后端發(fā)起請(qǐng)求,也不會(huì)觸發(fā)popstate事件的執(zhí)行。
也就是說,完成URL跳轉(zhuǎn)而無需重新加載頁面,由于vue是單頁面的形式,當(dāng)后臺(tái)沒有正確配置的時(shí)候,需要我們自己去配置404頁面
6、動(dòng)態(tài)路由添加
最好和vuex做一個(gè)案列理解
7、vue-router怎么重定向的?
用redirect即可定位到相對(duì)位置
const routes = [
{
path: '/users/:id/posts',
redirect: to => {
// 方法接收目標(biāo)路由作為參數(shù)
// return 重定向的字符串路徑/路徑對(duì)象
},
},
]
8、vue-router實(shí)現(xiàn)路由懶加載
路由懶加載也就是延遲加載沒在需要的時(shí)候記加載,隨用隨載,也是前端優(yōu)化的一種手段
懶加載的實(shí)現(xiàn)方法:
1、ES6標(biāo)準(zhǔn)語法import()
const Foo = () => import('../components/Foo')
const Aoo = () => import('../components/Aoo')
export default new Router({
routes: [
{
path: '/Foo',
name: 'Foo',
component: Foo
},
{
path: '/Aoo',
name: 'Aoo',
component: Aoo
}
]
})
就是定義一個(gè)變量,變量就是路由文件,然后在路由中隨用隨導(dǎo)入
2、Vue異步加載技術(shù)
1:vue-router配置路由,使用vue的異步組件技術(shù),可以實(shí)現(xiàn)懶加載,此時(shí)一個(gè)組件會(huì)生成一個(gè)js文件。
2:component: resolve => require(['放入需要加載的路由地址'], resolve)
{
path: '/problem',
name: 'problem',
component: resolve => require(['../pages/home/problemList'], resolve)
}
9、Vue-router跳轉(zhuǎn)和location.href有什么區(qū)別?
1、vue-router使用pushState進(jìn)行路由更新,靜態(tài)跳轉(zhuǎn),頁面不會(huì)重新加載;location.href會(huì)觸發(fā)瀏覽器,頁面重新加載一次
2、vue-router使用diff算法,實(shí)現(xiàn)按需加載,減少dom操作
3、vue-router是路由跳轉(zhuǎn)或同一個(gè)頁面跳轉(zhuǎn);location.href是不同頁面間跳轉(zhuǎn);
4、vue-router是異步加載this.$nextTick(()=>{獲取url});location.href是同步加載
10、怎么配置404頁面?
在router.js中 路由是從上到下執(zhí)行的 只需要在最后一行把path寫成 * 并且指定一個(gè)404.vue頁面即可
如何觸發(fā)404頁面,比如你的域名是http://localhost:8080/,當(dāng)你進(jìn)入一個(gè)沒有聲明/匹配的路由頁面時(shí)就會(huì)跳到404頁面,
比如訪問了http://localhost:8080/無此頁面,就會(huì)跳到404頁面,如果沒有聲明一個(gè)404頁面,那就會(huì)跳到一個(gè)空白頁面
{
path: '*',
name: '/404',
component: resolve => require(['@/components/404.vue'], resolve),
},
11、切換路由時(shí)需要保存草稿的功能,怎么實(shí)現(xiàn)?
1、用組件內(nèi)的守衛(wèi)中的:beforeRouteLeave去實(shí)現(xiàn)
keep-alivebeforeRouteLeave (to, from, next) {
if(用戶已經(jīng)輸入信息){
//出現(xiàn)彈窗提醒保存草稿,或者自動(dòng)后臺(tái)為其保存
}else{
next(true);//用戶離開
}
}
2、使用keep-alive去緩存組件
12、切換到新路由時(shí),頁面要滾動(dòng)到頂部或保持原先的滾動(dòng)位置怎么做呢?
1、使用afterEach
router.afterEach((to,from,next) => {
window.scrollTo(0,0);
});
2、該功能只能在H5 history下去使用
注意: 這個(gè)功能只在 html5 history 模式下可用。
const router = new vueRouter({
routes: [...],
scrollBehavior (to, from, savedPosition) {
// return 期望滾動(dòng)到哪個(gè)的位置
}
})
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0 }
}
}
13、說說vue-router完整的導(dǎo)航解析流程是什么?(選)
1.導(dǎo)航被觸發(fā)
2.在即將離開的組件里調(diào)用beforeRouteLeave守衛(wèi)
3.調(diào)用全局前置守衛(wèi)beforeEach守衛(wèi)
4.在重用的組件里調(diào)用beforeRouteUpdate守衛(wèi) / 調(diào)用路由配置的beforeEnter守衛(wèi)
5.解析異步路由組件
6.在被激活的組件里調(diào)用beforeRouteEnter
7.調(diào)用全局的beforeResolve守衛(wèi)
8.導(dǎo)航被確認(rèn)
9.調(diào)用全局的 afterEach 鉤子
10.觸發(fā)DOM更新
11.用創(chuàng)建好的實(shí)例調(diào)用 beforeRouteEnter 守衛(wèi)中傳給 next 的回調(diào)函數(shù)。
VUEX
要是看不懂官網(wǎng)的列子就看這篇博客入門就好了
https://www.jianshu.com/p/a804606ad8e9
關(guān)于mapState、mapAction等的了解可以看看這篇博客文章來源:http://www.zghlxwxcb.cn/news/detail-405025.html
https://www.cnblogs.com/m2maomao/p/9954640.html文章來源地址http://www.zghlxwxcb.cn/news/detail-405025.html
到了這里,關(guān)于前端常見面試八股文的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!