2021前端面试知识点总结之vue篇

461 阅读5分钟

这是我参与8月更文挑战的第30天,活动详情查看:8月更文挑战

MVVM 和 MVC

MVC

  • M(Model):模型,负责处理数据。
  • V(View):视图,负责数据的展示。
  • C(Controller):控制器,负责数据和视图之间的交互。
  • 总的来说就是:通过controller将Model的数据展示在View上。

MVVM

  • M(Model):模型,负责处理数据。
  • V(View):视图,负责数据的展示。
  • VM(View Model):实现了数据的双向绑定。主要通过两件事来实现:
    1. 通过数据绑定将Model转化为View;
    2. 通过DOM事件监听将View转化为Model
  • 实现了View和Model的自动同步。
  • MVVM 规定 View和Model不能直接通信。

什么是Vue

  • vue是一个用于构建用户界面的渐进式的javaScript框架。
  • 其具有灵活、易用、高效的特点。
  • 其采用虚拟DOM构建页面,单页面的路由。
  • 数据与视图分离、由数据驱动页面的刷新渲染。
  • 其借鉴了MVVM模型,但又完全不遵循MVVM,因为this.$refs的使用会破坏这种规则。
  • 缺点:单页面不利于seo,不支持IE8以下,首屏加载时间长。

Vue声明周期

2.x版本的生命周期

  • beforeCreate:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
  • created:在实例创建完成后立即被调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用。
  • beforMount:在挂载开始之前被调用:相关的render函数首次被调用。注意:
    1. 该钩子在服务端渲染期间不被调用
  • mounted:实例被挂载后调用。注意:
    1. mounted不能所有的子组件也被一起挂载
    2. 该钩子在服务端渲染期间不被调用
    3. 如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick
mounted: function () { 
    this.$nextTick(function () { 
        // 视图渲染完之后执行的一些操作
    }) 
}
  • beforUpdate:数据更新时调用,发生在虚拟DOM打补丁之前。此阶段适合 在更新DOM之前访问现有的DOM,比如手动移除已添加的事件监听器。注意:
    1. 该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
  • updated:在此阶段DOM已经被更新。注意:
    1. **应该避免在此阶段更改状态,最好使用computed或者watcher替代 **
    2. 该钩子在服务端渲染期间不会被调用
    3. updated 不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick
updated: function () { 
    this.$nextTick(function () { 
        // 视图渲染完之后执行的一些操作
    }) 
}
  • activated:被 keep-alive 缓存的组件激活时调用。 注意⚠️:
    1. 该钩子在服务端渲染期间不会被调用
  • deactivated:被 keep-alive 缓存的组件停用时调用。注意⚠️:
    1. 该钩子在服务端渲染期间不会被调用
  • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。注意:
    1. 该钩子在服务端渲染期间不会被调用
  • destroyed:实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。注意:
    1. 该钩子在服务端渲染期间不会被调用
  • errorCaptured:(v2.5.0+版本新增)当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

3.x版本的生命周期

由于3.x版本使用了setup组合式API(类似于react的hooks),而 setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。所以生命周期如下:

  • onBeforeMount
  • onMounted
  • onBeforeUpdate
  • onUpdated
  • onBeforeUnmount
  • onUnmounted
  • onErrorCaptured
  • onRenderTracked
  • onRenderTriggered
  • onActivated
  • onDeactivated

父子组件生命周期执行顺序

  • 加载渲染过程: 父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
  • 所以,为了更好的父子组件之间的数据传递,我们通常将数据请求放在created阶段进行。
  • 更新过程: 父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
  • 销毁过程: 父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

vue实现双向绑定的原理

  • vue2.x用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
  • vue3.x 通过proxy实现

组件之间的数据传递

父子组件

  • 父传子:通过props传递
  • 子传父:通过$emit
  • 爷孙之间通过 provide, inject

兄弟组件

  • 通过eventBus

路由之间传参

  • 通过 query、params

v-show 和 v-if

  • v-show 只是简单的通过css的display属性进行显示隐藏的切换
  • v-if 会真实的销毁和创建元素。

computed 和 watch

  • computed:  是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。(可以理解为自动的)
  • computed中的属性不能与data中的属性同名,否则会报错
  • watch 监听,只有当监听到某个属性的变化时,才会执行某些操作。(可以理解为手动的)

data 为什么是一个函数return回的对象?

  • 因为组件大多数情况下会被拿来复用,而js中对象是引用类型,如果组件中 data 是一个对象,那么作用域没有隔离,子组件中的 data 属性值会相互影响,如果组件中 data 选项是一个函数,那么每个实例可以维护一份被返回对象的独立的拷贝,组件实例之间的 data 属性值不会互相影响;而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。

@hook

  • 使用@hook可以监听子组件的生命周期函数,并且做一些你需要的操作
<Child @hook:mounted="dosomething"></Child>

v-model原理

  • v-model是一个语法糖,多数情况下用于表单元素上创建双向绑定。实现如下:
    • input框的 text 和 textarea 元素使用 value 属性和 input 事件;
    • checkbox 和 radio 使用 checked 属性和 change 事件;
    • select 使用 value 和 change 事件。

Vue 修饰符

修饰符阐述
.lazy改变输入框的值时value不会改变,当光标离开输入框时,v-model绑定的值value才会改变
.trim将v-model绑定的数据的值的首尾空格过滤掉
.number将值转成数字(先输入数字会将前面的数字部分截取出来;先输入字母则修饰符无效)
.stop阻止事件冒泡
.capture事件默认是由里往外冒泡capture修饰符的作用是反过来,由外向内捕获
.self只有点击事件绑定的本身才会触发事件
.once事件只执行一次
.prevent阻止默认事件
.native是加在自定义组件的事件上,保证事件能执行
.lfet鼠标左键触发的事件
.right鼠标右键触发的事件
.middle鼠标中间的键触发的事件
.passive相当于给滚动事件增加了.lazy修饰符
.camel确保绑定参数被识别为驼峰写法
.camel父子组件传值时,如果子组件想改变这个值可以使用此修饰符简写

v-for 和 v-if 为什么不建议一起使用?

  • v-for的优先级要高于v-if,将其放在同一个元素上时,每次数据渲染都会先循环再去判断条件,造成不必要的渲染,带来性能问题。

vue中使用了哪些设计模式?

  • 单例模式:整个应用程序有且仅有一个实例,即我们的入口文件处实例化的vue
  • 工厂模式:传入参数即可创建实例。
    • 虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode
  • 发布订阅模式:vue的事件机制
  • 观察者模式:响应式数据原理
  • 等。。。

你做过哪些vue的性能优化?

  • 对象层级不要过深,否则性能就会差。
  • 不需要响应式的数据不要放到 data 中(可以用 Object.freeze() 冻结数据)
  • v-if 和 v-show 区分使用场景
  • computed 和 watch 区分使用场景
  • v-for 遍历必须加 key,key 最好是 id 值,且避免同时使用 v-if
  • 大数据列表和表格性能优化-虚拟列表/虚拟表格
  • 防止内部泄漏,组件销毁后把全局变量和事件销毁
  • 图片懒加载
  • 路由懒加载
  • 第三方插件的按需引入
  • 适当采用 keep-alive 缓存组件
  • 防抖、节流运用
  • 服务端渲染 SSR or 预渲染

vue为什么要求组件模板只能有一个根元素?

我们在开发中通常都是写的单文件组件,如下:

<template>
    <div></div>
</template>
<script>

</script>
<style>

</style>
  • 单文件组件其实就是一个vue实例,既然是vue实例,那么就需要有一个入口,如果有多个div就无法指定入口。
  • 其次vue最终是要转换成DOM树,渲染到页面中的,而DOM的根节点只有一个。
  • template标签是不会真实的渲染到DOM中的。

vue中如何重置data

  • this.$data获取当前状态下的data;
  • this.$options.data()获取该组件初始状态下的data。
  • 使用Object.assgin(this.data,this.data, this.options.data())

说说你对vue的错误处理的了解

  • 分为errorCaptured与errorHandler。
  • errorCaptured是组件内部钩子,可捕捉本组件与子孙组件抛出的错误,接收error、vm、info三个参数,return false后可以阻止错误继续向上抛出。
  • errorHandler为全局钩子,使用Vue.config.errorHandler配置,接收参数与errorCaptured一致,2.6后可捕捉v-on与promise链的错误,可用于统一错误处理与错误兜底。

Vuex

  • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
  • Vuex 无法持久化、内部核心原理是通过创造一个全局实例 new Vue。(vuex-persist插件可实现持久化)
  • 主要包含以下几个核心概念:
    1. State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
    2. Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
    3. Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
    4. Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
    5. Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。