==面試題 ##1.vue2中的響應式原理簡述 響應式原理主要就是通過數據劫持,依賴收集,派發更新的方式來實現的 1.數據劫持,vue2是通過Object.defineProperty方法的get、set來將對對象進行遞歸劫持。 其中修改對象的屬性時 就會觸發set, 使用對象的屬性時就會觸發get ...
==面試題
1.vue2中的響應式原理簡述
響應式原理主要就是通過數據劫持,依賴收集,派發更新的方式來實現的
1.數據劫持,vue2是通過Object.defineProperty方法的get、set來將對對象進行遞歸劫持。
其中修改對象的屬性時 就會觸發set, 使用對象的屬性時就會觸發get
2.依賴收集(觀察者模式)。使用watcher
進行觀察數據使用的地方
3.派發更新(發佈訂閱模式):使用dep
收集watcher
,數據更改時,通過notify
方法通知dep
里的watcher
去進行相應的更新
使用Object.defineProperty做響應式的缺點有三點
1.深度監聽,不管數據用不用都會需要一次性遞歸到底,計算量比較大,會造成性能浪費。
2.描述符只有get和set,無法監聽新增屬性和刪除屬性的操作
3.數組沒有使用劫持的模式,而是通過重寫數組原型上的方法,來實現數組的響應式
這三個缺點中,第二點是defineProperty本身API的缺陷,而第一點和第三點都是出於性能考慮而做的取捨
解決缺點的方法:
當我們通過數組的方法去更改數組時或是直接刪除data數據,數據並不能實現響應式,因為Object.defineProperty是沒有辦法處理屬性刪除和新增的
因此vue2的響應式,通過數組方法(pop,push),或是刪除,vue是不能監聽的
vue2中通過vue2中可以通過vue.datele和vue.set這些vue內置api來改變屬性,實現響應式。
1.1為什麼只對對象劫持,而要對數組進行方法重寫?
數組的元素大概率是成百上千的,所以對數組下標進行劫持的話會非常消耗性能。Vue通過對數組原型上方法的重寫,實現數組的響應式
2.vue自定義指令介紹:
通過 Vue.directive 進行自定義指令的定義
指令的註冊方式和「過濾器」「混入」「組件」註冊的方式一樣都分為兩種:一是全局註冊,二是局部註冊。,先介紹自定義指令的鉤子函數.
(1)自定義指令的鉤子函數
Vue 提供了自定義指令的5個鉤子函數:
bind:指令第一次綁定到元素時調用,只執行一次。在這裡可以進行一次性的初始化設置。
inserted:被綁定的元素,插入到父節點的 DOM 中時調用(僅保證父節點存在)。
update:組件更新時調用。
componentUpdated:組件與子組件更新時調用。
unbind:指令與元素解綁時調用,只執行一次。
註意:
1.除 update 與 componentUpdated 鉤子函數之外,每個鉤子函數都含有 el、binding、vnode 這三個參數
2.在每個函數中,第一個參數永遠是 el, 表示被綁定了指令的那個 dom 元素,這個el 參數,是一個原生的 JS 對象,所以 Vue 自定義指令可以用來直接和 DOM 打交道
3.binding 是一個對象,它包含以下屬性:name、value、oldValue、expression、arg、modifiers
4.oldVnode 只有在 update 與 componentUpdated 鉤子中生效
5.除了 el 之外,binding、vnode 屬性都是只讀的
1.2生命周期
- 常用:4個階段,8個鉤子函數,已經父子組件生命周期的順序
beforeCreate() :組件已創建,數據觀測,
created():數據方法已掛載,作用:常用於發送請求
beforeMount() :dom掛在前
mounted():dom已掛載 ,作用:常用於放入操作dom的方法、
註:created()中也可以通過$nextTick()操作dom
beforeUpdate():更新階段,當數據變了,頁面沒變 (後數據驅動數據改變)
updated():數據頁面已經更新
beforeDestory():銷毀前
destoryed():銷毀後
可銷毀在window相關的掛載,如定時器,window事件,即定時器事件需在該階段銷毀
父子組件更新銷毀階段:
-
子有用父的數據: 父beforeUpdate > 子beforeUpdate > 子updated() > 父updated()
-
子沒用父:父自己更新
銷毀階段相同
父子組件創建掛載階段:
- 父beforeCreate > 父created > 父beforeMount >子beforeCreate > 子created > 子beforeMount > 子mounted > 父mounted
不常用的生命周期3個:
activated
:keep-alive所緩存組件激活時調用deactivated
:keep-alive所緩存組件停用時調用errorCaptured
:子孫組件的錯誤捕獲,此函數可返回false阻止繼續向上傳播
3.介紹 v-if/v-show
v-if和v-show的效果都是實現dom元素的顯隱,實現原理不同,v-if是通過移除或添加dom元素實現的,如果是組件會觸發生命周期,不適用於頻繁切換顯隱的場景;v-show是通過樣式的display:none/block來實現元素顯隱的,適用於頻繁切換顯隱的功能場景
4.vue組件的data 為什麼必須是一個函數
組件實例對象data必須為函數,目的是為了防止多個組件實例對象之間共用一個data,產生數據污染。因為當data是函數時,當每次組件實例化的時候這個函數將會被調用,返回一個新對象,電腦會給這個對象分配一個新的記憶體地址,所以各個組件的數據地址都不一樣,即每個組件中的數據不會相互干擾,也就是為了保證組件的獨立性和可復用性,如果data是個函數的話,每復用一次組件就會返回新的data,類似於給每個組件實例創建一個私有的數據空間,保護各自的數據互不影響
5.call/apply/bind作用和區別
1.call和apply 可以立即調用函數,this指向他們的第一個形參
2.bind 不能調用函數,會返回一個新函數,以後調用了才會執行,this指向他的第一個形參。
3.call和apply 作用類似,都可以改變指針和執行函數,區別在於傳參不同,call 需要單個傳參,apply 通過數組傳參
fucntion.call(thisArg, arg1, arg2, ...)
function.apply(thisArg, [arg1, arg2, ...])
fucntion.bind(thisArg, arg1, arg2, ...)
6.閉包是什麼
閉包:在JS中,局部變數即函數內的定義的變數,在函數執行完畢之後,局部變數作用域會被銷毀、記憶體也會被回收,但由於閉包在函數內部創建一個子函數,且子函數可訪問父函數中的作用域/變數(即持有引用,作用域內的變數不會被回收),即使父函數執行完,作用域也不會被銷毀,這就是閉包,而且閉包引用的變數是存於堆記憶體中
閉包作用:可以阻止變數被回收,數據私有化,防止污染全局
缺點:比普通函數更占用記憶體,因為閉包的數據沒有被回收,可能會造成記憶體泄漏
閉包作用:可以防止變數被回收,令數據私有化,延伸變數的作用範圍
閉包案例:迴圈註冊點擊事件,防抖節流
7.原型、原型鏈介紹
-
原型
每一個構造函數都有一個prototype屬性,指向另一個對象,構造函數通過原型分配的函數是所有對象所共用的。由於在構造函數中定義的方法在創建實例時,都會開闢一個新的記憶體從而造成記憶體浪費的問題,這時我們就可以把那些不變的方法直接定義在prototype對象上,這樣所有的對象的實例就可以共用這些方法。
-
對象原型_____proto_____
對象都會有一個_____proto_____屬性,指向構造函數的prototype原型對象,之所以我們對象可以使用原型對象的屬性和方法,就是因為對象有_____proto_____原型的存在。
①實例.__proto__和構造函數.prototype是等價的
②方法的查找規則:首先看實例對象上是否存在這個方法,如果存在就調用實例本身的方法,如果沒有就去構造函數原型對象上去查找,如果還是沒有就繼續向Object.prototype中查找,直到返回null (就近原則)
③__proto__對象原型的意義就在於為對象的查找機制提供一個方向,它是一個非標準屬性,因此實際開發中不可以使用這個屬性,它只是內部指向原型對象。
-
constructor構造函數
對象原型和構造函數原型對象裡面都有一個屬性:constructor。我們稱為構造函數,因為它指回構造函數本身。
而__proto__原型的constructor也是同樣指向的是構造函數,是通過 實例.proto 先指向原型對象然後再 通過 constructor指向構造函數
很多情況下,我們需要手動的利用constructor這個屬性指回原來的構造函數,例如,我們修改了原來的原型對象,給原型對象賦值的是一個對象,那麼就必須手動的利用constructor指回原來的構造函數。在對象中寫:constructor:目標構造函數。
-
原型鏈
①只要是對象就有__proto__原型,指向原型對象
②實例的原型對象裡面的proto原型指向的是Object.prototype
③Object.prototype裡面的proto原型指向的是null
④由__proto__原型連接而成的'鏈子'就是原型鏈
8.繼承方法有哪些?
- 原型鏈繼承
核心:將父類的實例作為子類的原型。
優點:父類方法可以復用。
缺點:
-
父類的引用屬性會被所有子類實例共用
-
子類構建實例時不能向父類傳遞參數
SubType.prototype = new SuperType()
// 所有涉及到原型鏈繼承的繼承方式都要修改子類構造函數的指向,否則子類實例的構造函數會指向SuperType。
SubType.prototype.constructor = SubType;
- 構造函數繼承
核心:將父類構造函數的內容複製給了子類的構造函數。這是所有繼承中唯一一個不涉及到prototype的繼承。
優點:和原型鏈繼承完全反過來
- 父類的引用屬性不會被共用
- 子類構建實例時可以向父類傳遞參數 -
缺點:父類的方法不能復用,子類實例的方法每次都是單獨創建的。
SuperType.call(SubType);
- 組合繼承
核心:原型式繼承和構造函數繼承的組合,兼具了二者的優點。
優點:
- 父類的方法可以被覆用
- 父類的引用屬性不會被共用
- 子類構建實例時可以向父類傳遞參數
缺點:
- 調用了兩次父類的構造函數,第一次給子類的原型添加了父類的name, arr屬性,第二次又給子類的構造函數添加了父類的name, arr屬性,從而覆蓋了子類原型中的同名參數。這種被覆蓋的情況造成了性能上的浪費。
-
ES6 Class extends
核心: ES6繼承的結果和寄生組合繼承相似,本質上,ES6繼承是一種語法糖。但是,寄生組合繼承是先創建子類實例this對象,然後再對其增強;而ES6先將父類實例對象的屬性和方法,加到this上面(所以必須先調用super方法),然後再用子類的構造函數修改this。
ES6繼承與ES5繼承的異同:
相同點:本質上ES6繼承是ES5繼承的語法糖。
不同點:
- ES6繼承中子類的構造函數的原型鏈指向父類的構造函數,ES5中使用的是構造函數複製,沒有原型鏈指向。
- ES6子類實例的構建,基於父類實例,ES5中不是。
9.token過期
- 前端主動處理(為什麼前端去處理?優先前端,如果已經判斷過期,不用發請求,可以較少網路請求)
- 藉助時間戳登錄成功存token的時間戳, 發請求時當前時間戳,當前時間戳 - 存token的時間戳 > token過期的時間
- 前端被動處理, 後端主動處理 , 根據後端的同學返回的code 處理
思考一下:如果該token過期,直接退出,跳轉到登錄頁,交互好嗎??
解決方案:refresh_token
token一般過期時間為2小時,refresh_token,過期時間較長(一周-兩周)
token過期後, 我們在背後(用戶不知情的情況下),偷偷的發送一個請求獲取新的token, 通過refresh_token進行換取,登錄狀態就可以維持一周-兩周,如果refresh_token也過期,跳到登錄頁
無感刷新: 更新token過程中如果有多個請求併發,可以第一個節流閥,並可先將請求介面配置項用數組存起來,待獲取新的token後面在重新發送,從而實現無感刷新,如果只有一個請求的話,獲取token後直接請求即可(return request(error.config))
let isRefreshing = false // 標記是否正在刷新 token
let requests = [] // 存儲待重發請求的數組
// 響應攔截器(更新token)
request.interceptors.response.use(
// 響應成功進入第1個函數
function (response) {
return response
},
// 響應失敗進入第2個函數,該函數的參數是錯誤對象
async function (error) {
// 如果響應碼是 401 ,則請求獲取新的 token
// 響應攔截器中的 error 就是那個響應的錯誤對象
console.dir(error.response)
if (error.response.status === 401) {
// 校驗是否有 refresh_token
const tokenObj = store.state.tokenObj
if (!tokenObj || !tokenObj.token || !tokenObj.refresh_token) {
router.push('/login')
// 代碼不要往後執行了
}
// 如果有refresh_token,則請求獲取新的 token
if (!isRefreshing) {
isRefreshing = true
try {
const res = await request({
method: 'POST',
url: '/v1_0/authorizations',
headers: {
Authorization: `Bearer ${tokenObj.refresh_token}`
},
data: {
code: '246810',
mobile: '18270164361'
}
})
// 如果獲取成功,則把新的 token 更新到容器中
console.log('刷新 token 成功', res)
store.commit('setUser', {
token: res.data.data.token, // 最新獲取的可用 token
refresh_token: tokenObj.refresh_token // 還是原來的 refresh_token(如果用新refresh_token的就永遠不會失效了)
})
// 把之前失敗的用戶請求繼續發出去
// config 是一個對象,其中包含本次失敗請求相關的那些配置信息,例如 url、method 都有
// return 把 request 的請求結果繼續返回給發請求的具體位置
const { token } = res.data.data
//依次請求上次因token過期請求失敗的介面
requests.forEach((cb) => cb(token))
requests = [] // 重新請求完清空
//請求第一個失敗的介面
return request(error.config)
} catch (err) {
// 如果獲取失敗,直接跳轉 登錄頁
console.log('請求刷線 token 失敗', err)
router.push('/login')
} finally {
isRefreshing = false
}
} else {
return new Promise(resolve => {
// 用函數形式將 resolve 存入,等待刷新後再執行
//儲存請求失敗的介面
requests.push(token => {
error.config.headers.Authorization = `Bearer ${token}`
resolve(request(error.config))
})
})
}
}
return Promise.reject(error)
}
)
export default request
10.vue watch偵聽屬性
作用:可以偵聽data/computed/prop屬性值改變, 併進行相關操作
註意點:數組的變化不需要深度監聽,在watch中不要使用箭頭函數,因為箭頭函數中的this是指向當前作用域
computed和watch之間的區別:
1.computed能完成的功能,watch都可以完成。
2.watch能完成的功能,computed不一定能完成,例如:watch可以進行非同步操作。
用法:
-
簡寫函數形式:"被偵聽的屬性名" (newVal, oldVal){... //newVal 是改變之後的值 oldVal 是改變之前的值 }
-
深度監聽對象寫法:"要偵聽的屬性名": { immediate: true, // 組件創建時立即執行一次監聽 deep: true, // 深度偵聽複雜類型內變化 handler (newVal, oldVal) {... }//觸發函數
註:如果對象的屬性較多,也可用簡寫形式監聽函數內某個屬性,寫法:'msg.count'(val, oldval) {...}
11.computed計算屬性
作用:當要用的屬性不存在,且可以通過已有屬性計算得來時,可以用到計算屬性
原理:底層藉助了Objcet.defineproperty方法提供的getter和setter實現的。即初次執行通過get屬性獲取
優勢:1. 與methods實現相比,計算屬性是依賴其他數據的,生成的數據放在緩存中,不像方法要每次要調用,直接從緩存取值,效率更高,調試方便。2. 依賴項值-變化, 函數會"自動"重新執行-並緩存新的值。
12.垃圾回收GC
定義:js 的記憶體是自動進行分配和回收的,記憶體在不使用的時候會被垃圾回收器自動進行回收,但是我們需要瞭解垃圾回收的機制,從而防止記憶體泄漏(記憶體無法被回收)。
通常情況下有兩種實現方式:引用計數,標記清除
- ie瀏覽器通過引用計數判斷記憶體是否需要被回收,即判斷當前記憶體在上下文引用計數為0時則需要銷毀釋放記憶體。其特點簡單有效,缺點是當記憶體變數存在互相迴圈引用時,引用計數不為0從而導致記憶體泄露,
- 現在的瀏覽器使用標記清除方式進行垃圾回收,標記就是通過根節點(全局),標記所有從根節點開始的能夠訪問到的對象。未被標記的對象就是未被全局引用的垃圾對象。最終清除所有未被標記的對象
註:根節點不是指window,還包括不在window中被const和let聲明的記憶體。
13.http 緩存 (協商緩存和強緩存)
http緩存指的是: 當客戶端向伺服器請求資源時,會先抵達瀏覽器緩存,如果瀏覽器有“要請求資源”的副本,就可以直接從瀏覽器緩存中提取而不是從原始伺服器中提取這個資源。常見的http緩存只能緩存get請求響應的資源。http緩存都是從第二次請求開始的。第一次請求資源時,伺服器返回資源,併在respone header頭中回傳資源的緩存參數;第二次請求時,瀏覽器判斷這些請求參數,命中強緩存就直接200,否則就把請求參數加到request header頭中傳給伺服器,看是否命中協商緩存,命中則返回304,否則伺服器會返回新的資源。
http緩存的分類
根據是否需要重新向伺服器發起請求來分類,可分為(強制緩存,協商緩存) 根據是否可以被單個或者多個用戶使用來分類,可分為(私有緩存,共用緩存) 。強制緩存如果生效,不需要再和伺服器發生交互,而協商緩存不管是否生效,都需要與服務端發生交互。
-
強緩存
強緩存簡單理解就是:給瀏覽器緩存設置過期時間,超過這個時間之後緩存就是過期,瀏覽器需要重新請求。存放的位置是由瀏覽器控制的(存在硬碟或記憶體中)。是否強緩存由 Expires、Cache-Control 和 Pragma 3 個 Header請求頭 屬性共同來控制。但是強制緩存存在一個問題,該緩存方式優先順序高,如果在過期時間內緩存的資源在伺服器上更新了,客服端不能及時獲取最新的資源。這時怎麼辦?於是就有了協商緩存.
這種方式頁面的載入速度是最快的,性能也是很好的,但是在這期間,如果伺服器端的資源修改了,頁面上是拿不到的,因為它不會再向伺服器發請求了。
這種情況就是我們在開發種經常遇到的,比如你修改了頁面上的某個樣式,在頁面上刷新了但沒有生效,因為走的是強緩存,所以Ctrl + F5一頓操作之後就好了。 跟強制緩存相關的header頭屬性有(Cache-Control/Expires), 當 cache-control 和 expires 同時存在 cache-control 的優先順序會比 expires 高
總結: 不向服務端發送請求,強制使用緩存數據
-
協商緩存
當第一次請求時伺服器返回的響應頭中沒有Cache-Control和Expires或者Cache-Control和Expires過期還或者Cache-Control的屬性設置為no-cache時(即不走強緩存),那麼瀏覽器第二次請求時就會與伺服器進行協商,與伺服器端對比判斷資源是否進行了修改更新。如果伺服器端的資源沒有修改,那麼就會返回304狀態碼,告訴瀏覽器可以使用緩存中的數據,這樣就減少了伺服器的數據傳輸壓力。如果數據有更新就會返回200狀態碼,伺服器就會返回更新後的資源並且將緩存信息一起返回。跟協商緩存相關的header頭屬性有(ETag/If-Not-Match 、Last-Modified/If-Modified-Since)請求頭和響應頭需要成對出現。
總結:當強緩存失效後,會使用協商緩存,協商緩存由伺服器決定是否使用緩存
14.http常用狀態碼
一、1開頭的狀態碼(信息類)
100,接受的請求正在處理,信息類狀態碼
二、2開頭的狀態碼(成功類)
2xx(成功)表示成功處理了請求的狀態碼
200(成功,命中強緩存)伺服器已成功處理了請求。
三、3開頭的狀態碼(重定向)
3xx(重定向)表示要完成請求,需要進一步操作。通常這些狀態代碼用來重定向。
301,永久性重定向,表示資源已被分配了新的 URL
302,臨時性重定向,表示資源臨時被分配了新的 URL
303,表示資源存在另一個URL,用GET方法獲取資源
304,(未修改命中協商緩存)自從上次請求後,請求網頁未修改過。伺服器返回此響應時,不會返回網頁內容
四、4開頭的狀態碼(客戶端錯誤)
4xx(請求錯誤)這些狀態碼表示請求可能出錯,妨礙了伺服器的處理
400(錯誤請求)伺服器不理解請求的語法
401表示發送的請求需要有通過HTTP認證的認證信息
403(禁止)伺服器拒絕請求(沒有許可權)
404(未找到,頁面失效)伺服器找不到請求網頁
405 請求方式錯誤 是get卻用來post
五、5開頭的狀態碼(伺服器錯誤)
5xx(伺服器錯誤)這些狀態碼表示伺服器在嘗試處理請求時發生內部錯誤。這些錯誤可能是伺服器本身的錯誤,而不是請求的錯誤
500,(伺服器內部錯誤)伺服器遇到錯誤,無法完成請求
503,表示伺服器處於停機維護或超負載,無法處理請求
15.什麼是防抖和節流
-
節流: n 秒內只運行一次,若在 n 秒內重覆觸發,只有一次生效
-
防抖: n 秒後在執行該事件,若在 n 秒內被重覆觸發,則重新計時
相同點:
- 都可以通過使用
setTimeout
實現 - 目的都是,降低回調執行頻率。節省計算資源
不同點:
- 函數防抖,在一段連續操作結束後,處理回調,利用
clearTimeout
和setTimeout
實現。函數節流,在一段連續操作中,每一段時間只執行一次,頻率較高的事件中使用來提高性能 - 函數防抖關註一定時間連續觸發的事件,只在最後執行一次,而函數節流一段時間內只執行一次
- 都可以通過使用
-
應用場景
- 防抖在連續的事件,只需觸發一次回調的場景有:
- 搜索框搜索輸入。只需用戶最後一次輸入完,再發送請求
- 手機號、郵箱驗證輸入檢測
- 視窗大小
resize
。只需視窗調整完成後,計算視窗大小。防止重覆渲染。
- 節流在間隔一段時間執行一次回調的場景有:
- 滾動載入,載入更多或滾到底部監聽
- 搜索框,搜索聯想功能
- 防抖在連續的事件,只需觸發一次回調的場景有:
16.Vue-router的三種模式
1、hash:#後面是路由路徑,特點是前端訪問,#後面的變化不會經過伺服器,使用URL的hash來模擬一個完整的URL,當URL發生改變時,頁面不會重新載入,其顯示的網路路徑中會有#號,這是最安全的模式,因為他相容所有的瀏覽器和伺服器
2、history:正常的/訪問模式,特點是後端訪問,任意地址的變化都會訪問伺服器。美化後的hash模式,路徑中會去掉#。依賴於html5的history,pushState API,所以要擔心IE9及以下的版本。並且還包括back、forward、go三個方法,對應瀏覽器的後退、前進、跳轉操作,就是瀏覽器左上角的前進後退等按鈕進行的操作
3、abstract:適用於所有JavaScript環境,例如伺服器端使用Node.js。如果沒有瀏覽器API,路由器將自動被強制進入此模式,然後在const router = new VueRouter({routes, mode:'hash|history|abstract',})
這裡進行切換
總結:
1:hash模式(vue-router預設模式URL後面帶#)使用URL的hash值來作為路由,支持所有瀏覽器 缺點:只能改變#後面的來實現路由跳轉。
2:history模式(通過mode: 'history’來改變為history模式)HTML5 (BOM)History API 和伺服器配置 缺點:怕刷新如果後端沒有處理這個情況的時候前端刷新就是實實在在的請求伺服器這樣消耗的時間很多還很慢。
17.js事件迴圈機制
是什麼:簡單的說,在js代碼執行時,同步任務進入主線程,即主執行棧,非同步任務進入任務隊列,主線程內的任務執行完畢為空時,會去任務隊列讀取對應的任務,推入主線程執行。上述過程的不斷重覆的也稱為事件迴圈eventloop
作用:將js分成同步任務和非同步任務執行,防止耗時任務造成阻塞
註:同步任務和非同步任務(es5之前無非同步,es5之後有promise才能發起非同步任務)
為了防止某個耗時任務導致程式假死的問題,Javascript 把待執行的任務分為了兩類:
同步任務 (synchronous)
又叫做非耗時任務,指的是在主線程上排隊執行的那些任務,它的執行順序是,只有前一個任務執行完畢,才能執行後一個任務
非同步任務 (asynchronous)
又叫做耗時任務,它執行機制的是這樣的,首先非同步任務由 JavaScript 委托給宿主環境(瀏覽器)進行執行,完成的非同步任務對應的回調函數後,會被加入到任務隊列中等待執行,當JavaScript 主線程的執行棧被清空,也就是同步任務都執行完後,會讀取任務隊列中的回調函數,按次序執行,另外這個JavaScript 主線程從“任務隊列”中讀取非同步任務的回調函數,在放到執行棧中依次執行。這個過程是迴圈的,這個機制也被叫做事件迴圈。
非同步任務也被分為巨集任務和微任務,每一個巨集任務執行完之後,都會檢查是否存在待執行的微任務,如果有,則執行完所有微任務之後,再繼續執行下一個巨集任務。如果沒有則直接執行下一個巨集任務。
- 常見的巨集任務有
- script (可理解為外層同步代碼)
- 定時器函數setTimeout/setInterval
- UI rendering/UI事件
- postMessage、MessageChannel
- setImmediate、I/O(Node.js)
- Ajax請求,文件操作方法
- 常見的微任務有
- (promise的.then().cath().finally()...)
.
- (promise的.then().cath().finally()...)
18.如何實現js函數緩存
函數緩存,就是將函數運算過的結果進行緩存,本質上就是用緩存空間替代函數的計算時間。它只是一個臨時的數據存儲,以便將來更快得到該數據。
如何實現:主要依靠閉包、高階函數、柯里化、的特性實現
- 閉包:父函數體內被子函數引用變數的不被回收的特性
- 高階函數:通過接收其他函數作為參數或返回其他函數的函數,所謂的參數函數和被返回的函數對高階函數內都持有引用關係,即變數不會被回收,實現緩存
- 柯里化:把一個有多個參數的函數轉換成多個單參數函數嵌套的形式,實際類似閉包函數作用域逐層可被訪問,即作用域變數不會被回收,從而實現緩存。
使用場景:
對於昂貴的函數調用,執行複雜計算的函數
對於具有有限且高度重覆輸入範圍的函數
對於具有重覆輸入值的遞歸函數
對於純函數,即每次使用特定輸入調用時返回相同輸出的函數
19.flex相關整理
flex佈局父項常見屬性:
flex-direction: 設置主軸的方向
justify-content: 設置主軸上的子元素排列方式
flex-wrap: 設置子元素是否換行
align-content: 設置側軸的子元素的排列方式(多行)
align-items:設置側軸上的子元素排列方式(單行)
flex-flow:複合屬性,相當於同時設置了flex-direction 和 flex-wrap
flex:1實際代表的是三個屬性的簡寫
{flex-grow:1;flex-shrink:1;flex-basis:0%}
- flex-grow是用來增大盒子的,比如,當父盒子的寬度大於子盒子的寬度,父盒子的剩餘空間可以利用flex-grow來設置子盒子增大的占比
- flex-shrink用來設置子盒子超過父盒子的寬度後,進行縮小的比例取值
- flex-basis:0% 設置盒子的基準寬度,並且basis和width同時存在會替代width
20.git相關整理
-
git分支和標簽的區別:
tag代表了當前的提交點,是個點,tag是當前提交點的一個記錄,tag名字是不能重覆的,就代表了唯一的這個點,branch代表裡新的支線,是個線,可以繼續延展 ,當在某個分支上打了個tag,那麼這個tag就代表了當前這個分支的這個點,當回滾或者檢出到這個tag的時候,代碼就會回到這個點
tag是靜態的,branch要向前走;
穩定版本備份用tag,新功能多人開發用branch(開發完成後merge到master)。
-
git命令
1、克隆遠程倉庫到本地:git clone ssh/https 2、克隆遠程倉庫到本地並重新命名:git clone ssh/https 倉庫名 3、查看本地分支:git branch 4、查看遠程分支:git branch -r 5、git branch 命令: git branch //查看本地所有分支 git branch -r //查看遠程所有分支 git branch -a //查看本地和遠程的所有分支 git branch <branchname> //新建分支 git branch -d <branchname> //刪除本地分支 git branch -d -r <branchname> //刪除遠程分支,刪除後還需推送到伺服器 git push origin:<branchname> //刪除後推送至伺服器 git branch -m <oldbranch> <newbranch> //重命名本地分支 6、檢查當前文件的狀態:git status -s 7、切換分支: git checkout 切換分支 git checkout -b mywork origin //基於遠程分支”origin“,創建一個叫”mywork“的分支 8、本地拉取遠程分支 git pull :將遠程主機最新內容拉到本地後直接合併 git fetch :將遠程主機的最新內容拉到本地,用戶在檢查了以後決定是否合併到工作分支中 //如果只想取回特定分支的更新,可以指定分支名 git fetch <遠程主機名> <分支名> //註意之間有空格 9、跟蹤文件並添加到臨時存儲區:git add 文件名 /git add . 添加所有文件 10、提交並添加註釋:git commit -m "註釋" 11、上傳至遠端倉庫:git push git merge//主要用於將兩個或兩個以上的開發歷史加入(合併)一起 git merge -b // 指將 b 分支合併到當前分支 git rebase //在另一個分支基礎之上重新應用,用於把一個分支的修改合併到當前分支
-
git合併分支
git checkout 分支1 ;git merge 分支2 ;git push //將分支2合併到分支1中
-
git打標記:
開發過程中會經過多次commit 提交才會確定一個版本,那麼除了用commit comments來標識一次提交記錄,還使用標簽可以對某一次提交記錄做上一個小標記,這可以讓我們以後可以更方便的索引。 git tag <lightweght_name>:為當前分支所在的提交記錄打上輕量標簽。 git tag <lightweght_name><commit SHA-1 value>:為某次具體的提交記錄打上輕量標簽。 git tag-a <anotated_name>-m <tag_message>:為當前分支所在的提交記錄打上附註標簽。 git tag:列出所有的標簽名。 git tag-d<tagname>:刪除某個標簽,本質上就是移除.git/refs/tags/中對應的文件。 git show<tag name>:顯示標簽對應提交記錄的具體信息。 git push <remote><tag name>:推送某個標簽到遠程倉庫。 git push <remote>--tags:推送所有標簽到遠程倉庫。 git push <remote>-delete <tag name>:刪除遠程倉庫中的某個標簽。
-
git pull 和git fetch的區別
區別:1、fetch能夠直接更改遠端跟蹤分支,而pull無法直接對遠程跟蹤分支操作;
2、fetch將數據拉取到本地倉庫不會自動合併或修改當前的工作,pull是從遠程獲取最新版本並merge到本地,會自動合併或修改當前的工作。
Git fetch和git pull區別為:遠端跟蹤分支不同、拉取不同、commitID不同。
一、遠端跟蹤分支不同
1、Git fetch:Git fetch能夠直接更改遠端跟蹤分支。
2、git pull:git pull無法直接對遠程跟蹤分支操作,我們必須先切回本地分支然後創建一個新的commit提交。
二、拉取不同
1、Git fetch:Git fetch會將數據拉取到本地倉庫 - 它並不會自動合併或修改當前的工作。
2、git pull:git pull是從遠程獲取最新版本並merge到本地,會自動合併或修改當前的工作。
三、commitID不同
1、Git fetch:使用Git fetch更新代碼,本地的庫中master的commitID不變,還是等於1。
2、git pull:使用git pull更新代碼,本地的庫中master的commitID發生改變,變成了2。
21.移動端相容性問題
- 移動端音視頻問題:自動播放
-
ios safari
iPhone Safari中不支持,但在webview中可能被開啟;iOS開發文檔明確說明蜂窩網路下不允許autoplay; -
chrome中,設置
mouted
後可以自動播放 -
微信中不允許自動播放。但是可以藉助
WeixinJSBridge
實現視頻:
-
preload,ios下是不支持的。通用的方法是對視頻進行
play()
後立即停止 -
ios視頻自動全屏播放:設置內聯屬性
playsinline webkit-playsinline
-
經典的1px邊框
一般是採用偽元素模擬的方式,原理:
把原先元素的 border 去掉,然後利用 :before 或者 :after 重做 border ,並 transform 的 scale 縮小一半,原先的元素相對定位,新做的 border 絕對定位。
-
CSS3動畫卡頓
儘量使用transform,避免使用height,width,margin,padding等。可以開啟GPU硬體加速,但用硬體加速的時候也要註意,因為這個也有坑,不合理使用反而會讓應用越來越卡!
- 設置圓角(border-radius:50%;)部分手機顯示為橢圓
具體是因為,使用了rem佈局,在部分機型上出現的問題,設置具體的px數值,不用50%即可
-
android里line-height不居中
把字型大小內外邊距等設置為需求大小的2倍,使用zoom進行縮放,可以完美解決。
22.vue路由切換後頁面滾動條位置不變(需回到頂部)
由於vue是單頁面應用,只是更換了路由內容,還在當前頁面滾動條是不會回到頂部的。解決辦法是在切換路由的時候,將滾動區域的滾動條複位為0。
-
方法一:配置vue-Router時,設置scrollBehavior屬性來管理路由切換時頁面的滾動行為。
const createRouter = () => new Router({ scrollBehavior: (to, from, savedPosition) => { // console.log(88, savedPosition) //savedPosition值瀏覽器箭頭切換時返回{x:0,y:0} if (to.path === '/attendances') { return { y: 100 } //自定義單個頁面滾動條位置 } return { y: 0 } }, // 管理滾動行為 如果出現滾動 切換就讓 讓頁面回到頂部 routes: [...] })
-
方法二:監聽路由改變
直接在app.vue監測路由變化,讓body的滾動距離 scrollTop=0或scrollTo(0,0)
// 使用 watch 監聽$router的變化, watch: { '$route': function(to, from) { window.scrollTo(0,0) //等於document.documentElement.scrollTop = 0 //或document.body.scrollTop = 0 } }
-
方法三:全局後置守衛,離開當前路由時執行
router.afterEach((to,from,next)=>{ window.scrol1To(0,0); });
23.實現切換頁面滾動條位置不變
第一步(監聽當前的滾動高度)
scroll:""
mounted(){ window.addEventListener('scroll',this.handleScroll)},
destroyed(){ window.removeEventListener('scrol1',this.handleScroll) },
methods:{
handleScroll(){
this.scroll=document.documentElement.scrollTop|| document.body.scrollTop
//console.1og(this.scrol1)
}
}
第二步(監聽當前的路由)
watch:{
'$route'(to, from){
this. $nextTick(()=>{
document. body. scrol1Top=this. scroll;
document. documentElement. scrollTop=this.scroll ;
})
}}
24.圖片懶載入原理
定義:滾動動態載入,也就是懶載入,顯示在屏幕之外的圖片預設不載入,隨著頁面的滾動,圖片進入了顯示的範圍,則觸發圖片的載入顯示
原理:
-
頁面的img標簽的url不能直接用圖片的真實路徑,否則會直接載入,可將真實路徑暫存在自定義屬性data-url中
<img data-url="真實url" />
-
img的src屬性也不能是空或者壞路徑(會出現圖片無顯示圖標),可將所有的img標簽的src屬性填入同一個1px的t透明圖片,用於占位,且設置loading效果的背景圖,
<img data-url="xxx"src="lpx. gif"width="180"height="180"style="background: url(loading. gif) no-repeat center;"/>
-
需要一個滾動事件,判斷元素是否在瀏覽器視窗,一旦進入視口才進行載入,當滾動載入的時候,就把這張透明的1px.gif圖片替換為真正的url地址(也就是data-url里保存的值)
-
最後圖片進入視口後,利用js提取data-url的真實圖片地址賦值給src屬性,就會去發送請求載入圖片,真正實現了按需載入
25.for, for in, for of, forEach的區別
for:
優點:程式簡潔,結構清晰,迴圈初始化,迴圈變數化和迴圈條件位置突出。
缺點:結構比while迴圈複雜,容易出編碼錯誤。
for..in:
優點:避免了for in的所有缺點,可以使用break,continue和return,不僅支持數組的遍歷,還可以遍歷類似數組的對象,支持字元串的遍歷最簡潔。
缺點:不適用於處理原有的原生對象。
for...of:僅用於遍歷可迭代(可按順序遍歷)對象的元素語法:for(var 變數of 數組名){console.log(變數)}
優點:避免了for..in的所有缺點,支持break,continue,return。支持遍歷map,object,array,set string等。
缺點:不適用於處理原有的原生對象。
forEach:
優點:便利的時候更加簡潔,效率和for迴圈相同,不用關心集合下標的問題,減少了出錯的效率缺點:不能同時遍歷多個集合,在遍歷的時候無法修改和刪除集合數據,方法不能使用break,continue語句跳出迴圈,或者使用return從函數體返回,對於空數組不會執行回調函數
區別:四個演算法語句區別主要體現在響應break,continue,return上和使用的對象上。
for 語句性能最好;能響應break,continue,return控制迴圈。
for in 無法響應break,continue,return控制迴圈;for in 主要針對對象,它不僅會迴圈對象本身的屬性,還會查找迴圈原型上的屬性;迴圈的順序不確定。s
for of 能響應break,continue,return控制迴圈,還能遍歷map、set等類數組,但是不能迴圈普通的對象forEach 無法響應break,continue,return控制迴圈。
26.es5和es6繼承實現的區別
es5和es6繼承的區別:ES5的繼承是通過原型或構造函數機制實現的;它先創建子類,再實例化父類並添加到子類this中。ES6先創建父類,再實例化子集中通過調用super方法訪問父級後,再通過修改this實現繼承。
es6繼承和es5繼承的區別
- ES5的繼承實質上是先創建子類的實例對象,然後再將父類的方法添加到this上(Parent.apply(this)).
- ES6的繼承機制完全不同,實質上是先創建父類的實例對象this(所以必須先調用父類的super)方法),然後再用子類的構造函數修改this。
- ES5的繼承是通過原型或構造函數機制來實現。
- ES6通過class關鍵字定義類,裡面有構造方法,類之間通過extends關鍵字實現繼承。子類必須在constructor方法中調用super方法,否則新建實例報錯。因為子類沒有自己的this對象,而是繼承了父類的this對象,然後對其進行加工。如果不調用super方法,子類得不到this對象。
註意super關鍵字指代父類的實例,即父類的this對象。
註意:在子類構造函數中,調用super後,才可使用this關鍵字,否則報錯。|
27.vue2中怎麼用echarts的
-
npm install echarts --save
-
在main.js中引入echarts ,下麵是全部引入和按需引入
import * as echarts from "echarts"; //引入所有的圖例 Vue.prototype.$echarts = echarts; //在原型上掛載,用於全局使用
在某個組件中按需引入
var echarts = require('echarts/lib/echarts') // 引入echarts主模塊 require('echarts/lib/chart/radar') // 引入雷達圖 // 引入提示框和標題組件 require('echarts/lib/component/tooltip') require('echarts/lib/component/title')
-
在組件中使用
export default { date(){ options:{ ... } }, method:{ //定義繪製函數 drawEc(){ let myChart = this.$echarts.init(this.$refs.myechart); myChart.setOption(this.options) } }, mounted(){ this.drawEc() //調用函數 } }
28.數據類型
值類型(基本類型)6個:字元串(String)、數字(Number)、布爾(Boolean)、對空(Null)、未定義(Undefined)、Symbol。
Symbol是ES6中新增的一種數據類型,用來表示一個獨一無二的值,製作框架或第三方插件時可避免使用者將框架內同名屬性覆蓋。
引用數據類型(對象類型)5個:對象(Object)、數組(Array)、函數(Function),還有兩個特殊的對象:正則(RegExp)和日期(Date)。
29.什麼是NaN,NaN==NaN輸出啥
NaN意思是指數據not a number不是一個數字,但是NAN卻屬於數字類型。需要註意的是,NAN 不會和任何一個值相等,包括NAN本身。運行結果都為false。
30. Vue的生命周期,有哪些?
beforeCreate
:實例話Vue,未初始化和響應式數據created
:已初始化和響應式數據,可訪問數據beforeMount
:render調用,虛擬DOM生成,未轉真實DOMmounted
:真實DOM掛載完成beforeUpdate
:數據更新,新虛擬DOM生成updated
:新舊虛擬DOM進行對比,打補丁,然後進行真實DOM更新beforeDestroy
:實例銷毀前,仍可訪問數據destroy
:實例銷毀,子實例銷毀,指令解綁,解綁本實例的事件activated
:keep-alive所緩存組件激活時調用deactivated
:keep-alive所緩存組件停用時調用errorCaptured
:子孫組件的錯誤捕獲,此函數可返回false阻止繼續向上傳播
鏈接:https://juejin.cn/post/7073300624707682317
31.顯示轉換和隱式轉換
顯示類型:轉換是通過 JS 提供的一些函數或運算符,可以直接將類型進行轉換
如Number() String() Boolean()parseInt()
隱式轉換:是指在代碼執行過程中,通過運算符運算或語句執行等操作,js 引擎會自動隱式的改變類型
32.為什麼v-if和v-for不建議用在同一標簽?
v-for
優先順序高於v-if
,每項都通過v-for
渲染出來後再去通過v-if
判斷顯隱,過程中會增加無用的dom操作,渲染了無用的節點
解決方案:
- 如果v-if後的數據與v-for遍歷的數據沒有依賴關係,可以直接找v-for外加template並用v-if判斷
- 如果v-if後的數據依賴於v-for遍歷的數據,可去掉v-if,並將v-for要遍歷的數據放在計算屬性中處理後遍歷
33. 組件之間的傳值方式有哪些?
-
父傳子: 組件使用
props
進行接收 -
子傳父: 子組件使用
$emit
+事件對父組件進行傳值 -
父子之間通過
$parent
和$chidren
獲取實例進而通信 -
使用
$refs
獲取組件實例,進而獲取數據。 -
使用vuex進行狀態管理,實現數據共用 // ocalStorage/sessionStorage持久化存儲
-
使用
eventBus
進行跨組件觸發事件,進而傳遞數據 -
使用瀏覽器本地緩存,例如
localstorage``sessionStorage
-
$attrs
和$listener
適用於多級組件嵌套,但是不做中間處理的情況。比如祖先組件向孫子組件傳遞數據。
$attrs
可以獲取父組件傳進來,但是沒有用props接收的屬性。可以通過v-bind="$attrs"傳入內部組件。
搭配inheritAttrs=true使用,這個只是用來控制attrs是否在DOM中渲染。$listeners
包含父作用域中的(不包含.native的) v-on時間監聽器。可以通過v-on="$listeners"
來傳入內部組件。 -
依賴註入provide/inject多個組件嵌套時,頂層組件provide提供變數,後代組件都可以通過inject來註入變數。
export default{ //頂層轉提供變數
provide(){ //與data同級
return{
msg:'hello world' //可通過 msg:this.xxx 實現響應式
}
}
}
======
export default{ //頂層轉提供變數
inject:['msg'] //與data同級,數組形式接收變數/方法名
}
34.國際化步驟
// npm install vue-i18n
// import VueI18n from 'vue-i18n'
// Vue.use(VueI18n) // 全局註冊國際化包
// import elementEN from 'element-ui/lib/locale/lang/en' // 引入餓了麽的英文包
// import elementZH from 'element-ui/lib/locale/lang/zh-CN' // 引入餓了麽的中文包
// import customEN from './en'
// import customZH from './zh'
// export default new VueI18n({
// locale: Cookie.get('language') || 'zh', // 從cookie中獲取語言類型 獲取不到就是中文
// messages: {
// en: {
// ...elementEN, // 將餓了麽的英文語言包引入
// ...customEN
// },
// zh: {
// ...elementZH, // 將餓了麽的中文語言包引入
// ...customZH
// }
// }
// })
// 使用$t('route.xxx')使用對應的語言文字
// 使用$tc('route.xxx',1)使用對應的第幾個語言文字(語言包中定義:xxx='he|hell|hello')
35.axios和ajax區別
1.區別
axios是通過promise實現對ajax技術的一種封裝,就像jQuery實現ajax封裝一樣。
簡單來說: ajax技術實現了網頁的局部數據刷新,axios實現了對ajax的封裝。
axios是ajax ajax不止axios。
2.優缺點:
ajax:
本身是針對MVC的編程,不符合現在前端MVVM的浪潮
基於原生的XHR開發,XHR本身的架構不清晰,已經有了fetch的替代方案
JQuery整個項目太大,單純使用ajax卻要引入整個JQuery非常的不合理(採取個性化打包的方案又不能享受CDN服務
axios:
從 node.js 創建 http 請求
支持 Promise API
客戶端支持防止CSRF
提供了一些併發請求的介面(重要,方便了很多的操作)
36.MVVM是什麼?和MVC有何區別呢?
Mvc
- Model(模型):負責從資料庫中取數據.
- View(視圖):負責展示數據的地方
- Controller(控制器):用戶交互的地方,例如點擊事件等等·思想:Controller將Model的數據展示在View 上
MVVM
VM: 也就是View-Model,數據的雙向綁定將【模型】轉化成【視圖】,即後端傳遞的數據轉化成所看到的頁面。實現的方式是:數據綁定。二是將【視圖】轉化成【模型】,即將所看到的頁面轉化成後端的數據。實現的方式是:DOM事件監聽。
區別
整體看來,MVVM 比MVC精簡很多,不僅簡化了業務與界面的依賴,還解決了數據頻繁更新的問題,不用再用選擇器操作DOM元素。因為在MVVM 中,View不知道 Model的存在,Model和ViewModel也觀察不到View,這種低耦合模式提高代碼的可重用性 Vue是不是MVVM框架? Vue是MVVM框架,但是不是嚴格符合MVVM,因為MVVM規定Model和View不能直接通信,而Vue的ref可以做到這點
37.說說nextTick的用處?
修改數據時不能馬上得到最新的DOM信息,所以需要使用nextTick,在nectTick回調中可以獲取最新DOM信息
38.router.push、router.replace、router.go的區別?
router.push
:跳轉,並向history棧中加一個記錄,可以後退到上一個頁面router.replace
:跳轉,不會向history棧中加一個記錄,不可以後退到上一個頁面router.go
:傳正數向前跳轉,傳負數向後跳轉
39.Vue中封裝的數組方法有哪些,如何實現頁面更新
- 在Vue中,對響應式處理利用的是Object.defineProperty對數據進行攔截,而這個方法並不能監聽到數組內部變化,數組長度變化,數組的截取變化等,所以需要對這些操作進行hack,讓Vue能監聽到其中的變化
- push()
- pop()
- shift()
- unshift()
- solice()
- sort()
- reverse()
40.請問 http協議為什麼一定要區分 post,get,put,delete
所有 http 請求,一律用 POST,在業務功能的實現是沒有問題的. post,get,put,delete 是標準, 大家都遵循這樣的規則. 這樣的api對於它人來說一目瞭然, get就是獲取數據, post就是提交數據, put就是更新數據, delete就做刪除操作. 如果一律使用post對一個項目組的內部人員來說是沒有問題的, 但是對於對外公開的介面就讓調用者摸不著頭腦了. 另外這四種方法還有特殊的用意. GET 請求可被緩存, 請求可保留在瀏覽器歷史記錄中, 請求可被收藏為書簽, get方法具有Safe特性會影響是否可以快取(post不支持快取) POST 請求不會被緩存, 請求不會保留在瀏覽器歷史記錄中, 不能被收藏為書簽 這就是為什麼取數據要使用get而不是post. 因為get可以快取, 緩存和保留歷史記錄及書簽等特殊功能. 除了上面的4種常見方法還有一個很重要的方法PATCH.
41.promise A+規範
規定了promise是如何設計的
42.Promise
-
用處:Promise 對象用於表示一個非同步操作的最終完成 (或失敗)及其結果值。使得控制非同步操作更加容易。可以將非同步操作以同步操作的流程表達出來,從而避免了傳統的層層嵌套的回調函數的非同步操作。
-
本質:Promise 是一個構造函數
-
Promise 相關的方法
-
Promise 構造函數原型上的方法(通過創建一個 Promise 實例進行調用)
-
Promise.prototype.then() :then 方法必須返回一個新的 promise 對象(實現鏈式調用的關鍵)
-
Promise.prototype.catch()
catch 異常處理函數,處理前面回調中可能拋出的異常。只接收一個參數onRejected處理程式。它相當於調用Promise.prototype.then(null,onRejected),所以它也會返回一個新的Promise
-
Promise.prototype.finally()
-
-
Promise 構造函數靜態方法,直接通過 Promise 函數調用
-
Promise.all()
Promise.all()參數可以傳遞一個數組,Promise.all()創建的Promise會在這一組Promise全部解決後在解決。也就是說會等待所有的promise程式都返回結果之後執行後續的程式。返回一個新的Promise。
- 如果所有都成功,則合成Promise的返回值就是所有子Promise的返回值數組。
- 如果有一個失敗,那麼第一個失敗的會把自己的理由作為合成Promise的失敗理由。
-
Promise.allSettled()
Promise.all 和 allSettled 基本一樣,區別是,then 始終可以獲取到非同步的狀態,哪怕其中有一個失敗
-
Promise.race()
Promise.race 使用和 all 一樣,但是只返回第一個結果(數組最快執行完成的那個函數的結果),不管成功或失敗,最後返回一個新的Promise
- Promise.any() 返回第一個成功的結果
- Promise.reject()
- Promise.resolve()
-
-
-
Promise對象特點
對象的狀態不受外界影響。
- 有三種狀態:
pending
(進行中)、fulfilled
(已成功)和rejected
(已失敗) - 只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態
一旦狀態改變,就不會再變,任何時候都可以得到這個結果
Promise
對象的狀態改變,只有兩種可能:從pending
變為fulfilled
和從pending
變為rejected
。- 只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱為 resolved(已定型)。
43.keep-alive組件
1.作用:vue自帶的一個用於緩存組件的組件標簽,避免重覆創建相同的組件,提升項目運行性能
2.用法:
-
搭配動態組件使用,在不同動態組件狀態的切換下,各組件內的狀態依舊維持在記憶體之中,在下次渲染時不需要重新創建。
-
配合router-view使用:有時候需要將整個路由頁面緩存下來,可用keep-alive包裹router-view標簽實現緩存
-
兩個與其相關的鉤子函數: 被緩存的組件不再創建和銷毀, 而是激活和非激活
-
activated:
keep-alive
所緩存組件激活時調用 -
deactivated:
keep-alive
所緩存組件停用時調用 -
初始進入和離開 created ---> mounted ---> activated --> deactivated
後續進入和離開 activated --> deactivated
-
-
keep-alive屬性
-
include = 字元串或正則表達式或數組。只有名稱匹配的組件會被緩存。
-
exclude =字元串或正則表達式或數組。任何名稱匹配的組件都不會被緩存。
-
// 指定home組件和about組件被緩存 <keep-alive include="home,about" > <router-view></router-view> </keep-alive>
-
-
keep-alive的應用場景舉例
- 查看表格某條數據詳情頁,返回還是之前的狀態,比如還是之前的篩選結果,還是之前的頁數等
- 填寫的表單的內容路由跳轉返回還在,比如input框、下選擇拉框、開關切換等用戶輸入了一大把東西,跳轉再回來不能清空啊,不用讓用戶再寫一遍
44.v-model和.sync
v-model:
v-model
是語法糖,預設情況下相當於:value
和@input
。通常在表單項上使用v-model
- 通過
<input v-model="xxx">
的方式將xxx的值綁定到表單元素value上;對於checkbox,可以使用true-value
和false-value指定特殊的值,對於radio可以使用value指定特殊的值;對於select可以通過options元素的value設置特殊的值;還可以結合.lazy,.number,.trim對v-mode的行為做進一步限定;v-model
用在自定義組件上時又會有很大不同,
.sync:sync修飾符是@update:屬性名 事件和 :屬性名=“傳值數據” 的語法糖,值組件可以通過$emit('update:屬性名',數據)觸發並向父組件傳值
45. 路由傳參方式(動態路由)