vue相关面试题(持续更新中)

文章目录

  • 1.vue数据监听
    • 1. vue2
    • 2.vue3
  • 2.生命周期
    • 1.vue2的生命周期
    • 2.vue3的生命周期
  • 3. vue2中常见的事件修饰符有哪些
  • 4. vue2中动态组件 VS 异步组件
    • 4.1 动态组件
    • 4.2 异步组件
  • 5. vue3中的组合式API常用的有哪些
  • 6. vue首屏加载优化的方式有哪些
  • 7. vue3父子组件嵌套时的生命周期顺序
  • 8.vue中使用$refs通信的弊端

1.vue数据监听

1. vue2

  • 面试官:如何使用defineProperty监听对象的所有属性值的变化?
  • 我:…
---js----
// 1. 创建一个监听类首先判断是数组还是对象类型
export class Observer {
	constructor(personInfo) {  // 给obj里面初始一个personInfo属性
		this.personInfo = personInfo;
		if (Array.isArray(personInfo)) {
			// 数组的情况
		} else {
			// 对象的情况
			this.walk(personInfo);
		}
	}
	
// 2. 循环遍历整个对象的属性,调用监听方法进行监听
	walk(obj) {
		const keys = Object.keys[obj];  // 将属性的键提取出来
		for (let i = 0; i < keys.length; i++) {  // 遍历监听
			ObserverObj(obj, keys[i]);	// 调用监听的方法
		}
	}
}
function ObserverObj(obj, key, val) {
	if (arguments.length === 2) {
		val = obj[key]  // 只传入两个参数的时候提取出键对应的值
	}
	if (typeof val === 'object') {  // 如果属性有套娃现象就再次进行递归监测
		new Observer(val) 
	}
	Object.defineProperty(obj, key, {
		get() {
			console.log(`${key}属性被读取了,属性值为${val}`); 
			return val;
		},
		set(newVal) {
			console.log(`${key}属性被修改了,新的属性值为${newVal}`);
			val = newVal;
		}
	})
}
---html---
import {Observer} from '.observer.js'
let obj = new Observer({
	name: '高起墙',
	age: 99
})
console.log(obj.personInfo.name);    // 属性读取
obj.personInfo.age = 1;  // 属性修改

2.vue3

let obj = {
	name: '路飞',
	age: 18
}
// 使用proxy方法对监听的对象的属性的crud操作进行拦截监听
const proxy = new Proxy(obj, {
	get(target,propName){
          console.log(`有人读取了proxy身上的${propName}`)
          return target[propName];  
          //反射
          return Reflect.get(target,propName)
      },
      // 改 
      // value属性必须放在最后面
      set(target, propName, value){
          console.log(`有人修改了p身上的${propName}属性`);
          target[propName] = value;
      },
      // 删
      deleteProperty(target, prop){
          console.log(`有人删除了p身上的${prop}属性`)
          return delete target[prop];
      }
})

效果
vue相关面试题(持续更新中)_第1张图片

2.生命周期

1.vue2的生命周期

  1. 什么是生命周期和生命周期函数?

    • 一个组件从 创建 -> 运行 -> 销毁 的过程被称为组件的生命周期
    • 为了能够在确切的某个周期执行某个操作,vue为开发者提供了生命周期函数来在确切的阶段做某件事
  2. 生命周期

    • 创建阶段:
      – beforeCrate() 组件创建之前,初始化组件实例和props, data, method等属性
      – created() 在内存中创建完成,但是没有完成DOM结构的渲染,不能够获取到组件里面的任何标签元素,此时可以操作props,data,method等属性
      – beforeMount() 在DOM结构渲染完成之前
      – mounted() DOM结构渲染完成,同时可以进行DOM元素的获取
    • 运行阶段
      – beforeUpdate()
      组件数据更新和页面结构重新渲染之前,这里的dom元素依旧是原始的dom元素,没有因为数据的更改进行dom结构的重新渲染
      – updated()
      DOM结构是最新的且数据也是最新的,这里页面至少进行了一次更新
    • 销毁阶段
      – beforeDestroy 组件销毁之前 这时的所有dom元素和data,method都是能够正常进行使用的
      – destroyed 组件已经销毁完成

    以下是原理图,可以对照着看…
    vue相关面试题(持续更新中)_第2张图片

总结:
生命周期函数里面主要使用的就是mounted, updated,页面dom结构渲染完成之后可以进行dom元素的获取和任何属性的获取;updated是数据完成了更新之后的时间点,所以这个时候的dom结构以及数据都是最新的。

2.vue3的生命周期

  1. 创建、挂载阶段
    vue3是没有beforeCreate、created这两个vue2的生命周期的,所以vue3的创建阶段的生命周期是onBeforeMount()、onMounted()这两个生命周期函数;在调用onBeforeMount钩子时DOM元素还没有进行渲染,根元素还不存在;在调用onMounted钩子时,DOM元素就存在了,可以直接访问
  2. 更新阶段
    onBeforeUpdate(),onUpdated()在调用onBeforeUpdate()之前dom元素和所有的数据都是原始的,还不是最新的,只有调用onUpdated之后所有数据才是最新的
  3. 销毁阶段
    onBeforeUnMount():组件卸载之前,这时候的组件实例还是完整的
    UnMounted():组件实例卸载之后,所有绑定的自定义事件和事件侦听器都会被移除
  4. API
    onBeforeMount()
    onMounted()
    onBeforeUpdate()
    onUpdated()
    onBeforeUnmount()
    onUnmounted()

3. vue2中常见的事件修饰符有哪些

  1. stop (阻止冒泡)
  2. prevent(阻止默认事件)
  3. once(只执行一次)
  4. sync(用于子组件想要更新父组件传递过来的props,然后使用this.$emit方法传递自定义事件和数据,父组件接收时给事件名加上.sync就可以实现响应式更新)

4. vue2中动态组件 VS 异步组件

4.1 动态组件

  1. 使用component标签来进行动态组件的渲染,:is属性输入你需要渲染的组件名即可,常用于需要频繁切换的组件显示,比如两个tab切换,点击之后更改组件名就可以实现组件的动态渲染

vue相关面试题(持续更新中)_第3张图片

  1. 动态组件常搭配keep-alive一起使用,因为我们希望切换之后能将数据进行缓存,切换回来时依旧能展示原来的数据,而不是被清空,避免再次重新渲染提升性能

  2. keep-alive包含三个参数 include (只有名称匹配的会被缓存) exclude(只有名称不匹配的会被缓存) max(可以缓存的组件实例个数),它是一个抽象函数,不会渲染真实的dom标签在里面

    3.1 activated deactivated 在组件切换的时候会调用这两个钩子函数

// 通过数组的形式输入需要渲染的组件名

  

4.2 异步组件

  1. 在组件需要被渲染的时候才进行渲染,可以使用一个函数来进行定义我们所需要异步渲染的组件,函数只要被触发之后就会进行缓存,后面就直接读取缓存中的内容进行渲染
// 动态导入我们需要异步渲染的组件
Vue.component('template-demo', () => import('./template-demo'))  // 其实这有点类似于路由懒加载的写法

5. vue3中的组合式API常用的有哪些

ref( )、reactive( )、onMounted( )、onUnmounted( )、nextTick( )、provide( )、inject( )

  1. 响应式API:
    ref:
    -ref可以定义任意的数据类型为响应式,只是在脚本操作中需要.value才能读取到值,但是在template中不需要.value
    reactive:
    -使对象本身具有响应式,将一个普通 JavaScript 对象转换为响应式代理对象,使对象的属性能够被 Vue 的响应式系统追踪和触发更新。
    区别:
    -ref声明的响应式在setup中读取值需要加上.value,而在template里面使用就可以不需要.value
    -ref声明的是一个特殊的包装对象,将数据转为响应式的应用对象,使之变得响应式;reactive声明使对象本身具有响应式,通过将一个普通的js对象转为响应式代理对象,使得对象的属性能够被vue的响应式系统追踪和触发更新;
    -ref可以用来包装基本的数据类型,而reactive只能用于包装js对象
  2. 生命周期钩子
    onMounted: 可以用来在组件完成初始渲染并创建 DOM 节点后运行代码
    onUnmounted: 钩子可以用来在组件实例被卸载之后调用
    nextTick: dom节点更新之后
  3. 依赖注入
    -当父组件需要给自己的子组件传递值,但目标子组件又经历了多层嵌套的场景(可以使用props但很麻烦)
    -如果需要在注入的组件对象中更改值,可以在注入之前的父组件声明一个方法传递给子组件对象,然后子组件解构,拿到方法进行值的修改
    -如果不允许子组件修改使用readonly(传递的值)
// 提供
/* 我们也可以在整个应用层app上面提供依赖注入  应用层级别提供的数据在该应用内的所有组件中都可以注入 */
provide(/* 注入名 */ 'message', /* 值 */ 'hello!')

// 注入
const message = inject('message')
  1. 为什么要有组合式API
    更好的逻辑复用,选项式api的逻辑服用机制是混入,而组合是api就解决了这种缺陷
    更灵活的代码组织
    更好的进行类型的推导,搭配ts
    减小打包体积

6. vue首屏加载优化的方式有哪些

  1. 使用路由懒加载、图片懒加载:
    只有在路由被使用到的时候才进行加载,提升页面加载的速度
  2. 异步组件:
    使用import+组件名+回调函数的形式加载你需要进行异步加载的组件
  3. 打包时使用代码分割:
    -该方法可以减少打包的体积,尤其是js文件的代码
    -主要是针对首屏需要用户主动去触发之后才会产生回调的js代码进行代码分割,这样就能极大的减少打包的体积,提升页面渲染的速度
    -将按需加载的功能单独拆分到一个文件中进行管理,在需要按需加载的位置使用function+return import的方式进行引入即可
  4. 服务端渲染、静态站点生成:
    -服务:将浏览器需要渲染的html代码在服务器端直接预先渲染成html字符串,然后再作为服务端响应数据返回给浏览器,最后在浏览器将静态的html激活渲染即可
    -静态:可能服务端渲染的页面数据是重复的,所以不需要每次都重新进行渲染,所i有可以将其预先渲染为静态的html文件交给服务器托管,然后需要的时候直接拿取即可,就减少了再次进行服务端渲染的时间

7. vue3父子组件嵌套时的生命周期顺序

  1. 页面加载(父子嵌套)

    父: beforeCreate => created => beforeMount

    子: beforeCreate => created => beforeMount=> mounted

    父: mounted

  2. 页面改动(父子嵌套)

    父:beforeUpdate

    子:beforeUpdate => updated

    父:updated

  3. 页面离开(父子嵌套)

    父:beforeUnmount

    子:beforeUnmount => unmounted

    父:unmounted

8.vue中使用$refs通信的弊端

$refs是一个可以访问组件实例或原生DOM元素的特殊属性,可以用在组件间的通信.

  1. 增加组件间的耦合度:

    导致组件间的依赖关系变的紧密,降低组件的复用性和维护性

  2. 扩展性差:

    在组件数量增加或者组件结构变得复杂的时候会变得难以管理,组件层次的不断变化就需要更改$refs来适应,增加代码的复杂性

  3. 依赖组件的生命周期:

    使用$refs必须在组件渲染完成之后才能访问,如果需要组件渲染之前进行事务处理是不可行的

  4. 难以进行跨级通信:
    refs属性只能访问直接子组件的或原生DOM元素,如果需要更深层次的跨组件通信,refs实现起来可能不是太友好

总结:
在大多数情况下,推荐使用更灵活、松耦合的方法,如事件总线、Vuex 状态管理或父子组件间的 props 和事件等方式来进行组件间的通信。

你可能感兴趣的:(前端面试,vue.js,javascript,前端)