vue必问核心面试题(vue2),下篇更新vue3面试题

发布时间 2023-11-21 16:30:43作者: 开源遗迹

Vue 面试题

  • v-if 和 v-show 的区别。

在频繁切换使用的场景建议用v-show
<p style="display: none;">B</p>
DOM会渲染所有的v-show,用不到就style="display: none;"

 

  • 为何 v-for 中使用 key(要说明原理)?

  • 描述 Vue 生命周期(有父子组件的情况下)。

  • Vue 组件通讯的常见方式。

  • 描述组件渲染和更新的过程(开放型题目,自由发挥)。

  • 用 Vue 设计一个购物车,请设计组件结构,设计 vuex 数据结构。

 

computed有缓存,data不变则不会重新计算

watch如何深度监听?

data{
name: 'sss'
info:{
city:'cc'
}
},
watch: {
name(oldVal,val) {
console.log('name',oldVal,val)//值类型,两个都能拿到
},
info: {
handler(oldVal,val) {
console.log('info',oldVal,val)//引用类型,拿不到oldVal
},
deep: true
}
}

watch监听应用类型,拿不到oldVal

 

class和style

<p :class="{black:isBack}">
<p :style="styleData">
data(){
return{
isBlack: true,
isYellow: true,
black: 'black',
}
styleData: {
fonSize: '40px'
}
}

 

循环(列表)渲染

如何遍历对象?v-for

key不能乱写

<li v-for="(item, index) in listArr" :key="item.id">
<li v-for="(val, key,index) in listObj" :key="key">

v-if和v-for不能一起使用,影响DOM渲染

v-model

常见表单项textarea checkbox radio select

修饰符lazy number trim

event参数,自定义参数

事件修饰符,按键修饰符

观察事件绑定到哪里

 

props和$emit

父组件向子组件传参数,子组件向父组件发送事件

creatd和munted

created是初始化完

munted是DOM渲染完

由外向内创建,由内向外渲染

 

自定义v-model

$nextTick

addItem() {
this.listpush(`${Date.now()}`)
this.listpush(`${Date.now()}`)
this.listpush(`${Date.now()}`)
1.异步渲染,$nextTick 待DOM渲染完后在回调
3.页面渲染时会将data的修改做整合,多次data修改只会渲染
this.$nextTick(() => {
//获取DOM元素
const ulElem = this.$refs.ul1
、、eslint-disable-next-line
console.log(ulElem.childNodes.length)
})
}

refs

slot

父组件
<a :href="url">
<solt>
默认内容
</solt>
</a>
子组件
<ScopedSlotDome :url="web.url">
{{web.title}}
</ScopedSlotDome>

动态组件

 

异步组件

什么时候用到什么时候加载

//同步
import FormDemo from './ScopedSlotDemo'

//异步
components: {

FormDemo: () => import('../BaseUse/FormDemo')

}

keep-alive

简单结构可以使用v-show,css层级使用display

像tab切换组件用keep-alive,框架层级,mounted缓存,不去destroyed

原理

<keep-alive>
<KeepDAliveA v-if="state === 'A'"/>
<KeepDAliveB v-if="state === 'B'"/>
<KeepDAliveC v-if="state === 'C'"/>
</keep-alive>

mixin

抽离公共逻辑

问题

变量来源不明确

如果引入多个混合组件使用,可能造成命名冲突

mixin和组件可能出现多对多的关系,复杂度较高

可能出现多对多问题

 

面试技巧

知识点要结合项目中的场景

 

 

Vuex

 

Vue-router路由配置

两种模式

hash(默认),如路由http://abc.com/#/user/10

H5 history模式,如http://abc.com/user/20

const roter = new VueRouter({
  mode: 'history',
  routes: [...]
})

后者需要server端支持,因此特殊需求选前者

动态路由

const router = new VueRouter({
routes: [
//动态路径参数 以冒号开头。能命中 '/user/10' '/user/20' '/user/30'等格式的路由
{path: '/user/:id',componet: User}
]
})

懒加载(和异步加载组件一样)

routes: [
{
path: '/',
component: () => import(
'./../components/Navigator'
)
},
{
path: '/',
component: () => import(
'./../components/FaceBack'
)
},
]

 

组件化

数据驱动试图

传统组件,只是静态渲染,更新还要依赖操作DOM

数据驱动视图-Vue MVVM

 

响应式

组件data的数据一旦变化,立即触发视图的更新

实现数据驱动视图的第一步

考察Vue原理

 

核心API-Object.defineProperty

如何实现响应式,代码演示

Object.defineProperty的缺点(Vue3启用Proxy)

const data = {}
const name = 'zhangsan'
Object.defineProperty(data,'name', {
get: function() {
console.log('get')
return name
},
set: function (newVal) {
console.log('set')
name = newVal
}
})
//测试
console.log(data.name)//get
data.name = 'lisi' //set

Proxy有兼容性问题

Proxy兼容性不好,而且无法polyfill

 

 

深度监听data变化

Object.defineProperty缺点

深度监听,需要递归到底,计算量很大

无法监听新增属性/删除属性(Vue.set Vue.delete)

无法监听数组

 

 

虚拟DOM和diff算法

首先,操作DOM非常消耗性能

diff算法时vdom的核心

diff算法就是基于两个DOM树去做对比

 

用JS模拟DOM结构

<div id="div1" class="container">
<p>vdom></p>
<ul style="font-size: 20px">
<li>a</li>
</ul>
</div>


{
tag: 'div',
propos: {
classNmae: 'container',
id: 'div1'
}
children: [
{

tag: 'p'
children: 'vdom'
},
{
tag: 'ul',
props: {style: 'font-size: 20px'}
children: [
{
tag: 'li'
children: 'a'
}
]
}
]
}

对虚拟节点比对,不一样就销毁重建

 

vnode

 

 

 

 

能用js实现的操作尽量少操作DOM

 

 

 

模板编译

模板是vue开发中最常用的部分

模板不是html,有指令、插值、JS表达式,到底是什么?

组件渲染和更新过程

 

前置知识:JS的with的语法

改变{}内自由变量查找规则,当作obj属性来查找

如果找不到匹配的obj属性,就会报错

with要慎用,他打破了作用域规则,易变形差

const obj = {a: 100, b: 200}
console.log(obj.a)
console.log(obj.b)
console.log(obj.c)//undefined

//使用with,能改变{}内自由变量的查找方式
//将{}内自由变量,当作obj的属性来查找
with(obj) {
  console.log(a)
  console.log(b)
  console.log(c)//会报错
}

 

 

 

 

 

vue template complier 将模板编译为render函数

执行render函数生成vnode

举例

插值
const template = '<p>{{message}}</p>'
with(this){return _c('p',[_v(_s(message))])}
属性和动态属性
const template = '
<div id="div1" class="container">
<img :src="imgUrl">
</div>
'
//with(this){return _c('div',{staticClass:"container",attrs:["id":"div1"]},
[
_c('img',{attrs:{"src":imgUrl}})]
)}

缩写函数
_s=toString
_v=createTextVNode
_c=createElement
_l=rederList

 

 

 

vue组件中使用render替代template

Vue.component('heading',{
render: function (createElement) {
return createElment(
'h' + this.levl,
[
createElement('a',{
attrs: {
name: {
name: 'headerId',
href: '#' + 'headerId'
}
}, 'this is a tag'
})
]
)
}
})

 

with语法

模板到render函数,再到vnode,再到渲染和更新

vue组件可以用render替代template

 

vue渲染和更新的过程

初次渲染

解析模板为render函数(或在开发环境已完成,vue-loader)

触发响应式,监听data属性getter setter

执行render函数,生成vnode,patch(elem,vnode)

 

更新过程

修改data,触发setter(在此之前getter中已被监听)

重新执行reder函数,生成newVnode

patch(vnode,newVnode)

 

 

回顾$nextTick

汇总data的修改,一次性更新视图

减少DOM操作次数,提高性能

methods: {
addItem() {
this.list.push('$(Date.now())')
this.list.push('$(Date.now())')
this.list.push('$(Date.now())')
//1.页面渲染是异步的,$nextTick渲染完再回调
//2.页面渲染时会将data的修改整合,多次data修改只会渲染一次
this.$nextTick(() => {
const ulElem = this.$refs.ul1
console.log(ulElem.childNodes.length)
})
}
}

 

前端路由

to B的系统推荐用hash,简单易容,对url规范不敏感

to C的系统,可以考虑选择H5 history,但需要服务端支持

能选择简单的,就别用复杂的,要考虑成本和收益

 

hash window.onhashchange

window.onhashchange = (event) => {
console.log('old url',event.oldURL)
}

H5 history-history.pushState和window.onpopstate

document.getElementById('bnt1').addEventListener('click',
const state = {name: 'page1'}
history.pushState(state,'','page1')
)
window.onpostate = (event) => {
console.log('onpopstate',event.state,location.pathname)
}

H5 history 需要后端支持

 

 

为何在v-for中用key

必须用key,且不能是index和random

diff算法通过tag和key来判断,是否是sameNode

减少渲染次数,提升渲染性能

 

vue父子组件通讯方式

父子组件props和this.$emit

自定义事件event.$no event.$off event.$emit

vuex

 

 

为何data是一个函数?

首先,定义的vue组件或文件他是一个类,类里面就是方法函数,每个地方使用这个函数其实就是对这个类的实例化

 

 

ajax请求应该放到哪个生命周期?

mounted(组件加载完,DOM渲染完)

JS是单线程的,ajax异步获取数据

放在mounted之前没有用,只会让逻辑更混乱

 

何时使用keep-alive

缓存组件,不需要重新渲染·

如多个静态tab页的切换

优化性能

 

何时需要使用beforeDestory

解绑自定事件event.$off

清除定时器

解绑自定义的DOM事件,如window scroll等

Vuex中action和mutation有何区别

action中处理异步,mutation不可以

mutation做原子操作

action可以整合mutation

 

 

描述响应式原理

监听data变化

监听data变化的核心API是什么

Object.defineProperty

以及深度监听、监听数组

缺点

Object.defineProperty不能监听数组变化

重新定义原型,重写push pop等方法,实现监听

Proxy可以原生支持监听数组变化

组件渲染和更新过程

 

Vue何为异步渲染,$nextTick何用?

异步渲染,(以及合并data修改)以提高渲染性能

$nextTick在DOM更新完成后,触发回调

 

 

Vue常见性能优化方式

data层级不要做太深

使用vue-loader在开发环境做模板编译(预编译)

合理使用keep-alive

自定义事件、DOM事件销毁,防止内存泄漏