前端高频考题(vue)

一、介绍一下 vue 的生命周期

1. 有哪些生命周期

一共有八个生命周期

  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • beforeDestroy(beforeUnmount)
  • destroyed(Unmount)

2. 一旦进入组件会执行哪些生命周期

  • beforeCreate
  • created
  • beforeMount
  • mounted

3. 在那个阶段有$el $data

  • beforeCreate undefined undefined
  • created undefined $data
  • beforeMount undefined $data
  • mounted $el $data

4. 如果加入keep-alive多两个生命周期

  • activated
  • deactivated

5. 加入keep-alive,第一次进入组件会执行哪些生命周期

  • beforeCreate
  • created
  • beforeMount
  • mounted
  • activated

6. 加入keep-alive,第二次进入组件会执行哪些生命周期

  • activated

7. 为什么要 beforeDestroy(vue2) → beforeUnmount(vue3)

  • 准确描述生命周期阶段:强调组件从 DOM 卸载,而非实例被销毁。
  • 统一行业术语:与 React 等框架保持一致,降低学习成本。

二、什么是渐进式框架

  • vue.js只是一个核心库专注于视图层渲染,而其他功能(router、vuex等)则通过官方或第三方插件扩展。

三、谈谈你对keep-alive的了解

  1. 是什么?
  • vue 自带的一个组件,功能:是来缓存组件的 -> 提升性能
  1. 使用场景
  • 就是来缓存组件,提升项目的性能。具体实现比如:首页进入详情页,如果用户在首页每次点击都是相同的,那么详情页就没必要请求n次,直接缓存起来就可以了,如果点击的不是同一个,那么就直接请求

四、v-if和v-show的区别

  1. 展示形式不同
  • v-if 是创建一个dom节点
  • v-show 不是
  1. 使用场景不同
  • 初次加载v-if要比v-show好,页面不会做加载盒子
  • 频繁切换v-show要比v-if好,创建和删除的开销太大了,显示和隐藏开销较小

五、v-if和v-for的优先级

  • v-for的优先级要比v-if更高,源码中的genElement体现
  • 如果同时出现,每次渲染都会执行循环再判断条件,无论如何循环都不可避免,浪费了性能
  • 要避免出现这种情况,则在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环

六、ref是什么

  • 来获取dom的

七、scoped原理

  • 作用:让css样式在本组件中生效,不影响其他组件
  • 原理:给节点新增自定义属性,然后css根据属性选择器添加样式

八、vue样式穿透

  • scss:父元素 /deep/ 子元素
  • stylus:父元素 >>> 子元素

九、vue组件通信

首先是父子组件通信,这是最基础的。父组件向子组件传递数据可以通过 props,在子组件中定义 props 选项,父组件在使用子组件时通过属性传递值;子组件向父组件传递信息则用 $emit 触发事件,父组件通过 v-on 监听。比如父组件给子组件传一个 title,子组件通过点击事件把输入的内容传给父组件。

然后是兄弟组件通信,这种情况可以借助一个共同的父组件作为中间层,子组件 A 通过 $emit 把数据传给父组件,父组件再通过 props 传给子组件 B;也可以用 Vuex 或 Pinia 这样的状态管理库,把共享数据放在 store 里,兄弟组件都去操作和读取这个 store 中的数据。

十、vue的双向数据绑定原理

通过数据劫持和发布订阅者模式来实现,同时利用Object.defineProperty()劫持各个属性的setter和getter或者利用proxy去代理整个对象,在数据发生变化的时候发布消息给订阅者,触发对应的监听回调渲染视图,也就是说数据和视图是同步的,数据发生变化,视图跟着发生变化,视图变化,数据也会发生改变。

  • Vue 2 :基于 Object.defineProperty() 劫持对象属性的 getter/setter,通过递归遍历实现深度响应式,但无法检测对象新增属性或数组索引变更。
  • Vue 3 :基于 Proxy 代理整个对象,直接拦截对象的所有操作(包括属性新增 / 删除、数组变异方法),并通过 Reflect 反射机制保持原始行为,实现更高效、全面的响应式系统。

十一、axios的简单封装

javascript 复制代码
import axios from 'axios';

// 创建 axios 实例
const service = axios.create({
  baseURL: process.env.NODE_ENV === 'production' ? 'https://api.example.com' : '/api', // 生产环境和开发环境的基础 URL
  timeout: 5000, // 请求超时时间
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  }
});

// 请求拦截器
service.interceptors.request.use(
  config => {
    // 在发送请求前做些什么
    // 例如:添加 token
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  error => {
    // 对请求错误做些什么
    console.error('请求错误:', error);
    return Promise.reject(error);
  }
);

// 响应拦截器
service.interceptors.response.use(
  response => {
    // 对响应数据做些什么
    const res = response.data;
    // 假设业务状态码 200 表示成功
    if (res.code !== 200) {
      console.error('业务错误:', res.message || '请求失败');
      return Promise.reject(new Error(res.message || '请求失败'));
    } else {
      return res.data; // 直接返回业务数据
    }
  },
  error => {
    // 对响应错误做些什么
    console.error('响应错误:', error.message);
    // 可以根据错误类型进行不同处理
    if (error.response) {
      switch (error.response.status) {
        case 401:
          // 未登录处理
          console.error('未登录或登录已过期');
          break;
        case 403:
          // 权限不足处理
          console.error('权限不足');
          break;
        case 500:
          // 服务器错误处理
          console.error('服务器内部错误');
          break;
      }
    }
    return Promise.reject(error);
  }
);

// 封装常用请求方法
const request = {
  get(url, params = {}) {
    return service.get(url, { params });
  },

  post(url, data = {}) {
    return service.post(url, data);
  },

  put(url, data = {}) {
    return service.put(url, data);
  },

  delete(url, params = {}) {
    return service.delete(url, { params });
  }
};

export default request;
typescript 复制代码
import request from './request';

// GET 请求
request.get('/users', { id: 123 })
  .then(data => {
    console.log('用户数据:', data);
  })
  .catch(error => {
    console.error('获取用户失败:', error);
  });

// POST 请求
request.post('/login', { username: 'test', password: '123456' })
  .then(data => {
    console.log('登录成功:', data);
  })
  .catch(error => {
    console.error('登录失败:', error);
  });

十二、vue路由的hash和history模式有什么区别

1. URL 表现形式

  • hash 模式

    • URL 中包含 # 符号,例如:https://example.com/#/home
    • # 后的内容是路由路径,不会被发送到服务器。
  • history 模式

    • URL 看起来像传统的 URL,没有 #,例如:https://example.com/home
    • 路径会被完整发送到服务器,需要服务器配合处理。

2. 实现原理

  • hash 模式

    • 基于浏览器的 hashchange 事件,监听 URL 中 # 后的变化。
    • 无论 # 后的路径如何变化,浏览器都不会向服务器发送请求,因此不会刷新页面。
  • history 模式

    • 基于 HTML5 的 History APIpushStatereplaceState)。
    • 通过 pushStatereplaceState 修改浏览器历史记录,实现无刷新切换路由

3. 如何选择

  • 如果项目对 URL 美观度、SEO 有要求(爬虫忽略#后的路径不处理),且服务器支持配置(如 Nginx、Node.js),推荐使用 history 模式。
  • 需要兼容低版本浏览器(如 IE9 及以下),对 URL 格式没有严格要求。

十三、vue路由是如何传参的

  • params传参
php 复制代码
this.$router.push({name:'index',params:{id:item.id}})
this.$router.params.id
  • 路由属性传参
css 复制代码
this.$router.push({name:'/index/${item.id}'})
路由配置:{path:'/index/:id'}
  • query传参(可解决页面刷新参数丢失的问题)
php 复制代码
this,$router.push({
    name:'index',
    query:{id:item.id}
})
xml 复制代码
<template>
    <ul>
        <li v-for="item in blogList">
            <router-link :to="'/blog'+item.id">
                {{item.title}}
            </router-link>
        </li>
    </ul>
</template>
<script>
export default {
    data(){
        return {
            blogList:[
                {id:1,title:'1'},
                {id:2,title:'2'},
                {id:3,title:'3'}      
            ]
        }
    }
}
</script>
xml 复制代码
<template>
    <h1>博客详情:{{$route.params.id}}</h1>
</template>
php 复制代码
const router = createRouter({
    history:createWebHashHistory(),
    routes:[
        {
            path:"/",
            component:List
        },
        {
            path:"/blog/:id",
            component:Blog
        }
    ]

})

十四、路由拦截

scss 复制代码
{
    name:'index',
    path:'/index',
    component:Index,
    meta:{
        requireAuth:ture
    }
}
router.beforeEach((to,from,next)=>{ //路由守卫
    if(to.meta.requirAuth){
        if(store.satte.token){
            next()
        }else{}
    }
})

十五、动态路由

动态路由是指在路由配置中使用可变参数(如 :id:name)来匹配一类相似页面的路由机制,其核心是用同一套路由规则处理不同数据的访问需求,而非为每个具体页面单独配置路由。这种设计减少了路由配置的冗余,实现了 "一套组件处理多组数据" 的复用效果。在技术实现上,动态路由通过路径参数(如 $route.params.id)传递数据标识,并需注意组件复用场景下的路由变化监听(如使用 watchbeforeRouteUpdate 钩子)。典型应用场景包括用户个人主页(/user/:username)、文章详情页(/article/:id)等。

十六、vue组件是什么

Vue 组件是 Vue.js 框架中构建用户界面的基本单元,它将 HTML 模板、JavaScript 逻辑和 CSS 样式封装在一起,实现了代码复用、模块化开发和关注点分离,使大型应用的构建和维护更高效。

十七、v-for中的key有什么用

key属性是DOM元素的唯一标识

  • key的作用主要是为了高效的更新虚拟dom,其原理是vue在patch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同的元素,使得整个patch过程更加高效,减少dom操作量,提高性能
  • 当组件使用v-for渲染且需维护内部状态时,key可确保状态与特定元素绑定。若没有key,Vue 可能复用错误的组件实例,导致状态混乱。

十八、vue2 和 vue3 的区别

Vue 3 是一次全面升级,主要体现在 架构范式性能优化开发体验 三个层面:

  1. 范式转变
特性 Vue2 Vue3
API 风格 选项式(data/methods) 组合式(setup ())
响应式 Object.defineProperty Proxy
多根节点 不支持 支持
TypeScript 需额外配置 原生支持
性能 一般 更好(编译优化、体积小)
逻辑复用 mixins(有缺陷) 组合式函数(更灵活)
  1. 性能飞跃
特性 Vue2 (Object.defineProperty) Vue3 (Proxy)
拦截方式 劫持单个属性 代理整个对象
新增 / 删除属性 需手动调用 Vue.set/Vue.delete 自动响应
深层嵌套对象 初始化时递归处理 访问时懒代理
数组索引修改 不支持(需用 splice 等方法) 支持
性能 初始化时递归遍历所有属性,开销大 按需代理,内存占用更少
缺陷 存在响应式死角,代码冗余 兼容性问题(IE 不支持 Proxy)
  1. 开发体验升级

    • 原生支持 TypeScript,结合 Composition API 提供更完善的类型推导。
    • 新增特性如 Teleport 和 Suspense 简化了复杂场景的实现(如模态框、异步加载)。

十九、ref和reactive的区别

  • ref
    • 接收一个基本数据类型作为参数,返回一个有.value属性的对象
    • ref 解构后仍保持响应式
  • reactive
    • 接受一个对象或数组作为参数,返回一个处理过后的对象,直接通过属性访问
    • reactive 解构后会失去响应式,需配合 toRefs 保持

二十、vue常见的内置令

v-if,v-else,v-show,v-bind,v-on,v-model

二十一、watch和computed的区别

  • computed:像「公式」,根据已有数据自动计算新值。
  • watch:像「监控器」,当数据变化时执行特定操作。
  • 有「计算逻辑」→ 用 computed
  • 有「副作用」(如发请求、改 DOM)→ 用 watch

二十二、首屏优化

  • 缓存:将长时间不会改变的第三方类库或者静态资源设置为强缓存,将 max-age 设置为一个非常长的时间,再将访问路径加上哈希达到哈希值变了以后保证获取到最新资源,好的缓存策略有助于减轻服务器的压力。
  • 懒加载:当 url 匹配到相应的路径时,通过 import 动态加载页面组件,这样首屏的代码量会大幅减少,webpack 会把动态加载的页面组件分离成单独的一个 chunk.js 文件
  • 预渲染:由于浏览器在渲染出页面之前,需要先加载和解析相应的 html、css 和 js 文件,为此会有一段白屏的时间,可以添加loading,或者骨架屏幕尽可能的减少白屏对用户的影响体积优化
  • http2:可以在多个 tcp 连接中并发多个请求没有限制

二十三、页面性能指标

  • LCP( Largest Contentful Paint,最大内容绘制)

    • 定义:衡量页面加载的速度,即视口内最大的内容元素(如图片、文本块)完成渲染的时间。
    • 目标:理想值≤2.5 秒,超过 4 秒则为差。
    • 意义:反映用户 "页面是否加载完成" 的第一印象。
  • FID(First Input Delay,首次输入延迟)

    • 定义:衡量页面的交互响应速度,即用户首次与页面交互(如点击按钮、输入文本)到浏览器开始处理该交互的时间。
    • 目标:理想值≤100 毫秒,超过 300 毫秒则为差。
    • 意义:反映页面 "是否卡顿" 的即时体验。
      注:未来将被 INP(Interaction to Next Paint)替代,INP 更全面地衡量所有交互的响应延迟。
  • CLS(Cumulative Layout Shift,累积布局偏移)

    • 定义:衡量页面的视觉稳定性,即页面元素在加载过程中意外偏移的累积分数。
    • 目标:理想值≤0.1,超过 0.25 则为差。
    • 意义:避免用户因元素突然移位(如图片加载后挤压文本)而误操作。

二十四、data为什么是函数而不是对象

vue组件可能存在多个实例,如果用对象形式定义data,则会导致它们共用一个data对象,那么状态变更将会影响所有组件实例,这是不合理的;采用函数式定义,有效规避多实例之间状态污染问题。而在vue根实例创建过程中则不存在该限制,也是因为根实例只能有一个,不需要担心这种情况。

二十五、spa 和 mpa 的区别

  • 组成
    • spa:一个主页以及多个页面片段
    • mpa:多个主页面
  • 刷新
    • spa:局部刷新
    • mpa:多个主页面
  • url
    • spa:hash/history
    • mpa:history
  • seo
    • spa:比较难
    • mpa:任意实现

二十六、双向绑定和响应式

特性 响应式 双向绑定
数据流方向 单向(数据 → 视图) 双向(数据 ⇄ 视图)
触发机制 数据变化触发视图更新 数据变化或视图事件(如输入)触发更新
适用场景 展示数据(如列表、详情页) 表单交互(如登录、注册)
实现方式 数据劫持 / 发布 - 订阅模式 响应式 + 事件监听
相关推荐
水星记_4 小时前
时间轴组件开发:实现灵活的时间范围选择
前端·vue
麦麦大数据4 小时前
vue+Django 双推荐算法旅游大数据可视化系统Echarts mysql数据库 带爬虫
数据库·vue.js·django·可视化·推荐算法·百度地图·旅游景点
2501_930124704 小时前
Linux之Shell编程(三)流程控制
linux·前端·chrome
潘小安4 小时前
『译』React useEffect:早知道这些调试技巧就好了
前端·react.js·面试
@大迁世界5 小时前
告别 React 中丑陋的导入路径,借助 Vite 的魔法
前端·javascript·react.js·前端框架·ecmascript
EndingCoder5 小时前
Electron Fiddle:快速实验与原型开发
前端·javascript·electron·前端框架
EndingCoder5 小时前
Electron 进程模型:主进程与渲染进程详解
前端·javascript·electron·前端框架
Nicholas685 小时前
flutter滚动视图之ScrollNotificationObserve源码解析(十)
前端
@菜菜_达6 小时前
CSS scale函数详解
前端·css
不吃香菜的蟹老板6 小时前
随手小记:elementUI的勾选框使用的坑
vue.js