武汉前端面试(1)

发布于:2025-03-05 ⋅ 阅读:(10) ⋅ 点赞:(0)

面一:

  • vue2和vue3的响应式原理比较?

vue2通过object.defineProperty对对象的每个属性进行劫持,会遍历对象的每一个属性,使用getter和setter,只能监听部分方法

vue3是基于Proxy代理整个对象,不是逐个属性监听,可以监听新增属性和删除属性,使用reactive函数返回通过proxy创建的代理对象,

  • vue3使用proxy的优点:

支持新增和删除属性的响应式

可以监听所有类型的数组操作,节省内存

  • proxy的缺点:浏览器兼容问题,低版本不能用,代理对象如果不及时销毁,会导致内存泄露
  • vue2和vue3的区别:

响应式系统不同:vue3proxy解决了vue2无法监听新增属性,删除属性和索引变化的问题,性能更好。

vue2是选项是api 用data,methods.,computed等 vue3是组合式api 用setup ref,reactive和选项式api相结合,逻辑比较集中。

vue3支持异步加载 支持跨dom传送节点,支持多个根节点,但vue2组件只能有一个根节点。支持typeScript

  • Vue 3 最直观的感受:优点与不舒服的地方

最直观的感受是灵活和性能提升,不舒服的地方:reactive和ref响应式转换规则复杂

老项目的迁移很麻烦吧,浏览器不兼容,部分插件不兼容vue3

TIS好像是用来处理数据的工具,数据可视化什么的,但没用过。

  • 讲讲组件传参

父组件传子组件:父组件通过props向子组件传递数据,子组件通过props选项接收数据

props是只读的,子组件不能直接修改props

子组件传给父组件:子组件通过$emit函数触发事件,把数据传给父组件,父组件中用@事件名或v-on指令监听子组件的事件。

非父子组件的通信:使用事件总线event bus实现通信vue2,适合中小型项目,大型项目建议用vuex或Pinia管理工具,使用于vue3的用provide和inject

<!-- 父组件 (App.vue) -->
<template>
  <ChildComponent />
</template>

<script setup>
import { provide } from 'vue';
provide('appTitle', 'Vue 3 的新特性!');
</script>
<!-- 深层子组件 (GrandChild.vue) -->
<template>
  <h1>{{ title }}</h1>
</template>

<script setup>
import { inject } from 'vue';
const title = inject('appTitle');
</script>

跨组件通信vuex ,创建store/index.js的文件 ,创建实例,再新创建一个menu模块,并将其注册到store中,使用vuex-persistedstate插件持久化store中的状态,在menu.js文件中定义一个vuex模块,state是用来状态定义的,从本地存储中获取缓存数据,mutations变更方法,这个文件主要用来管理菜单中的状态和相关操作,

  • vue中nextTike的作用:

用于等待下一次dom更新循环结束之后执行延迟回调,确保在数据变化之后,dom已经更新完成,然后再执行某些依赖于新dom状态的操作。

vue采用了异步更新策略,当数据发生变化时,不会立即更新dom,而是等待同一事件循环中的所有数据变更完成后,再统一进行dom更新,这种方式可以减少dom操作的次数,但在数据变化之后,无法立即获取dom状态,因此,提供nextTick来解决这个问题。

  • 说一下css伪类伪元素:

伪类是一种选择器,以冒号(:)开头的关键字,用于选择处于特定状态的元素,如悬停:hover,聚焦:focus :first-child

伪元素:作用是模拟在HTML文档中添加新的元素,以双冒号(::)开头的关键字,如常见伪元素::before,::after

伪类主要用于选择处于特定状态的元素,而伪元素用于模拟添加新的元素或控制文本样式。

  • 水平垂直居中

flexbox布局:

display:flex;
justify-content:center;  水平居中
align-items:center;   垂直居中
height:100%;  容器高度,可根据需要调整

绝对定位和transform:

.container {
  position: relative;
  height: 100vh; /* 容器高度,可根据需要调整 */
}

.element {
  position: absolute;  相对于最近的祖先元素进行定位
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); /* 将元素自身的中心点移动到容器的中心点 */
}

绝对定位和负边距

.container {
  position: relative; 参考点是其原始位置,不会脱离文档流
  height: 100vh; /* 容器高度,可根据需要调整 */
}

.element {
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -50px; /* 元素高度的一半,负数表示向上移动 */
  margin-left: -50px; /* 元素宽度的一半,负数表示向左移动 */
  width: 100px; /* 元素宽度 */
  height: 100px; /* 元素高度 */
}

Grid布局

.container {
  display: grid;
  place-items: center; /* 水平垂直居中,是align-items: center 和 justify-items: center 的简写 */
  height: 100vh; /* 容器高度,可根据需要调整 */
}
  • vuex和pinia:

都是vue中的管理应用状态工具

vuex使用mutations、actions、getters来定义状态、修改和异步操作,需要定义命名空间,每次状态变更都会重新计算所有getters 可能导致性能开销 

pinia无需mutations直接用state、getter和actions,每个store都是独立的,声明更清晰,通过composition API优化了状态追踪机制,具备更好的性能表现。

  • vue生命周期:

创建流程:beforeCreate:在实例创建之前的阶段, created:vue实例已经被创建,可以通过vue实例访问到data中的数据以及methods中的方法了,但页面还没有渲染。

挂载流程:beforeMount:vue实例已经完成了模板的解析生成虚拟的dom 。mounted:这个阶段vue实例已经将虚拟dom转化成真实的dom 并插入页面中。

更新流程:beforeUpdata:当vue实例中数据发生变化时,会触发这个钩子函数,updated:此时vue实例已经完成页面更新,数据和页面已经保持同步

销毁流程:beforeDestroy:vue实例即将被销毁,但data、methods指令还处于可用状态

destoryed:在这个阶段,vue实例已经被彻底销毁

  • data为什么是函数而不是对象

如何让数据或对象变为响应式:

使用ref()函数,基本数据类型,像字符串数字等,使用reactive()函数,定义复杂的数据类型,如对象数组。使用toRef()函数,从响应式对象中提取一个属性,使用 toRef() 时,它接受两个参数:一个响应式对象和一个字符串(表示要从该对象中提取的属性名)

import { reactive, toRef } from 'vue';

const state = reactive({
  count: 0
});

// 使用 toRef() 提取 count 属性
const countRef = toRef(state, 'count');
  • diff算法简述:

用于比较和查找两个对象之间差异的算法,能够识别出哪些节点被添加,删除或修改了,缺点是当虚拟dom树非常大或复杂时,性能开销会很显著,通常只在同层级节点之间进行比较,不会跨级比较,

  • 路由传参的方式:

主要用于不同页面和组件之间传递参数,params传参

显示参数:

  • 声明式导航:使用<router-link>组件的to属性。
<router-link :to="/search/123">搜索</router-link>
  • 使用this.$router.push方法。
this.$router.push({ path: '/search/123' });

不显示参数:配置路由时不需要占位,但需要指定name声名式导航:

<router-link :to="{ name: 'search', params: { keyword: 123 } }">搜索</router-link>

在目标组件中通过this.$route.params获取传递的参数。

query传参

<router-link :to="{ path: '/search', query: { keyword: 123 } }">搜索</router-link>
this.$router.push({ path: '/search', query: { keyword: 123 } });

在目标组件中通过this.$route.query获取传递的参数

props传参

布尔模式:

{ path: '/search/:keyword?', name: 'Search', component: () => import('../views/Search'), props: true }

对象模式:

{ path: '/search/:keyword?', name: 'Search', component: () => import('../views/Search'), props: { a: 1, b: 2 } }

函数模式:返回一个props函数

{
  path: '/search/:keyword?',
  name: 'Search',
  component: () => import('../views/Search'),
  props: route => ({ keyword: route.params.keyword, otherProp: 'some value' })
}

注意:使用params传参时,必须使用name而不能使用path,否则params会被忽略

当params参数可以传递也可以不传递时,如果传递为空字符串,可以使用undefined来解决。

vue2组件通信:

父组件通过$refs属性可以访问子组件的实例或dom元素

$parent属性用于访问当前组件的父组件实例

$children属性用于访问当前组件的子组件实例

event Bus(事件总线):创建一个新的vue实例来实现跨组件通信 通多$emit在事件总线上触发事件,通过$on监听事件,在vue3中不能用了。

provide/inject:父组件通过provide选项提供数据或方法,跨层级的子组件通过inject选项接收提供的数据或方法。

插槽:让父组件能够向子组件指定内容插入点的机制

vue3组件通信:

props父传子:子组件通过defineProps接收父组件的数据,父组件在使用子组件时,通过属性绑定的方式将数据传递给子组件。

子传父:同vue2

provide/inject:同vue2

v-model:在vue3中用于组件中的双向数据绑定

插槽:同vue2