Vue全家桶+React全家桶面試題及部分原理整理


Vue全家桶+React全家桶面試題及部分原理整理



Vue
v-if和v-show的區別?
v-if表達式為true顯示該元素,為false隱藏該元素(直接刪除)
v-show根據表達式的真假來顯示與隱藏元素,會在標簽加入display屬性
為何v-for中要用key
vue中列表循環需加:key=“唯一標識” 唯一標識可以是item里面id index等,因為vue組件高度復用增加Key可以標識組件的唯一性,為了更好的區別各個組件,key的作用主要是為了高效的更新虛擬DOM
注意:v-for和v-if不能同時使用
父子組件之間的通訊
父傳子組件標簽中,子組件通過props接收
子組件通過$emit()傳送事件,父組件需要通過v-on去監聽自定義事件
vue生命周期
------------------beforeCreate初始化之前狀態(el,data,msg還沒有初始化)
el:undefined
data:undefined
msg:undefined
------------------created初始化之后狀態(el還沒有掛載,data中已經初始化有了數據)
el:undefined
data:[object Object]
msg:hello vue
------------------beforeMount掛載之前狀態(el已經掛載,但還沒有渲染)
el:

{{msg}}


data:[object Object]
msg:hello vue
------------------mounted掛載之后狀態(el掛載並渲染)
el:

hello vue


data:[object Object]
msg:hello vue
------------------beforeUpdate更新前
------------------updated更新后
------------------beforeDestroy銷毀前的狀態
------------------destroyed銷毀后的狀態
父子組件生命周期調用順序
先父組件created,然后子組件created,之后子組件mounted,再父組件mounted
(創建是從外到內,渲染是從內到外,子組件渲染完再父組件)
更新階段,先父組件update,然后子組件update,然后子組件updated,再父組件updated
何時需要使用beforeDestory
解綁自定義事件event.$off
清除自定義的DOM事件,如window scroll等
Vuex中action和mutation有何區別
action中處理異步,mutation不可以
mutation做原子操作
action可以整合多個mutation
Vue3升級內容
全部用ts重寫(響應式、dom、模板編譯等)
性能提升,代碼量減少,會調整部分API
Proxy實現響應式(基本使用)
Proxy能規避Object.defineProperty的問題,但Proxy無法兼容所有瀏覽器,無法polyfill


Vue高級特性
自定義v-model

//---------------子組件傳值
//綁定 input 事件,$emit 觸發父組件的 input 事件
<input type="text" @input="$emit('input', $event.target.value)">
//父組件監聽 input 事件,然后將事件攜帶的 input 輸入的值傳入到 data 狀態中
<my-children @input="value = $event"></my-children>
export default {
data () {
return {
value: ''
}
}
}
//-------------父組件傳值
//將value值傳遞給子組件,子組件再綁定 value值到 input的value屬性上
<my-children :value="value" @input="value = $event"></my-children>
//子組件中綁定 input 的 value 屬性
<input type="text" @input="$emit('input', $event.target.value)" :value="value">
//props設定value值
export default {
name: 'myChildren',
props: ['value']
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$nextTick

Vue是異步渲染,data改變之后,DOM不會立即渲染,$nextTick會在DOM渲染之后被觸發,以獲取最新DOM節點
頁面渲染時會將data的修改做整合,多次data修改只會渲染一次

<ul ref="uls">
<li>***</li>
</ul>

this.$nextTick(()=>{
//獲取DOM元素
const ulElem =this.$refs.uls
console.log(ulElem.childNodes.length)
})
1
2
3
4
5
6
7
8
9
slot

<div id="app">
<my_cpn>
<button>按鈕</button>
<span slot="btn">具名插槽使用</span>
<my_cpn>
<template v-slot="get">
<span v-for="item in get.set_data">{{item}}</span>
</template>
</my_cpn>
</my_cpn>
</div>
<template id="p">
<div>
<slot><p>匿名slot插件默認內容</p></slot>
<slot name="btn"><button>按鈕</button></slot>//具名插槽
<slot :set_data="str">//作用域插槽使用
<ul>
<li v-for="item in str">{{item}}</li>
</ul>
</slot>
</div>
</template>
const vm = new Vue({
el:"#app",
data:{},
components:{
my_cpn:{
template:"#p",
data(){
return {
str:["一","二","三","四"]
}
}
}
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
動態異步組件
:is="component-name"用法,需要根據數據,動態渲染的場景。即組件類型不確定

<component :is="NextTickName"/>//使用動態組件

<FormDemo v-if="showFormDemo"/>//異步組件
<button @click="showFormDemo = true">show form demo </button>
import NextTick from "./NextTick"//導入外部組件
export default{
components:{
NextTick,
FormDemo:() => import("../BaseUse/FormDemo")//異步加載組件
},
data(){
return {
name:"home",
NextTickName:"NextTickName"
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
keep-alive
緩存組件,頻繁切換,不需要重復渲染(被包裹的組件不會被銷毀)
mixin
多個組件有相同的邏輯,抽離出來
mixin並不是完美的解決方案,會有一些問題(
變量來源不明確,不利於閱讀,多mixin可能造成命名沖突,mixin和組件可能出現多對多的關系,復雜度較高
),vue3提出的composition API旨在解決這些問題

<div>
<p>{{name}}{{age}}{{sex}}</p>
</div>
import myMixin from "./mixin"
export default {
mixins:[myMixin],//可以添加多個,會自動合並起來
data(){
return {
name:"張三",
age:18
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
Vue部分原理(≠源碼)
組件化(MVVM,數據驅動視圖)

MVVM 即模型-視圖-視圖模型。【模型(M)】指的是后端傳遞的數據。【視圖(V)】指的是所看到的頁面。【視圖模型(VM)】mvvm模式的核心,它是連接view和model的橋梁。它有兩個方向:一是將【模型】轉化成【視圖】,即將后端傳遞的數據轉化成所看到的頁面。實現的方式是:數據綁定。二是將【視圖】轉化成【模型】,即將所看到的頁面轉化成后端的數據。實現的方式是:DOM 事件監聽。這兩個方向都實現的,我們稱之為數據的雙向綁定
響應式(數據驅動視圖第一步)
核心API:Object.defineProperty(Vue3.0之前)

//基本使用
const data ={}
const name="zhangsan"
Object.defineProperty(data,"name",{
get:function(){//get返回內容
console.log("get")
return name
},
set:function(newVal){//set賦值內容
console.log("set")
name=newVal
}
})
//如果監聽的類型是對象,需要判斷進行深度監聽
//如果監聽的類型是數組,不污染全局的數組原型情況下,重新定義數組原型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Object.defineProperty的缺點:深度監聽,需要遞歸到底,一次性計算量大
無法監聽新增屬性/刪除屬性(需要Vue.set Vue.delete兩個API來使用)
Vue3.0使用Proxy取代,但Proxy有兼容性問題,且無法polyfill,所以Vue2.x還會存在一段時間

vdom(Virtual DOM)和diff(虛擬DOM和diff算法,面試中的熱門問題)
vdom----用js模擬DOM結構,計算出最小的變更,操作DOM

vue是參考snabbdom實現的vdom和diff
----------diff算法
diff即對比,是一個廣泛的概念,如linux diff命令,git diff等
diff算法過程:patch(elem,vnode)和patch(vnode,newVnode)
patchVnode和addVnodes和removeVnodes
updateChidren(key的重要性)
兩課樹做diff

 

 

模板編譯
前置知識點:with語法

改變{}內自由變量的查找規則,當做obj屬性來查找,如果找不到匹配的obj屬性,就會報錯
with要慎用,它打破了作用域規則,易讀性變差

模板它不是html,有指令,插值,js表達式,能實現判斷,循環
模板編譯為render函數,執行render函數返回vnode
基於vnode再執行patch和diff
vue組件中使用render代替template
渲染過程
①初次渲染過程
解析模板為render函數
觸發響應式,監聽data屬性 getter setter
執行render函數,生成vnode,patch(elem,vnode)

②更新過程
修改data,觸發setter(此前在getter中已被監聽)
重新執行render函數,生成newVnode
path(vnode,newVnode)

③異步渲染
通過$nextTick方法
匯總data的修改,一次性更新視圖,減少DOM操作次數,提高性能

前端路由
①hash

hash的特點:hash變化不會觸發網頁跳轉,即瀏覽器的前進、后退
hash變化不會刷新頁面,SPA必需的特點
hash永遠不會提交到server端
②H5 history
用url規范的路由,但跳轉時不刷新頁面
H5 history需要后端支持
to B的系統推薦用hash,簡單易用,對url規范不敏感
to C的系統,可以考慮選擇H5 history,但需要服務端支持

React
React vs Vue
React和Vue一樣重要(特別是大廠面試),力求兩者都學會
React和Vue有很多相通之處,而且正在趨於一致
React比Vue學習成本高,尤其對於初學者
React的event
①event是SyntheticEvent,模擬出來DOM事件所有能力
②event.nativeEvent是原生事件對象
③所有的事件,都被掛載到document上
④和DOM事件不一樣,和Vue事件也不一樣
受控組件和非受控組件
例如等元素都要綁定一個change事件,當表單的狀態發生變化,就會觸發onChange事件,更新組件的state。這種組件在React中被稱為受控組件,在受控組件中,組件渲染出的狀態與他的value或checked屬性相對應,react通過這種方式消除了組件的局部狀態,使整個狀態可控。react官方同樣推薦使用受控表單組件
如果一個表單組件沒有value props(單選和復選按鈕對應的是checked props)時,就可以稱為非受控組件.
在非受控組件中,我們可以使用一個ref來從DOM獲得表單值。而不是為每個狀態更新編寫一個事件處理程序。
setState(同步還是異步)
setState之前不可變值,可能是異步更新,可能會被合並(傳入對象的情況下,多個setState只執行一次,傳入函數,不會被合並)
同步還是異步?
setState直接使用是異步的,想獲取state中最新的值,在setState加入回調
setTimeout中setState是同步的,自定義的DOM事件中也是同步的
React組件生命周期
1.第一次初始化渲染顯示:ReactDOM.render()
construction() 創建對象初始化state
componentWillMount() 組件渲染之前
render() 渲染組件
componentDidMount() 組件渲染之后
2.每次更新this.setState()
componentWillUpdata() 將要更新之前
render() 更新(重新渲染)
componentDidUpdata()已經更新之后
3.移除組件ReactDOM.unmountComponentAtNode(containerDom dom容器)
componentWillUnmount()組件要被移除回調

React高級特性
函數組件


非受控組件
使用場景
必須手動操作DOM元素,setState實現不了
文件上傳

showInput = () => {
const input = this.refs.content//之前版本獲取ref的標簽
console.log(input.value);
console.log(this.input.value);//新方法
}
render(){
<input type="text" ref={input => this.input = input}//ref標識組件內的元素
<button onClick={this.showInput}>獲取input值</button>
}
1
2
3
4
5
6
7
8
9
Portals
組件默認會按照既定層次嵌套渲染。如何讓組件渲染到父組件以外?
Portals使用場景
overflow:hidden 父組件z-index值太小 fixed需要放在body第一層級
基本使用:

render(){
//使用Portals渲染到body上
return ReactDOM.createPortal(
<div className="modal">{this.props.children}</div>,
document.body
)
}
1
2
3
4
5
6
7
context
公共信息(語言、主題)如何傳遞給每個組件?用props太繁瑣,用redux小題大做
React.createContext:創建一個上下文的容器(組件), defaultValue可以設置共享的默認數據

const {Provider, Consumer} = React.createContext(defaultValue)
1
Provider(生產者): 和他的名字一樣。用於生產共享數據的地方。生產什么呢? 那就看value定義的是什么了。value:放置共享的數據。

<Provider value={/*共享的數據*/}>
/*里面可以渲染對應的內容*/
</Provider>
1
2
3
Consumer(消費者):這個可以理解為消費者。 他是專門消費供應商(Provider 上面提到的)產生數據。Consumer需要嵌套在生產者下面。才能通過回調的方式拿到共享的數據源。當然也可以單獨使用,那就只能消費到上文提到的defaultValue

<Consumer>
{value => /*根據上下文 進行渲染相應內容*/}
</Consumer>
1
2
3
異步組件
Vue中使用import() React中使用React.lazy React.Suspense

從 React 中引入 lazy 方法和 Suspense 組件,然后用 lazy 方法處理我們的組件,lazy 會返回一個新的React 組件,我們可以直接在 Suspense 標簽內使用,這樣組件就會在匹配的時候才加載。
lazy 接受一個函數作為參數,函數內部使用 import() 方法異步加載組件,加載的結果返回。
Suspense 組件的 fallback 屬性是必填屬性,它接受一個組件,在內部的異步組件還未加載完成時顯示,所以我們通常傳遞一個 Loading 組件給它,如果沒有傳遞的話,就會報錯。
基本使用:

import React, { lazy, Suspense } from 'react';

const Index = lazy(() => import('components/Index'));
const List = lazy(() => import('components/List'));

class App extends React.Component {
render() {
return <div>
<Suspense fallback={Loading}>//fallback 屬性是必填屬性,它接受一個組件
<Index></Index>
<List></List>
</Suspense>
</div>
}
}
function Loading() {
return <div>
Loading...
</div>
}
export default App;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
性能優化
shouldComponentUpdate(簡稱SCU)

_.isEqual方法做對象或者數組的深度比較
SCU默認返回true,即React默認重新渲染所有子組件,必須配合“不可變值”一起使用,可先不用SCU,有性能問題時再考慮使用

PureComponent和React.memo
PureComponent,SCU中實現了淺比較
memo,函數組件中的PuceComponent,淺比較已使用大部分情況(盡量不要做深度比較)

不可變值immutable.js
徹底擁抱“不可變值”,基於共享數據(不是深拷貝),速度好,按需使用

高階組件HOC
基本用法


Render Props


Redux使用
和Vuex作用相同,但比Vuex學習成本高,不可變值,純函數
基本概念
store state
action
reducer

import { createStore } from 'redux';
/**
* 這是一個 reducer,形式為 (state, action) => state 的純函數。
* 描述了 action 如何把 state 轉變成下一個 state。
*
* state 的形式取決於你,可以是基本類型、數組、對象、
* 甚至是 Immutable.js 生成的數據結構。惟一的要點是
* 當 state 變化時需要返回全新的對象,而不是修改傳入的參數。
*
* 下面例子使用 `switch` 語句和字符串來做判斷,但你可以寫幫助類(helper)
* 根據不同的約定(如方法映射)來判斷,只要適用你的項目即可。
*/
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
// 創建 Redux store 來存放應用的狀態。
// API 是 { subscribe, dispatch, getState }。
let store = createStore(counter);
// 可以手動訂閱更新,也可以事件綁定到視圖層。
store.subscribe(() =>
console.log(store.getState())
);
// 改變內部 state 惟一方法是 dispatch 一個 action。
// action 可以被序列化,用日記記錄和儲存下來,后期還可以以回放的方式執行
store.dispatch({ type: 'INCREMENT' });
// 1
store.dispatch({ type: 'INCREMENT' });
// 2
store.dispatch({ type: 'DECREMENT' });
// 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
單項數據流

react-redux

異步action

 

redux中間件

 

 

React-router使用
路由模式(hash、H5 history),同vue-router,路由配置(動態路由、懶加載),同vue-router

 

 

React部分原理(≠源碼)
函數式編程
一種編程范式,概念比較多,純函數,不可變值
函數式編程:是一種設計思想,盡量用函數組合來進行編程,先聲明函數,然后調用函數的每一步都有返回值,將具體的每一步邏輯運算抽象,封裝在函數中。再將函數組合來編寫程序。
vdom和diff

 

JSX本質

 

合並事件

 

batchUpdate機制

setState

 

batchUpdate機制

 

transaction事務機制

 

組件渲染過程

 

 

內容來源bilibili,鏈接視頻


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM