一 vue
vue的優(yōu)點?
- 漸進式
- 組件化開發(fā)
- 虛擬dom
- 響應式數(shù)據(jù)
- 單頁面路由
- 數(shù)據(jù)與試圖分開
用戶體檢好,內(nèi)容改變的時候不需要加載整個頁面,避免不必要的重復渲染和跳轉(zhuǎn)
基于上面一點 single 相對于服務器壓力小
前后端職責分離入桂,架構清晰
vue的缺點?
- 單頁面不利于SEO
- 首屏加載時間長
- 不兼容IE
初始加載耗時, seo難度較大: 由于所有的內(nèi)容都在一個頁面中動態(tài)替換顯示 所有 seo有著天然的劣勢
為什么說Vue是一個漸進式框架递递?
Vue的全家桶粘茄,你可以選擇不用簿寂,或者只選幾樣去用,比如不用vuex
根據(jù)場景颜屠,官方提供了方便的框架供你使用
Vue跟React的異同點寓辱?
相同點:
- 都是單向數(shù)據(jù)流
- 都使用了虛擬DOM的技術
- 都支持SSR
- 組件化開發(fā)
不同點:
- 前者template蝗岖,后者JSX
- 數(shù)據(jù)改變,前者響應式架曹,后者手動setState
- React單向綁定隘冲,Vue雙向綁定
- React狀態(tài)管理工具Redux、Mobx绑雄,Vue狀態(tài)管理工具Vuex
MVVM是什么展辞?和MVC有何區(qū)別呢?
MVC
- Model:負責從數(shù)據(jù)庫中取數(shù)據(jù)
- View:負責展示數(shù)據(jù)
- Controller:用戶交互的地方万牺,例如點擊事件
MVVM
- VM:就是View-Model罗珍,數(shù)據(jù)雙向綁定
- Model:取數(shù)據(jù)的地方
- View:展示數(shù)據(jù)的地方
組件中的data是個函數(shù)并且返回一個對象呢?
組件是用來復用的, js 的對象是引用關系,如果組件中的data是一個對象,這樣作用域沒有隔離,子組件中的data屬性值會互相影響
使用過哪些Vue的修飾符呢脚粟?
- .lazy:輸入框失焦時才會更新v-model的值
- .trim:講v-model綁定的值首位空格給去掉
- .number:將v-medol綁定的值轉(zhuǎn)數(shù)字
- .stop:阻止事件冒泡
- .capture:事件的捕獲
- .self:點擊事件綁定本身才觸發(fā)
- .once:事件只觸發(fā)一次
- .prevent:阻止默認事件
- .native:綁定事件在自定義組件上時覆旱,確保能執(zhí)行
- .left、.middle核无、.right:鼠標左中右鍵的觸發(fā)
- passive:相當于給移動端滾動事件加一個.lazy
- camel:確保變量名會被識別成駝峰命名
- .sync:簡化子修改父值的步驟
這樣理解vue單向數(shù)據(jù)流?
父組件傳輸props給子組件時,子組件只能使用不能修改,這是為了組件之間更好的去解耦.比如有一個父組件,傳props給10個子組件,如果某一個子組件修改了,那么會影響其它9個子組件跟著刷新,所以不推薦子組件修改props
組件之間的通信方式都有哪些,用過eventBus,eventbus的是想是什么
- 父組件傳值給子組件數(shù)據(jù)props
- 子組件傳值給父組件,通過$emit事件對父組件進行傳值
- 父組件和之組件通過children進行獲取實例數(shù)據(jù)
- 二次封裝時經(jīng)常使用listener進行傳值
- 使用$refs 獲取實例組件,進行數(shù)據(jù)獲取
- 使用vuex 進行狀態(tài)管理
- 使用eventBus 進行跨組件傳值 進而傳遞數(shù)據(jù)(發(fā)布訂閱模式)
- 使用provide 和inject官方不建議 一般用戶UI組件開發(fā)
- 瀏覽器本地緩存 例如localStorage
- 路由傳值
寫個自定義 v-model扣唱?
v-model實際是:value + @input的語法糖
<input v-model="inputValue" />
<input
:value="inputValue"
@input="inputValue = $event.target.value"
/>
attrs 和 $listener 有了解嗎?
常用于對組件進行二次封裝時团南,比如A -> B -> C噪沙,B可以直接將爺爺組件的所有數(shù)據(jù)或者事件直接傳給孫子
Vue 生命周期有哪些,都是做什么的吐根,updated 什么情況下會觸發(fā)正歼,beforeCreate 的時候能拿到 Vue 實例么,組件銷毀的時候調(diào)用的是哪個 API
- beforeVCreated:實例了Vue但是還沒有進行數(shù)據(jù)初始化與響應式處理
- created 數(shù)據(jù)已經(jīng)被初始化和響應式處理拷橘,這里可以訪問和修改數(shù)據(jù)
- beforeMount render函數(shù)在這里調(diào)用,生成虛擬DOM,但是還沒有轉(zhuǎn)真實DOM并替代到el
- mounted 真實DOM掛載完畢
- beforeUpdated 數(shù)據(jù)更新后,新的虛擬DOM生成,但還沒更舊虛擬DOM對比打補丁
- update 新舊虛擬DOM對比打補丁后,進行真實DOM的更新
- activated 被keep-alive 緩存的組件被激活時調(diào)用
- deactivated 被keep-alive緩存的組件停用時調(diào)用
- beforeDestroy 實例銷毀之前調(diào)用,在這一步,依然可以訪問數(shù)據(jù)
- destroyd 實例銷毀后調(diào)用 vue實例的所有指令都被解綁,實例的監(jiān)聽器被移除,所有子實例也都被銷毀
- errorCapured 捕獲子孫組件的錯誤時被調(diào)用局义。此鉤子會收到三個參數(shù):錯誤對象齐疙、發(fā)生錯誤的組件實例以及一個包含錯誤來源信息的字符串。此鉤子可以返回false以阻止該錯誤繼續(xù)向上傳播旭咽。
什么情況下會觸發(fā)組件銷毀贞奋,銷毀的時候會卸載自定義事件和原生事件么?
組件銷毀時會自動卸載組件本身綁定的事件穷绵,但是僅限于組件本身轿塔。例如一些定時器、全局對象的事件綁定仲墨、eventBus則不會自動解綁勾缭,需要手動解綁。
自定義指令寫過么目养,自定義指令都有哪些鉤子俩由?
vue2
- bind 指令綁定到指定元素時觸發(fā),只觸發(fā)一次
- inserted 指令元素插入到DOM時觸發(fā),只觸發(fā)一次
- update:VNode更新時觸發(fā),會觸發(fā)多次
- unbind 指令解綁時觸發(fā),只觸發(fā)一次
vue3
- created:指定元素的attribute或事件監(jiān)聽器被應用之前被調(diào)用
- beforeMount:指令綁定到指定元素上觸發(fā)
- mounted:指定元素被掛載時觸發(fā)
- beforeUpdate:在更新包含組件的VNode之前觸發(fā)
- updated:在包含組件的VNode及其VNode更新后調(diào)用
- beforeUnMount:在卸載指定元素的父組件之前觸發(fā)
- unmounted:指令解綁時觸發(fā)
Vue2 的數(shù)據(jù)響應式有兩個缺陷癌蚁,你知道是哪兩個缺陷么幻梯,為什么會有這樣的缺陷,如何解決努释?
- 對象新增屬性或修改新增的屬性時碘梢,無法觸發(fā)視圖更新,需要使用 Vue.set伐蒂,對象刪除屬性時需要使用Vue.delete才能觸發(fā)更新
- 數(shù)組直接通過下標修改元素無法觸發(fā)視圖更新煞躬,需要使用數(shù)組的方法splice、push等等
vue 如何實現(xiàn)對數(shù)組的監(jiān)聽,為什么vue沒有對數(shù)組下標修改做劫持?
vue2是通過重寫了數(shù)組原型上的方法來達到對數(shù)組的修改的監(jiān)聽,vue2沒有對數(shù)組下標做劫持,是出于心梗的考慮逸邦,因為通常數(shù)組元素都是非常多的恩沛,可能成百上千,如果每個元素都進行劫持缕减,則非常耗費性能雷客。
路由的幾種模式?
- hash 哈希模式 根據(jù)hash值的更改進行組件切換,而不刷新頁面
- history 歷史模式 依賴于HTML5 的pushState和replaceState
- abstract:適用于Node
路由的鉤子函數(shù)?
全局鉤子
beforeEach:跳轉(zhuǎn)路由前
- to:將要跳轉(zhuǎn)進入的路由對象
- from:將要離開的路由對象
- next:執(zhí)行跳轉(zhuǎn)的方法
afterEach:路由跳轉(zhuǎn)后
- to: 將要跳轉(zhuǎn)進入的路由對象
路由獨享鉤子
routes: [
{
path: '/xxx',
component: xxx,
beforeEnter: (to, from, next) => {
}
}
]
組件內(nèi)路由鉤子
- beforeRouteEnter(to, from, next):跳轉(zhuǎn)路由渲染組件時觸發(fā)
- beforeRouteUpdate(to, from, next):跳轉(zhuǎn)路由且組件被復用時觸發(fā)
- beforeRouteLeave(to, from, next):跳轉(zhuǎn)路由且離開組件時觸發(fā)
使用過哪些Vue的內(nèi)部指令呢烛卧?
- v-text:元素的textContent
- v-html:元素的innerHTML
- v-show:通過樣式display改變顯隱
- v-if:通過操作DOM改變顯隱
- v-else:配合v-if
- v-else-id:配合v-else
- v-for:循環(huán)渲染
- v-on:綁定事件佛纫,縮寫@
- v-bind:綁定變量,縮寫:
- v-model:雙向綁定
- v-slot:插槽
- v-once:只渲染一次
- v-pre:跳過元素編譯
- v-cloak:隱藏雙括號总放,有值再顯示
v-if和v-show有何區(qū)別呈宇?
- v-if 通過操作dom來控制顯隱,適用于偶爾顯隱的情況
- v-show 通過改變樣式display屬性控制顯隱,適用于頻繁顯隱的情況
computed和watch有何區(qū)別?
computed
計算屬性將會混入到Vue的實例當中局雄,所有 getter 和 setter 的 this 上下文自動地綁定為 Vue 實例甥啄。
- 監(jiān)控自定義變量,這個變量不可以和data 和props里面的變量重復;
- computed屬性的屬性值是函數(shù)默認走get方法(必須有返回值)屬性都有一個get和set方法;
- 支持緩存,依賴多個變量計算出一個變量,只有所依賴的數(shù)據(jù)發(fā)生變化才會重新計算,否則會取緩存中的數(shù)據(jù);
- 不支持異步 在computed里面操作異步無效;
watch
- 監(jiān)聽data、props里面數(shù)據(jù)的變化炬搭;
- 不支持緩存蜈漓,每次都會重新計算穆桂;
- 支持異步,監(jiān)聽的函數(shù)接收兩個參數(shù)融虽,第一個參數(shù)是最新的值享完;第二個參數(shù)是輸入之前的值;
一般情況下,computed的是 多對一 watch 是一對多
為什么v-if和v-for不建議用在同一個標簽上?
v-for的優(yōu)先級高于v-if每項都通過v-for渲染出來后再去通過v-if判斷顯隱有额,做了很多無用功
uex的有哪些屬性般又?用處是什么?
- state 定義初始狀態(tài)
- getter 從store取數(shù)據(jù)
- mutation 更改store中的狀態(tài) 只能同步操作
- action 用于提交mutation巍佑,而不直接更改狀態(tài)茴迁,可異步操作
-
module:store的模塊拆分
不需要響應式的數(shù)據(jù)應該怎么處理?
- 定義在data的return之外
- 使用Object.freeze進行數(shù)據(jù)凍結
watch有哪些屬性萤衰,分別有什么用堕义?
- immediate: 初次加載時立即執(zhí)行
- deep 是否進行深度監(jiān)聽
- handler 監(jiān)聽的回調(diào)函數(shù)
父子組件生命周期順序?
1.父beforeCreate --> 2.父created --> 3.父beforeMount --->
4.子beforeCreate --> 5.子created ---> 6.子beforeMount ---->
7.子mounted ----> 8.父mounted
對象新屬性無法更新視圖脆栋,刪除屬性無法更新視圖倦卖,為什么?怎么辦筹吐?
- 原因:Object.defineProperty沒有對對象的新屬性進行劫持
- 解決:
1.新增屬性:Vue.set(target, key, value)
2.刪除屬性:Vue.delete(target, key)
直接arr[index] = xxx無法更新視圖怎么辦糖耸?為什么?怎么辦丘薛?
- 原因:Vue出于性能考慮沒有對數(shù)組下標進行劫持,而是通過改寫數(shù)組原型方法
- 解決:
- splice:arr.splice(index, 1, value)
- Vue.set(target, index, value)
nextTick的原理?
維護一個數(shù)組邦危,每次調(diào)用時講回調(diào)函數(shù)壓入這個數(shù)組洋侨,然后優(yōu)先選擇微任務,在微任務回調(diào)中去執(zhí)行數(shù)組中的所有回調(diào)倦蚪,同時維護一個布爾值希坚,確保每一次隊列進行一次執(zhí)行數(shù)組所有回調(diào)
let callbacks = []; //回調(diào)函數(shù)
let pending = false;
function flushCallbacks() {
pending = false; //把標志還原為false
// 依次執(zhí)行回調(diào)
for (let i = 0; i < callbacks.length; i++) {
callbacks[i]();
}
}
let timerFunc; //先采用微任務并按照優(yōu)先級優(yōu)雅降級的方式實現(xiàn)異步刷新
if (typeof Promise !== "undefined") {
// 如果支持promise
const p = Promise.resolve();
timerFunc = () => {
p.then(flushCallbacks);
};
} else if (typeof MutationObserver !== "undefined") {
// MutationObserver 主要是監(jiān)聽dom變化 也是一個異步方法
let counter = 1;
const observer = new MutationObserver(flushCallbacks);
const textNode = document.createTextNode(String(counter));
observer.observe(textNode, {
characterData: true,
});
timerFunc = () => {
counter = (counter + 1) % 2;
textNode.data = String(counter);
};
} else if (typeof setImmediate !== "undefined") {
// 如果前面都不支持 判斷setImmediate
timerFunc = () => {
setImmediate(flushCallbacks);
};
} else {
// 最后降級采用setTimeout
timerFunc = () => {
setTimeout(flushCallbacks, 0);
};
}
export function nextTick(cb) {
callbacks.push(cb);
if (!pending) {
pending = true;
timerFunc();
}
}
審查元素時發(fā)現(xiàn)data-v-xxxxx,這是啥陵且?
樣式模塊化scoped的效果裁僧,在本組件的標簽都會帶上data-v-xxx的屬性,然后通過屬性選擇器實現(xiàn)樣式模塊化的效果
provide 和inject是響應式的嗎?
引用數(shù)據(jù)類型是響應式,基礎數(shù)據(jù)類型不響應式
自定義v-model
export default {
model: {
event: 'change',
prop: 'checked'
}
}
為什么不建議用index做key慕购,為什么不建議用隨機數(shù)做key聊疲?
舉個例子:
<div v-for="(item, index) in list" :key="index">{{item.name}}</div>
list: [
{ name: '小明', id: '123' },
{ name: '小紅', id: '124' },
{ name: '小花', id: '125' }
]
渲染為
<div key="0">小明</div>
<div key="1">小紅</div>
<div key="2">小花</div>
現(xiàn)在我執(zhí)行 list.unshift({ name: '小林', id: '122' })
渲染為
<div key="0">小林</div>
<div key="1">小明</div>
<div key="2">小紅</div>
<div key="3">小花</div>
新舊對比
<div key="0">小明</div> <div key="0">小林</div>
<div key="1">小紅</div> <div key="1">小明</div>
<div key="2">小花</div> <div key="2">小紅</div>
<div key="3">小花</div>
可以看出,如果用index做key的話沪悲,其實是更新了原有的三項获洲,并新增了小花,雖然達到了渲染目的殿如,但是損耗性能
現(xiàn)在我們使用id來做key贡珊,渲染為
<div key="123">小明</div>
<div key="124">小紅</div>
<div key="125">小花</div>
現(xiàn)在我執(zhí)行 list.unshift({ name: '小林', id: '122' })最爬,渲染為
<div key="122">小林</div>
<div key="123">小明</div>
<div key="124">小紅</div>
<div key="125">小花</div>
新舊對比
<div key="122">小林</div>
<div key="123">小明</div> <div key="123">小明</div>
<div key="124">小紅</div> <div key="124">小紅</div>
<div key="125">小花</div> <div key="125">小花</div>
可以看出,原有的三項都不變门岔,只是新增了小林這個人爱致,這才是最理想的結果
插槽的使用以及原理?
普通插槽 普通插槽slot會被當做子元素進行解析寒随,最終會被解析成一個_t函數(shù)糠悯,他接收的第一個參數(shù)為插槽的名稱,默認是default牢裳,也就是_t('default')逢防,執(zhí)行此函數(shù)進行最終元素的渲染,如果是具名插槽蒲讯,則傳對應的插槽名 作用域插槽 插槽會被封裝成一個函數(shù)放置在scopeSlotes對象中忘朝,解析時_t第二個參數(shù)接收子組件的數(shù)據(jù),并進行渲染
說說nextTick的用處判帮?
修改數(shù)據(jù)時不能馬上得到最新的DOM信息局嘁,所以需要使用nextTick,在nectTick回調(diào)中可以獲取最新DOM信息
vue的hook的使用晦墙?
同一組件中使用
這是我們常用的使用定時器的方式
export default{
data(){
timer:null
},
mounted(){
this.timer = setInterval(()=>{
//具體執(zhí)行內(nèi)容
console.log('1');
},1000);
}
beforeDestory(){
clearInterval(this.timer);
this.timer = null;
}
}
上面做法不好的地方在于:得全局多定義一個timer變量悦昵,可以使用hook這么做:
export default{
methods:{
fn(){
let timer = setInterval(()=>{
//具體執(zhí)行代碼
console.log('1');
},1000);
this.$once('hook:beforeDestroy',()=>{
clearInterval(timer);
timer = null;
})
}
}
}
父子組件使用
如果子組件需要在mounted時觸發(fā)父組件的某一個函數(shù),平時都會這么寫:
//父組件
<rl-child @childMounted="childMountedHandle"
/>
method () {
childMountedHandle() {
// do something...
}
},
// 子組件
mounted () {
this.$emit('childMounted')
},
使用hook的話可以更方便:
//父組件
<rl-child @hook:mounted="childMountedHandle"
/>
method () {
childMountedHandle() {
// do something...
}
},
三 ES6
Symbol 有了解嗎晌畅,迭代器有了解嗎但指,哪些是可迭代的?
是ES6的特性抗楔,具體使用場景有:
symbol
- 充當對象的屬性名棋凳,實現(xiàn)私有屬性
- 充當變量,實現(xiàn)單獨變量
- 用來定義類里的私有屬性
迭代
迭代器:Iterator连躏,可迭代對象有Array剩岳、Set、Map入热,想將不可迭代對象變成可迭代對象拍棕,可以設置Symbol.iterator屬性
const t = {
name: '林三心',
age: 12
}
t[Symbol.iterator] = function () {
let index = 0,
self = this,
keys = Object.keys(this)
return {
next() {
if (index < keys.length) {
return {
value: self[keys[index++]],
done: false
}
} else {
return {
value: undefined,
done: true
}
}
}
}
}
for (let value of t) {
console.log(value)
}
用Set獲取兩個數(shù)組的交集,如何做勺良?
合集
const heji = (arr1, arr2) => {
return [...new Set(arr1.concat(arr2))]
}
交集
const jiaoji = (arr1, arr2) => {
const temp = new Set(arr1)
return Array.from(new Set(arr2)).filter(item => {
return temp.has(item)
})
}
差集
const chaji = (arr1, arr2) => {
const temp1 = new Set(arr1)
const temp2 = new Set(arr2)
const res = []
for (let item of temp1) {
!temp2.has(item) && res.push(item)
}
return res
}
實現(xiàn) Promise.all绰播?
Promise.sx_all = (promises) => {
return new Promise((resolve, reject) => {
const result = []
let count = 0
for (let i = 0; i < promises.length; i++) {
const promise = Promise.resolve(promises[i])
promise.then(res => {
result[i] = res
count++
if (count === promises.length) {
resolve(result)
}
}).catch(err => {
reject(err)
})
}
})
}
animation 和 transition 的區(qū)別?
- animation需配合@keyframe郑气,而transition不需要
- animation可以出發(fā)多次幅垮,transition只能觸發(fā)一次
- animation可以設置多個幀,而transition只有兩幀
- 前者可能會引起多次重回回流,后者會比較少