主頁 > 企業開發 > 2021高頻核心前端面試題總結

2021高頻核心前端面試題總結

2021-09-01 07:26:41 企業開發

@

目錄
  • HTML
    • 1. 如何理解HTML語意化
    • 2. 默認情況下,哪些HTML標簽是塊級元素、哪些是行內元素
    • 3. HTML5 新增內容和 API
  • CSS
    • 1. 盒子模型
    • 2. margin 縱向重疊
    • 3. margin 負值
    • 4. BFC(塊級格式化背景關系)
    • 5. float布局
    • 6. flex布局
    • 7. 三欄布局
    • 8. CSS定位
    • 9. 居中對齊實作方式
    • 10. line-height的繼承問題
    • 11. CSS長度單位
    • 12. CSS回應式媒體查詢
    • 13. 網頁視口尺寸
    • 14. CSS3 vw / vh
  • JS
    • 1. ES6
    • 2. 資料型別與檢測
    • 3. 深拷貝和淺拷貝
    • 4. 原型與原型鏈(三座大山之一)
      • prototype(顯式原型)
      • _proto _ (隱式原型)
      • constructor ( 指向創建該物件的建構式)
      • 原型鏈
      • 原型與原型鏈的終極圖
      • instanceof 原理
      • 繼承方式
    • 5. 作用域、this 和閉包 (三座大山之二)
      • 作用域
      • 作用域鏈
      • this
      • 閉包
    • 6. 異步 (三座大山之三)
      • 單執行緒與多執行緒
      • 同步與異步
      • 事件回圈(Event Loop)
      • Promise
      • async與await
      • 異步加載JS方式
    • 7. DOM 與 BOM
      • DOM
      • BOM
    • 8. 事件流
      • 事件捕獲
      • 事件冒泡(默認)
      • DOM 標準事件流
      • 阻止事件冒泡/捕獲
      • 阻止默認事件
      • 事件代理/委托
    • 9. 跨域
      • 同源策略
      • 不存在跨域的情況(無視同源策略)
      • 常見的幾種跨域方法
      • 安全
    • 10. HTTP
      • HTTP三大特點
      • HTTP 訊息結構
      • HTTP 狀態碼
      • HTTP 請求方法
      • HTTP 快取
    • 11. 手寫常見JS方法
  • 工具
    • 1. Git
    • 2. 瀏覽器
      • 瀏覽器從輸入URL到渲染完頁面的整個程序
      • 瀏覽器渲染程序
    • 3. 其他
      • yarn
      • gulp
      • babel
      • vConsole
  • Vue
    • 1. MVVM
    • 2. 生命周期
      • Vue2生命周期
      • Vue3生命周期
    • 3. computed 與 watch
      • computed(計算屬性)
      • watch(監聽屬性)
    • 4. v-if 與 v-show
      • v-if
      • v-show
    • 5. data 必須是一個函式,而不是物件
    • 6. diff 演算法
    • 7. for 回圈中 key 的作用
    • 8. 雙向系結
      • v-model
    • 9. 組件的通信
      • 父組件向子組件傳值(props)
      • 子組件向父組件傳值($emit)
      • 兄弟組件傳值(EventBus)
      • Vuex
    • 10. 路由
      • router-link
      • router.push
      • $router 和 $route 的區別
      • router.js (含路由懶加載和路由鑒權)
    • 11. 其他
      • vue3中CompositionAPI
      • Vue中對axios的封裝(含攔截器)


HTML

1. 如何理解HTML語意化

HTML5語意化

  • 讓人更容易讀懂(代碼結構清晰,增加代碼的可讀性)
  • 讓搜索引擎更容易讀懂(SEO),搜索引擎爬蟲會根據不同的標簽來賦予不同的權重

語意化標簽 : header nav main article section aside footer

2. 默認情況下,哪些HTML標簽是塊級元素、哪些是行內元素

  • 塊級元素:display: block/table,有div div h1 h2 table ul ol li p
  • 行內元素:display: inline/inline-block,有span img input button i b

3. HTML5 新增內容和 API

HTML5 新增內容和 API

  • classList 屬性
  • querySelector() 與 querySelectorAll()
  • getElementsByClassName()
  • 自定義資料屬性
  • 本地存盤
  • insertAdjacentHtml()、insertAdjacentText()、insertAdjacentElement()
  • 內容可編輯
  • 預加載

CSS

1. 盒子模型

CSS盒子模型

box-sizing屬性

CSS盒子模型包含2種:

  • W3C標準盒子模型(box-sizing: content-box ,默認),寬高不受 padding、border影響
  • IE怪異盒子模型 (box-sizing: border-box),寬高受 padding、border影響

2. margin 縱向重疊

  • 相鄰元素的margin-topmargin-bottom會重疊
  • 空內容的元素也會重疊

思考:如下代碼,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
在這里插入圖片描述

3. margin 負值

  • margin-top 負值,元素會上移
  • margin-left 負值,元素會左移
  • margin-right 負值,右側元素會左移,自身不受影響
  • margin-bottom 負值,下方元素會上移,自身不受影響
    在這里插入圖片描述

4. BFC(塊級格式化背景關系)

3分鐘理解BFC

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

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

  1. 根元素(即<html>標簽)
  2. 浮動元素 float 不為 none (為 leftright
  3. 絕對定位元素 position 不為 static 或 relative,(為 absolutefixed
  4. overflow 的值不為 visible 的塊元素(為 autoscrollhidden)
  5. display 的值為inline-blockflexgrid tabletable-celltable-caption...

同一BFC內:

  1. Box會在垂直方向上一個接一個的放置
  2. 垂直方向的距離由margin決定(屬于同一個BFC的兩個相鄰Box的margin會發生重疊,與方向無關)
  3. 每個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對于從左往右的格式化,否則相反),即使存在浮動也是如此
  4. BFC的區域不會與float的元素區域重疊
  5. 計算BFC的高度時,浮動子元素也參與計算
  6. BFC就是頁面上的一個隔離的獨立容器,容器里面的子元素不會影響到外面元素,反之亦然

應用:

  1. 分屬于不同的BFC時,可以防止margin重疊
  2. 清除內部浮動
  3. 自適應多欄布局

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平分布局

在這里插入圖片描述

7. 三欄布局

實作三欄布局的8種方式:

  1. 浮動布局
  2. 定位布局
  3. flex布局
  4. 表格布局
  5. 網格布局
  6. calc函式布局
  7. 圣杯布局
  8. 雙飛翼布局

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

  • 三欄布局,中間一欄最先加載和渲染(內容最重要)
  • 兩側內容固定,中間內容隨著寬度自適應
  • 一般用于PC端

8. CSS定位

css中position屬性詳解

思考:relativeabsolutefixed依據什么定位?

答案:

  • relative依據自身定位(相對的是它原本在檔案流中的位置而進行的偏移),在最外層時,是以<body>標簽為定位原點的
  • absolute依據最近一層的定位元素定位(根據postionstatic的祖先類元素進行定位),在無父級是postionstatic定位時,是以<html>作為原點定位
  • fixed根據視窗為原點進行偏移定位 (也就是說它不會根據滾動條的滾動而進行偏移)

9. 居中對齊實作方式

css居中常見方法總結

10. line-height的繼承問題

思考: 以下代碼中p標簽的行高是多少?

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

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

<p>AAA</p>

答案是 40px

在這里插入圖片描述

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

11. CSS長度單位

  1. px 固定的像素,一旦設定了就無法因為適應頁面大小而改變,
  2. em 相對于父元素的長度單位,(不常用)
  3. rem 相對于根<html>元素的長度單位,(常用)
  4. rpx 微信小程式的相對長度單位,小程式規定螢屏寬為750rpx,如在 iPhone6 上,螢屏寬度為375px,共有750個物理像素,則750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素,(僅微信小程式)

12. CSS回應式媒體查詢

假如一個終端的解析度小于 980px,那么可以這樣寫:

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

假如我們要設定兼容 iPad 和 iPhone 的視圖,那么可以這樣設定:

/** 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單位實作回應式,因此rem具有階梯性的弊端

13. 網頁視口尺寸

  • 螢屏高度 window.screen.height (顯示幕螢屏設備高度)
  • 網頁視口高度 window.innerHeight (去掉瀏覽器自身的頭部和底部后的高度,含滾動條高)
  • body高度 document.body.clientHeight (頁面內容的真實高度)

在這里插入圖片描述

神圖
在這里插入圖片描述
寬度同理 略~

14. CSS3 vw / vh

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

JS

1. ES6

查看ES6專輯

  1. ES6之 let 和 const 關鍵字

  2. ES6之 解構賦值

  3. ES6之 擴展運算子

  4. ES6之 字串新特性

  5. ES6之 數值新特性

  6. ES6之 陣列新特性

  7. ES6之 函式優化(默認引數、剩余引數、 箭頭函式)

  8. ES6之 Promise

  9. ES6之 async/await

  10. ES6之 class(類)

  11. ES6之 Map和Set

  12. ES6之 import和export

  13. ES6之 Generator 函式

  14. ES6之 for...of 回圈

2. 資料型別與檢測

js檢測資料型別的幾種方法總結

JavaScript 資料型別:

  1. Number (基本型別)
  2. String (基本型別)
  3. Boolean (基本型別)
  4. null (基本型別)
  5. undefined (基本型別)
  6. symbol (ES6 - 基本型別)
  7. bigInt (ES10 - 基本型別)
  8. object (參考型別,包含 function、[ ]、{ })

基本型別的特點:直接存盤在堆疊(stack)記憶體中的資料
參考型別的特點:存盤的是該物件在堆疊中參考,真實的資料存放在堆(heap)記憶體中

在這里插入圖片描述

3. 深拷貝和淺拷貝

JavaScript中的深拷貝和淺拷貝

深拷貝和淺拷貝最根本的區別在于是否是真正獲取了一個物件的拷貝物體,而不是參考

淺拷貝只拷貝一層物件的屬性,而深拷貝則遞回拷貝了所有層級,

  • 深拷貝在計算機中開辟了一塊新的記憶體地址用于存放拷貝的物件
  • 淺拷貝僅僅是指向被拷貝的記憶體地址,如果原地址中物件被改變了,那么淺拷貝出來的物件也會相應改變

在這里插入圖片描述

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

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

prototype(顯式原型)

所有函式(僅限函式)擁有 prototype 屬性

prototype 物件用于放某同一型別實體的共享屬性和方法,實質上是為了記憶體著想,

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

在這里插入圖片描述


_proto _ (隱式原型)

所有物件擁有 _proto _ 屬性

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

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

/*2、構造器方式*/
var A = function (){}; 
var a = new A();
console.log(a.constructor === A); // true(即構造器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  (即構造器Object)
console.log(a2.__proto__ === a1); // true 
console.log(a2.__proto__ === a2.constructor.prototype); //false(此處即為圖1中的例外情況)

在這里插入圖片描述


constructor ( 指向創建該物件的建構式)

每個原型物件都可以通過物件.constructor 指向創建該物件的建構式

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

// 實體化物件的constructor屬性指向建構式本身
person1.constructor === Person; 

// 建構式的prototype屬性有個constructor屬性,指向建構式本身
Person.prototype.constructor === Person;

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

person1.__proto__ === Person.prototype

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

在這里插入圖片描述


原型鏈

在這里插入圖片描述

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

下圖中由相互關聯的原型組成的鏈狀結構就是原型鏈,也就是藍色的這條線,
在這里插入圖片描述


原型與原型鏈的終極圖

這個圖要是看懂了,原型與原型鏈就基本摸清了,
在這里插入圖片描述


instanceof 原理

instanceof 只能用來判斷物件型別,原始型別不可以,并且所有物件型別 instanceof Object 都是 true

instanceof 的內部機制是通過判斷物件的原型鏈中是不是能找到型別的 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的判斷隊則是:沿著s1的__proto__這條線來找,同時沿著Student的prototype這條線來找,如果兩條線能找到同一個參考,即同一個物件,那么就回傳true,如果找到終點還未重合,則回傳false,這就很好地解釋了上述代碼的輸出結果啦,


繼承方式

JavaScript中的繼承方式

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

作用域

在 Javascript 中,作用域分為 全域作用域函式作用域

全域作用域
代碼在程式的任何地方都能被訪問,window 物件的內置屬性都擁有全域作用域,

函式作用域
在固定的代碼片段才能被訪問
在這里插入圖片描述
作用域有上下級關系,上下級關系的確定就看函式是在哪個作用域下創建的,如上,fn作用域下創建了bar函式,那么“fn作用域”就是“bar作用域”的上級,

作用域最大的用處就是隔離變數不同作用域下同名變數不會有沖突


作用域鏈

ES6之塊級作用域

ES6之let關鍵字

變數取值:創建這個變數的函式的作用域中向上取值,而不是呼叫這個函式時向上取值
如果在當前作用域中沒有查到值,就會向上級作用域去查,直到查到全域作用域,這么一個查找程序形成的鏈條就叫做作用域鏈

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

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

創建的函式向上取值,而不是呼叫函式時向上取值


this

徹底理解JavaScript中this指向

this永遠指向的是最后呼叫它的物件,也就是看它執行的時候是誰呼叫的

特別注意:

  • 匿名函式的自我執行,沒有被上級物件呼叫,所以this指向window
  • setTimeout(function () { console.log(this) }); ,this指向window
  • setTimeout(() => { console.log(this) }); ,this指向背景關系
  • 建構式中的this,指向實體物件
  • bindcallapply 可以改變 this 指向

JavaScript中call,apply,bind方法的總結


閉包

JavaScript閉包

閉包就是指有權訪問另一個函式作用域中的變數的函式,

創建閉包的最常見的方式就是在一個函式內創建另一個函式,通過另一個函式訪問這個函式的區域變數

閉包的特性:

  1. 函式嵌套函式
  2. 函式內部可以參考外部的引數和變數
  3. 引數和變數不會被垃圾回識訓制回收
function aaa() {  
    var a = 1;  
    return function(){
        alert(a++)
    };  
}         
var fun = aaa();  
fun();// 1 執行后 a++,,然后a還在~   a會長期駐扎在記憶體中
fun();// 2   
fun = null;//a被回收!! 

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

單執行緒與多執行緒

  • JavaScript是單執行緒語言(可以說這是JavaScript最核心也是最基本的特性)
  • 瀏覽器的內核是多執行緒的

雖然JavaScript是單執行緒的,可是瀏覽器內部不是單執行緒的,
一些I/O操作、定時器的計時和事件監聽(click, keydown...)等都是由瀏覽器提供的其他執行緒來完成的,


同步與異步

  • 同步:是指在主執行緒上排隊執行的任務,只有前一個任務執行完畢,才能繼續執行下一個任務,
    當我們打開網站時,網站的渲染程序,比如元素的渲染,其實就是一個同步任務

  • 異步:是指不進入主執行緒,而進入任務佇列的任務,只有任務佇列通知主執行緒,某個異步任務可以執行了,該任務才會進入主執行緒,
    當我們打開網站時,像圖片加載等網路請求(ajax、axios)、定時任務(setTimeout),其實就是一個異步任務

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

console.log(2);

事件回圈(Event Loop)

淺談事件回圈Event Loop

事件回圈機制:

  1. 首先判斷JS是同步還是異步,同步就進入主執行緒,異步就進入event table
  2. 異步任務在event table中注冊函式,當滿足觸發條件后,被推入訊息佇列event queue
  3. 同步任務進入主執行緒后一直執行,直到主執行緒空閑時,才會去訊息佇列中查看是否有可執行的異步任務,如果有就推入主執行緒中

在這里插入圖片描述

異步任務又可以分為:

  • macrotask(宏任務)
    等待執行堆疊和微任務佇列都執行完畢才會執行,并且在執行完每一個宏任務之后,會去看看微任務佇列有沒有新添加的任務,如果有,會先將微任務佇列中的任務清空,才會繼續執行下一個宏任務
    包括:script代碼塊,setTimeout,setInterval,I/O

  • microtask(微任務)
    當執行堆疊中的代碼執行完畢,會在執行宏任務佇列之前先看看微任務佇列中有沒有任務,如果有會先將微任務佇列中的任務清空才會去執行宏任務佇列
    包括:Promise,nextTick,callback,Object.observe,MutationObserver

執行的順序是 執行堆疊中的代碼 => 微任務 => 宏任務 => 微任務 => 宏任務 => ...

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

異步任務的執行也是有先后順序的:

  1. 執行一個宏任務,程序中如果遇到微任務,就將其放到微任務的【事件佇列】里
  2. 當前宏任務執行完成后,會查看微任務的【事件佇列】,并將里面全部的微任務依次執行完

在這里插入圖片描述


Promise

徹底掌握 Promise

手寫一個Promise

Promise 是異步編程的一種解決方案,有三種狀態:

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

一旦 Promiseresolvereject,不能再遷移至其他任何狀態(即狀態 immutable),創造 promise 實體后,它會立即執行,

在這里插入圖片描述
基本程序:

  1. 初始化 Promise 狀態(pending);
  2. 立即執行 Promise 中傳入的 fn 函式,將Promise 內部 resolvereject 函式作為引數傳遞給 fn ,按事件機制時機處理;
  3. 執行 then(…) 注冊回呼處理陣列(then 方法可被同一個 promise 呼叫多次);
  4. Promise 里的關鍵是要保證,then方法傳入的引數 onFulfilledonRejected,必須在then方法被呼叫的那一輪事件回圈之后的新執行堆疊中執行;

簡單用法:

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

// 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

細說 async/await

核心:

  1. 執行 async 函式,默認回傳一個 promise 物件
  2. await 相當于 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 {
        //把await及獲取它的值的操作放在try里
        let n = await dice('大');  // await 相當于 Promise 的 then
        console.log('贏了' + n);
    } catch (error) {
        //失敗的操作放在catch里
        console.log('輸了' + error); // 相當于 Promise 的 catch
    }
}
test();

思考:以下代碼輸出順序

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

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

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

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

async1();

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

答案

4
1
3
6
2
5

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


異步加載JS方式

1. 匿名函式自調動態創建script標簽加載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屬性

// async屬性規定一旦加載腳本可用,則會異步執行
<script type="text/javascript" src="https://www.cnblogs.com/bingcola/p/xxx.js" async="async"></script>

3. defer屬性

// defer屬性規定是否對腳本執行進行延遲,直到頁面加載為止
<script type="text/javascript" src="https://www.cnblogs.com/bingcola/p/xxx.js" defer="defer"></script>

7. DOM 與 BOM

DOM物件和BOM物件

DOM

DOM (Document Object Model)是 W3C 的標準,是指檔案物件模型(樹結構),
DOM 定義了訪問和操作 HTML 檔案的標準方法,通過它,可以訪問HTML檔案的所有元素

1. HTML DOM 樹:
在這里插入圖片描述

2. DOM 節點:

根據 W3C 的 HTML DOM 標準,HTML 檔案中的所有內容都是節點(NODE):

  • 檔案節點:整個檔案(document物件)
  • 元素節點:每個 HTML 元素(element 物件)
  • 文本節點:HTML 元素內的文本(text物件)
  • 屬性節點:每個 HTML 屬性(attribute物件)
  • 注釋節點:注釋(comment物件)

3. DOM 查找:

// 根據標簽名獲取標簽合集
const div1 = document.getElementsByTagName("div"); // div1 div2 div3 div4 div5 (元素集合 HTMLCollection)
const div2 = document.querySelectorAll("div"); // div1 div2 div3 div4 div5 (節點集合 NodeList)

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

// 根據id屬性值獲取
const div5 = document.getElementById("div"); // div3 (一個標簽)
const div6 = document.querySelectorAll("#div"); // div3 (節點集合 NodeList)

// 根據name屬性值獲取
const div7 = document.getElementsByName("div"); // div4 div5 (節點集合 NodeList)

// 根據標簽名獲取標第一個
const div8 = document.querySelector("div"); // div1 (一個標簽)

4. DOM 操作:

// 創建節點
var divEle = document.createElement("div");
var pEle = document.createElement("p");
var aEle = document.createElement("a");

// 添加節點
document.body.appendChild(divEle);  // 將上面創建的div元素加入到body的尾部
document.body.insertBefore(pEle, divEle);  // 在body下,將p元素添加到div元素前面

//替換節點
document.body.replaceChild(aEle, pEle);  // 在body下,用a元素替換p元素

//設定文本節點
aEle.innerText = "在干嘛"
divEle .innerHTML = "<p>在干嘛<p/>"

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

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

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

5. DOM 優化:

DOM 操作都是代價昂貴的操作,它會導致 WEB 應用程式的 UI 反應遲鈍,所以,應當盡可能減少這類程序的發生,

// 不快取 DOM 查詢結果
for (let i = 0; i < document.getElementsByTagName("div").length; i++) {
    // 每次回圈,都會計算length,頻繁進行 DOM 查詢
}

// 快取 DOM 查詢結果
const div = document.getElementsByTagName("div");
const length = div.length;
for (let i = 0; i < length; i++) {
    // 只進行一次 DOM 查詢
}

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

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

// 未優化前的DOM操作,會導致三次重排
el.style.borderLeft = '1px';
el.style.borderRight = '2px';
el.style.padding = '5px';

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

BOM

BOM(Browser Object Model)是指瀏覽器物件模型,可以對瀏覽器視窗進行訪問和操作
使用 BOM,開發者可以移動視窗、改變狀態欄中的文本以及執行其他與頁面內容不直接相關的動作,使 JavaScript 有能力與瀏覽器"對話",

  1. Window 物件 (window.alert()window.open()window.setTimeout() ...)
  2. Navigator 物件(navigator.userAgent ...)
  3. Screen 物件 (screen.widthscreen.height ...)
  4. Location 物件 (location.hreflocation.reload()location.replace() ...)
  5. History 物件(history.forward()history.back() ...)

8. 事件流

JavaScript 事件流

事件傳播的順序對應瀏覽器的兩種事件流模型:

  • 冒泡型事件流中click事件傳播順序為 <div> => <body> => <html> => document (默認)
  • 捕獲型事件流中click事件傳播順序為 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');
        });

		// 默認是事件捕獲,因此按順序輸出:
		// this is div
		// this is body
		// this is html
		// this is document
    </script>
</body>
</html>

事件捕獲

在這里插入圖片描述

事件冒泡(默認)

在這里插入圖片描述


DOM 標準事件流

在這里插入圖片描述
系結事件時通過addEventListener函式,它有三個引數,第三個引數若是true,則表示采用事件捕獲,若是false(默認),則表示采用事件冒泡,

<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)

第三個引數useCapture,可選,布林值,指定事件是否在捕獲或冒泡階段執行:

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

阻止事件冒泡/捕獲

使用 event.stopPropagation() 起到阻止捕獲和冒泡階段中當前事件的進一步傳播,

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


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

兼容IE的寫法:

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

阻止默認事件

  • W3C的方法是: event.preventDefault()
  • IE則是使用: event.returnValue = https://www.cnblogs.com/bingcola/p/false

既然是說默認行為,當然是元素必須有默認行為才能被取消,如果元素本身就沒有默認行為,呼叫當然就無效了,

<a href="https://www.baidu.com/" id="a">阻止默認跳轉</a>

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

事件代理/委托

事件代理的原理用到的就是事件冒泡和目標元素,把事件處理器添加到父元素,等待子元素事件冒泡,并且父元素能夠通過target(IE為srcElement)判斷是哪個子元素,從而做相應處理,

<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); // 給每個li系結一個點擊事件
	    };
	
	    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的父級一個點擊事件

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

9. 跨域

JS 跨域詳解

跨域是指從一個域名的網頁去請求另一個域名的資源,比如從 www.baidu.com 頁面去請求 www.google.com 的資源,
非同源,在請求資料時,瀏覽器會在控制臺中報一個例外,提示拒絕訪問,它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript施加的安全限制


同源策略

同源策略是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響,可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實作,

  • 同源:協議、域名、埠,三者全部相同,才是同源,
  • 跨域:協議、域名、埠,只要有一個的不同,就是跨域,

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

  1. 服務端請求服務端不存在跨域(瀏覽器請求服務器才存在同源策略)
  2. <img src="https://www.cnblogs.com/bingcola/p/跨域的圖片地址"><img>標簽的 src 屬性不存在跨域)
  3. <link href="https://www.cnblogs.com/bingcola/p/跨域的css地址"><link>標簽的 href 屬性不存在跨域)
  4. <script src="https://www.cnblogs.com/bingcola/p/跨域的js地址"></script><script>標簽的 src 屬性不存在跨域)

常見的幾種跨域方法

  1. jsonp 跨域 (動態添加<script>標簽,利用src屬性跨域, 常用)
  2. CORS 跨域資源共享(由服務端實作, 常用且主流)
  3. node 代理跨域(利用proxyTable使本地的node服務器代理請求真正的服務器, 常用)
  4. document.domain + iframe 跨域
  5. postMessage 跨域

安全

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

10. HTTP

淺談 HTTP

HTTP協議是一個基于 TCP/IP 通信協議來傳遞資料(HTML 檔案, 圖片檔案, 查詢結果等),用于從服務器傳輸超文本到本地瀏覽器的傳送協議,

TCP的三次握手四次揮手


HTTP三大特點

  • HTTP是無連接的:無連接的含義是限制每次連接只處理一個請求,服務器處理完客戶的請求,并收到客戶的應答后,即斷開連接,采用這種方式可以節省傳輸時間,
  • HTTP是媒體獨立的:這意味著,只要客戶端和服務器知道如何處理的資料內容,任何型別的資料都可以通過HTTP發送,客戶端以及服務器指定使用適合的MIME-type內容型別,
  • HTTP是無狀態的:無狀態是指協議對于事務處理沒有記憶能力,缺少狀態意味著如果后續處理需要前面的資訊,則它必須重傳,這樣可能導致每次連接傳送的資料量增大,另一方面,在服務器不需要先前資訊時它的應答就較快,

HTTP 訊息結構

客戶端請求訊息(Request Headers):
客戶端發送一個HTTP請求到服務器的請求訊息包括以下格式:請求行(request line)、請求頭部(header)、空行和請求資料四個部分組成,下圖給出了請求報文的一般格式,
在這里插入圖片描述

服務器回應訊息(Response Headers):
HTTP回應也由四個部分組成,分別是:狀態行、訊息報頭、空行和回應正文,
在這里插入圖片描述


HTTP 狀態碼

HTTP狀態碼詳解

RFC 規定 HTTP 的狀態碼為三位數,被分為五類:

  • 1xx: 資訊,服務器收到請求,需要請求者繼續執行操作
  • 2xx: 成功,操作被成功接收并處理 (200 - 請求成功)
  • 3xx: 重定向,需要進一步的操作以完成請求(302 - 資源(網頁等)被臨時轉移到其它URL,瀏覽器自動處理)
  • 4xx: 客戶端錯誤,請求包含語法錯誤或無法完成請求(404 - 請求的資源(網頁等)不存在)
  • 5xx: 服務器錯誤,服務器在處理請求的程序中發生了錯誤(500 - 內部服務器錯誤)

HTTP 請求方法

GET和POST最詳細的總結

方法 協議版本 描述
GET HTTP1.0 請求指定的頁面資訊,并回傳物體主體,(獲取資料
HEAD HTTP1.0 類似于 GET 請求,只不過回傳的回應中沒有具體的內容,用于獲取報頭,
POST HTTP1.0 向指定資源提交資料進行處理請求(例如提交表單或者上傳檔案),資料被包含在請求體中,POST 請求可能會導致新的資源的建立和/或已有資源的修改,(新建資料
PUT HTTP1.1 從客戶端向服務器傳送的資料取代指定的檔案的內容,
DELETE HTTP1.1 請求服務器洗掉指定的頁面,(洗掉資料
CONNECT HTTP1.1 預留給能夠將連接改為管道方式的代理服務器,
OPTIONS HTTP1.1 允許客戶端查看服務器的性能,
TRACE HTTP1.1 回顯服務器收到的請求,主要用于測驗或診斷,
PATCH HTTP1.1 是對 PUT 方法的補充,用來對已知資源進行區域更新 ,(更新資料

HTTP 快取

一文讀懂http快取(超詳細)

當客戶端向服務器請求資源時,會先抵達瀏覽器快取,如果瀏覽器有“要請求資源”的副本,就可以直接從瀏覽器快取中提取而不是從原始服務器中提取這個資源,

常見的http快取只能快取get請求回應的資源,對于其他型別的回應則無能為力,

快取的優點:

  • 減少了冗余的資料傳輸,節省了你的網路費用,
  • 緩解了網路瓶頸的問題,不需要更多的帶寬就能夠更快地加載頁面,
  • 降低了對原始服務器的要求,服務器可以更快地回應,避免過載的出現,
  • 降低了距離時延,因為從較遠的地方加載頁面會更慢一些,

強快取與協商快取:

  • 第一次請求資源時,服務器回傳資源,并在respone header中回傳資源和資源標識Last-ModifiedEtag),
  • 第二次請求資源時,瀏覽器會判斷 response headers 是否命中(cache-control屬性強快取,如果命中,直接從本地讀取快取(狀態碼200),不會向服務器發送請求,
  • 當強快取沒有命中時,就把請求引數(含If-Modified-SinceIf-Not-Match)加到 request header 頭中傳給服務器,判斷協商快取是否命中,如果命中(If-Modified-Since == Last-ModifiedIf-Not-Match == Etag)則服務器將請求回傳(狀態碼304),不會回傳資源,告訴瀏覽器從本地讀取快取,
  • 當協商快取沒有命中(If-Modified-Since != Last-ModifiedIf-Not-Match != Etag)時,服務器直接回傳新的資源(狀態碼200)和新的資源標識(新的Last-Modified、新的Etag) ,

資源標識:

  • Last-Modified:資源的最后修改時間(只能精確到秒級)
  • Etag:資源的唯一標識,會優先使用(一個字串,類似人類的指紋)

如果資源被重復生產,而內容不變,則 Etag 更精準

在這里插入圖片描述

區別:

  • 強快取命中:不會請求服務器,直接請求快取;(非常快)
  • 協商快取命中:會請求服務器,不會回傳內容,然后讀取快取;(服務端快取策略)
    在這里插入圖片描述

11. 手寫常見JS方法

手寫常見JS方法

  • 判斷資料型別
  • 深拷貝
  • 物件是否全等
  • 防抖
  • 節流
  • 陣列拍平
  • 陣列去重
  • new函式

工具

1. Git

Git詳細教程

在這里插入圖片描述

專案常用命令:

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

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

4. git branch // 查看分支

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

6. git status	// 顯示有變更的檔案  如果字體為紅色,則表示列出的是當前目錄所有還沒有被git管理的檔案和被git管理且被修改但還未提交(git commit)的檔案,也就是所有改動檔案,

7. git diff           // 查看所有修改內容
   git diff test.txt  // 查看具體檔案修改內容
   
8. git log          // 查看提交的記錄日志
   git log test.txt	// 查看具體檔案提交的記錄日志

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

10. git stash pop  // 恢復之前快取

11. git checkout .         // (有個點) 撤銷當前所有的修改
   git checkout test.txt  // 撤銷具體檔案的修改

12. git add .		  // (有個點) 表示添加當前目錄下的所有檔案和子目錄(或git add -A)
    git add test.txt  // 添加具體檔案(test.txt)

13. git commit -m 'test' // 將檔案上傳至遠程 master 分支并添加備注"test"

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

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主機,同時指定origin為默認主機,后面就可以不加任何引數使用git push了,
	git push // 設定默認主機后(git push -u origin master)可簡寫

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

2. 瀏覽器

瀏覽器從輸入URL到渲染完頁面的整個程序

  1. 獲取IP地址
  2. TCP/IP三次握手建立連接
  3. 瀏覽器向web服務器發送http請求
  4. 瀏覽器渲染
  5. 四次揮手斷開連接

瀏覽器渲染程序

  1. DOM 樹:決議 HTML 構建 DOM(DOM 樹)
  2. CSS 樹:決議 CSS 構建 CSSOM(CSS 樹)
  3. 渲染樹:CSSOM 和 DOM 一起生成 Render Tree(渲染樹)
  4. 布局(layout):根據Render Tree瀏覽器就知道網頁中有哪些節點,以及各個節點與 CSS 的關系,從而知道每個節點的位置和幾何屬性(重排)
  5. 繪制(Paint):根據計算好的資訊繪制整個頁面(重繪)

3. 其他

yarn

gulp

babel

vConsole


Vue

vue 3.0 超詳細入門教程

1. MVVM

對MVVM的理解

MVVM 分為 ModelViewViewModel 三者:

  • Model資料層,資料和業務邏輯都在Model層中定義,
  • View視圖層,也就是用戶界面,負責資料的展示,
  • ViewModel視圖資料層, ViewModel層通過雙向資料系結將View層和Model層連接了起來(View和Model層的橋梁),使得View層和Model層的同步作業完全是自動的,
    在這里插入圖片描述
    Model和View并無直接關聯,而是通過ViewModel這個橋梁來進行聯系的,ViewModel就是View與Model的連接器,View與Model通過ViewModel實作雙向系結,

2. 生命周期

Vue2生命周期

  1. beforeCreate:創建之前eldatamessage都還是undefined,不可用的)
  2. created:創建完畢(能讀取到資料data的值,但是DOM還沒生成)
  3. beforeMount:掛載之前(生成DOM,但此時{{ message }}還沒有掛載data中的資料)
  4. mounted:掛載完畢{{ message }}已經成功掛載渲染data的值)
  5. beforeUpdate:更新之前
  6. updated:更新完畢
  7. beforeDestroy:銷毀之前
  8. destroyed:銷毀完畢(實體與視圖的關系解綁,再修改message的值,視圖再也不會更新了)
  9. activated:keep-alive 組件激活時呼叫
  10. deactivated:keep-alive 組件停用時呼叫

注:

  • activateddeactivated 是比較特殊的兩個鉤子,需要keep-live配合使用
  • 當引入 keep-alive 的時候,頁面第一次進入,鉤子的觸發順序 created => mounted => activated,退出時觸發 deactivated,當再次進入(前進或者后退)時,只觸發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(計算屬性)

  1. 屬性的結果會被快取(默認走快取),當computed中的函式所依賴的屬性沒有發生改變的時候,那么呼叫當前函式的時候結果會從快取中讀取,除非依賴的回應式屬性變化時才會重新計算;
  2. 不支持異步,當computed內有異步操作時無效,無法監聽資料的變化;
  3. computed中的函式必須用return回傳最終的結果,computed更高效,優先使用;
  4. 當一個屬性受多個屬性影響的時候,一般用computed(例如:詳細地址 = 省+市+區+街道+樓棟+房號 );

watch(監聽屬性)

  1. 不支持快取,資料變,直接會觸發相應的操作;
  2. 支持異步
  3. 監聽的函式接收兩個引數,第一個引數是最新的值(newVal);第二個引數是輸入之前的值(oldVal);
  4. 當一條資料影響多條資料的時候,一般使用watch(例如:搜索資料(異步) ,觸發一系列資料的變化);

4. v-if 與 v-show

v-if

  1. 是通過控制 DOM 元素的存在與否來控制元素的顯隱;
  2. 切換時,是對 DOM 元素進行一個創建和銷毀的動作
  3. 惰性的,如果初始條件為假,則什么也不做;只有在條件第一次變為真時才開始區域編譯;
  4. 有更高的切換消耗;

v-show

  1. 是通過設定 DOM 元素的 display 樣式,block 為顯示,none 為隱藏;
  2. 切換時,只是簡單的基于CSS切換
  3. 是在任何條件下(首次條件是否為真)都被編譯,然后被快取,而且 DOM 元素保留;
  4. 有更高的初始渲染消耗;

基于以上區別,因此,如果需要非常頻繁地切換,則使用 v-show 較好如果在運行時條件很少改變,則使用 v-if 較好


5. data 必須是一個函式,而不是物件

如果 Vue 組件中的 data 是個物件,那么就像所有復用這個組件的地方,都在使用這個組件里面唯一的一個 data,所有使用組件的地方的 data 都會指向堆疊內這一個 data 的地址,那么會造成一個改 data 的值,所有其他組件的 data 都會被改變,

如果在函式中回傳一個物件,那么在每次創建一個組件的時候,每次回傳的都是一個新物件(Object的實體),在記憶體中同時開辟一塊空間給當前組件存放 data ,這樣就不會出現共用一個 data 的現象


6. diff 演算法

Vue中的diff演算法

diff 演算法是一種優化手段,比如有時候我們修改了某個資料,如果直接渲染到真實 DOM 上會引起整個 DOM 樹的重繪和重排,這樣開銷是非常大的,

我們可以先根據真實 DOM 生成一棵虛擬DOM(virtual DOM)樹,當虛擬DOM某個節點的資料改變后,會生成一個新的 Vnode(虛擬節點),然后 VnodeoldVnode 作對比,發現有不一樣的地方就直接修改在真實的 DOM 上,然后使 oldVnode 的值為Vnode,此時我們只更新我們修改的那一小塊 DOM,而不要更新整個 DOM,

diff的程序就是呼叫patch函式,比較新舊節點,一邊比較一邊給真實的DOM打補丁,
在采取 diff 演算法比較新舊節點的時候,比較只會在同層級進行, 不會跨層級比較,
在這里插入圖片描述
概括起來就是:對操作前后的 DOM 樹同一層的節點進行對比,一層一層對比,然后再插入真實的dom中,重新渲染,


7. for 回圈中 key 的作用

vue中串列回圈需加 :key="唯一標識", 唯一標識可以是 item 里面 idindex 等,

  • key 的作用主要是為了更高效的對比虛擬DOM中每個節點是否是相同節點;
  • Vue 在 patch 程序中判斷兩個節點是否是相同節點, key 是一個必要條件,渲染一組串列時,key往往是唯一標識,所以如果不定義 key 的話,Vue 只能認為比較的兩個節點是同一個,哪怕它們實際上不是,這導致了頻繁更新元素,使得整個 patch 程序比較低效,影響性能;
  • 從原始碼中可以知道,Vue 判斷兩個節點是否相同時主要判斷兩者的 key 和元素型別等,因此如果不設定 key ,它的值就是undefined,則可能永遠認為這是兩個相同的節點,只能去做更新操作,這造成了大量的 DOM 更新操作,明顯是不可取的,

不建議 用 index 作為 key,和沒寫基本上沒區別,因為不管你陣列的順序怎么顛倒,index 都是 0, 1, 2 這樣排列,導致 Vue 會復用錯誤的舊子節點,做很多額外的作業


8. 雙向系結

當一個Vue實體創建時,Vue會遍歷 data 選項的屬性,利用 Object.defineProperty 將它們轉為 getter/setter 并且在內部追蹤相關依賴,在屬性被訪問和修改時通知變化,每個組件實體都有相應的 watcher 程式實體,它會在組件渲染的程序中把屬性記錄為依賴,之后當依賴項的 setter 被呼叫時,會通知 watcher 重新計算,從而致使它關聯的組件得以更新,

在這里插入圖片描述
極簡版雙向系結:

<input type="text" id="input" value="">
<span id="span"></span>
<script>
    let obj = {}
    Object.defineProperty(obj, 'text', { // 監聽obj的text屬性
        set(newVal = '') {
            document.getElementById('input').value = https://www.cnblogs.com/bingcola/p/newVal;
            document.getElementById('span').innerHTML = newVal;
        }
    });

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

v-model

vue 中雙向系結是一個指令v-model,可以系結一個動態值到視圖,同時視圖中變化能改變該值,

v-model 是語法糖,默認情況下相于:value@input

<template>
    <div id="app">
        {{username}} <br />
        <input type="text" v-model="username"></input>
        <!-- 等價于 -->
        <input type="text" :value="https://www.cnblogs.com/bingcola/p/username" @input="username=$event.target.value">
    </div>
</template>

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

9. 組件的通信

Vue組件通信方式總結

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

<div id="app">
	<!-- 1.通過 v-bind 將資料傳給子組件 -->
    <test :ss='name'></test>
</div>

<script>
    var a = new Vue({
        el:'#app',
        data:{
            name:'bing',
        },
        components: {
        	// 子組件<test>
            test:{
                props: ['ss'],   // 2.接收父組件傳遞過來的資料
                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: '子組件的資料'
            } 
        },
        methods: {
            increment: function () {
            	// 通過 $emit 定義一個自定義事件 increment ,同時傳入 this.counter 引數,對外拋出
                this.$emit('increment', this.counter); // 步驟2
            }
        }
    });


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

兄弟組件傳值(EventBus)

  1. 新創建一個 event-bus.js 檔案
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue();
  1. A 頁面發送資料
<!-- A.vue -->
<template>
    <button @click="sendMsg()">-</button>
</template>

<script> 
import { EventBus } from "../event-bus.js";
export default {
  methods: {
    sendMsg() {
      EventBus.$emit("aMsg", '來自A頁面的訊息'); // 對外發送資料
    }
  }
}; 
</script>
  1. B 頁面接收資料
<!-- 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 發送來的訊息
			this.msg = msg;
		});
	}
};
</script>
  1. 移除事件監聽
import { EventBus } from "../event-bus.js";
EventBus.$off('aMsg', {}); // 移除應用內所有對此某個事件的監聽
// 或
EventBus.$off(); // 移除所有事件監聽

Vuex

vuex詳解

  • state:定義了應用狀態的資料結構,可以在這里設定默認的初始狀態,
  • getter:可以認為是 store 的計算屬性(有快取,只有當它的依賴值發生了改變才會被重新計算),
  • mutation:是唯一更改 store 中狀態的方法,且必須是同步函式,
  • action:用于提交 mutation(再由mutation更改 store 中狀態),而不是直接變更狀態,可以包含任意異步操作,
  • module:可以將 store 分割成模塊(module),每個模塊擁有自己的 statemutationactiongetter、甚至是嵌套子模塊

基本用法:

//創建一個 store
const store = new Vuex.Store({
    //state存盤應用層的狀態
    state: {
        count: 5 // 組件中通過 this.$store.state.count; 獲取
    },
    getters: {
        newCount: state => state.count * 3 // 組件中通過 this.$store.getters.newCount; 獲取
    },
    // mutations是修改state中資料的唯一途徑
    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 的狀態
store.state.b // -> moduleB 的狀態

10. 路由

Vue路由導航 router-link 和 router.push

1. 不攜帶引數

// 字串
<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 攜帶引數:

  1. 地址欄變成 /login?color=red
  2. 可通過 {{$route.query.color}}this.$route.query.color 獲取引數
<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 攜帶引數:

  1. 地址欄變成 /login/red
  2. 可通過 {{$route.params.color}}this.$route.params.color 獲取引數
// 無法獲取引數  
// 報警告(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 獲取引數,
<router-link :to="{name: 'Login', params: { color: 'red' }}"> to login</router-link>

此時 router.js 中需要設定 path: '/login/:color?'

// router.js

var router = new Router({
routes: [{
	path: '/login/:color?', //  :color? => ?問號的意思是該引數不是必傳項,不傳不會報錯
	name: 'Login',
	component: Login
}]

router.push

1. 不攜帶引數

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

// 物件
router.push({path:'/login'})

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

2. 通過 query 攜帶引數:

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

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

3. 通過 params 攜帶引數:

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

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

$router 和 $route 的區別

  1. $router :是指整個路由實體,你可以操控整個路由,用法如下:
    this.$router.go(-1);  // 向前或者向后跳轉n個頁面,n可為正整數或負整數
    this.$router.push('/'); // 跳轉到指定url路徑,history堆疊中會有記錄,點擊回傳會跳轉到上個頁面
    this.$router.replace('/'); // 跳轉到指定url路徑,但是history堆疊中不會有記錄,點擊回傳會跳轉到上上個頁面
    
  2. $route:是指當前路由實體$router跳轉到的路由物件;路由實體可以包含多個路由物件,它們是父子包含關系
    // 獲取路由傳遞過來的引數
    this.$route.params.userId  
    this.$route.query.userName 
    

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

router.js相關配置

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,不需要做鑒權處理
        }
    },
    {
        path: '/test',
        name: 'test',
        component: () => import('./views/Test.vue'),// vue路由懶加載  異步加載
        meta: {
            title: 'test',
            requireAuth: true // 只要此欄位為true,必須做鑒權處理
        }
    },
    {
        path: '/login',
        name: 'login',
        component: () => import('./views/Login.vue'),// vue路由懶加載  異步加載
        meta: {
            noNav: true // 不顯示nav
        }
    }]
});

let indexScrollTop = 0;

router.beforeEach((to, from, next) => {
    // 路由鑒權:在路由meta物件中由個requireAuth欄位,只要此欄位為true,必須做鑒權處理
    if (to.matched.some(res => res.meta.requireAuth)) {
        const token = getStore({ name: 'access_token', type: "string" });// 獲取localstorage中的access_token
        console.log(token);
        // 路由進入下一個路由物件前,判斷是否需要登陸
        if (!token) {
            // 未登錄
            next({
                path: '/login',
                query: {
                    redirect: to.path // 將跳轉的路由path作為引數,登錄成功后再跳轉到該路由
                }
            })
        } else {
            // 用戶資訊是否過期
            let overdueTime = token.overdueTime;
            let nowTime = +new Date();
            // 登陸過期和未過期
            if (nowTime > overdueTime) {
                // 登錄過期的處理,君可按需處理之后再執行如下方法去登錄頁面
                // 我這里沒有其他處理,直接去了登錄頁面
                next({
                    path: '/login',
                    query: {
                        redirect: to.path
                    }
                })
            } else {
                next()
            }
        }
    } else {
        next()
    }
    if (to.path !== '/') {
        // 記錄現在滾動的位置
        indexScrollTop = document.body.scrollTop
    }
    document.title = to.meta.title || document.title
})

router.afterEach(route => {
    if (route.path !== '/') {
        document.body.scrollTop = 0
    } else {
        Vue.nextTick(() => {
            // 回到之前滾動位置
            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中CompositionAPI

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

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/296359.html

標籤:JavaScript

上一篇:滲透測驗帶防御的內網域

下一篇:vue-router各個屬性的作用及用法

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more