前端高频考题(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:任意实现

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

特性 响应式 双向绑定
数据流方向 单向(数据 → 视图) 双向(数据 ⇄ 视图)
触发机制 数据变化触发视图更新 数据变化或视图事件(如输入)触发更新
适用场景 展示数据(如列表、详情页) 表单交互(如登录、注册)
实现方式 数据劫持 / 发布 - 订阅模式 响应式 + 事件监听
相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端