面一:
- 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