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
proxy基本使用

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']
}

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

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:["一","二","三","四"]
          }
        }
      }
      }
    })

动态异步组件
: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"
	}
	}
}

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

Vue部分原理(≠源码)

组件化(MVVM,数据驱动视图)
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
	}
})
//如果监听的类型是对象,需要判断进行深度监听
//如果监听的类型是数组,不污染全局的数组原型情况下,重新定义数组原型

Object.defineProperty的缺点:深度监听,需要递归到底,一次性计算量大
无法监听新增属性/删除属性(需要Vue.set Vue.delete两个API来使用)
Vue3.0使用Proxy取代,但Proxy有兼容性问题,且无法polyfill,所以Vue2.x还会存在一段时间

vdom(Virtual DOM)和diff(虚拟DOM和diff算法,面试中的热门问题)
vdom----用js模拟DOM结构,计算出最小的变更,操作DOM
真实DOMvdom
vue是参考snabbdom实现的vdom和diff
----------diff算法
diff即对比,是一个广泛的概念,如linux diff命令,git diff等
diff算法过程:patch(elem,vnode)和patch(vnode,newVnode)
patchVnode和addVnodes和removeVnodes
updateChidren(key的重要性)
两课树做diff
diff对比
之前的diff每次要计算n的3次方

只比较同一层级
tag不同直接删掉重建
模板编译
前置知识点: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
URL组成部分
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>
	}

Portals
组件默认会按照既定层次嵌套渲染。如何让组件渲染到父组件以外?
Portals使用场景
overflow:hidden 父组件z-index值太小 fixed需要放在body第一层级
基本使用:

	render(){
	//使用Portals渲染到body上
	return ReactDOM.createPortal(
		<div className="modal">{this.props.children}</div>,
		document.body
	)
	}

context
公共信息(语言、主题)如何传递给每个组件?用props太繁琐,用redux小题大做
React.createContext:创建一个上下文的容器(组件), defaultValue可以设置共享的默认数据

const {Provider, Consumer} = React.createContext(defaultValue)

Provider(生产者): 和他的名字一样。用于生产共享数据的地方。生产什么呢? 那就看value定义的是什么了。value:放置共享的数据。

<Provider value={/*共享的数据*/}>
    /*里面可以渲染对应的内容*/
</Provider>

Consumer(消费者):这个可以理解为消费者。 他是专门消费供应商(Provider 上面提到的)产生数据。Consumer需要嵌套在生产者下面。才能通过回调的方式拿到共享的数据源。当然也可以单独使用,那就只能消费到上文提到的defaultValue

<Consumer>
  {value => /*根据上下文  进行渲染相应内容*/}
</Consumer>

异步组件
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;

性能优化
shouldComponentUpdate(简称SCU)
SCU基本用法
_.isEqual方法做对象或者数组的深度比较
SCU默认返回true,即React默认重新渲染所有子组件,必须配合“不可变值”一起使用,可先不用SCU,有性能问题时再考虑使用

PureComponent和React.memo
PureComponent,SCU中实现了浅比较
memo,函数组件中的PuceComponent,浅比较已使用大部分情况(尽量不要做深度比较)
React.memo
不可变值immutable.js
彻底拥抱“不可变值”,基于共享数据(不是深拷贝),速度好,按需使用
immutable.js
高阶组件HOC
基本用法
高阶组件
高阶组件
Render Props
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

单项数据流
单项数据流
react-redux
react-redux
异步action
异步action
异步action
异步action
redux中间件
redux中间件
redux中间件
redux中间件
redux数据流程图

React-router使用

路由模式(hash、H5 history),同vue-router,路由配置(动态路由、懒加载),同vue-router
React-router路由模式
路由配置、动态路由
跳转路由
懒加载

React部分原理(≠源码)

函数式编程
一种编程范式,概念比较多,纯函数,不可变值
函数式编程:是一种设计思想,尽量用函数组合来进行编程,先声明函数,然后调用函数的每一步都有返回值,将具体的每一步逻辑运算抽象,封装在函数中。再将函数组合来编写程序。
vdom和diff
vdom
diff
总结
JSX本质
JSX
本质
JSX本质
合并事件
合成事件
图示
需求
batchUpdate机制
简述
setState
核心
setState流程图
流程
batchUpdate机制
isBatchingUpdares
能命中机制
不能命中机制
transaction事务机制
transaction
事务机制
transaction事务机制
组件渲染过程
回顾vue
JSX本质
回顾
渲染过程
更新过程
内容来源bilibili,链接视频

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值