目录
扫描二维码关注公众号,回复:
14887633 查看本文章
18. Vuex 中 action 和 mutation 有何区别?
1. v-show 和 v-if 的区别
- v-show 通过 CSS display 控制显示和隐藏
- v-if 组件真正的渲染和销毁,而不是显示和隐藏
- 频繁切换显示状态用 v-show,否则用 v-if
2. 为何在 v-for 中使用 key
- 必须用 key,且不能是 index 和 random
- diff 算法中通过 tag 和 key 来判断,是否是 sameNode
- 减少渲染次数,提高渲染性能
3. 描述 Vue 组件生命周期(父子组件)
- 挂载
- 更新
- 销毁
3.1 单个组件
3.2 父子组件
- 挂载过程
父- beforeCreate -> 父-created -> 父- beforeMount -> 子-beforeCreate -> 子- created -> 子-beforeMount -> 子-mounted -> 父-mounted
- 更新过程
父-beforeUpdate -> 子-beforeUpdate -> 子-updated -> 父-updated
- 销毁过程
父-beforeDestory -> 子-beforeDestory -> 子-destoryed -> 父destoryed
简易版:父-created -> 子- created -> 子-mounted -> 父-mounted
初始化:由外到内
渲染:从内到外(子组件渲染完,父组件才算完)
更新:先触发父组件数据的变化,然后更新子组件,(子组件更新完,父组件才算完)
销毁:先触发父组件的销毁,然后销毁子组件,(子组件销毁完,父组件才算完)
4. Vue组件如何通讯(常见)
- 父子组件 props 和 this.$emit
- 自定义事件 event.$on event.$off event.$emit
- vuex(所有组件共享)
5. 描述组件渲染和更新的过程
Vue 原理三大模块:
- 响应式(紫色 Data 监听属性变化)
- 模板渲染(黄色部分)
- 虚拟 DOM(绿色部分)
过程:渲染时执行 render 函数会触发 Touch 的 getter ,之后收集依赖到 Watcher 里面,在触发 Data 更改时,会通知 Watcher,看之前是不是收集过这个 data 数据,如果收集过,就触发 setter 函数,然后触发 render 函数,重新渲染,如果之前没有收集过(即在页面模板没有用到)则不会触发 setter ,也不会重新渲染
6. 双向数据绑定 v-model 的实现原理
- input 元素的 value = this.name
- 绑定 input 事件,@input=“name = $event.target.value”
- data 更新触发 re-render
7. 对 MVVM 的理解
- Model:后端传递的数据
- View:所看到的页面
- ViewModel:MVVM模式的核心,它是连接 Model和View的模型
ViewModel有两个方向(实现双向数据绑定)
- 将Model转换成View,将后端传递的数据转换成所看到的页面,实现的方式是数据绑定(Data Bindings)
- 将View转换成Model,将所看到的页面转换成后端数据,实现的方式是DOM监听事件(DOM Listeners)
8. computed 有何特点
- 缓存,data 不变不会重新计算
- 提高性能
9. 为何组件 data 必须是一个函数?
<script>
export default {
name: 'app',
data() {
return {
name: 'vue',
list: ['a', 'b', 'c']
}
},
methods: {
changeName() {
this.name = '双越'
},
addItem() {
this.list.push(`${Date.now()}`)
}
}
}
</script>
- 因为 .vue 组件编译出来以后,是一个 class(一个类),
- 在每个地方使用这个 class 的时候,实际上是对 class 进行实例化,
- 在实例化的时候去执行 data,
- 如果 data 不是函数的话,那每个组件的数据 data 都一样了,就共享了,
- 如果 data 是一个函数,那么两个 data 就在闭包之中,不会相互影响
10. ajax 请求应该放在哪个生命周期?
- mounted(DOM 加载完成之后)
- JS 是单线程的,ajax 异步获取数据(DOM 渲染完成之后,再触发 ajax 请求,请求完之后再把数据渲染到页面,合理)
- 放在 mounted 之前没用,只会让逻辑更加混乱(DOM 没渲染完,也不会执行,在排队之中)
11. 如何将组件所有 props 传递给子组件?
- $props
- <User v-bind="$props" />
12. 如何自定义实现 v-model
// 父组件
<CustomVModel v-model="name"/>
// 子组件
<template>
<!-- 例如:vue 颜色选择 -->
<input type="text"
:value="text1"
@input="$emit('change1', $event.target.value)"
>
<!--
1. 上面的 input 使用了 :value 而不是 v-model
2. 上面的 change1 和 model.event1 要对应起来
3. text1 属性对应起来
-->
</template>
<script>
export default {
model: {
prop: 'text1', // 对应 props text1
event: 'change1'
},
props: {
text1: String,
default() {
return ''
}
}
}
13. 多个组件有相同的逻辑,如何抽离?
- mixin
- 变量来源不明确
- 多mixin可能会造成命名冲突
- mixin和组件可能出现多对多的关系,复杂度较高
- Vue3 提出的Composition API旨在解决这些问题
14. 何时要使用异步组件?
- 加载大组件(编辑器,图表)
- 路由异步加载
- 优化性能
15. 何时需要使用 keep-alive ?
- 缓存组件,不需要重复渲染
- 如多个静态 tab 切换
- 优化性能
16. 何时需要使用 beforeDestory ?
- 解绑自定义事件 event.$off
- 清除定时器
- 解绑自定义 DOM 事件(addEventListener),如 window scroll 等
- 以上不解绑容易内存泄露
17. 什么是作用域插槽?
// 父组件
<ScopedSlotDemo :url="website.url">
<template v-slot="slotProps">
{
{slotProps.slotData.title}}
</template>
</ScopedSlotDemo>
// 子组件
<template>
<a :href="url">
<slot :slotData="website">
{
{website.subTitle}} <!-- 默认值显示 subTitle ,即父组件不传内容时 -->
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {
website: {
url: 'http://wangEditor.com/',
title: 'wangEditor',
subTitle: '轻量级富文本编辑器'
}
}
}
}
</script>
18. Vuex 中 action 和 mutation 有何区别?
- action 中处理异步,mutation 不可以
- mutation 做原子操作(每次操作一个)
- action 可以整合多个 mutation
19. Vue-router 常用的路由模式?
- to B 的系统推荐使用 hash,简单易用,对 url 规则不敏感
- to C 的系统,可以考虑选择 H5 history(SEO,性能优化),但需要服务端支持
- 能选择简单的,就别用复杂的,要考虑成本和收益
- hash (默认) window.onhashchange
- 特点:
- hash 变化会触发网页跳转,即浏览器的前进,后退
- hash 变化不会刷新页面,SPA 必需的特点
- hash 永远不会提交到 server 端(前端自生自灭)
- H5 history (需要服务端支出)history.pushState 和 window.onpopstate
- 特点:
- 用 url 规范的路由,但跳转时不刷新页面
20. 如何配置 Vue-router 异步加载
通过 import 加载异步组件的方式配置
21. 请用 vnode 描述一个 DOM 结构
<!-- 页面dom结构 -->
<div id="div1" class="container">
<p>vdom</p>
<ul style="font-size: 20px;">
<li>a</li>
</ul>
</div>
<script>
/* js模拟dom结构 */
const vdom = {
tag: 'div',
props: {
className: 'container',
id: 'div1'
},
children: [
{
tag: 'p',
children: 'vdom'
},
{
tag: 'ul',
props: {
style: 'font-size: 20px'
},
children: [
{
tag: 'li',
children: 'a'
}
]
}
]
}
</script>
22. 监听 data 变化的核心 API 是什么?
- Object.defineProperty
- 以及深度监听,监听数组
- 有何缺点
23. Vue 如何监听数组变化?
- Object.defineProperty 不能监听数组变化
- 重新定义原型,重写 push pop 等方法,实现监听
- Vue3 Proxy 可以原生支持监听数组变化
24. 请描述响应式原理
- 监听 data 变化(Object.defineProperty)
- 组件渲染和更新的流程
25. diff 算法的时间复杂度
O(n)
- 在 O(n ^3) 基础上做了一些调整
- 只比较同一层级,不跨级比较
- tag 不相同,则直接删掉重建,不再深度比较
- tag 和 key,两者都相同,则认为是相同节点,不再深度比较
26. 简述 diff 算法过程
- patch(elem,vnode)和 patch(vnode,newVnode)
- pathchVnode 和 addVnodes 和 removeVnodes
- updateChildren (key 的重要性)
27. Vue为何是异步渲染,$nextTick 何用?
- 异步渲染(以及合并 data 修改),以提高渲染性能
- $nextTick 在DOM 更新完成之后,触发回调
28. Vue常见性能优化
- 合理使用 v-show 和 v-if
- 合理使用 computed
- v-for 时加 key,以及避免和 v-if 同时使用,(v-for 优先级高,每层都要判断 v-if,造成性能浪费)
- 自定义事件,DOM 事件及时销毁(beforeDestory)
- 合理使用异步组件
- 合理使用 keep-live
- data 层级不要太深
- 使用 vue-loader 在开发环境做模板编译(预编译)
- webpack 层面优化
- 前端通用的性能优化,如图片懒加载
- 使用 SSR