0%

Vue

主观能动性是一个哲学概念,亦称“自觉能动性”,它指人的主观意识和实践活动对于客观世界的能动作用。主观能动性有两方面的含义: 一是人们能动地认识客观世界;二是在认识的指导下能动地改造客观世界。在实践的基础上使二者统一起来,即表现出人区别于物的主观能动性。能动性是指对外界或内部的刺激或影响作出积极的、有选择的反应或回答。人的能动性与无机物、有机生命体、高等动物的能动性有别,称为主观能动性,其特点是通过思维与实践的结合,自觉地、有目的地、有计划地反作用于客观世界。

一、基础

  1. 简介
          Vue(读音 /vjuː/,类似于view)是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

  2. 特性

    • 轻量级20kb min + gzip
    • 渐进式框架
    • 响应式的更新机制
    • 学习成本低
  3. 生命周期

    • beforeCreate->created->beforeMount->mounted->beforeUpdate->updated->beforeDestroy->destroyed。
  4. 环境搭建

    • 谷歌浏览器
    • vs code编辑器
    • Nodejs + npm
  5. 开干

    • 引入vue
    • new Vue
    • Vue.component及其缺点
    • v-on:click简写@click
    • v-model
    • v-bind
    • v-for
    • scope作用域
  6. vue cli

    • 安装npm install -g @vue/cli
    • 单文件组件
    • 插槽v-slot

二、脚手架

  1. 安装node
    • node -v 查看node版本
    • npm是集成在node中的,npm -v 查看npm版本
    • Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
    • Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
  2. 安装cnpm
  3. 安装webpack
    • npm install webpack -g
    • webpack -v
    • webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
  4. 安装vue cnpm install vue
  5. 安装vue-cli脚手架构建工具 cnpm install –global vue-cli
  6. 创建一个基于webpack模板的新项目 vue init webpack project-name
  7. 安装依赖 cnpm install
  8. 运行项目 cnpm run dev

三、双向绑定

  1. 单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新。有单向绑定,就有双向绑定。如果用户更新了View,Model的数据也自动被更新了,这种情况就是双向绑定。

四、自定义指令

五、异步编程

六、组件间传值

七、solt用法

  1. Slot的通俗理解就是是“占坑”,在组件模板中占好了位置,当使用该组件标签时候,组件标签里面的内容就会自动填坑(替换组件模板中<slot>位置),当插槽<slot name=”mySlot”>有命名时,组件标签中使用属性slot=”mySlot”的元素就会替换该对应位置内容。

八、Vuex

  1. vuex是怎么存储变量的
  2. vuex中muation和action分别是怎么实现同步和异步更改store的值的
  3. Eventbus和vuex的区别

    由于props和$emit一般用于父子组件间传递数据,当子组件过多时使用起来会很复杂,因此可以引入一个eventBus来订阅和发送全部组件间的数据。

九、Vue 常见知识点

9.1 生命周期

  1. 0.x ~ 1.x 的旧生命周期:init → created → beforeCompile → compiled → ready → beforeDestroy → destroyed
  2. 2.x 的生命周期:beforeCreate → created → beforeMount → mounted → beforeUpdate → updated → activated / deactivated → beforeDestroy → destroyed
  3. 加了 keep-alive 之后:只多两个钩子——activated(被缓存组件重新激活时触发)与 deactivated(组件被停用时触发)。
    • activated:常用于进入页面时重新拉取列表、开启定时器、恢复滚动位置
    • deactivated:常用于离开页面时清除定时器、保存草稿
    • 注意:keep-alive 的组件不会走 destroyed,所以清理逻辑不要只写在 destroyed 里,否则内存和定时器都不会释放。

9.2 父子组件之间传值(含非父子)

方向 方式 说明
父 → 子 props 单向数据流,子组件不能直接改 prop(要改需 emit 让父改,或改本地副本)
子 → 父 $emit 自定义事件 父用 @event="handler" 监听
父调子 ref + $refs 直接拿到子组件实例,调其方法或读其 data
双向 v-model 本质是 :value + @input 的语法糖(组件上为 :modelValue + @update:modelValue)
任意组件 EventBus / $bus 订阅-发布模式,$emit 发、$on 收;组件过多时用起来会失控,建议只在少量场景使用
任意组件 Vuex / Pinia 集中式状态管理,跨层级、跨模块共享数据的正解
跨层级 provide / inject 祖先直接向后代注入,跳过中间层级
跨层级 $attrs / $listeners 属性与事件透传

由于 props 和 $emit 一般用于父子组件间传递数据,当子组件过多时使用起来会很复杂,因此可以引入一个 EventBus 来订阅和发送全部组件间的数据。

9.3 获取 DOM 元素

  1. ref:给元素加 ref="myRef",用 this.$refs.myRef 直接拿到真实 DOM 节点。
  2. el:mounted 里 this.$el 拿组件自身根节点;this.$el.querySelector('.cls') 可查内部节点。
  3. document.getElementById 等原生 API:能用,但丧失响应式语义,容易与虚拟 DOM 的更新时机打架,不推荐。
    • 时机要点:ref 只有在 mounted 及之后才拿得到,created 阶段 DOM 还没生成。

9.4 data 为什么是一个函数?

  • 因为组件是可以被复用的,如果 data 直接是一个对象,那么所有组件实例就会共享同一个对象引用,一个实例改了数据,其他实例也跟着变。
  • 写成函数,每次创建组件实例时都会调用它并 return 一个全新的对象,各实例持有独立的数据副本。
  • 根实例 new Vue({ data: {...} }) 只有一个实例、不会被复用,所以可以写成对象。

9.5 双向绑定原理

  1. Vue 2.x:Object.defineProperty
    • 在 Observer 中递归遍历 data 的每个属性,用 Object.defineProperty 改写为 getter / setter
    • getter 负责依赖收集:把当前正在求值的 Watcher 记录进 Dep(一个依赖收集容器)
    • setter 负责派发更新:数据变化时通知 Dep,Dep 再通知所有 Watcher 执行 update
    • Watcher 分三种:渲染 Watcher(更新视图)、用户 Watcher($watch)、计算属性 Watcher
    • 缺点:无法监听数组下标赋值和对象属性的新增/删除(所以需要 Vue.set / Vue.delete);初始化时递归遍历所有属性,数据量大时性能开销明显。
  2. Vue 3.x:Proxy
    • 用 Proxy 代理整个对象,配合 Reflect 操作原对象
    • 直接解决了 2.x 的数组下标和属性增删问题,并且是惰性的(访问到才递归代理),初始化更快
    • 通过 track(收集)和 trigger(触发)两个函数完成依赖管理

9.6 双向数据绑定在什么时候收集订阅者,怎么收集的?

  • 时机:在 new Watcher() 阶段,构造函数最后会主动调用一次 this.get();get() 内部先执行 pushTarget(this) 把当前 Watcher 挂到 Dep.target,然后求值被监听的那个表达式(比如渲染 Watcher 就是执行 render)。
  • 怎么收集:求值过程中必然会读到响应式属性,从而触发该属性的 getter;getter 里判断 Dep.target 存在,就调用 dep.depend(),把当前 Watcher 加进自己的 subs 队列,同时反向在 Watcher 里记录该 Dep。
  • 求值结束后执行 popTarget() 清空 Dep.target,避免收集到无关依赖。
  • 一句话总结:订阅者在”读数据”时被动地被收进 Dep.subs,而”读数据”这个动作由 Watcher.get() 主动触发。

9.7 router 跳转方式与传参

方式 写法 说明
声明式 <router-link :to="..."> 渲染成 <a>,最常规的跳转
编程式 this.$router.push(...) 压入历史栈,可回退
编程式 this.$router.replace(...) 替换当前记录,不可回退
编程式 this.$router.go(n) 前进/后退 n 步,等价于 history.go(n)

传参方式对比:

方式 写法 取值 特点
查询参数 query push({ path:'/a', query:{ id:1 } }) this.$route.query.id 参数暴露在 URL,刷新不丢
命名路由 params 路由需定义 name,push({ name:'a', params:{ id:1 } }) this.$route.params.id 参数不在 URL(除非路由 path 中声明了占位符),刷新会丢
动态路由参数 路由 path 写 /user/:id this.$route.params.id 参数是 URL 的一部分,刷新不丢
props 解耦 路由配置 props: true 组件里直接 props: ['id'] 组件不依赖 $route,复用性最好

导航守卫(按执行顺序):

类型 钩子 触发时机
全局前置 router.beforeEach 每次路由跳转前,最常用(登录校验、权限)
全局解析 router.beforeResolve 所有组件内守卫和异步路由组件解析完之后
全局后置 router.afterEach 跳转完成后,无 next,常用于改标题、埋点
路由独享 beforeEnter 写在某条路由配置里
组件内 beforeRouteEnter 进入该组件前,此时 this 还不可用,需在 next(vm => {}) 里拿实例
组件内 beforeRouteUpdate 当前路由改变但该组件被复用时(如 /user/1 → /user/2)
组件内 beforeRouteLeave 离开该组件前,常用于”有未保存内容,确认离开?”

9.8 路由实现:hash 模式与 history 模式

对比项 hash 模式 history 模式
URL 形态 example.com/#/user/1 example.com/user/1
原理 监听 hashchange 事件,# 后的内容变化不触发页面请求 依赖 HTML5 history.pushState / replaceState,通过 popstate 监听
是否请求服务端 否,# 之后的部分不会发给服务器 是,刷新时会带完整路径请求服务端
是否需要服务端配合 不需要 需要,服务器必须把未匹配的路径统一回退到 index.html,否则刷新 404
兼容性 好(低版本 IE 也支持) 需 HTML5 支持
美观度 带 #,略丑 干净,对 SEO 相对友好
  • nginx 上 history 模式的经典配置:try_files $uri $uri/ /index.html;

9.9 单页面应用(SPA)的优缺点

维度 优点 缺点
体验 页面切换无需整页刷新,流畅;可做转场动画 首屏需要等 JS 加载并执行完才能渲染,白屏时间较长
前后端 前后端职责分离清晰,前端专注交互,后端专注数据接口 需要在客户端处理大量原本由服务端承担的逻辑
开发 组件化、路由化,复用性与可维护性高 工程化配置复杂(构建、打包、路由、状态管理)
SEO 可以做预渲染/SSR 纯 CSR 对搜索引擎不友好
浏览器 — 前进后退需自行管理(路由拦截),且依赖 JS,禁用 JS 后不可用
部署 一套静态资源即可 需处理缓存、路由回退、首屏体积优化

9.10 会话存储与本地存储

对比项 cookie sessionStorage localStorage
存储容量 约 4KB 约 5MB 约 5MB
生命周期 可设 expires,默认关浏览器即失效 关闭标签页即清除 永久,除非手动清除
作用域 同源,可设 path / domain 同源 + 同一标签页 同源,多标签页共享
随请求发送 会,每次 HTTP 请求都带在 header 里 不会 不会
服务端可读 可以 不可以 不可以
典型用途 会话标识、登录态 表单临时数据、一次性流程状态 长期偏好设置、Token

9.11 什么是 WebSQL,是 H5 的一部分吗?

  • WebSQL 是一套在浏览器中通过 SQL 语句操作客户端数据库的 API(openDatabase / transaction / executeSql)。
  • 它曾经是 HTML5 规范草案的一部分,但由于各家浏览器底层实现不统一(SQLite 版本差异)、标准难以收敛,W3C 已于 2010 年停止维护该规范,所以严格来说它现在不属于 HTML5 标准。
  • 现状:Chrome / Safari 仍保留,Firefox 从未支持。新项目应改用 IndexedDB(标准化的 NoSQL 客户端数据库)。

9.12 Vue / React / Angular 的区别

对比项 Vue React Angular
定位 渐进式框架,可只引核心库 专注视图层的 UI 库 大而全的完整框架
数据绑定 双向绑定(v-model) 单向数据流,双向需自己写 双向绑定([(ngModel)])
模板 HTML 模板 + 指令 JSX(JS 里写标签) HTML 模板 + 指令
数据更新 响应式(2.x defineProperty / 3.x Proxy) setState + 虚拟 DOM diff 脏值检查(Zone.js)
语言 JS / TS JS / TS 强绑定 TypeScript
学习曲线 低,上手最快 中,需理解 JSX 与状态管理 陡,概念多(模块、依赖注入、RxJS)
生态 官方维护 router / vuex,风格统一 生态最繁荣,选型自由但需自己拼装 官方全家桶,开箱即用
适合 中小型项目、快速迭代 大型项目、跨端(React Native) 大型企业级应用

补充:

  • vuex:Vue 的集中式状态管理,解决多组件共享状态、跨层级传参的问题。
  • axios:基于 Promise 的 HTTP 客户端,用于发起请求(区别于 jQuery 的 ajax,更现代、支持拦截器与取消)。
  • UI 框架:Vue 系常用 Element UI / Element Plus / Vant(移动端)/ Ant Design Vue;React 系常用 Ant Design / MUI。

常见面试题

一、语言基础

  1. 用到了 ES6 的哪些特性,有什么感受,跟 ES5 对比有什么不同?
  2. 闭包的作用与举例
  3. JS 的原型链和继承
  4. this 的指向规则
  5. let / const / var 的区别,什么是暂时性死区

二、框架与工程化

  1. webpack 常用的哪些功能,自己的理解,和 gulp 对比有什么不同?
  2. vue-cli 怎么使用自定义组件
  3. Vue 生命周期
  4. 父组件和子组件之间的通信
  5. 3 个 Vue 常用的生命周期钩子函数
  6. vuex 有哪几种特性
  7. React 与 Vue 在数据更新机制上的差异

三、浏览器与网络

  1. 从输入 URL 到页面展示发生了什么
  2. 跨域是怎么产生的,有哪些解决方案
  3. 强缓存与协商缓存的区别
  4. 事件循环中宏任务与微任务的执行顺序

前端三大框架

框架 核心特性 实现原理
React 组件化、JSX、单向数据流、虚拟 DOM、Hooks、函数式编程 虚拟 DOM + Diff 算法;setState 触发重渲染,通过 Fiber 架构把渲染拆成可中断的小任务,实现时间切片与优先级调度
Vue 模板 + 指令、双向绑定、响应式、单文件组件、渐进式 2.x:Object.defineProperty 劫持 + Dep/Watcher 依赖收集 + 虚拟 DOM Diff;3.x:Proxy + effect 副作用收集 + 编译期优化(静态提升、Patch Flag)
Angular 完整框架、TypeScript、依赖注入、模块化、RxJS、指令 变更检测(Change Detection):Zone.js 拦截异步任务,触发自上而下的脏值检查;也可切换为 OnPush 策略手动控制检测范围

选型一句话:要生态和灵活选 React,要上手快和模板直观选 Vue,要企业级全家桶和强类型约束选 Angular。