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渲染
常见表单项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/
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事件销毁,防止内存泄漏