ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Vue全家桶+React全家桶面试题及部分原理整理

2020-06-11 10:06:24  阅读:214  来源: 互联网

标签:面试题 Vue 渲染 DOM 全家 value React 组件 data


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,链接视频

标签:面试题,Vue,渲染,DOM,全家,value,React,组件,data
来源: https://www.cnblogs.com/onesea/p/13091470.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有