九、Vue-前端面试题库

本文深入探讨了Vue.js的核心概念,包括MVVM模式、生命周期、组件通信和响应式系统。详细讲解了Vue中网络请求的最佳时机、各种组件通信方式,如props、$emit、eventBus、$refs、provide/inject、Vuex,以及计算属性和watch的差异。还介绍了Vue的双向绑定原理、key的作用和路由传参方式。同时,讨论了Vue项目中的SEO优化策略,包括服务器渲染、静态化和预渲染。此外,文章还涵盖了Vue项目中的权限处理、支付功能实现和性能优化,展示了面试中可能遇到的技术难点及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Vue

1. 什么是 MVVM

Model-View-ViewModel 模式

image-20210223221853817.png

Model 层: 数据模型层

通过 Ajaxfetch 等 API 完成客户端和服务端业务模型的同步。

View 层: 视图层

作为视图模板存在,其实View 就是⼀个动态模板。

ViewModel 层: 视图模型层

负责暴露数据给 View 层,并对 View 层中的数据绑定声明、 指令声明、 事件绑定声明, 进行实际的业务逻辑实现。

数据变化了, 视图自动更新 => ViewModel 底层会做好监听Object.defineProperty,当数据变化时,View 层会自动更新

视图变化了, 绑定的数据自动更新 => 会监听双向绑定的表单元素的变化,⼀旦变化,绑定的数据也会得到⾃动更新。

2. MVVM的优缺点有哪些?

优点

  1. 实现了视图(View)和模型(Model)的分离,降低代码耦合、提⾼视图或逻辑的复⽤性
  2. 提⾼了可测试性:ViewModel 的存在可以帮助开发者更好地编写测试代码
  3. 能⾃动更新 DOM:利⽤双向绑定,数据更新后视图⾃动更新,让开发者从繁琐的⼿动操作 DOM 中解放出来

缺点

  1. Bug 难被调试:因为使⽤了双向绑定的模式,当我们看到界⾯发生异常了,有可能是 View 的代码产生的 Bug,
    也有可能是Model 代码的问题。数据绑定使得⼀个位置的 Bug 被快速传递到别的位置,
    要定位原始出问题的地⽅就变得不那么容易了
    可采用的调试方案:
    (1) 注释掉一段代码, 确定代码的位置
    (2) debugger 打断点 或者 console 进行调试
  2. 在⼀个⼤的模块中 Model 也会很⼤,虽然使⽤上来说⽅便了,但如果⻓期持有不释放内存,就会造成更多的内存消耗
    占用的是 浏览器的 内存

3. 谈谈对Vue生命周期的理解?

生命周期的概念

每个 Vue 实例(每个组件也都是一个vue实例)都有⼀个完整的⽣命周期:

  1. 开始创建 (空实例)
  2. 初始化数据
  3. 编译模版
  4. 挂载 DOM
  5. 渲染、更新数据 => 重新渲染
  6. 卸载

这⼀系列过程我们称之为 Vue 的⽣命周期。

各个生命周期的作用

生命周期 执行时机
beforeCreate 在组件实例被创建之初、组件的属性⽣效之前被调用
created 在组件实例已创建完毕。此时属性也已绑定,但真实DOM还未⽣成,$el 还不可⽤
beforeMount 在组件挂载开始之前被调⽤。相关的 render 函数⾸次被调⽤
mounted 在 el 被新建的 vm.$el 替换并挂载到实例上之后被调用
beforeUpdate 在组件数据修改了, 视图更新之前调⽤。发⽣在虚拟 DOM 打补丁之前
updated 在组件数据修改了, 视图更新之后被调用
activited 在组件被激活时调⽤(使用了 <keep-alive>
的情况下)
deactivated 在组件被停用时调⽤(使用了 <keep-alive>
的情况下)
beforeDestory 在组件销毁前调⽤ (销毁: vue默认会进行释放掉实例所有的监听, 释放掉所有的组件…)
destoryed 在组件销毁后调⽤ (像定时器, webscoket连接, … 跟vue没有太大关联的资源, 需要手动释放!)

生命周期示意图

image-20210224084130350.png

4. 在Vue中网络请求应该放在哪个生命周期中发起?

至少在 created 之后, 因为数据才基本初始化完毕, 当然 mounted 中也可以 (比created稍晚一些)

5. Vue组件之间如何进行通信?

父传子, 子传父, 非父子, Vuex

5.1 props 和 $emit

(1) 通过 props 将数据在组件树中进行⾃上⽽下的传递;

<jack :money="count" :obj="myobj"></jack>
export default {
  // props: ['money']
  props: {
      money: {
          type: Number,
          default: 1
      },
      obj: {
          type: Object,
          default: () => {
              return {
                  name: 'zs',
                  age: 18
              }
          }
      }
  }
}

附件: props 验证

(2) 通过 $emit@ 来作信息的向上传递。

this.$emit('add-action', 参数1, 参数2, ...)
<jack @add-action="fatherFn"></jack>

5.2 eventBus事件总线

可通过 EventBus 进⾏信息的发布与订阅。 (创建一个都能访问到的事件总线)

Vue.prototype.$eventBus = new Vue()   // this.$eventBus
// A组件中, 监听 bus的事件
this.$eventBus.$on('事件名', function(参数1, 参数2, ...) {
   
   
	...
})

// B组件中, 触发 bus的事件
this.$eventBus.$emit('事件名', 参数1, 参数2, ...)

5.3 $children $parent $refs

(1) $children

父组件中, $children 返回的是一个组件集合,如果你能清楚的知道子组件的顺序,你也可以使用下标来操作

// 父组件中
<template>
  <div class="hello_world">
    <com-a></com-a>
    <com-b></com-b>
  </div>
</template>

this.$children[0] => <com-a></com-a>

this.$children[1] => <com-b></com-b>

(2) $parent

子组件中, this.$parent 指向父组件

this.$parent.xxx = 200

this.$parent.fn()

(3) $refs

通过添加 ref 和 $refs 配合, 也可以很方便的获取子组件, 访问调用子组件的属性或方法

// 父组件中
<template>
  <div class="hello_world">
    <com-a ref="coma"></com-a>  // this.$refs.coma.count = 200
    <com-b ref="comb">
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值