前端面试题(vue篇持续更新ing)
1.v-if和v-show的区别?
v-if
和 v-show
是 Vue.js 中用于条件渲染的指令,它们的作用是根据表达式的值来控制元素的显示与隐藏。它们的区别在于:
-
v-if
:- 指令用法:
v-if
是一个指令,它通过计算绑定的表达式的值来决定是否渲染元素。 - 渲染方式:如果表达式的值为
true
,则渲染对应的元素;如果为false
,则不渲染(从 DOM 中移除)。 - 性能特点:当
v-if
的条件为false
时,元素及其内部的 Vue 组件会被销毁并重建,每次切换时都会触发销毁和重新渲染的过程。
示例:
<div v-if="isVisible">这是通过v-if条件渲染的元素</div>
- 指令用法:
-
v-show
:- 指令用法:
v-show
是一个指令,它同样通过计算绑定的表达式的值来决定元素的显示与隐藏。 - 渲染方式:如果表达式的值为
true
,则显示元素(通过 CSS 的display
属性控制);如果为false
,则隐藏元素(通过display: none
)。 - 性能特点:当
v-show
的条件为false
时,元素并未从 DOM 中移除,而是通过 CSS 控制隐藏,不会触发销毁和重新渲染的过程。
示例:
<div v-show="isVisible">这是通过v-show条件渲染的元素</div>
- 指令用法:
选择使用:
- 如果需要频繁切换元素的显示与隐藏,并且对性能要求较高,可以使用
v-show
,因为它不会频繁触发 DOM 的销毁和重建。 - 如果元素的显示与隐藏不频繁,或者希望在条件为
false
时完全从 DOM 中移除元素以节省资源,可以考虑使用v-if
。
2.如何理解MVVM的?
MVVM(Model-View-ViewModel)是一种软件架构模式,旨在分离用户界面(UI)的开发与业务逻辑的开发,以提高代码的可维护性、可测试性和复用性。MVVM 架构包含三个主要部分:
- Model(模型):
- 模型代表应用程序的数据和业务逻辑。模型通常是指应用程序的数据结构、数据库连接、业务规则等。在前端开发中,模型可以是应用程序的数据模型,用于管理数据的获取、存储和处理。
- View(视图):
- 视图是用户界面的可视化部分,负责展示数据给用户,并接收用户的输入操作。视图通常是由 HTML、CSS 和 UI 组件组成。在 MVVM 中,视图通过数据绑定与 ViewModel 进行交互,根据 ViewModel 中的数据和状态来动态更新视图。
- ViewModel(视图模型):
- 视图模型是连接视图和模型之间的中间层。它负责从模型中获取数据,并对视图中显示的数据进行处理和准备。视图模型通常包含了视图所需的数据、命令(用于处理用户交互)和其他业务逻辑。在前端开发中,ViewModel 通常由 JavaScript 或其他前端框架中的组件来实现。
MVVM 的工作原理如下:
- 数据绑定:视图通过数据绑定与 ViewModel 中的数据进行绑定。当 ViewModel 中的数据发生变化时,视图会自动更新,反之亦然。
- 命令绑定:视图中的用户交互操作(比如按钮点击、输入框输入等)通过命令绑定绑定到 ViewModel 中的命令。ViewModel 接收并处理这些命令,执行相应的业务逻辑或数据操作。
- 解耦:MVVM 的核心思想是将视图与业务逻辑解耦,使得视图的开发和维护更加简单。通过视图模型将视图与模型分离,可以使开发团队更好地进行并行开发,提高开发效率和代码质量。
3.v-for中的key值的作用是什么?
- 唯一标识子元素:
key
属性提供了一种唯一标识列表中每个子元素的方式。Vue 使用这些key
来识别每个子元素,并在更新 DOM 时使用它们来确定哪些元素是新增的、删除的或重新排序的。 - 优化列表渲染: 使用
key
属性能够帮助 Vue 优化列表的渲染性能。当列表中的数据发生变化时,Vue 可以根据key
属性识别出哪些元素是已知的,从而避免不必要的 DOM 操作,提高渲染效率。 - 配合
v-for
使用: 在使用v-for
指令渲染列表时,为每个列表项添加key
属性是推荐的做法。这样可以确保 Vue 能够正确地跟踪和管理列表中的每个子元素,确保 DOM 的正确更新和重用。
例如,在您的 Vue 模板中的 v-for
循环中,您可以将每个列表项的 id
作为 key
属性,以确保每个列表项都有一个唯一的标识:
<ul>
<li v-for="item in list" :key="item.id">{{ item.name }}</li>
</ul>
在这里,假设 item.id
是列表项的唯一标识符,将其用作 key
属性能够帮助 Vue 在列表项发生变化时更有效地管理和更新 DOM。
4.说一下你对vue生命周期的理解。
Vue.js 的生命周期钩子函数是一组可以让我们在 Vue 实例中的特定阶段添加自定义逻辑的方法。这些钩子函数可以帮助我们在组件的不同生命周期阶段执行任务,从而实现对应用状态的管理和控制。
Vue.js 的生命周期包括以下阶段:
- beforeCreate: 在 Vue 实例被创建之初,实例的数据观测和事件系统都尚未初始化。此时无法访问
data
、methods
、computed
等属性和方法。 - created: 在实例被创建后,完成数据观测、属性和方法的运算,但尚未挂载到 DOM 上。此时可以访问实例的数据,也可以进行 Ajax 请求等操作。
- beforeMount: 在 Vue 实例挂载到 DOM 之前调用。此时 Vue 实例的模板编译完成,但尚未将其渲染到页面上。
- mounted: 在 Vue 实例挂载到 DOM 后调用。此时 Vue 实例已经被挂载,并且可以访问到 DOM 元素。通常在这个阶段进行 DOM 相关的操作和初始化工作。
- beforeUpdate: 数据更新导致重新渲染之前调用。在这个阶段,虚拟 DOM 已经更新,但尚未应用到页面上的 DOM 中。
- updated: 数据更新导致重新渲染之后调用。在这个阶段,Vue 实例已经更新,DOM 也已经重新渲染。通常在这里可以进行一些依赖于 DOM 的操作。
- beforeDestroy: 在 Vue 实例销毁之前调用。在这个阶段,Vue 实例仍然完全可用,可以执行一些清理工作,如清除定时器、解绑事件等。
- destroyed: Vue 实例销毁后调用。在这个阶段,Vue 实例的所有事件监听器和子实例都已经被销毁,不再可用。
除了这些主要的生命周期钩子函数外,Vue 还提供了一些其它的钩子函数,用于处理特定场景下的逻辑,例如 activated
和 deactivated
用于 keep-alive 组件,errorCaptured
用于捕获子孙组件的错误等。
5.在created和mounted去请求数据,有什么区别?
在 Vue.js 中,created
和 mounted
都是生命周期钩子函数,用于在 Vue 实例的不同阶段执行任务。虽然它们看起来有些类似,但在请求数据时有一些重要的区别:
-
created 钩子:
created
钩子函数在 Vue 实例被创建之后立即执行,此时 Vue 实例的数据观测 (data observer) 已经完成,但是挂载阶段还未开始,因此实例还没有被挂载到 DOM 上。- 在
created
钩子中进行数据请求时,一般适合初始化实例数据、设置计算属性或监听事件,因为此时实例已经创建,但 DOM 和模板还未渲染完成,无法操作页面上的元素。
created() { axios.get('https://api.example.com/data') .then(response => { this.data = response.data; }) .catch(error => { console.error('Error fetching data:', error); }); }
-
mounted 钩子:
mounted
钩子函数在 Vue 实例被挂载到 DOM 后执行,此时 Vue 实例已经完成了挂载,可以访问到 DOM 元素。- 在
mounted
钩子中进行数据请求时,适合执行需要操作 DOM 元素的任务,例如初始化第三方库、调用 DOM API、绑定事件等。
mounted() { axios.get('https://api.example.com/data') .then(response => { this.data = response.data; }) .catch(error => { console.error('Error fetching data:', error); }); }
区别总结:
- 如果数据请求不需要依赖 DOM 元素,可以在
created
钩子中发起请求,这样可以更早地获取数据并初始化组件状态。 - 如果数据请求需要依赖 DOM 元素,或者需要操作 DOM 元素后再进行请求,应该在
mounted
钩子中执行,以确保能够访问到已挂载的 DOM 元素。 - 在大多数情况下,推荐将数据请求放在
mounted
钩子中,因为这样可以避免一些由于数据获取过早而导致的问题,例如初始化数据可能在实例完全创建前就被访问。
6.vue中的修饰符有哪些?
在 Vue.js 中,修饰符是用于对指令或事件进行额外控制或修改行为的特殊标记。以下是常见的 Vue.js 指令和事件修饰符:
指令修饰符
-
.prevent
- 阻止默认事件行为,等同于调用
event.preventDefault()
<form @submit.prevent="handleSubmit"></form>
- 阻止默认事件行为,等同于调用
-
.stop
- 阻止事件继续传播,等同于调用
event.stopPropagation()
<div @click.stop="handleClick"></div>
- 阻止事件继续传播,等同于调用
-
.capture
- 添加事件监听器时使用事件捕获模式
<div @click.capture="handleClick"></div>
-
.self
- 只在事件是从事件目标自身触发时才触发回调
<div @click.self="handleClick"></div>
-
.once
- 只触发一次事件,等同于使用
vm.$once
方法
<button @click.once="handleClick">Click Me</button>
- 只触发一次事件,等同于使用
-
.passive
- 指示浏览器不要等待
preventDefault
完成,可以加快页面滚动的性能
<div @touchstart.passive="handleTouchStart"></div>
- 指示浏览器不要等待
事件修饰符
-
.stop
- 阻止事件继续传播,等同于在事件处理函数中调用
event.stopPropagation()
<button @click.stop="handleClick"></button>
- 阻止事件继续传播,等同于在事件处理函数中调用
-
.prevent
- 阻止默认事件行为,等同于在事件处理函数中调用
event.preventDefault()
<form @submit.prevent="handleSubmit"></form>
- 阻止默认事件行为,等同于在事件处理函数中调用
-
.capture
- 添加事件监听器时使用事件捕获模式
<div @click.capture="handleClick"></div>
-
.self
- 只在事件是从事件目标自身触发时才触发回调
<div @click.self="handleClick"></div>
-
.once
- 只触发一次事件,等同于使用
vm.$once
方法
<button @click.once="handleClick"></button>
- 只触发一次事件,等同于使用
-
.passive
- 指示浏览器不要等待
preventDefault
完成,可以加快页面滚动的性能
<div @touchstart.passive="handleTouchStart"></div>
- 指示浏览器不要等待
7.elementui是怎么做表单验证的?
Element UI 是一个基于 Vue.js 的组件库,提供了丰富的 UI 组件和功能,包括表单验证。Element UI 中的表单验证是通过使用 el-form
和 el-form-item
组件结合内置的验证规则和方法来实现的。
下面是 Element UI 表单验证的基本步骤和示例:
-
使用
el-form
组件包裹表单内容<template> <el-form :model="formData" :rules="formRules" ref="form" label-width="100px"> <el-form-item label="用户名" prop="username"> <el-input v-model="formData.username"></el-input> </el-form-item> <el-form-item label="密码" prop="password"> <el-input type="password" v-model="formData.password"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm">提交</el-button> </el-form-item> </el-form> </template> <script> export default { data() { return { formData: { username: '', password: '' }, formRules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' } ] } }; }, methods: { submitForm() { this.$refs.form.validate(valid => { if (valid) { // 表单验证通过,执行提交操作 // 可以在这里调用接口等操作 console.log('表单验证通过'); } else { // 表单验证不通过 console.log('表单验证未通过'); return false; } }); } } }; </script>
-
在
el-form
中设置:model
和:rules
:model
绑定表单数据对象,用于收集表单数据。:rules
绑定表单验证规则,定义每个字段的验证规则。
-
使用
el-form-item
包裹表单项- 每个表单项都需要用
el-form-item
组件包裹,设置label
属性为表单项的标签名,设置prop
属性为表单项数据对象中的字段名。
- 每个表单项都需要用
-
定义表单验证规则
- 在
data
中定义formRules
对象,为每个表单字段设置验证规则数组。
- 在
-
提交表单
- 在提交按钮的点击事件中,通过调用
this.$refs.form.validate(callback)
方法进行表单验证。 callback
回调函数接收一个valid
参数,表示表单验证结果是否通过。
- 在提交按钮的点击事件中,通过调用
通过以上步骤,可以实现基于 Element UI 的表单验证功能。验证规则中的 trigger
属性指定了触发验证的时机,常见的值有 'blur'
(失去焦点时触发)和 'change'
(数据变化时触发)。 Element UI 提供了丰富的验证规则和验证方法,可以满足常见的表单验证需求。
8.vue如何进行组件通信?
Vue.js 中有多种方法用于组件之间的通信,其中包括 props、事件、vuex 状态管理以及 provide/inject 等。这些方法可以根据不同的场景和需求来选择和组合使用。
-
Props/Events
-
父组件通过 props 向子组件传递数据,子组件通过事件
$emit
向父组件发送消息。 -
父组件向子组件传递数据:
<!-- ParentComponent.vue --> <template> <!-- 使用 ChildComponent 组件,并通过 :message 属性传递 parentMessage 数据 --> <ChildComponent :message="parentMessage" @notify="handleNotify" /> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, data() { return { // 定义一个数据属性 parentMessage,用于传递给子组件 parentMessage: 'Hello from parent' }; }, methods: { // 定义一个方法 handleNotify,用于处理子组件发出的 notify 事件 handleNotify(message) { console.log('Received message from child:', message); } } }; //输出结果:Received message from child: Hello from child </script>
-
子组件接收 props 并发送事件:
<template> <!-- 一个按钮,点击时触发 notifyParent 方法 --> <button @click="notifyParent">Send Message to Parent</button> </template> <script> export default { props: ['message'], methods: { // 定义一个方法 notifyParent,用于向父组件发送消息 notifyParent() { // 使用 $emit 方法发出一个名为 notify 的事件,并传递消息 'Hello from child' this.$emit('notify', 'Hello from child'); } } }; </script>
-
-
Event Bus
-
使用 Vue 实例作为事件总线,用于任意组件之间的通信。
// main.js import Vue from 'vue'; export const bus = new Vue();
在组件中使用:
// ComponentA.vue import { bus } from './main.js'; bus.$emit('event-name', data); // ComponentB.vue import { bus } from './main.js'; bus.$on('event-name', (data) => { console.log('Received data:', data); });
-
-
Vuex
- 用于管理应用程序的状态,可以在任何组件中访问共享状态。
-
Provide/Inject
-
父组件使用
provide
来提供数据,子组件使用inject
来注入数据。<!-- ParentComponent.vue --> <template> <child-component /> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, provide() { return { sharedData: 'Data from parent' }; } }; </script> <!-- ChildComponent.vue --> <template> <div>{{ sharedData }}</div> </template> <script> export default { inject: ['sharedData'] }; //显示的结果为Data from parent </script>
-
9.keep-alive是什么?怎么使用?
keep-alive 是 Vue.js 中的一个内置组件,用于将包含的组件保留状态,或避免重新渲染。这意味着当组件被切换出去时,它的状态和 DOM 结构不会被销毁,而是被缓存起来,当再次切换回该组件时,可以直接使用缓存的状态和 DOM,而不需要重新初始化组件。这对于需要保持状态或避免不必要的重新渲染的组件非常有用。比如当我们从首页
–>列表页
–>商详页
–>再返回
,这时候列表页应该是需要keep-alive
,从首页
–>列表页
–>商详页
–>返回到列表页(需要缓存)
–>返回到首页(需要缓存)
–>再次进入列表页(不需要缓存)
,这时候可以按需来控制页面的keep-alive
。
<template>
<div id="app">
<router-view v-if="shouldKeepAlive"></router-view>
<keep-alive v-else>
<router-view></router-view>
</keep-alive>
</div>
</template>
<script>
export default {
data() {
return {
shouldKeepAlive: false,
};
},
watch: {
'$route'(to, from) {
// 当从列表页返回到首页时,需要缓存
if (from.name === 'ListPage' && to.name === 'HomePage') {
this.shouldKeepAlive = true;
}
// 当从首页返回到列表页时,不需要缓存
else if (from.name === 'HomePage' && to.name === 'ListPage') {
this.shouldKeepAlive = false;
}
// 当再次进入列表页时,不需要缓存
else if (from.name === 'ListPage' && to.name === 'ListPage') {
this.shouldKeepAlive = false;
}
},
},
};
</script>
10.axios是怎么做封装的?
Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 node.js。它提供了一种简单的方式来发送异步 HTTP 请求到 REST endpoints 并且处理响应。封装 Axios 主要是为了提高代码的可维护性和重用性,以及为了简化 HTTP 请求的使用。
封装 Axios 的一种常见方法是创建一个单独的服务文件或模块,这个文件或模块包含了一些预设的配置和方法,用于处理常见的 HTTP 请求。这样,当你需要发送 HTTP 请求时,你可以直接调用这些预设的方法,而不是每次都需要手动配置 Axios 实例。
以下是一个简单的 Axios 封装示例:
// api.js
import axios from 'axios';
// 创建 axios 实例
const instance = axios.create({
baseURL: 'https://api.example.com', // 基础 URL
timeout: 1000, // 请求超时时间
headers: {
'Content-Type': 'application/json',
},
});
// 请求拦截器
instance.interceptors.request.use((config) => {
// 在发送请求之前做些什么
return config;
}, (error) => {
// 对请求错误做些什么
return Promise.reject(error);
});
// 响应拦截器
instance.interceptors.response.use((response) => {
// 对响应数据做点什么
return response;
}, (error) => {
// 对响应错误做点什么
return Promise.reject(error);
});
// 导出实例
export default instance;
在这个示例中,创建了一个 Axios 实例,并设置了基础 URL、超时时间和默认的请求头。还添加了请求和响应拦截器,以便在发送请求或接收响应时进行一些预处理或后处理。最后,导出了这个实例,以便在其他文件中使用。
使用这个封装后,可以在其他文件中这样使用:
import api from './api';
// 使用封装后的 axios 实例发送 GET 请求
api.get('/user')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});