vue2 面试题及详细答案150道(41 - 60)

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。

前后端面试题-专栏总目录

在这里插入图片描述

一、本文面试题目录

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>标签引用。
    1. 安装loader:npm install svg-sprite-loader --save-dev
    2. 配置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]' });
      }
    };
    
    1. 使用:
    <svg>
      <use xlink:href="#icon-my-icon"></use>
    </svg>
    

45. Vue项目中如何实现主题切换功能

实现主题切换功能通常有以下步骤:

  1. 定义主题样式:通过CSS变量定义不同主题的样式,如在全局样式中定义:
:root {
  --primary-color: #42b983; /* 默认主题主色 */
  --bg-color: #ffffff; /* 默认主题背景色 */
}
.dark-theme {
  --primary-color: #35495e; /* 深色主题主色 */
  --bg-color: #1a1a1a; /* 深色主题背景色 */
}
  1. 在组件中使用CSS变量
.button {
  background-color: var(--primary-color);
  color: var(--text-color);
}
  1. 切换主题类名:在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');
      }
      // 可选:将主题偏好存储到localStorage
      localStorage.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的步骤如下:

  1. 安装EChartsnpm install echarts --save
  2. 在组件中引入并使用
<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 教程】
1Openlayers 【入门教程】 - 【源代码+示例 300+】
2Leaflet 【入门教程】 - 【源代码+图文示例 150+】
3MapboxGL【入门教程】 - 【源代码+图文示例150+】
4Cesium 【入门教程】 - 【源代码+综合教程 200+】
5threejs【中文API】 - 【源代码+图文示例200+】

51. Vue项目中如何实现文件上传功能

Vue项目中实现文件上传的基本步骤如下:

  1. 模板部分:使用<input type="file">元素获取文件,通过@change事件监听文件选择。
<template>
  <div>
    <input type="file" @change="handleFileChange" accept="image/*">
    <button @click="uploadFile">上传文件</button>
  </div>
</template>
  1. 脚本部分
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);
      });
    }
  }
};
  1. 可选:实现多文件上传可将inputmultiple属性设为true,并处理files数组。

52. Vue中如何实现组件的递归调用

组件递归调用即组件自身调用自身,常用于实现树形结构、菜单等功能,实现方式如下:

  1. 定义组件:在组件中通过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>
  1. 使用组件
<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分割成多个模块,每个模块拥有自己的stategettermutationaction,甚至可以嵌套子模块。

使用方式

  1. 定义模块
// 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);
    }
  }
};
  1. 注册模块
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
  }
});
  1. 访问模块内容
  • 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项目中配置环境变量可通过以下步骤:

  1. 创建环境变量文件:在项目根目录下创建不同环境的配置文件:
    • .env:全局默认配置,所有环境都会加载。
    • .env.development:开发环境配置(npm run serve时加载)。
    • .env.production:生产环境配置(npm run build时加载)。
    • .env.test:测试环境配置(可自定义脚本加载)。
  2. 定义环境变量:文件中变量以VUE_APP_为前缀,例如:
# .env.development
VUE_APP_API_URL = 'http://dev.api.example.com'
VUE_APP_ENV = 'development'
  1. 在项目中使用:通过process.env访问环境变量。
console.log(process.env.VUE_APP_API_URL); // 输出http://dev.api.example.com
  1. 配置启动脚本(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

  1. 安装:npm install vue-cropper --save
  2. 使用:
<template>
  <div>
    <input type="file" @change="selectImage" accept="image/*">
    <vue-cropper
      v-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的生命周期钩子有所变化,如beforeCreatecreatedsetup替代,mounted对应onMounted等(组合式API中)。
  • Vue3的全局API改为使用createApp创建应用实例,如Vue.createApp(App).mount('#app'),替代Vue2的new Vue({ el: '#app' })

二、150道面试题目录列表

文章序号vue2面试题150道
1vue2 面试题及详细答案(01 - 20)
2vue2 面试题及详细答案(21 - 40)
3vue2 面试题及详细答案(41 - 60)
4vue2 面试题及详细答案(61 - 70)
5vue2 面试题及详细答案(71 - 80)
6vue2 面试题及详细答案(81 - 90)
7vue2 面试题及详细答案(91 - 100)
8vue2 面试题及详细答案(101 - 120)
9vue2 面试题及详细答案(121 - 130)
10vue2 面试题及详细答案(131 - 140)
11vue2 面试题及详细答案(141 - 150)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

还是大剑师兰特

打赏一杯可口可乐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值