vue2 面试题及详细答案150道(41 - 60)
《前后端面试题
》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。
文章目录
- 一、本文面试题目录
- 41. Vue中$nextTick的作用及使用场景
- 42. Vuex中的getter有什么作用
- 43. Vue中的过滤器(filter)有什么作用及使用方式
- 44. 如何在Vue中使用SVG图标
- 45. Vue项目中如何实现主题切换功能
- 46. 简述Vue的虚拟DOM及Diff算法
- 47. Vue中如何实现路由跳转及参数传递
- 48. Vue项目中如何使用ECharts绘制图表
- 49. Vue中mixin的优缺点
- 50. Vue中如何监听对象或数组的变化
- 51. Vue项目中如何实现文件上传功能
- 52. Vue中如何实现组件的递归调用
- 53. Vuex中的module是什么?如何使用
- 54. Vue中如何实现页面刷新不丢失状态
- 55. 简述Vue的混入(mixin)和Vuex的区别
- 56. Vue中如何实现滚动到页面顶部或指定位置
- 57. Vue项目中如何配置环境变量
- 58. Vue中如何实现禁止浏览器回退
- 59. Vue中如何实现图片的预览和裁剪功能
- 60. 简述Vue2和Vue3的主要区别
- 二、150道面试题目录列表
一、本文面试题目录
41. Vue中$nextTick的作用及使用场景
$nextTick是Vue提供的一个异步方法,其作用是在DOM更新完成后执行回调函数。因为Vue的DOM更新是异步的,当数据发生变化时,Vue不会立即更新DOM,而是将更新操作放入队列中,等同一事件循环中的所有数据变化完成后,再统一进行DOM更新。
使用场景包括:在修改数据后,需要立即操作更新后的DOM(如获取元素尺寸、位置等);在使用v-if/v-for等指令动态渲染元素后,需要对新生成的DOM进行操作。例如:
this.msg = '新内容';
this.$nextTick(() => {// 此时DOM已更新,可以获取到更新后的元素console.log(document.getElementById('content').innerText); // 输出'新内容'
});
42. Vuex中的getter有什么作用
getter相当于Vuex中的计算属性,它可以对store中的state进行加工处理,形成新的数据。其主要作用包括:
- 缓存结果:getter的返回值会根据其依赖的state自动缓存,只有当依赖的state发生变化时,才会重新计算。
- 简化组件代码:将对state的复杂计算逻辑抽离到getter中,避免在多个组件中重复编写相同逻辑,使组件代码更简洁。
示例:
const store = new Vuex.Store({state: {todos: [{ id: 1, text: '学习Vue', done: true },{ id: 2, text: '学习Vuex', done: false }]},getters: {doneTodos: state => {return state.todos.filter(todo => todo.done);}}
});
在组件中通过this.$store.getters.doneTodos
获取过滤后的结果。
43. Vue中的过滤器(filter)有什么作用及使用方式
过滤器用于对文本进行格式化处理,可在模板插值和v-bind表达式中使用。
作用:对数据进行格式化,如日期格式化、字符串大小写转换等,不改变原始数据,只在显示时生效。
使用方式分为全局过滤器和局部过滤器:
- 全局过滤器:通过
Vue.filter()
注册,可在所有组件中使用。
Vue.filter('uppercase', function(value) {if (!value) return '';return value.toUpperCase();
});
- 局部过滤器:在组件的
filters
选项中定义,仅在当前组件中使用。
export default {filters: {lowercase: function(value) {if (!value) return '';return value.toLowerCase();}}
};
使用示例:
<p>{{ message | uppercase }}</p>
<img :src="imageUrl | formatUrl">
44. 如何在Vue中使用SVG图标
在Vue中使用SVG图标主要有以下几种方式:
- 直接引入SVG文件:将SVG文件作为组件引入,在模板中直接使用。
<template><div><MySvgIcon /></div>
</template>
<script>
import MySvgIcon from './icons/my-icon.svg';
export default {components: { MySvgIcon }
};
</script>
- 使用svg-sprite-loader:通过webpack配置svg-sprite-loader,将SVG图标合并为雪碧图,然后在模板中通过
<use>
标签引用。- 安装loader:
npm install svg-sprite-loader --save-dev
- 配置webpack(vue.config.js):
module.exports = {chainWebpack: config => {config.module.rules.delete('svg');config.module.rule('svg').test(/\.svg$/).include.add(resolve('src/icons')).end().use('svg-sprite-loader').loader('svg-sprite-loader').options({ symbolId: 'icon-[name]' });} };
- 使用:
<svg><use xlink:href="#icon-my-icon"></use> </svg>
- 安装loader:
45. Vue项目中如何实现主题切换功能
实现主题切换功能通常有以下步骤:
- 定义主题样式:通过CSS变量定义不同主题的样式,如在全局样式中定义:
:root {--primary-color: #42b983; /* 默认主题主色 */--bg-color: #ffffff; /* 默认主题背景色 */
}
.dark-theme {--primary-color: #35495e; /* 深色主题主色 */--bg-color: #1a1a1a; /* 深色主题背景色 */
}
- 在组件中使用CSS变量:
.button {background-color: var(--primary-color);color: var(--text-color);
}
- 切换主题类名:在Vue实例中通过控制body或根元素的类名来切换主题:
export default {data() {return {isDarkTheme: false};},methods: {toggleTheme() {this.isDarkTheme = !this.isDarkTheme;if (this.isDarkTheme) {document.documentElement.classList.add('dark-theme');} else {document.documentElement.classList.remove('dark-theme');}// 可选:将主题偏好存储到localStoragelocalStorage.setItem('theme', this.isDarkTheme ? 'dark' : 'light');}},mounted() {// 初始化时读取本地存储的主题偏好const theme = localStorage.getItem('theme');if (theme === 'dark') {this.toggleTheme();}}
};
46. 简述Vue的虚拟DOM及Diff算法
虚拟DOM:是一个用JavaScript对象描述真实DOM结构的轻量级对象,它包含了标签名、属性、子节点等信息。虚拟DOM的存在避免了频繁操作真实DOM带来的性能开销,因为操作JavaScript对象比操作DOM更高效。
Diff算法:是Vue用于比较新旧虚拟DOM差异的算法,其核心思想是:
- 同级比较:只比较同一层级的节点,不跨层级比较。
- key的作用:通过key标识节点的唯一性,当节点顺序变化时,可复用已有节点,减少DOM操作。
- 标签名比对:如果标签名不同,直接销毁旧节点并创建新节点。
- 属性比对:如果标签名相同,则比较节点属性,只更新变化的属性。
- 列表比对:对于列表节点,通过key找到可复用的节点,进行移动、新增或删除操作。
Diff算法的最终目的是计算出新旧虚拟DOM的差异,然后只将这些差异更新到真实DOM上,从而提高页面渲染性能。
47. Vue中如何实现路由跳转及参数传递
路由跳转方式:
- 声明式导航:使用
<router-link>
组件,to
属性指定跳转路径。
<router-link to="/home">首页</router-link>
<router-link :to="{ path: '/user', query: { id: 1 } }">用户页</router-link>
- 编程式导航:使用
$router.push()
方法。
// 字符串路径
this.$router.push('/home');
// 对象形式
this.$router.push({ path: '/user', params: { id: 1 } });
参数传递方式:
- query参数:类似于URL中的查询字符串,会显示在URL上,刷新页面参数不丢失。
传递:this.$router.push({ path: '/user', query: { name: '张三' } })
接收:this.$route.query.name
- params参数:参数不会显示在URL上,需要在路由配置中定义占位符,刷新页面参数会丢失(若要保留需配合路由模式为history且服务端配置)。
路由配置:{ path: '/user/:id', component: User }
传递:this.$router.push({ name: 'User', params: { id: 1 } })
(注意使用name跳转)
接收:this.$route.params.id
48. Vue项目中如何使用ECharts绘制图表
在Vue项目中使用ECharts的步骤如下:
- 安装ECharts:
npm install echarts --save
- 在组件中引入并使用:
<template><div class="chart-container" ref="chart"></div>
</template>
<script>
import echarts from 'echarts';
export default {mounted() {// 初始化图表实例this.chart = echarts.init(this.$refs.chart);// 配置图表选项const option = {title: { text: '示例图表' },xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'] },yAxis: { type: 'value' },series: [{ data: [120, 200, 150, 80, 70], type: 'bar' }]};// 设置图表选项this.chart.setOption(option);// 监听窗口大小变化,重绘图表window.addEventListener('resize', this.handleResize);},methods: {handleResize() {this.chart.resize();}},beforeDestroy() {// 销毁图表实例,移除事件监听this.chart.dispose();window.removeEventListener('resize', this.handleResize);}
};
</script>
<style>
.chart-container {width: 100%;height: 400px;
}
</style>
49. Vue中mixin的优缺点
优点:
- 代码复用:可以将多个组件共用的逻辑(如数据、方法、生命周期钩子等)抽离到mixin中,减少代码冗余。
- 灵活性:多个mixin可以被同一个组件引入,实现逻辑的组合。
缺点:
- 命名冲突:当组件和mixin或多个mixin之间存在同名的属性、方法或钩子函数时,会产生命名冲突,Vue的处理规则可能导致预期之外的结果(如数据对象浅合并,方法和钩子函数同名时mixin的会被组件的覆盖,钩子函数会被合并执行)。
- 逻辑来源不清晰:组件中使用了多个mixin后,难以追踪某个功能或数据的具体来源,增加了代码的维护难度。
- 耦合性高:mixin和组件之间可能存在隐式依赖,修改mixin可能会影响多个使用它的组件,不利于代码的模块化和独立性。
50. Vue中如何监听对象或数组的变化
由于JavaScript的限制,Vue不能直接检测对象属性的添加或删除,以及数组的某些变异方法(如length
修改、通过索引直接修改元素)。但可以通过以下方式实现监听:
对象监听:
- 初始化时声明属性:在data中预先声明对象的属性,Vue会将其转为响应式。
- 使用Vue.set():添加新属性时,使用
Vue.set(object, propertyName, value)
或this.$set(object, propertyName, value)
。
this.$set(this.user, 'age', 20); // 给user对象添加age属性并使其响应式
- 替换对象:将原对象替换为一个新的包含新增属性的对象。
this.user = { ...this.user, age: 20 };
数组监听:
- 使用数组变异方法:Vue对数组的
push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
方法进行了封装,调用这些方法会触发视图更新。 - 使用Vue.set():通过索引修改数组元素时,使用
Vue.set(array, index, value)
或this.$set(array, index, value)
。
this.$set(this.list, 0, '新值'); // 修改list数组索引为0的元素
- 替换数组:将原数组替换为一个新的数组。
this.list = this.list.map(item => item + 1);
No. | 大剑师精品GIS教程推荐 |
---|---|
0 | 地图渲染基础- 【WebGL 教程】 - 【Canvas 教程】 - 【SVG 教程】 |
1 | Openlayers 【入门教程】 - 【源代码+示例 300+】 |
2 | Leaflet 【入门教程】 - 【源代码+图文示例 150+】 |
3 | MapboxGL 【入门教程】 - 【源代码+图文示例150+】 |
4 | Cesium 【入门教程】 - 【源代码+综合教程 200+】 |
5 | threejs 【中文API】 - 【源代码+图文示例200+】 |
51. Vue项目中如何实现文件上传功能
Vue项目中实现文件上传的基本步骤如下:
- 模板部分:使用
<input type="file">
元素获取文件,通过@change
事件监听文件选择。
<template><div><input type="file" @change="handleFileChange" accept="image/*"><button @click="uploadFile">上传文件</button></div>
</template>
- 脚本部分:
export default {data() {return {file: null};},methods: {handleFileChange(e) {this.file = e.target.files[0]; // 获取选择的文件},uploadFile() {if (!this.file) return;const formData = new FormData();formData.append('file', this.file); // 将文件添加到FormData// 发送请求this.$axios.post('/api/upload', formData, {headers: {'Content-Type': 'multipart/form-data' // 设置正确的Content-Type}}).then(response => {console.log('上传成功', response.data);}).catch(error => {console.error('上传失败', error);});}}
};
- 可选:实现多文件上传可将
input
的multiple
属性设为true
,并处理files
数组。
52. Vue中如何实现组件的递归调用
组件递归调用即组件自身调用自身,常用于实现树形结构、菜单等功能,实现方式如下:
- 定义组件:在组件中通过
name
选项指定组件名,然后在模板中使用该组件名进行递归调用。
<template><div class="tree-node"><div>{{ node.label }}</div><div v-if="node.children && node.children.length"><!-- 递归调用自身 --><tree-node v-for="(child, index) in node.children" :key="index" :node="child"></tree-node></div></div>
</template>
<script>
export default {name: 'TreeNode', // 必须指定组件名,用于递归调用props: {node: {type: Object,required: true}}
};
</script>
- 使用组件:
<template><div><tree-node :node="treeData"></tree-node></div>
</template>
<script>
import TreeNode from './TreeNode.vue';
export default {components: { TreeNode },data() {return {treeData: {label: '根节点',children: [{label: '子节点1',children: [{ label: '孙节点1-1' }]},{ label: '子节点2' }]}};}
};
</script>
53. Vuex中的module是什么?如何使用
当Vuex的store变得庞大时,可使用module
将store分割成多个模块,每个模块拥有自己的state
、getter
、mutation
、action
,甚至可以嵌套子模块。
使用方式:
- 定义模块:
// moduleA.js
export default {state: () => ({ count: 0 }),mutations: {increment(state) {state.count++;}},getters: {doubleCount(state) {return state.count * 2;}},actions: {incrementAsync({ commit }) {setTimeout(() => {commit('increment');}, 1000);}}
};
- 注册模块:
import Vue from 'vue';
import Vuex from 'vuex';
import moduleA from './moduleA';Vue.use(Vuex);const store = new Vuex.Store({modules: {a: moduleA // 将模块A注册到store,命名为a}
});
- 访问模块内容:
- state:
this.$store.state.a.count
- getter:
this.$store.getters.doubleCount
(若模块内getter依赖全局state,可通过第二个参数获取) - mutation:
this.$store.commit('increment')
(默认模块内mutation是全局的,可通过namespaced: true
开启命名空间) - action:
this.$store.dispatch('incrementAsync')
命名空间:为避免模块间命名冲突,可在模块中设置namespaced: true
,此时访问模块内的mutation、action、getter需加上模块名:
// moduleA中添加 namespaced: true
// 调用mutation
this.$store.commit('a/increment');
// 调用action
this.$store.dispatch('a/incrementAsync');
// 访问getter
this.$store.getters['a/doubleCount'];
54. Vue中如何实现页面刷新不丢失状态
实现页面刷新不丢失状态的常用方法有:
- localStorage/sessionStorage:将需要持久化的状态存储在localStorage(永久存储)或sessionStorage(会话期间存储)中,在页面加载时读取并恢复状态。
// 存储
localStorage.setItem('userInfo', JSON.stringify(this.userInfo));
// 读取
mounted() {const userInfo = localStorage.getItem('userInfo');if (userInfo) {this.userInfo = JSON.parse(userInfo);}
}
- Vuex持久化:使用
vuex-persistedstate
插件,自动将Vuex的state存储到localStorage等位置,具体配置见第21题。 - Cookie:将少量关键信息存储在Cookie中,Cookie会随请求发送到服务器,也可在客户端读取,适合存储用户认证信息等。
55. 简述Vue的混入(mixin)和Vuex的区别
mixin:
- 用于组件间共享可复用的逻辑(数据、方法、生命周期等)。
- 每个组件引入mixin后,mixin中的数据和方法会被合并到组件中,组件可以直接使用。
- 数据是组件内部的,不同组件的mixin数据相互独立,修改不会相互影响。
- 主要解决组件间逻辑复用问题,但存在命名冲突、逻辑来源不清晰等问题。
Vuex:
- 用于管理应用级别的共享状态,是一个集中式状态管理库。
- 状态存储在全局的store中,所有组件都可以访问和修改(通过规定的方式)。
- 数据是全局共享的,任何组件对状态的修改都会反映到所有使用该状态的组件中。
- 主要解决跨组件、跨层级的数据共享和状态管理问题,遵循单向数据流,状态修改可追踪。
两者的核心区别在于:mixin用于组件级别的逻辑复用,数据是组件私有;Vuex用于应用级别的状态共享,数据是全局共享的。
56. Vue中如何实现滚动到页面顶部或指定位置
滚动到页面顶部:
- 使用
window.scrollTo()
方法:
// 滚动到顶部,behavior: 'smooth'实现平滑滚动
window.scrollTo({ top: 0, behavior: 'smooth' });
- 在Vue中可通过按钮点击事件触发:
<button @click="scrollToTop">回到顶部</button>
methods: {scrollToTop() {window.scrollTo({ top: 0, behavior: 'smooth' });}
}
滚动到指定位置:
- 通过元素的
scrollIntoView()
方法:
<div ref="target">目标位置</div>
<button @click="scrollToTarget">滚动到目标</button>
methods: {scrollToTarget() {this.$refs.target.scrollIntoView({ behavior: 'smooth' });}
}
- 使用
window.scrollTo()
指定滚动距离:
// 滚动到距离顶部500px的位置
window.scrollTo({ top: 500, behavior: 'smooth' });
57. Vue项目中如何配置环境变量
Vue项目中配置环境变量可通过以下步骤:
- 创建环境变量文件:在项目根目录下创建不同环境的配置文件:
.env
:全局默认配置,所有环境都会加载。.env.development
:开发环境配置(npm run serve
时加载)。.env.production
:生产环境配置(npm run build
时加载)。.env.test
:测试环境配置(可自定义脚本加载)。
- 定义环境变量:文件中变量以
VUE_APP_
为前缀,例如:
# .env.development
VUE_APP_API_URL = 'http://dev.api.example.com'
VUE_APP_ENV = 'development'
- 在项目中使用:通过
process.env
访问环境变量。
console.log(process.env.VUE_APP_API_URL); // 输出http://dev.api.example.com
- 配置启动脚本(package.json):
"scripts": {"serve": "vue-cli-service serve","build": "vue-cli-service build","build:test": "vue-cli-service build --mode test" // 加载.env.test
}
58. Vue中如何实现禁止浏览器回退
实现禁止浏览器回退可通过监听popstate
事件并阻止其默认行为,具体如下:
mounted() {// 监听浏览器历史记录变化window.addEventListener('popstate', this.handlePopState);// 推入一个空的历史记录,防止初始状态下回退到上一页history.pushState(null, null, document.URL);
},
methods: {handlePopState() {// 当用户点击回退时,再推入一个历史记录,抵消回退操作history.pushState(null, null, document.URL);// 可选:提示用户不能回退alert('禁止回退');}
},
beforeDestroy() {// 移除事件监听,避免影响其他页面window.removeEventListener('popstate', this.handlePopState);
}
注意:这种方法会修改浏览器的历史记录,可能影响用户体验,需谨慎使用,通常用于支付页、表单提交页等不希望用户回退的场景。
59. Vue中如何实现图片的预览和裁剪功能
图片预览:可通过FileReader
读取本地图片文件并显示:
<input type="file" @change="previewImage" accept="image/*">
<img :src="imageUrl" v-if="imageUrl" alt="预览图">
data() {return {imageUrl: ''};
},
methods: {previewImage(e) {const file = e.target.files[0];if (!file) return;const reader = new FileReader();reader.onload = (event) => {this.imageUrl = event.target.result; // 得到图片的base64编码,用于预览};reader.readAsDataURL(file);}
}
图片裁剪:通常使用成熟的插件如vue-cropper
:
- 安装:
npm install vue-cropper --save
- 使用:
<template><div><input type="file" @change="selectImage" accept="image/*"><vue-cropperv-if="imageUrl"ref="cropper":img="imageUrl":info="true":outputSize="0.8":outputType="'jpeg'"></vue-cropper><button @click="getCroppedImage">裁剪图片</button><img :src="croppedImage" v-if="croppedImage" alt="裁剪后"></div>
</template>
<script>
import { VueCropper } from 'vue-cropper';
export default {components: { VueCropper },data() {return {imageUrl: '',croppedImage: ''};},methods: {selectImage(e) {// 同上,获取imageUrl},getCroppedImage() {// 获取裁剪后的图片this.$refs.cropper.getCropBlob(blob => {const reader = new FileReader();reader.onload = (event) => {this.croppedImage = event.target.result;// 可将blob上传到服务器};reader.readAsDataURL(blob);});}}
};
</script>
60. 简述Vue2和Vue3的主要区别
响应式系统:
- Vue2:使用
Object.defineProperty()
劫持对象的getter和setter,无法直接监听对象属性的添加/删除和数组索引修改。 - Vue3:使用
Proxy
代理对象,能原生支持监听对象属性的添加/删除、数组索引修改,以及Map、Set等数据结构。
组合式API vs 选项式API:
- Vue2:主要使用选项式API(data、methods、computed等选项)组织代码,逻辑复杂时容易出现“代码碎片化”。
- Vue3:推出组合式API(setup、ref、reactive、computed等),可将相关逻辑组织在一起,提高代码的可维护性和复用性,同时保留选项式API供选择。
模板语法:
- Vue3支持多根节点模板,Vue2模板必须有且仅有一个根节点。
- Vue3新增了
v-memo
指令,用于缓存模板片段,优化性能。
性能优化:
- Vue3的Diff算法进行了优化,对静态节点进行标记,减少比较次数。
- Vue3的打包体积更小,通过tree-shaking移除未使用的代码。
其他:
- Vue3支持TypeScript,类型推断更友好。
- Vue3的生命周期钩子有所变化,如
beforeCreate
和created
被setup
替代,mounted
对应onMounted
等(组合式API中)。 - Vue3的全局API改为使用
createApp
创建应用实例,如Vue.createApp(App).mount('#app')
,替代Vue2的new Vue({ el: '#app' })
。
二、150道面试题目录列表
文章序号 | vue2面试题150道 |
---|---|
1 | vue2 面试题及详细答案(01 - 20) |
2 | vue2 面试题及详细答案(21 - 40) |
3 | vue2 面试题及详细答案(41 - 60) |
4 | vue2 面试题及详细答案(61 - 70) |
5 | vue2 面试题及详细答案(71 - 80) |
6 | vue2 面试题及详细答案(81 - 90) |
7 | vue2 面试题及详细答案(91 - 100) |
8 | vue2 面试题及详细答案(101 - 120) |
9 | vue2 面试题及详细答案(121 - 130) |
10 | vue2 面试题及详细答案(131 - 140) |
11 | vue2 面试题及详细答案(141 - 150) |