大廠高頻核心前端面試題總結(jié)舀瓢,爆肝五萬多字廷雅,面試必考 秒變大佬 ??(建議收藏~)

??HTML

1. 如何理解HTML語義化

HTML5語義化

  • 讓人更容易讀懂(代碼結(jié)構(gòu)清晰耗美,增加代碼的可讀性)
  • 讓搜索引擎更容易讀懂(SEO)京髓,搜索引擎爬蟲會(huì)根據(jù)不同的標(biāo)簽來賦予不同的權(quán)重

語義化標(biāo)簽 : header nav main article section aside footer

2. 默認(rèn)情況下,哪些HTML標(biāo)簽是塊級元素商架、哪些是內(nèi)聯(lián)元素

  • 塊級元素:display: block/table堰怨,有div div h1 h2 table ul ol li p
  • 內(nèi)聯(lián)元素:display: inline/inline-block,有span img input button i b

3. ??HTML5 新增內(nèi)容和 API

HTML5 新增內(nèi)容和 API

  • classList 屬性
  • querySelector() 與 querySelectorAll()
  • getElementsByClassName()
  • 自定義數(shù)據(jù)屬性
  • 本地存儲(chǔ)
  • insertAdjacentHtml()蛇摸、insertAdjacentText()备图、insertAdjacentElement()
  • 內(nèi)容可編輯
  • 預(yù)加載

??CSS

1. 盒子模型

CSS盒子模型

box-sizing屬性

CSS盒子模型包含2種:

  • W3C標(biāo)準(zhǔn)盒子模型(box-sizing: content-box ,默認(rèn))赶袄,寬高不受 padding揽涮、border影響
  • IE怪異盒子模型 (box-sizing: border-box),寬高受 padding饿肺、border影響

2. margin 縱向重疊

  • 相鄰元素的margin-topmargin-bottom會(huì)重疊
  • 空內(nèi)容的元素也會(huì)重疊

思考:如下代碼蒋困,AAABBB之間的間距是多少 ?

<style>
    p{
        font-size:16px;
        line-height:1;
        margin-top:10px;
        margin-bottom:15px
    }
</style>

<body>
    <p>AAA</p>
    <p></p>
    <p></p>
    <p></p>
    <p>BBB</p>
</body>

答案是 15px


margin 縱向重疊

3. margin 負(fù)值

  • margin-top 負(fù)值敬辣,元素會(huì)上移
  • margin-left 負(fù)值雪标,元素會(huì)左移
  • margin-right 負(fù)值零院,右側(cè)元素會(huì)左移,自身不受影響
  • margin-bottom 負(fù)值村刨,下方元素會(huì)上移告抄,自身不受影響
    margin 負(fù)值

4. ??BFC(塊級格式化上下文)

3分鐘理解BFC

具有 BFC 特性的元素可以看作是隔離了的獨(dú)立容器,容器里面的元素不會(huì)在布局上影響到外面的元素

只要元素滿足下面任一條件即可觸發(fā) BFC 特性:

  1. 根元素(即<html>標(biāo)簽)
  2. 浮動(dòng)元素 float 不為 none (為 left嵌牺、right
  3. 絕對定位元素 position 不為 static 或 relative打洼。(為 absolutefixed
  4. overflow 的值不為 visible 的塊元素(為 auto逆粹、scroll拟蜻、hidden)
  5. display 的值為inline-blockflex枯饿、grid酝锅、table奢方、table-cell蟋字、table-caption...

同一BFC內(nèi):

  1. Box會(huì)在垂直方向上一個(gè)接一個(gè)的放置
  2. 垂直方向的距離由margin決定(屬于同一個(gè)BFC的兩個(gè)相鄰Box的margin會(huì)發(fā)生重疊稿蹲,與方向無關(guān))
  3. 每個(gè)元素的margin box的左邊, 與包含塊border box的左邊相接觸(對于從左往右的格式化鹊奖,否則相反)苛聘。即使存在浮動(dòng)也是如此
  4. BFC的區(qū)域不會(huì)與float的元素區(qū)域重疊
  5. 計(jì)算BFC的高度時(shí),浮動(dòng)子元素也參與計(jì)算
  6. BFC就是頁面上的一個(gè)隔離的獨(dú)立容器忠聚,容器里面的子元素不會(huì)影響到外面元素设哗,反之亦然

應(yīng)用:

  1. 分屬于不同的BFC時(shí),可以防止margin重疊
  2. 清除內(nèi)部浮動(dòng)
  3. 自適應(yīng)多欄布局

5. float布局

.fl {
    float: left;
}

.fr {
    float: right;
}

.clearfix {
    zoom: 1; // 兼容IE
}

.clearfix:after {
    content: '';
    display: block;
    clear: both;
    visibility: hidden;
    overflow: hidden;
}

6. ??flex布局

flex布局

flex平分布局

flex布局

7. ??三欄布局

實(shí)現(xiàn)三欄布局的8種方式:

  1. 浮動(dòng)布局
  2. 定位布局
  3. flex布局
  4. 表格布局
  5. 網(wǎng)格布局
  6. calc函數(shù)布局
  7. 圣杯布局
  8. 雙飛翼布局

面試常考的圣杯布局和雙飛翼布局:

  • 三欄布局两蟀,中間一欄最先加載和渲染(內(nèi)容最重要)
  • 兩側(cè)內(nèi)容固定网梢,中間內(nèi)容隨著寬度自適應(yīng)
  • 一般用于PC端

8. CSS定位

css中position屬性詳解

思考:relative颜启、absolute川抡、fixed依據(jù)什么定位?

答案:

  • relative依據(jù)自身定位(相對的是它原本在文檔流中的位置而進(jìn)行的偏移)气笙。在最外層時(shí)谭期,是以<body>標(biāo)簽為定位原點(diǎn)的胀瞪。
  • absolute依據(jù)最近一層的定位元素定位(根據(jù)postionstatic的祖先類元素進(jìn)行定位)帆谍。在無父級是postionstatic定位時(shí),是以<html>作為原點(diǎn)定位
  • fixed根據(jù)窗口為原點(diǎn)進(jìn)行偏移定位 (也就是說它不會(huì)根據(jù)滾動(dòng)條的滾動(dòng)而進(jìn)行偏移)

9. 居中對齊實(shí)現(xiàn)方式

css居中常見方法總結(jié)

10. line-height的繼承問題

思考: 以下代碼中p標(biāo)簽的行高是多少橡疼?

<style>
    body {
        font-size: 20px;
        line-height: 200%;
    }

    p {
        font-size: 16px;
    }
</style>

<p>AAA</p>

答案是 40px

line-height的繼承
  • 寫具體數(shù)值,如body{ line-height: 30px;},則繼承該值 ( p 的行高就是30px
  • 寫比例睹栖,如body{ line-height: 2;} 曼氛,則繼承該比例 ( p 的行高就是16px*2 = 32pxp字體大小的2倍
  • 寫百分比(有坑)构舟,如body{ line-height: 200%;} 苦蒿,則繼承計(jì)算出來的值 ( p 的行高就是20px*2 = 40pxbody字體大小的2倍

11. CSS長度單位

  1. px 固定的像素,一旦設(shè)置了就無法因?yàn)檫m應(yīng)頁面大小而改變。
  2. em 相對于父元素的長度單位弄跌。(不常用)
  3. rem 相對于根<html>元素的長度單位格仲。(常用)
  4. rpx 微信小程序的相對長度單位圈盔。小程序規(guī)定屏幕寬為750rpx容诬。如在 iPhone6 上,屏幕寬度為375px纽什,共有750個(gè)物理像素,則750rpx = 375px = 750物理像素友雳,1rpx = 0.5px = 1物理像素稿湿。(僅微信小程序)

12. CSS響應(yīng)式媒體查詢

假如一個(gè)終端的分辨率小于 980px神帅,那么可以這樣寫:

@media only screen and (max-width: 980px) {
  #head { … }
  #content { … }
  #footer { … }
}

假如我們要設(shè)定兼容 iPad 和 iPhone 的視圖揪漩,那么可以這樣設(shè)置:

/** iPad **/
@media only screen and (min-width: 768px) and (max-width: 1024px) {}
/** iPhone **/
@media only screen and (min-width: 320px) and (max-width: 767px) {}

媒體查詢一般配合rem單位實(shí)現(xiàn)響應(yīng)式血柳,因此rem具有階梯性的弊端

13. 網(wǎng)頁視口尺寸

  • 屏幕高度 window.screen.height (顯示器屏幕設(shè)備高度)
  • 網(wǎng)頁視口高度 window.innerHeight (去掉瀏覽器自身的頭部和底部后的高度沃斤,含滾動(dòng)條高)
  • body高度 document.body.clientHeight (頁面內(nèi)容的真實(shí)高度)
網(wǎng)頁視口尺寸

神圖


神圖

寬度同理 略~

14. CSS3 vw / vh

  • vw 網(wǎng)頁視口寬度的1% ( window.innerWidth = 1vw
  • vh 網(wǎng)頁視口高度的1% ( window.innerHeight = 1vh )
  • vmin 選取vwvh中最小的那個(gè)
  • vmax 選取vwvh中最大的那個(gè)

??JS

1. ??ES6新特性

查看ES6專輯

  1. ES6之 let 和 const 關(guān)鍵字

  2. ES6之 解構(gòu)賦值

  3. ES6之 擴(kuò)展運(yùn)算符

  4. ES6之 字符串新特性

  5. ES6之 數(shù)值新特性

  6. ES6之 數(shù)組新特性

  7. ES6之 函數(shù)優(yōu)化(默認(rèn)參數(shù)和屎、剩余參數(shù)、 箭頭函數(shù))

  8. ES6之 Promise

  9. ES6之 async/await

  10. ES6之 class(類)

  11. ES6之 Map和Set

  12. ES6之Module語法(import/export)

  13. ES6之 Generator 函數(shù)

  14. ES6之 for...of 循環(huán)

2. 數(shù)據(jù)類型與檢測

js檢測數(shù)據(jù)類型的幾種方法總結(jié)

JavaScript 數(shù)據(jù)類型:

  1. Number (基本類型)
  2. String (基本類型)
  3. Boolean (基本類型)
  4. null (基本類型)
  5. undefined (基本類型)
  6. symbol (ES6 - 基本類型)
  7. bigInt (ES10 - 基本類型)
  8. object (引用類型昙读,包含 function环础、[ ]缎除、{ })

基本類型的特點(diǎn):直接存儲(chǔ)在棧(stack)內(nèi)存中的數(shù)據(jù)
引用類型的特點(diǎn):存儲(chǔ)的是該對象在棧中引用严就,真實(shí)的數(shù)據(jù)存放在堆(heap)內(nèi)存中

堆內(nèi)存與棧內(nèi)存

3. ??深拷貝和淺拷貝

JavaScript中的深拷貝和淺拷貝

深拷貝和淺拷貝最根本的區(qū)別在于是否是真正獲取了一個(gè)對象的拷貝實(shí)體,而不是引用伴找。

淺拷貝只拷貝一層對象的屬性盈蛮,而深拷貝則遞歸拷貝了所有層級。

  • 深拷貝在計(jì)算機(jī)中開辟了一塊新的內(nèi)存地址用于存放拷貝的對象
  • 淺拷貝僅僅是指向被拷貝的內(nèi)存地址技矮,如果原地址中對象被改變了抖誉,那么淺拷貝出來的對象也會(huì)相應(yīng)改變
深拷貝和淺拷貝

4. ??原型與原型鏈(三座大山之一)

深入理解javascript之原型和原型鏈

prototype(顯式原型)

所有函數(shù)(僅限函數(shù))擁有 prototype 屬性

prototype 對象用于放某同一類型實(shí)例的共享屬性和方法,實(shí)質(zhì)上是為了內(nèi)存著想衰倦。

Person.prototype.sayHello = function() {
    console.log('Hello!')
}
console.log(person1.sayHello === person2.sayHello) // true袒炉,同一個(gè)方法
prototype

_proto _ (隱式原型)

所有對象擁有 _proto _ 屬性

_proto _ 指向誰?分以下三種情況:

/*1樊零、字面量方式*/
var a = {};
console.log(a.constructor === Object); // true (即構(gòu)造器Object)
console.log(a.__proto__ === a.constructor.prototype); // true
console.log(a.__proto__ === Object.prototype); // true

/*2我磁、構(gòu)造器方式*/
var A = function (){}; 
var a = new A();
console.log(a.constructor === A); // true(即構(gòu)造器function A)
console.log(a.__proto__ === a.constructor.prototype); // true

/*3、Object.create()方式*/
var a1 = {a:1} 
var a2 = Object.create(a1);
console.log(a2.constructor === Object); // true  (即構(gòu)造器Object)
console.log(a2.__proto__ === a1); // true 
console.log(a2.__proto__ === a2.constructor.prototype); //false(此處即為圖1中的例外情況)
_proto _

constructor ( 指向創(chuàng)建該對象的構(gòu)造函數(shù))

每個(gè)原型對象都可以通過對象.constructor 指向創(chuàng)建該對象的構(gòu)造函數(shù)

function Person() {};
var person1 = new Person();
var person2 = new Person();

// 實(shí)例化對象的constructor屬性指向構(gòu)造函數(shù)本身
person1.constructor === Person; 

// 構(gòu)造函數(shù)的prototype屬性有個(gè)constructor屬性驻襟,指向構(gòu)造函數(shù)本身
Person.prototype.constructor === Person;

// 由以上兩條得出
person1.constructor === Person.prototype.constructor

person1.__proto__ === Person.prototype

Person.constructor === Function; 
Function.constructor === Function; 
constructor

原型鏈

image
a.__proto__ === A.prototype
A.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null

下圖中由相互關(guān)聯(lián)的原型組成的鏈狀結(jié)構(gòu)就是原型鏈夺艰,也就是藍(lán)色的這條線。

原型鏈


原型與原型鏈的終極圖

這個(gè)圖要是看懂了沉衣,原型與原型鏈就基本摸清了郁副。


原型鏈

instanceof 原理

instanceof 只能用來判斷對象類型,原始類型不可以豌习。并且所有對象類型instanceof Object 都是 true

instanceof 的內(nèi)部機(jī)制是通過判斷對象的原型鏈中是不是能找到類型的 prototype存谎。

class People {};
class Student extends People {};

let s1 = new Student();

console.log(s1 instanceof Student); // true
console.log(s1 instanceof People);  // true
console.log(s1 instanceof Object);  // true

console.log(s1.__proto__ === Student.prototype); // true
console.log(Student.prototype.__proto__ === People.prototype); // true
console.log(People.prototype.__proto__ === Object.prototype); // true

s1.__proto__ === Student.prototype                =>   s1 instanceof Student
Student.prototype.__proto__ === People.prototype  =>   Student.prototype instanceof People
People.prototype.__proto__ === Object.prototype   =>   People.prototype instanceof Object

Instanceof的判斷隊(duì)則是:沿著s1的proto這條線來找拔疚,同時(shí)沿著Student的prototype這條線來找,如果兩條線能找到同一個(gè)引用既荚,即同一個(gè)對象稚失,那么就返回true。如果找到終點(diǎn)還未重合恰聘,則返回false句各。這就很好地解釋了上述代碼的輸出結(jié)果啦。


繼承方式

JavaScript中的繼承方式

5. ??作用域憨琳、this 和閉包 (三座大山之二)

作用域

ES5只有 全局作用域函數(shù)作用域诫钓,ES6增加塊級作用域

全局作用域
代碼在程序的任何地方都能被訪問,window 對象的內(nèi)置屬性都擁有全局作用域篙螟。

函數(shù)作用域
在固定的代碼片段才能被訪問

作用域

塊級作用域

let 和 const 命令聲明變量具有塊級作用域:

  1. ES6之塊級作用域

  2. ES6之 let 和 const 關(guān)鍵字

作用域有上下級關(guān)系,上下級關(guān)系的確定就看函數(shù)是在哪個(gè)作用域下創(chuàng)建的问拘。如上遍略,fn作用域下創(chuàng)建了bar函數(shù),那么“fn作用域”就是“bar作用域”的上級骤坐。

作用域最大的用處就是隔離變量绪杏,不同作用域下同名變量不會(huì)有沖突


作用域鏈

變量取值:到創(chuàng)建這個(gè)變量的函數(shù)的作用域中向上取值纽绍,而不是調(diào)用這個(gè)函數(shù)時(shí)向上取值蕾久,
如果在當(dāng)前作用域中沒有查到值,就會(huì)向上級作用域去查拌夏,直到查到全局作用域僧著,這么一個(gè)查找過程形成的鏈條就叫做作用域鏈

思考:以下代碼輸出什么障簿?

function create() {
    const a = 100;
    return function () {
        console.log(a);
    }
}
const fn = create();
const a = 200;
fn();  // 100
function print(fn) {
    const a = 200;
    fn();
}
const a = 100;
function fn() {
    console.log(a);
}
print(fn); // 100

創(chuàng)建的函數(shù)向上取值盹愚,而不是調(diào)用函數(shù)時(shí)向上取值


this

徹底理解JavaScript中this指向

this永遠(yuǎn)指向的是最后調(diào)用它的對象,也就是看它執(zhí)行的時(shí)候是誰調(diào)用的

特別注意:

  • 匿名函數(shù)的自我執(zhí)行站故,沒有被上級對象調(diào)用皆怕,所以this指向window
  • setTimeout(function () { console.log(this) }); ,this指向window
  • setTimeout(() => { console.log(this) }); 西篓,this指向上下文
  • 構(gòu)造函數(shù)中的this愈腾,指向?qū)嵗龑ο?/li>
  • bindcall岂津、apply 可以改變 this 指向

JavaScript中call,apply,bind方法的總結(jié)


閉包

JavaScript閉包

閉包就是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)虱黄。

創(chuàng)建閉包的最常見的方式就是在一個(gè)函數(shù)內(nèi)創(chuàng)建另一個(gè)函數(shù),通過另一個(gè)函數(shù)訪問這個(gè)函數(shù)的局部變量

閉包的特性:

  1. 函數(shù)嵌套函數(shù)
  2. 函數(shù)內(nèi)部可以引用外部的參數(shù)和變量
  3. 參數(shù)和變量不會(huì)被垃圾回收機(jī)制回收
function aaa() {  
    var a = 1;  
    return function(){
        alert(a++)
    };  
}         
var fun = aaa();  
fun();// 1 執(zhí)行后 a++寸爆,礁鲁,然后a還在~   a會(huì)長期駐扎在內(nèi)存中
fun();// 2   
fun = null;//a被回收Q纹邸! 

6. ??異步 (三座大山之三)

單線程與多線程

  • JavaScript是單線程語言(可以說這是JavaScript最核心也是最基本的特性)
  • 瀏覽器的內(nèi)核是多線程的

雖然JavaScript是單線程的仅醇,可是瀏覽器內(nèi)部不是單線程的冗美。
一些I/O操作、定時(shí)器的計(jì)時(shí)和事件監(jiān)聽(click, keydown...)等都是由瀏覽器提供的其他線程來完成的析二。


同步與異步

  • 同步:是指在主線程上排隊(duì)執(zhí)行的任務(wù)粉洼,只有前一個(gè)任務(wù)執(zhí)行完畢,才能繼續(xù)執(zhí)行下一個(gè)任務(wù)叶摄。
    當(dāng)我們打開網(wǎng)站時(shí)属韧,網(wǎng)站的渲染過程,比如元素的渲染蛤吓,其實(shí)就是一個(gè)同步任務(wù)

  • 異步:是指不進(jìn)入主線程宵喂,而進(jìn)入任務(wù)隊(duì)列的任務(wù),只有任務(wù)隊(duì)列通知主線程会傲,某個(gè)異步任務(wù)可以執(zhí)行了锅棕,該任務(wù)才會(huì)進(jìn)入主線程。
    當(dāng)我們打開網(wǎng)站時(shí)淌山,像圖片加載等網(wǎng)絡(luò)請求(ajax裸燎、axios)、定時(shí)任務(wù)(setTimeout)泼疑,其實(shí)就是一個(gè)異步任務(wù)

console.log(1);
alert(2); // 同步德绿,會(huì)阻塞代碼的執(zhí)行
console.log(3);
setTimeout(function(){
    console.log(1); // 異步,不會(huì)阻塞代碼的執(zhí)行
},100)

console.log(2);

事件循環(huán)(Event Loop)

淺談事件循環(huán)Event Loop

事件循環(huán)機(jī)制:

  1. 首先判斷JS是同步還是異步,同步就進(jìn)入主線程,異步就進(jìn)入event table
  2. 異步任務(wù)在event table中注冊函數(shù),當(dāng)滿足觸發(fā)條件后,被推入消息隊(duì)列event queue
  3. 同步任務(wù)進(jìn)入主線程后一直執(zhí)行,直到主線程空閑時(shí),才會(huì)去消息隊(duì)列中查看是否有可執(zhí)行的異步任務(wù),如果有就推入主線程中
事件循環(huán)(Event Loop)

異步任務(wù)又可以分為:

  • macrotask(宏任務(wù))
    等待執(zhí)行棧和微任務(wù)隊(duì)列都執(zhí)行完畢才會(huì)執(zhí)行退渗,并且在執(zhí)行完每一個(gè)宏任務(wù)之后移稳,會(huì)去看看微任務(wù)隊(duì)列有沒有新添加的任務(wù),如果有氓辣,會(huì)先將微任務(wù)隊(duì)列中的任務(wù)清空秒裕,才會(huì)繼續(xù)執(zhí)行下一個(gè)宏任務(wù)
    包括:script代碼塊,setTimeout钞啸,setInterval几蜻,I/O

  • microtask(微任務(wù))
    當(dāng)執(zhí)行棧中的代碼執(zhí)行完畢,會(huì)在執(zhí)行宏任務(wù)隊(duì)列之前先看看微任務(wù)隊(duì)列中有沒有任務(wù)体斩,如果有會(huì)先將微任務(wù)隊(duì)列中的任務(wù)清空才會(huì)去執(zhí)行宏任務(wù)隊(duì)列
    包括:Promise梭稚,nextTick,callback絮吵,Object.observe弧烤,MutationObserver

執(zhí)行的順序是 執(zhí)行棧中的代碼 => 微任務(wù) => 宏任務(wù) => 微任務(wù) => 宏任務(wù) => ...

DOM事件也是基于Event Loop蹬敲,但不是異步

異步任務(wù)的執(zhí)行也是有先后順序的:

  1. 執(zhí)行一個(gè)宏任務(wù),過程中如果遇到微任務(wù),就將其放到微任務(wù)的【事件隊(duì)列】里
  2. 當(dāng)前宏任務(wù)執(zhí)行完成后,會(huì)查看微任務(wù)的【事件隊(duì)列】,并將里面全部的微任務(wù)依次執(zhí)行完
事件循環(huán)(Event Loop)

Promise

徹底掌握 Promise

手寫一個(gè)Promise

Promise 是異步編程的一種解決方案暇昂,有三種狀態(tài):

  • pending (等待態(tài))
  • fulfiled (成功態(tài))
  • rejected (失敗態(tài))

一旦 Promiseresolvereject莺戒,不能再遷移至其他任何狀態(tài)(即狀態(tài) immutable)。創(chuàng)造 promise 實(shí)例后急波,它會(huì)立即執(zhí)行从铲。

Promise

基本過程:

  1. 初始化 Promise 狀態(tài)(pending);
  2. 立即執(zhí)行 Promise 中傳入的 fn 函數(shù)澄暮,將Promise 內(nèi)部 resolve名段、reject 函數(shù)作為參數(shù)傳遞給 fn ,按事件機(jī)制時(shí)機(jī)處理泣懊;
  3. 執(zhí)行 then(…) 注冊回調(diào)處理數(shù)組(then 方法可被同一個(gè) promise 調(diào)用多次)伸辟;
  4. Promise 里的關(guān)鍵是要保證,then方法傳入的參數(shù) onFulfilledonRejected馍刮,必須在then方法被調(diào)用的那一輪事件循環(huán)之后的新執(zhí)行棧中執(zhí)行信夫;

簡單用法:

let p = new Promise((resolve, reject) => {
    var num = Math.ceil(Math.random() * 10); //生成1-10的隨機(jī)數(shù)
    if (num <= 5) {
        resolve(num);
    } else {
        reject('數(shù)字太大了');
    }
})

// then的用法
p.then((data) => {
    console.log('resolve:' + data);
}, (err) => {
    console.log('reject:' + err);
})

// catch的用法
p.then((data) => { console.log('resolve:' + data); })
 .catch((err) => { console.log('reject:' + err); })

async與await

細(xì)說 async/await

核心:

  1. 執(zhí)行 async 函數(shù),默認(rèn)返回一個(gè) promise 對象
  2. await 相當(dāng)于 promise 的 then
  3. try...catch 可捕獲異常渠退,代替了 promise 的 catch
function dice(val) {
    return new Promise((resolve, reject) => {
        let sino = parseInt(Math.random() * 6 + 1);
        if (sino > 3) {
            val === '大' ? resolve(sino) : reject(sino);
        } else {
            val === '大' ? reject(sino) : resolve(sino);
        }
    })
}
async function test() {
    // try...catch 可捕獲異常忙迁,代替了 Promise 的 catch 
    try {
        //把a(bǔ)wait及獲取它的值的操作放在try里
        let n = await dice('大');  // await 相當(dāng)于 Promise 的 then
        console.log('贏了' + n);
    } catch (error) {
        //失敗的操作放在catch里
        console.log('輸了' + error); // 相當(dāng)于 Promise 的 catch
    }
}
test();

思考:以下代碼輸出順序

async function async1() {
    console.log(1); // 同步2
    await async2(); // 先執(zhí)行async2(),再await 
    console.log(2); // 異步(await下面所有的代碼都是異步)
}

async function async2() {
    console.log(3); // 同步3
}

console.log(4); // 同步1

setTimeout(() => {
    console.log(5); // 異步2 宏任務(wù)
}, 0);

async1();

console.log(6); // 同步4

答案

4
1
3
6
2
5

await 下面所有的代碼都是異步


異步加載JS方式

1. 匿名函數(shù)自調(diào)動(dòng)態(tài)創(chuàng)建script標(biāo)簽加載js

(function(){
    var scriptEle = document.createElement("script");
    scriptEle.type = "text/javasctipt";
    scriptEle.async = true;
    scriptEle.src = "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js";
    var x = document.getElementsByTagName("head")[0];
    x.insertBefore(scriptEle, x.firstChild);        
 })();

2. async屬性(異步加載腳本)

瀏覽器解析到 HTML 里的該行 script標(biāo)簽碎乃,發(fā)現(xiàn)指定為 async,會(huì)異步下載解析執(zhí)行腳本惠奸。不會(huì)阻塞其他資源文件的下載

<!-- async是HTML5屬性 -->
<script type="text/javascript" src="xxx.js" async="async"></script>

3. defer屬性(延遲加載腳本)

瀏覽器解析到 HTML 里的該行 script標(biāo)簽梅誓,發(fā)現(xiàn)指定為 defer,會(huì)暫緩下載解析執(zhí)行腳本佛南。等到頁面加載完畢后梗掰,才加載腳本(更精確地說,是在 DOM樹 構(gòu)建完成后嗅回,在 window.onload 觸發(fā)前及穗,加載 defer 的腳本)。

<script type="text/javascript" src="xxx.js" defer="defer"></script>

7. DOM 與 BOM

DOM對象和BOM對象

DOM

DOM (Document Object Model)是 W3C 的標(biāo)準(zhǔn)绵载,是指文檔對象模型(樹結(jié)構(gòu))埂陆。
DOM 定義了訪問和操作 HTML 文檔的標(biāo)準(zhǔn)方法。通過它娃豹,可以訪問HTML文檔的所有元素焚虱。

1. HTML DOM 樹:

HTML DOM 樹

2. DOM 節(jié)點(diǎn):

根據(jù) W3C 的 HTML DOM 標(biāo)準(zhǔn),HTML 文檔中的所有內(nèi)容都是節(jié)點(diǎn)(NODE):

  • 文檔節(jié)點(diǎn):整個(gè)文檔(document對象)
  • 元素節(jié)點(diǎn):每個(gè) HTML 元素(element 對象)
  • 文本節(jié)點(diǎn):HTML 元素內(nèi)的文本(text對象)
  • 屬性節(jié)點(diǎn):每個(gè) HTML 屬性(attribute對象)
  • 注釋節(jié)點(diǎn):注釋(comment對象)

3. DOM 查找:

// 根據(jù)標(biāo)簽名獲取標(biāo)簽合集
const div1 = document.getElementsByTagName("div"); // div1 div2 div3 div4 div5 (元素集合 HTMLCollection)
const div2 = document.querySelectorAll("div"); // div1 div2 div3 div4 div5 (節(jié)點(diǎn)集合 NodeList)

// 根據(jù)class屬性獲取
const div3 = document.getElementsByClassName("div"); // div1 div2 (元素集合 HTMLCollection)
const div4 = document.querySelectorAll(".div"); // div1 div2 (節(jié)點(diǎn)集合 NodeList)

// 根據(jù)id屬性值獲取
const div5 = document.getElementById("div"); // div3 (一個(gè)標(biāo)簽)
const div6 = document.querySelectorAll("#div"); // div3 (節(jié)點(diǎn)集合 NodeList)

// 根據(jù)name屬性值獲取
const div7 = document.getElementsByName("div"); // div4 div5 (節(jié)點(diǎn)集合 NodeList)

// 根據(jù)標(biāo)簽名獲取標(biāo)第一個(gè)
const div8 = document.querySelector("div"); // div1 (一個(gè)標(biāo)簽)

4. DOM 操作:

// 創(chuàng)建節(jié)點(diǎn)
var divEle = document.createElement("div");
var pEle = document.createElement("p");
var aEle = document.createElement("a");

// 添加節(jié)點(diǎn)
document.body.appendChild(divEle);  // 將上面創(chuàng)建的div元素加入到body的尾部
document.body.insertBefore(pEle, divEle);  // 在body下懂版,將p元素添加到div元素前面

//替換節(jié)點(diǎn)
document.body.replaceChild(aEle, pEle);  // 在body下鹃栽,用a元素替換p元素

//設(shè)置文本節(jié)點(diǎn)
aEle.innerText = "在干嘛"
divEle .innerHTML = "<p>在干嘛<p/>"

//設(shè)置屬性
divEle .setAttribute("class","list"); // 給div元素加上class='list'屬性

//獲取class值
divEle.className // 獲取div元素上的class

// 設(shè)置style樣式
divEle.style.color = "red"; // 把div元素的color樣式設(shè)置成red
divEle.style.margin = "10px"
divEle.style.width = "10px"
divEle.style.left = "10px"
divEle.style.position = "relative"

5. DOM 優(yōu)化:

DOM 操作都是代價(jià)昂貴的操作,它會(huì)導(dǎo)致 WEB 應(yīng)用程序的 UI 反應(yīng)遲鈍躯畴。所以民鼓,應(yīng)當(dāng)盡可能減少這類過程的發(fā)生薇芝。

// 不緩存 DOM 查詢結(jié)果
for (let i = 0; i < document.getElementsByTagName("div").length; i++) {
    // 每次循環(huán),都會(huì)計(jì)算length丰嘉,頻繁進(jìn)行 DOM 查詢
}

// 緩存 DOM 查詢結(jié)果
const div = document.getElementsByTagName("div");
const length = div.length;
for (let i = 0; i < length; i++) {
    // 只進(jìn)行一次 DOM 查詢
}

將頻繁的 DOM 操作改成一次性操作:

var el = document.getElementById('mydiv');

// 未優(yōu)化前的DOM操作夯到,會(huì)導(dǎo)致三次重排
el.style.borderLeft = '1px';
el.style.borderRight = '2px';
el.style.padding = '5px';

// 優(yōu)化后的DOM操作,只會(huì)一次重排
el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;';

BOM

BOM(Browser Object Model)是指瀏覽器對象模型,可以對瀏覽器窗口進(jìn)行訪問和操作闽坡。
使用 BOM账嚎,開發(fā)者可以移動(dòng)窗口、改變狀態(tài)欄中的文本以及執(zhí)行其他與頁面內(nèi)容不直接相關(guān)的動(dòng)作逼争。使 JavaScript 有能力與瀏覽器"對話"。

  1. Window 對象 (window.alert()劝赔、window.open()誓焦、window.setTimeout() ...)
  2. Navigator 對象(navigator.userAgent ...)
  3. Screen 對象 (screen.widthscreen.height ...)
  4. Location 對象 (location.href着帽、location.reload()杂伟、location.replace() ...)
  5. History 對象(history.forward()history.back() ...)

8. ??事件流

JavaScript 事件流

事件傳播的順序?qū)?yīng)瀏覽器的兩種事件流模型:

  • 冒泡型事件流中click事件傳播順序?yàn)?<div> => <body> => <html> => document (默認(rèn))
  • 捕獲型事件流中click事件傳播順序?yàn)?document => <html> => <body> => <div>
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <div id="div">Click me!</div>
    <script>
        document.getElementById("div").addEventListener("click", (event) => {
            console.log('this is div');
        });

        document.body.addEventListener("click", (event) => {
            console.log('this is body');
        });

        document.documentElement.addEventListener("click", (event) => {
            console.log('this is html');
        });

        document.addEventListener("click", (event) => {
            console.log('this is document');
        });

        // 默認(rèn)是事件捕獲仍翰,因此按順序輸出:
        // this is div
        // this is body
        // this is html
        // this is document
    </script>
</body>
</html>

事件捕獲

事件捕獲

事件冒泡(默認(rèn))

事件冒泡

DOM 標(biāo)準(zhǔn)事件流

DOM 標(biāo)準(zhǔn)事件流

綁定事件時(shí)通過addEventListener函數(shù)赫粥,它有三個(gè)參數(shù),第三個(gè)參數(shù)若是true予借,則表示采用事件捕獲越平,若是false(默認(rèn)),則表示采用事件冒泡灵迫。

<div id="box1">box1
    <div id="box2">box2
        <div id="box3">box3</div>
    </div>
</div>

<script>    
    box1.addEventListener('click', function () {
        console.log('box1 捕獲階段');
    }, true);
    box2.addEventListener('click', function () {
        console.log('box2 捕獲階段');
    }, true);
    box3.addEventListener('click', function () {
        console.log('box3 捕獲階段');
    }, true);
    box1.addEventListener('click', function () {
        console.log('box1 冒泡階段');
    }, false);
    box2.addEventListener('click', function () {
        console.log('box2 冒泡階段');
    }, false);
    box3.addEventListener('click', function () {
        console.log('box3 冒泡階段');
    }, false);
</script>

事件流

element.addEventListener(event, function, useCapture)

第三個(gè)參數(shù)useCapture秦叛,可選。布爾值瀑粥,指定事件是否在捕獲或冒泡階段執(zhí)行:

  • true - 事件句柄在捕獲階段執(zhí)行
  • false(默認(rèn))- 事件句柄在冒泡階段執(zhí)行

阻止事件冒泡/捕獲

使用 event.stopPropagation() 起到阻止捕獲和冒泡階段中當(dāng)前事件的進(jìn)一步傳播挣跋。

  • W3C的方法是: event.stopPropagation()
  • IE則是使用: event.cancelBubble = true
p.addEventListener("click", (event) => {
    event.stopPropagation(); // 阻止事件冒泡
    console.log('this is p');  // 只會(huì)輸出 'this is p'
});


document.addEventListener("click", (event) => {
    event.stopPropagation(); // 阻止事件捕獲
    console.log('this is document');  // 只會(huì)輸出 'this is document'
}, true);

兼容IE的寫法:

window.event? window.event.cancelBubble = true : event.stopPropagation();

阻止默認(rèn)事件

  • W3C的方法是: event.preventDefault()
  • IE則是使用: event.returnValue = false

既然是說默認(rèn)行為,當(dāng)然是元素必須有默認(rèn)行為才能被取消狞换,如果元素本身就沒有默認(rèn)行為避咆,調(diào)用當(dāng)然就無效了。

<a  id="a">阻止默認(rèn)跳轉(zhuǎn)</a>

<script>
    document.getElementById("a").addEventListener("click", (event) => {
        event.preventDefault();
        console.log('已阻止a鏈接跳轉(zhuǎn)');
    });
</script>

事件代理/委托

事件代理的原理用到的就是事件冒泡和目標(biāo)元素哀澈,把事件處理器添加到父元素牌借,等待子元素事件冒泡,并且父元素能夠通過target(IE為srcElement)判斷是哪個(gè)子元素割按,從而做相應(yīng)處理膨报。

<ul id="color-list">
    <li>red</li>
    <li>orange</li>
    <li>yellow</li>
    <li>green</li>
    <li>blue</li>
    <li>indigo</li>
    <li>purple</li>
</ul>

<script>
    // 不使用事件代理
    (function(){
        var colorList = document.getElementById("color-list");
        var colors = colorList.getElementsByTagName("li");
        for (var i = 0; i < colors.length; i++) {
            colors[i].addEventListener('click', showColor); // 給每個(gè)li綁定一個(gè)點(diǎn)擊事件
        };
    
        function showColor(e) {
            e = e || window.event;
            var targetElement = e.target || e.srcElement;
            console.log(targetElement.innerHTML);
        }
    })();
    
     // 使用事件代理
    (function(){    
        var colorList = document.getElementById("color-list");
        colorList.addEventListener('click', showColor); // 通過冒泡,只需要給li的父級一個(gè)點(diǎn)擊事件

        function showColor(e) {
            e = e || window.event;
            var targetElement = e.target || e.srcElement;
            console.log(targetElement.innerHTML);
        }
    })();
</script>

9. ??跨域

JS 跨域詳解

跨域是指從一個(gè)域名的網(wǎng)頁去請求另一個(gè)域名的資源。比如從 www.baidu.com 頁面去請求 www.google.com 的資源现柠。
非同源院领,在請求數(shù)據(jù)時(shí),瀏覽器會(huì)在控制臺(tái)中報(bào)一個(gè)異常够吩,提示拒絕訪問比然。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript施加的安全限制周循。


同源策略

同源策略是瀏覽器最核心也最基本的安全功能强法。如果缺少了同源策略,則瀏覽器的正常功能可能都會(huì)受到影響湾笛∫樱可以說Web是構(gòu)建在同源策略基礎(chǔ)之上的,瀏覽器只是針對同源策略的一種實(shí)現(xiàn)嚎研。

  • 同源:協(xié)議蓖墅、域名、端口临扮,三者全部相同论矾,才是同源。
  • 跨域:協(xié)議杆勇、域名贪壳、端口,只要有一個(gè)的不同蚜退,就是跨域寥袭。

不存在跨域的情況(無視同源策略)

  1. 服務(wù)端請求服務(wù)端不存在跨域(瀏覽器請求服務(wù)器才存在同源策略)
  2. <img src="跨域的圖片地址"><img>標(biāo)簽的 src 屬性不存在跨域)
  3. <link href="跨域的css地址"><link>標(biāo)簽的 href 屬性不存在跨域)
  4. <script src="跨域的js地址"></script><script>標(biāo)簽的 src 屬性不存在跨域)

常見的幾種跨域方法

  1. jsonp 跨域 (動(dòng)態(tài)添加<script>標(biāo)簽,利用src屬性跨域关霸。 常用)
  2. CORS 跨域資源共享(由服務(wù)端實(shí)現(xiàn)。 常用且主流)
  3. node 代理跨域(利用proxyTable使本地的node服務(wù)器代理請求真正的服務(wù)器杰扫。 常用)
  4. document.domain + iframe 跨域
  5. postMessage 跨域

安全

  1. XSS 跨站腳本攻擊
  2. CSRF 跨站請求偽造

10. HTTP

淺談 HTTP

HTTP協(xié)議是一個(gè)基于 TCP/IP 通信協(xié)議來傳遞數(shù)據(jù)(HTML 文件, 圖片文件, 查詢結(jié)果等)队寇,用于從服務(wù)器傳輸超文本到本地瀏覽器的傳送協(xié)議。

TCP的三次握手四次揮手


HTTP三大特點(diǎn)

  • HTTP是無連接的:無連接的含義是限制每次連接只處理一個(gè)請求章姓。服務(wù)器處理完客戶的請求佳遣,并收到客戶的應(yīng)答后,即斷開連接凡伊。采用這種方式可以節(jié)省傳輸時(shí)間零渐。
  • HTTP是媒體獨(dú)立的:這意味著,只要客戶端和服務(wù)器知道如何處理的數(shù)據(jù)內(nèi)容系忙,任何類型的數(shù)據(jù)都可以通過HTTP發(fā)送诵盼。客戶端以及服務(wù)器指定使用適合的MIME-type內(nèi)容類型。
  • HTTP是無狀態(tài)的:無狀態(tài)是指協(xié)議對于事務(wù)處理沒有記憶能力风宁。缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息洁墙,則它必須重傳,這樣可能導(dǎo)致每次連接傳送的數(shù)據(jù)量增大戒财。另一方面热监,在服務(wù)器不需要先前信息時(shí)它的應(yīng)答就較快。

HTTP 消息結(jié)構(gòu)

客戶端請求消息(Request Headers):
客戶端發(fā)送一個(gè)HTTP請求到服務(wù)器的請求消息包括以下格式:請求行(request line)饮寞、請求頭部(header)孝扛、空行和請求數(shù)據(jù)四個(gè)部分組成,下圖給出了請求報(bào)文的一般格式幽崩。

客戶端請求消息

服務(wù)器響應(yīng)消息(Response Headers):
HTTP響應(yīng)也由四個(gè)部分組成苦始,分別是:狀態(tài)行、消息報(bào)頭歉铝、空行和響應(yīng)正文盈简。

服務(wù)器響應(yīng)消息


HTTP 狀態(tài)碼

HTTP狀態(tài)碼詳解

RFC 規(guī)定 HTTP 的狀態(tài)碼為三位數(shù),被分為五類:

  • 1xx: 信息太示,服務(wù)器收到請求柠贤,需要請求者繼續(xù)執(zhí)行操作
  • 2xx: 成功,操作被成功接收并處理 (200 - 請求成功)
  • 3xx: 重定向类缤,需要進(jìn)一步的操作以完成請求(302 - 資源(網(wǎng)頁等)被臨時(shí)轉(zhuǎn)移到其它URL臼勉,瀏覽器自動(dòng)處理)
  • 4xx: 客戶端錯(cuò)誤,請求包含語法錯(cuò)誤或無法完成請求(404 - 請求的資源(網(wǎng)頁等)不存在)
  • 5xx: 服務(wù)器錯(cuò)誤餐弱,服務(wù)器在處理請求的過程中發(fā)生了錯(cuò)誤(500 - 內(nèi)部服務(wù)器錯(cuò)誤)

HTTP 請求方法

GET和POST最詳細(xì)的總結(jié)

方法 協(xié)議版本 描述
GET HTTP1.0 請求指定的頁面信息宴霸,并返回實(shí)體主體。(獲取數(shù)據(jù)
HEAD HTTP1.0 類似于 GET 請求膏蚓,只不過返回的響應(yīng)中沒有具體的內(nèi)容瓢谢,用于獲取報(bào)頭。
POST HTTP1.0 向指定資源提交數(shù)據(jù)進(jìn)行處理請求(例如提交表單或者上傳文件)驮瞧。數(shù)據(jù)被包含在請求體中氓扛。POST 請求可能會(huì)導(dǎo)致新的資源的建立和/或已有資源的修改。(新建數(shù)據(jù)
PUT HTTP1.1 從客戶端向服務(wù)器傳送的數(shù)據(jù)取代指定的文檔的內(nèi)容论笔。
DELETE HTTP1.1 請求服務(wù)器刪除指定的頁面采郎。(刪除數(shù)據(jù)
CONNECT HTTP1.1 預(yù)留給能夠?qū)⑦B接改為管道方式的代理服務(wù)器。
OPTIONS HTTP1.1 允許客戶端查看服務(wù)器的性能狂魔。
TRACE HTTP1.1 回顯服務(wù)器收到的請求蒜埋,主要用于測試或診斷。
PATCH HTTP1.1 是對 PUT 方法的補(bǔ)充最楷,用來對已知資源進(jìn)行局部更新 整份。(更新數(shù)據(jù)

HTTP 緩存

一文讀懂http緩存(超詳細(xì))

當(dāng)客戶端向服務(wù)器請求資源時(shí)待错,會(huì)先抵達(dá)瀏覽器緩存,如果瀏覽器有“要請求資源”的副本皂林,就可以直接從瀏覽器緩存中提取而不是從原始服務(wù)器中提取這個(gè)資源忆家。

常見的http緩存只能緩存get請求響應(yīng)的資源,對于其他類型的響應(yīng)則無能為力袭蝗。

緩存的優(yōu)點(diǎn):

  • 減少了冗余的數(shù)據(jù)傳輸闰蚕,節(jié)省了你的網(wǎng)絡(luò)費(fèi)用童番。
  • 緩解了網(wǎng)絡(luò)瓶頸的問題丽已。不需要更多的帶寬就能夠更快地加載頁面。
  • 降低了對原始服務(wù)器的要求。服務(wù)器可以更快地響應(yīng)煤蚌,避免過載的出現(xiàn)。
  • 降低了距離時(shí)延,因?yàn)閺妮^遠(yuǎn)的地方加載頁面會(huì)更慢一些巍实。

強(qiáng)緩存與協(xié)商緩存:

  1. 第一次請求資源時(shí)令漂,服務(wù)器返回資源,并在respone header中回傳資源和資源標(biāo)識(shí)Last-Modified丸边、Etag)叠必。
  2. 第二次請求資源時(shí),瀏覽器會(huì)判斷 response headers 是否命中強(qiáng)緩存妹窖,如果命中纬朝,直接從本地讀取緩存(狀態(tài)碼200),不會(huì)向服務(wù)器發(fā)送請求骄呼。(命中強(qiáng)緩存:cache-control: max-age=31536000 => 最大緩存時(shí)間365天共苛、Expires有效期未過期)
  3. 當(dāng)強(qiáng)緩存沒有命中時(shí)(cache-control: no-cachePragma: no-cache)蜓萄,就把請求參數(shù)(含If-Modified-Since隅茎、If-Not-Match)加到 request header 頭中傳給服務(wù)器,判斷協(xié)商緩存是否命中嫉沽,如果命中(If-Modified-Since == Last-Modified患膛、If-Not-Match == Etag)則服務(wù)器將請求返回(狀態(tài)碼304),不會(huì)返回資源耻蛇,告訴瀏覽器從本地讀取緩存踪蹬。
  4. 當(dāng)協(xié)商緩存沒有命中(If-Modified-Since != Last-ModifiedIf-Not-Match != Etag)時(shí)臣咖,服務(wù)器直接返回新的資源(狀態(tài)碼200)和新的資源標(biāo)識(shí)(新的Last-Modified跃捣、新的Etag) 。

資源標(biāo)識(shí):

  • Last-Modified:資源的最后修改時(shí)間(只能精確到秒級)
  • Etag:資源的唯一標(biāo)識(shí)夺蛇,會(huì)優(yōu)先使用(一個(gè)字符串疚漆,類似人類的指紋)

如果資源被重復(fù)生產(chǎn),而內(nèi)容不變刁赦,則 Etag 更精準(zhǔn)

HTTP緩存

區(qū)別:

  • 強(qiáng)緩存命中:不會(huì)請求服務(wù)器娶聘,直接請求緩存;(非成趼觯快)
  • 協(xié)商緩存命中:會(huì)請求服務(wù)器丸升,不會(huì)返回內(nèi)容,然后讀取緩存牺氨;(服務(wù)端緩存策略)


    區(qū)別

11. 手寫常見JS方法

手寫常見JS方法

  • 判斷數(shù)據(jù)類型
  • 深拷貝
  • 對象是否全等
  • 防抖
  • 節(jié)流
  • 數(shù)組拍平
  • 數(shù)組去重
  • new函數(shù)

??工具

1. Git

Git詳細(xì)教程

Git

項(xiàng)目常用命令:

1. git init                 // 在當(dāng)前目錄新建一個(gè)Git代碼庫  
                
2. git branch dev-bing      // 創(chuàng)建本地分支(dev-bing)

3. git checkout dev-bing      // 切換到本地分支(dev-bing)
   git checkout -b dev-bind   // 創(chuàng)建并切換到本地分支(dev-bing)  相當(dāng)于上面第2 + 第3 的簡寫

4. git branch // 查看分支

5. git push --set-upstream origin dev-bing  // 上傳本地當(dāng)前分支代碼到master分支

6. git status   // 顯示有變更的文件  如果字體為紅色狡耻,則表示列出的是當(dāng)前目錄所有還沒有被git管理的文件和被git管理且被修改但還未提交(git commit)的文件,也就是所有改動(dòng)文件猴凹。

7. git diff           // 查看所有修改內(nèi)容
   git diff test.txt  // 查看具體文件修改內(nèi)容
   
8. git log          // 查看提交的記錄日志
   git log test.txt // 查看具體文件提交的記錄日志

9. git stash  // 臨時(shí)保存,可跨分支 (只能在未add之前才能使用)

10. git stash pop  // 恢復(fù)之前緩存

11. git checkout .         // (有個(gè)點(diǎn)) 撤銷當(dāng)前所有的修改
   git checkout test.txt  // 撤銷具體文件的修改

12. git add .         // (有個(gè)點(diǎn)) 表示添加當(dāng)前目錄下的所有文件和子目錄(或git add -A)
    git add test.txt  // 添加具體文件(test.txt)

13. git commit -m 'test' // 將文件上傳至遠(yuǎn)程 master 分支并添加備注"test"

14. git pull origin dev-bing  // 從遠(yuǎn)程倉庫下載到dev-bing倉庫   
    git pull  // 如果當(dāng)前分支是dev-bing   git pull相當(dāng)于git pull origin dev-bing
      
15. git push origin dev-bing // 從本地倉庫上傳到遠(yuǎn)程倉庫(提交)

16. git checkout master // 切換到master主分支 

17. git merge --no-ff dev-bing  // 把dev-bing分支合并到master  :wq    

18. git push origin master    // 提交合并后的master分支
    git push -u origin master // 將本地的master分支推送到origin主機(jī)夷狰,同時(shí)指定origin為默認(rèn)主機(jī),后面就可以不加任何參數(shù)使用git push了郊霎。
    git push // 設(shè)置默認(rèn)主機(jī)后(git push -u origin master)可簡寫

19. git checkout dev-bing  // 返回dev-bing分支

2. ??瀏覽器

瀏覽器從輸入U(xiǎn)RL到渲染完頁面的整個(gè)過程

  1. 獲取IP地址
  2. TCP/IP三次握手建立連接
  3. 瀏覽器向web服務(wù)器發(fā)送http請求
  4. 瀏覽器渲染
  5. 四次揮手?jǐn)嚅_連接

瀏覽器渲染過程

  1. DOM 樹:解析 HTML 構(gòu)建 DOM(DOM 樹)
  2. CSS 樹:解析 CSS 構(gòu)建 CSSOM(CSS 樹)
  3. 渲染樹:CSSOM 和 DOM 一起生成 Render Tree(渲染樹)
  4. 布局(layout):根據(jù)Render Tree瀏覽器就知道網(wǎng)頁中有哪些節(jié)點(diǎn)沼头,以及各個(gè)節(jié)點(diǎn)與 CSS 的關(guān)系,從而知道每個(gè)節(jié)點(diǎn)的位置和幾何屬性(重排)
  5. 繪制(Paint):根據(jù)計(jì)算好的信息繪制整個(gè)頁面(重繪)

3. 其他

yarn

gulp

babel

vConsole


??Vue

vue 3.0 超詳細(xì)入門教程

1. MVVM

對MVVM的理解

MVVM 分為 Model 书劝、 View 进倍、 ViewModel 三者:

  • Model數(shù)據(jù)層,數(shù)據(jù)和業(yè)務(wù)邏輯都在Model層中定義庄撮。
  • View視圖層背捌,也就是用戶界面,負(fù)責(zé)數(shù)據(jù)的展示洞斯。
  • ViewModel視圖數(shù)據(jù)層毡庆, ViewModel層通過雙向數(shù)據(jù)綁定將View層和Model層連接了起來(View和Model層的橋梁),使得View層和Model層的同步工作完全是自動(dòng)的烙如。
    MVVM

    Model和View并無直接關(guān)聯(lián)么抗,而是通過ViewModel這個(gè)橋梁來進(jìn)行聯(lián)系的,ViewModel就是View與Model的連接器亚铁,View與Model通過ViewModel實(shí)現(xiàn)雙向綁定蝇刀。

2. ??生命周期

Vue2生命周期

  1. beforeCreate:創(chuàng)建之前eldatamessage都還是undefined,不可用的)
  2. created:創(chuàng)建完畢(能讀取到數(shù)據(jù)data的值,但是DOM還沒生成)
  3. beforeMount:掛載之前(生成DOM,但此時(shí){{ message }}還沒有掛載data中的數(shù)據(jù))
  4. mounted:掛載完畢{{ message }}已經(jīng)成功掛載渲染data的值)
  5. beforeUpdate:更新之前
  6. updated:更新完畢
  7. beforeDestroy:銷毀之前
  8. destroyed:銷毀完畢(實(shí)例與視圖的關(guān)系解綁徘溢,再修改message的值吞琐,視圖再也不會(huì)更新了)
  9. activated:keep-alive 組件激活時(shí)調(diào)用
  10. deactivated:keep-alive 組件停用時(shí)調(diào)用

注:

  • activateddeactivated 是比較特殊的兩個(gè)鉤子捆探,需要keep-live配合使用
  • 當(dāng)引入 keep-alive 的時(shí)候,頁面第一次進(jìn)入站粟,鉤子的觸發(fā)順序 created => mounted => activated黍图,退出時(shí)觸發(fā) deactivated。當(dāng)再次進(jìn)入(前進(jìn)或者后退)時(shí)奴烙,只觸發(fā)activated助被。

Vue3生命周期

  1. onBeforeMount
  2. onMounted
  3. onBeforeUpdate
  4. onUpdated
  5. onBeforeUnmount
  6. onUnmounted
  7. onActivated
  8. onDeactivated
  9. onErrorCaptured
  10. onRenderTracked
  11. onRenderTriggered

3. ??computed 與 watch

Vue中computed與watch

computed(計(jì)算屬性)

  1. 屬性的結(jié)果會(huì)被緩存(默認(rèn)走緩存),當(dāng)computed中的函數(shù)所依賴的屬性沒有發(fā)生改變的時(shí)候切诀,那么調(diào)用當(dāng)前函數(shù)的時(shí)候結(jié)果會(huì)從緩存中讀取揩环,除非依賴的響應(yīng)式屬性變化時(shí)才會(huì)重新計(jì)算;
  2. 不支持異步幅虑,當(dāng)computed內(nèi)有異步操作時(shí)無效丰滑,無法監(jiān)聽數(shù)據(jù)的變化;
  3. computed中的函數(shù)必須用return返回最終的結(jié)果翘单。computed更高效吨枉,優(yōu)先使用;
  4. 當(dāng)一個(gè)屬性受多個(gè)屬性影響的時(shí)候哄芜,一般用computed(例如:詳細(xì)地址 = 省+市+區(qū)+街道+樓棟+房號 )貌亭;

watch(監(jiān)聽屬性)

  1. 不支持緩存,數(shù)據(jù)變认臊,直接會(huì)觸發(fā)相應(yīng)的操作圃庭;
  2. 支持異步
  3. 監(jiān)聽的函數(shù)接收兩個(gè)參數(shù)失晴,第一個(gè)參數(shù)是最新的值(newVal)剧腻;第二個(gè)參數(shù)是輸入之前的值(oldVal);
  4. 當(dāng)一條數(shù)據(jù)影響多條數(shù)據(jù)的時(shí)候涂屁,一般使用watch(例如:搜索數(shù)據(jù)(異步) 书在,觸發(fā)一系列數(shù)據(jù)的變化);

4. ??v-if 與 v-show

v-if

  1. 是通過控制 DOM 元素的存在與否來控制元素的顯隱拆又;
  2. 切換時(shí)儒旬,是對 DOM 元素進(jìn)行一個(gè)創(chuàng)建和銷毀的動(dòng)作
  3. 惰性的帖族,如果初始條件為假栈源,則什么也不做;只有在條件第一次變?yōu)檎鏁r(shí)才開始局部編譯;
  4. 有更高的切換消耗竖般;

v-show

  1. 是通過設(shè)置 DOM 元素的 display 樣式甚垦,block 為顯示晦毙,none 為隱藏微酬;
  2. 切換時(shí)已骇,只是簡單的基于CSS切換误债;
  3. 是在任何條件下(首次條件是否為真)都被編譯,然后被緩存迄埃,而且 DOM 元素保留男杈;
  4. 有更高的初始渲染消耗;

基于以上區(qū)別调俘,因此,如果需要非常頻繁地切換旺垒,則使用 v-show 較好彩库;如果在運(yùn)行時(shí)條件很少改變,則使用 v-if 較好先蒋。


5. data 必須是一個(gè)函數(shù)骇钦,而不是對象

如果 Vue 組件中的 data 是個(gè)對象,那么就像所有復(fù)用這個(gè)組件的地方竞漾,都在使用這個(gè)組件里面唯一的一個(gè) data眯搭,所有使用組件的地方的 data 都會(huì)指向棧內(nèi)這一個(gè) data 的地址,那么會(huì)造成一個(gè)改 data 的值业岁,所有其他組件的 data 都會(huì)被改變鳞仙。

如果在函數(shù)中返回一個(gè)對象,那么在每次創(chuàng)建一個(gè)組件的時(shí)候笔时,每次返回的都是一個(gè)新對象(Object的實(shí)例)棍好,在內(nèi)存中同時(shí)開辟一塊空間給當(dāng)前組件存放 data 。這樣就不會(huì)出現(xiàn)共用一個(gè) data 的現(xiàn)象


6. ??diff 算法

Vue中的diff算法

diff 算法是一種優(yōu)化手段允耿。比如有時(shí)候我們修改了某個(gè)數(shù)據(jù)借笙,如果直接渲染到真實(shí) DOM 上會(huì)引起整個(gè) DOM 樹的重繪和重排,這樣開銷是非常大的较锡。

我們可以先根據(jù)真實(shí) DOM 生成一棵虛擬DOM(virtual DOM)樹业稼,當(dāng)虛擬DOM某個(gè)節(jié)點(diǎn)的數(shù)據(jù)改變后,會(huì)生成一個(gè)新的 Vnode(虛擬節(jié)點(diǎn))蚂蕴。然后 VnodeoldVnode 作對比低散,發(fā)現(xiàn)有不一樣的地方就直接修改在真實(shí)的 DOM 上,然后使 oldVnode 的值為Vnode掂墓。此時(shí)我們只更新我們修改的那一小塊 DOM谦纱,而不要更新整個(gè) DOM。

diff的過程就是調(diào)用patch函數(shù)跨嘉,比較新舊節(jié)點(diǎn)吃嘿,一邊比較一邊給真實(shí)的DOM打補(bǔ)丁梦重。
在采取 diff 算法比較新舊節(jié)點(diǎn)的時(shí)候亮瓷,比較只會(huì)在同層級進(jìn)行, 不會(huì)跨層級比較。

diff 算法

概括起來就是:對操作前后的 DOM 樹同一層的節(jié)點(diǎn)進(jìn)行對比蚓胸,一層一層對比除师,然后再插入真實(shí)的dom中,重新渲染锹安。


7. for 循環(huán)中 key 的作用

vue中列表循環(huán)需加 :key="唯一標(biāo)識(shí)"倚舀, 唯一標(biāo)識(shí)可以是 item 里面 idindex 等痕貌。

  • key 的作用主要是為了更高效的對比虛擬DOM中每個(gè)節(jié)點(diǎn)是否是相同節(jié)點(diǎn);
  • Vue 在 patch 過程中判斷兩個(gè)節(jié)點(diǎn)是否是相同節(jié)點(diǎn), key 是一個(gè)必要條件风罩,渲染一組列表時(shí),key往往是唯一標(biāo)識(shí)芯侥,所以如果不定義 key 的話泊交,Vue 只能認(rèn)為比較的兩個(gè)節(jié)點(diǎn)是同一個(gè),哪怕它們實(shí)際上不是柱查,這導(dǎo)致了頻繁更新元素廓俭,使得整個(gè) patch 過程比較低效,影響性能;
  • 從源碼中可以知道唉工,Vue 判斷兩個(gè)節(jié)點(diǎn)是否相同時(shí)主要判斷兩者的 key 和元素類型等研乒,因此如果不設(shè)置 key ,它的值就是undefined,則可能永遠(yuǎn)認(rèn)為這是兩個(gè)相同的節(jié)點(diǎn)淋硝,只能去做更新操作雹熬,這造成了大量的 DOM 更新操作,明顯是不可取的谣膳。

不建議 用 index 作為 key竿报,和沒寫基本上沒區(qū)別,因?yàn)椴还苣銛?shù)組的順序怎么顛倒继谚,index 都是 0, 1, 2 這樣排列烈菌,導(dǎo)致 Vue 會(huì)復(fù)用錯(cuò)誤的舊子節(jié)點(diǎn),做很多額外的工作


8. 雙向綁定

當(dāng)一個(gè)Vue實(shí)例創(chuàng)建時(shí),Vue會(huì)遍歷 data 選項(xiàng)的屬性芽世,利用 Object.defineProperty 將它們轉(zhuǎn)為 getter/setter 并且在內(nèi)部追蹤相關(guān)依賴挚赊,在屬性被訪問和修改時(shí)通知變化。每個(gè)組件實(shí)例都有相應(yīng)的 watcher 程序?qū)嵗闷埃鼤?huì)在組件渲染的過程中把屬性記錄為依賴荠割,之后當(dāng)依賴項(xiàng)的 setter 被調(diào)用時(shí),會(huì)通知 watcher 重新計(jì)算蔑鹦,從而致使它關(guān)聯(lián)的組件得以更新举反。

雙向綁定

極簡版雙向綁定:

<input type="text" id="input" value="">
<span id="span"></span>
<script>
    let obj = {}
    Object.defineProperty(obj, 'text', { // 監(jiān)聽obj的text屬性
        set(newVal = '') {
            document.getElementById('input').value = newVal;
            document.getElementById('span').innerHTML = newVal;
        }
    });

    document.addEventListener('keyup', function (e) {
        obj.text = e.target.value;
    })
</script>

v-model

vue 中雙向綁定是一個(gè)指令v-model室囊,可以綁定一個(gè)動(dòng)態(tài)值到視圖融撞,同時(shí)視圖中變化能改變該值饶火。

v-model 是語法糖肤寝,默認(rèn)情況下相于:value@input

<template>
    <div id="app">
        {{username}} <br />
        <input type="text" v-model="username"></input>
        <!-- 等價(jià)于 -->
        <input type="text" :value="username" @input="username=$event.target.value">
    </div>
</template>

<script>
    export default {
        name: 'App',
        data() {
            return {
                username: ''
            }
        }
    }
</script>

9. ??組件的通信

Vue組件通信方式總結(jié)

父組件向子組件傳值(props)

<div id="app">
    <!-- 1.通過 v-bind 將數(shù)據(jù)傳給子組件 -->
    <test :ss='name'></test>
</div>

<script>
    var a = new Vue({
        el:'#app',
        data:{
            name:'bing',
        },
        components: {
            // 子組件<test>
            test:{
                props: ['ss'],   // 2.接收父組件傳遞過來的數(shù)據(jù)
                template:"<p>{{ss}}</p>"
            }
        }
    })
</script>

子組件向父組件傳值($emit)

<div id="app">
    <p>{{ total }}</p>
    <button-counter @increment="incrementTotal"></button-counter> <!-- 步驟3 -->
</div>

<script>
    Vue.component('button-counter', {
        template: '<button @click="increment">{{ counter }}</button>', // 步驟1
        data: function () {
            return {
                counter: '子組件的數(shù)據(jù)'
            } 
        },
        methods: {
            increment: function () {
                // 通過 $emit 定義一個(gè)自定義事件 increment ,同時(shí)傳入 this.counter 參數(shù)义桂,對外拋出
                this.$emit('increment', this.counter); // 步驟2
            }
        }
    });


    new Vue({
        el: '#app',
        data: {
            total: '父組件的數(shù)據(jù):'
        },
        methods: {
            // 能接收到子組件傳遞過來的數(shù)據(jù)(e)
            incrementTotal: function (e) { // 步驟4
                this.total = this.total + e[0]
                console.log(e);
            }
        }
    })
</script>

兄弟組件傳值(EventBus)

  1. 新創(chuàng)建一個(gè) event-bus.js 文件
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue();
  1. A 頁面發(fā)送數(shù)據(jù)
<!-- A.vue -->
<template>
    <button @click="sendMsg()">-</button>
</template>

<script> 
import { EventBus } from "../event-bus.js";
export default {
  methods: {
    sendMsg() {
      EventBus.$emit("aMsg", '來自A頁面的消息'); // 對外發(fā)送數(shù)據(jù)
    }
  }
}; 
</script>
  1. B 頁面接收數(shù)據(jù)
<!-- B.vue -->
<template>
    <p>{{msg}}</p>
</template>

<script> 
import { EventBus } from "../event-bus.js";
export default {
    data() {
        return {
            msg: ''
        }
    },
    mounted() {
        EventBus.$on("aMsg", (msg) => { // 接收 A 發(fā)送來的消息
            this.msg = msg;
        });
    }
};
</script>
  1. 移除事件監(jiān)聽
import { EventBus } from "../event-bus.js";
EventBus.$off('aMsg', {}); // 移除應(yīng)用內(nèi)所有對此某個(gè)事件的監(jiān)聽
// 或
EventBus.$off(); // 移除所有事件監(jiān)聽

Vuex

vuex詳解

  • state:定義了應(yīng)用狀態(tài)的數(shù)據(jù)結(jié)構(gòu),可以在這里設(shè)置默認(rèn)的初始狀態(tài)溉瓶。
  • getter:可以認(rèn)為是 store 的計(jì)算屬性(有緩存嚷闭,只有當(dāng)它的依賴值發(fā)生了改變才會(huì)被重新計(jì)算)灾锯。
  • mutation:是唯一更改 store 中狀態(tài)的方法顺饮,且必須是同步函數(shù)兼雄。
  • action:用于提交 mutation(再由mutation更改 store 中狀態(tài))赦肋,而不是直接變更狀態(tài),可以包含任意異步操作趣避。
  • module:可以將 store 分割成模塊(module)程帕。每個(gè)模塊擁有自己的 state愁拭、mutation敛苇、action枫攀、getter来涨、甚至是嵌套子模塊

基本用法:

//創(chuàng)建一個(gè) store
const store = new Vuex.Store({
    //state存儲(chǔ)應(yīng)用層的狀態(tài)
    state: {
        count: 5 // 組件中通過 this.$store.state.count; 獲取
    },
    getters: {
        newCount: state => state.count * 3 // 組件中通過 this.$store.getters.newCount; 獲取
    },
    // mutations是修改state中數(shù)據(jù)的唯一途徑
    mutations: {
        increment(state, value) {
            state.count += value; // 組件中通過 this.$store.commit("increment", 'hello'); 修改
        }
    },
    actions: {
        getParamSync(store, value) {
            // 處理異步操作
            setTimeout(() => {
                store.commit('increment', value); // 組件中通過 this.$store.dispatch('getParamSync','hi'); 修改
            }, 1000);
        }
    }
});

module 用法

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)

10. 路由

Vue路由導(dǎo)航 router-link 和 router.push

router-link

1. 不攜帶參數(shù)

// 字符串
<router-link to="login">to login</router-link>
<router-link to="/login">to login</router-link>

// 對象
<router-link :to="{path:'/login'}"> to login</router-link>

// 命名路由
<router-link :to="{name: 'Login'}"> to login</router-link>

2. 通過 query 攜帶參數(shù):

  1. 地址欄變成 /login?color=red
  2. 可通過 {{$route.query.color}}this.$route.query.color 獲取參數(shù)
<router-link :to="{path: '/login', query: {color: 'red' }}"> to login</router-link>

<router-link :to="{name: 'Login', query: {color: 'red' }}"> to login</router-link>

3. 通過 params 攜帶參數(shù):

  1. 地址欄變成 /login/red
  2. 可通過 {{$route.params.color}}this.$route.params.color 獲取參數(shù)
// 無法獲取參數(shù)  
// 報(bào)警告(Path "/login" was passed with params but they will be ignored. Use a named route alongside params instead.)
<router-link :to="{path: '/login', params: { color: 'red' }}"> to login</router-link>


// 通過 {{$route.params.color}} 或 this.$route.params.color 獲取參數(shù)技羔。
<router-link :to="{name: 'Login', params: { color: 'red' }}"> to login</router-link>

此時(shí) router.js 中需要設(shè)置 path: '/login/:color?'

// router.js

var router = new Router({
routes: [{
    path: '/login/:color?', //  :color? => ?問號的意思是該參數(shù)不是必傳項(xiàng)藤滥,不傳不會(huì)報(bào)錯(cuò)
    name: 'Login',
    component: Login
}]

router.push

1. 不攜帶參數(shù)

// 字符串
router.push('/login')

// 對象
router.push({path:'/login'})

// 命名路由
router.push({name: 'Login'})

2. 通過 query 攜帶參數(shù):

// 可通過 {{$route.query.color}} 或 this.$route.query.color 獲取參數(shù)
router.push({path: '/login', query: {color: 'red' }})

// 可通過 {{$route.query.color}} 或 this.$route.query.color 獲取參數(shù)
router.push({name: 'Login', query: {color: 'red' }})

3. 通過 params 攜帶參數(shù):

// 無法獲取參數(shù) 
router.push({path:'/login', params:{ color: 'red' }})

// 通過 {{$route.params.color}} 或 this.$route.params.color 獲取參數(shù)。
router.push({name:'Login', params:{ color: 'red' }})

router 和route 的區(qū)別

  1. $router :是指整個(gè)路由實(shí)例,你可以操控整個(gè)路由标沪,用法如下:
    this.$router.go(-1);  // 向前或者向后跳轉(zhuǎn)n個(gè)頁面金句,n可為正整數(shù)或負(fù)整數(shù)
    this.$router.push('/'); // 跳轉(zhuǎn)到指定url路徑违寞,history棧中會(huì)有記錄坞靶,點(diǎn)擊返回會(huì)跳轉(zhuǎn)到上個(gè)頁面
    this.$router.replace('/'); // 跳轉(zhuǎn)到指定url路徑,但是history棧中不會(huì)有記錄拍冠,點(diǎn)擊返回會(huì)跳轉(zhuǎn)到上上個(gè)頁面
    
  2. $route:是指當(dāng)前路由實(shí)例$router跳轉(zhuǎn)到的路由對象庆杜;路由實(shí)例可以包含多個(gè)路由對象晃财,它們是父子包含關(guān)系
    // 獲取路由傳遞過來的參數(shù)
    this.$route.params.userId  
    this.$route.query.userName 
    

router.js (含路由懶加載和路由鑒權(quán))

router.js相關(guān)配置

import Vue from 'vue'
import Router from 'vue-router'
import { getStore } from 'js/store'

Vue.use(Router);

var router = new Router({
    routes: [
    {
        path: '*',
        redirect: '/'
    },
    {
        path: '/',
        name: '/',
        component: () => import('./views/Index.vue'), // vue路由懶加載  異步加載
        meta: {
            title: '首頁',
            requireAuth: false // 此字段為false,不需要做鑒權(quán)處理
        }
    },
    {
        path: '/test',
        name: 'test',
        component: () => import('./views/Test.vue'),// vue路由懶加載  異步加載
        meta: {
            title: 'test',
            requireAuth: true // 只要此字段為true钢猛,必須做鑒權(quán)處理
        }
    },
    {
        path: '/login',
        name: 'login',
        component: () => import('./views/Login.vue'),// vue路由懶加載  異步加載
        meta: {
            noNav: true // 不顯示nav
        }
    }]
});

let indexScrollTop = 0;

router.beforeEach((to, from, next) => {
    // 路由鑒權(quán):在路由meta對象中由個(gè)requireAuth字段命迈,只要此字段為true壶愤,必須做鑒權(quán)處理
    if (to.matched.some(res => res.meta.requireAuth)) {
        const token = getStore({ name: 'access_token', type: "string" });// 獲取localstorage中的access_token
        console.log(token);
        // 路由進(jìn)入下一個(gè)路由對象前征椒,判斷是否需要登陸
        if (!token) {
            // 未登錄
            next({
                path: '/login',
                query: {
                    redirect: to.path // 將跳轉(zhuǎn)的路由path作為參數(shù)迂尝,登錄成功后再跳轉(zhuǎn)到該路由
                }
            })
        } else {
            // 用戶信息是否過期
            let overdueTime = token.overdueTime;
            let nowTime = +new Date();
            // 登陸過期和未過期
            if (nowTime > overdueTime) {
                // 登錄過期的處理垄开,君可按需處理之后再執(zhí)行如下方法去登錄頁面
                // 我這里沒有其他處理溉躲,直接去了登錄頁面
                next({
                    path: '/login',
                    query: {
                        redirect: to.path
                    }
                })
            } else {
                next()
            }
        }
    } else {
        next()
    }
    if (to.path !== '/') {
        // 記錄現(xiàn)在滾動(dòng)的位置
        indexScrollTop = document.body.scrollTop
    }
    document.title = to.meta.title || document.title
})

router.afterEach(route => {
    if (route.path !== '/') {
        document.body.scrollTop = 0
    } else {
        Vue.nextTick(() => {
            // 回到之前滾動(dòng)位置
            document.body.scrollTop = indexScrollTop
        })
    }
})

export default router;

路由懶加載的不同寫法:

  1. webpack < 2.4版(vue-cli2)的懶加載
const Index = resolve => require(['./views/Index.vue'], resolve);
  1. webpack > 2.4版(vue-cli3)的懶加載
const Index = () => import('./views/Index.vue');

11. 其他

Vue3.x新特性總結(jié)

Vue中對axios的封裝(含攔截器)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載锻梳,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。
  • 序言:七十年代末蛔六,一起剝皮案震驚了整個(gè)濱河市具钥,隨后出現(xiàn)的幾起案子骂删,更是在濱河造成了極大的恐慌宁玫,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恋追,死亡現(xiàn)場離奇詭異苦囱,居然都是意外死亡撕彤,警方通過查閱死者的電腦和手機(jī)蚀狰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扮授,“玉大人刹勃,你說我怎么就攤上這事荔仁。” “怎么了收奔?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長翩肌。 經(jīng)常有香客問我念祭,道長隶糕,這世上最難降的妖魔是什么枚驻? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮锉矢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缠俺。我一直安慰自己壹士,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布盒使。 她就那樣靜靜地躺著,像睡著了一般英妓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吗蚌,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天腿倚,我揣著相機(jī)與錄音,去河邊找鬼蚯妇。 笑死敷燎,一個(gè)胖子當(dāng)著我的面吹牛暂筝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播懈叹,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼乖杠,長吁一口氣:“原來是場噩夢啊……” “哼澄成!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起镐确,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤嚷狞,失蹤者是張志新(化名)和其女友劉穎薇搁,沒想到半個(gè)月后裂允,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體十饥,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年帅刊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吧兔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欧穴。...
    茶點(diǎn)故事閱讀 40,427評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖妇多,靈堂內(nèi)的尸體忽然破棺而出蜓耻,到底是詐尸還是另有隱情嚷往,我是刑警寧澤贷祈,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布挤忙,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜此改,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一薪者、第九天 我趴在偏房一處隱蔽的房頂上張望蓬坡。 院中可真熱鬧臣缀,春花似錦踱蠢、人聲如沸打却。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蓖救,卻和暖如春柠衍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背民泵。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留槽畔,地道東北人栈妆。 一個(gè)月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像厢钧,于是被迫代替她去往敵國和親鳞尔。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容