Vue常见题

  1. Vue请求一般放在哪个生命周期内
    1. 可以在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。
    2. 但是推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:
    3. 能更快获取到服务端数据,减少页面loading 时间;
    4. ssr不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;
  2. v-model原理
    1. v-model是value+input事件的语法糖,可以通过model配置对象prop+event来进行自定义
  3. Vue事件绑定原理
    1. 原生事件通过addEventListener进行绑定,组件事件通过Vue自定义的$on进行绑定
  4. Vue中组件生命周期调用顺序说一下
    1. 组件的调用顺序都是先父后子,渲染完成的顺序是先子后父
    2. 组件的销毁操作都是先父后子,销毁完成的顺序是先子后父
    3. 加载渲染过程:父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
    4. 销毁过程:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
    5. 子组件更新过程:父beforeUpdate->子beforeUpdate->子updated->父updated
    6. 父组件更新过程:父beforeUpdate->父updated
  5. Vue2.x组件通信方式
    1. 父子通信
      1. props、$parent、$children、$ref、$on、$emit
    2. 兄弟组件通信
      1. vuex、event bus、
    3. 跨级组件通信
      1. inject、provide、vuex、$attrs、$listeners
  6. 在Vue方面做过哪些性能优化:优化是一个大专栏,很多内容
    1. 减少data中的属性,data中的属性会增加getter、setter,一般配置数据从文件引入或在当前文件定义变量
    2. for循环列表中如果有事件处理,则采用事件委托进行代理处理
    3. SPA页面采用Keep-alive缓存组件
    4. key值设置为唯一值
    5. 细分Vue组件,提高Vue组件渲染速度
    6. 图片资源按需加载:v-lazy以及监听鼠标事件,滚动到指定位置再进行加载
    7. 页面加载loading
    8. 选择性使用v-if、v-show
    9. 代码按需加载
    10. 全局引入SASS变量,node-sass,sass-loader,vue-cli3通过css.loaderOptions.sass进行配置

  7. v-if和v-show的区别
    1. v-if会在切换过程中对组件或元素进行销毁和重建,如果初始为false则不会进行任何操作,v-show不管条件如果都会创建,然后通过display:none进行显隐
  8. $on的原理
    1. 将监听的事件绑定在vm._events对象上,将事件函数收集到数组中,_events是在Vue init初始化时创建的
    2. $emit将事件对象上绑定的函数依次循环调用
  9. $forceUpdate
    1. 手动执行vm._watcher.update()方法
  10. Vue销毁组件流程
    1. 清除当前组件与父组件的联系,通过$children删除当前组件实例
    2. 实例的teardown清除实例绑定的相关状态
  11. Vue状态发生变更时,watcher会收到通知,然后触发虚拟DOM更新
  12. Vue的选项初始化顺序

    1. 属性、方法、数据、计算属性、watch

      Vue filter原理

  13. 过滤器保存在this.$options.filters中,通过resolveFilter函数将过滤器名称传入进去,查找到对应的过滤器函数再进行执行,将变量作为参数传递给函数,最后编译为文本交给页面渲染

虚拟DOM

  1. 虚拟DOM是根据状态生成一棵虚拟状态树,根据虚拟树进行渲染,当状态发生了变更,进行虚拟节点对比,只更新变更的节点
  2. jQuery命令式操作DOM,框架帮助我们声明式操作DOM,我们只需要维护状态,DOM映射由框架帮助我们完成
  3. Vue中模块转换成视图的过程:
    1. 模块编译为render函数
      1. 根据模板标签解析成为AST语法树

      2. 根据AST语法树生成代码
        1. (_c(‘div’,{id:”app”,a:”1”,style:{“color”:”red”}},_v(“hello”+_s(arr)+”world”)))
      3. 代码通过new Function + with解析为函数返回render函数
    2. 执行render函数得到虚拟DOM
    3. 虚拟DOM生成DOM
      1. 虚拟DOM与AST语法树的区别为可以增加自定义属性
  4. 状态发生变更,通过patch对比newVnode、oldVnode,得出需要变更的dom
  5. patch是虚拟DOM对比最核心的算法,提供两个虚拟DOM的差异,dom对比其实就是增删改
  6. 之所以不直接根据状态直接生成DOM,需要借助虚拟DOM,因为可以缓存数据,通过对比差异可以减少操作DOM

虚拟DOM的好处

  1. template变成render函数
  2. render函数返回一个虚拟DOM
  3. 让Vue的性能更快,其实是JS对象,将真实DOM的映射
  4. 让虚拟DOM具备跨平台的能力,比如weex
  5. template -> render -> 虚拟DOM(JS对象)-> 真实DOM -> 渲染页面

Diff算法

  1. 暴击比对:生成两个新老DOM,新节点直接替换老节点
  2. 对比直接节点、属性、子节点
  3. 由易到难:
    1. 一个有子元素,一个无子元素
    2. 两个元素都有子元素(双指针对比)
  4. 为什么需要key
    1. diff算法可以通过key进行方便比较,可以不需要创建元素,达到复用元素的作用
  5. 比较主要靠tag key

    视图更新

  6. 通过观察者模式进行数据观察,当数据发生变化,观察都做刷新视图的变化

实现原理

  1. Vue中模板编译原理

    1. 第一步:parserHTML-先将模板解析成为AST语法树,并打上标签tag

      1. {
      2. attrs: (3) [{…}, {…}, {…}]
      3. children: [{…}]
      4. parent: null
      5. tag: "div"
      6. type: 1
      7. }
    2. 第二步:genCode-将AST语法树生成字符串代码

      1. _c('div',{id:"app",a:"1",style:{"color":"red","background":"blue"}},_v("hello"+_s(arr)+"world"))
    3. 第三步:new Function + with将字符串代码执行,返回render函数

      1. anonymous() {
      2. with(this){return _c('div',{id:"app",a:"1",style:{"color":"red","background":"blue"}},_v("hello"+_s(arr)+"world"))}
      3. }
  2. 如何将render函数转换为视图

    1. render函数调用后生成虚拟dom
      1. {
      2. children: [{…}]
      3. data: {id: "app", a: "1", style: {…}}
      4. el: div
      5. key: undefined
      6. tag: "div"
      7. text: undefined
      8. vm: Vue {$options: {…}, _data: {…}, $el: div#app}
      9. }
      b. 通过调用patch方法,将虚拟dom使用原生createElement创建对应的元素,挂载到页面
      1. let elm = createElm(vnode); //根据虚拟节点 创建元素
      2. parentElm.insertBefore(elm, oldVnode.nextSibling);
      3. parentElm.removeChild(oldVnode);
  3. $watch:在对象上配置watch选项与vm.$watch没有任何区别,对象上配置的三种写法,结果也是也是调用的原型上$watch方法

  4. 生命周期原理:全局合并、生命周期合并

    Vue-Router

  5. hash模式和history模式是如何实现的

    1. hash模式:地址后面hash值的变化,不会导致浏览器向服务器发出请求,浏览器不发出请求,就不会刷新页面,同时监听hashchange事件可以知道hash发生了哪些变化,根据hash变化来实现更新页面内容
    2. history模式:history是采用H5新的API-history来实现,主要有pushState、replaceState等API,这两个API可以在改变url,但是不会发送请求,也是通过监听url变化来实现更新页面
  6. hash模式与history模式的区别
    1. hash后面带有#号字符
    2. hash模式兼容性更好,history模式需要服务端支持
  7. 有哪些导航守卫
    1. 全局导航守卫:beforeEach、afterEach、beforeResolve
      1. beforeEach做了哪些事
      2. 关闭模态框、验证访问权限、动态添加模块路由、验证用户token
    2. 组件内的守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
    3. 组件配置路由时守卫:beforeEnter
    4. 完整的导航流程:整体是先离开的组件再全局守卫再局部组件守卫再全局完成
  1. 为什么要use Router、use做了什么
  2. 为什么要放到router选项中
  3. 为什么要放到router-view中

响应式的数据发生变化,使用属性的render函数就会重新执行

Vuex

  1. muations里为什么只能包含同步操作

Vue服务端渲染

  1. 主要解决两个问题
    1. 首屏白屏时间过长
    2. SEO
  2. 服务端渲染的缺陷
    1. 需要占用服务的CPU和内存
    2. 前端框架中的很多生命周期无法使用

接口使用优化

  1. 接口数据缓存:使用Vuex统一缓存接口数据
  2. 页面切换接口清除:在axios请求时创建token存储到vuex,统一在vuex清除,在全局路由钩子清除
    1. 节约流量
    2. 取消不再处理的接口请求
  3. 接口列表缓存:在axios请求时创建映射对象,返回时清空接口列表
    1. 页面请求时可以添加Loading,页面所有请求返回时取消Loading
  4. 异步组件,可以在组件加载时创建loading效果,在弱网情况下很有效
  5. 接口loading:在axios创建请求时为接口创建loading

    组件设计

  6. 功能上拆分层次

  7. 尽量让组件原子化
  8. 容器组件(管理数据)UI组件(只显示视图)

    项目流程

  9. 项目分多人、多角色参与

  10. 项目计划与执行
  11. 开发阶段:写出开发文档、单元测试、Mock API、Code Review

    Vue3

    变更

  12. slot变化

  13. 全局API区别
  14. 增加teleport
  15. Composition API
  16. 指定变化,.sync去掉,统一使用v-model
  17. non-props特性
  18. 增加emits:[‘add’, ‘test’]
  19. modelValue新双向绑定,也可重新命名
  20. 注意keep-alive组件使用

    Vue3生命周期钩子

    image.png

  21. 实例生成之前调用的钩子

  22. 实例生成之后调用的钩子
  23. 当有挂载元素时,在组件内容被渲染到页面之前执行的函数
  24. 在组件内容被渲染到页面之后执行的函数
  25. 当data中的数据发生改变时执行的函数
  26. 当data中的数据发生改变,同时页面完成更新后,执行的函数
  27. 当Vue实例销毁时执行的函数
  28. 当Vue实例和DOM完全销毁完毕时执行的函数
  29. 每次渲染后重新收集响应式依赖
  30. 每次触发页面重新渲染时自动执行

Vue事件

  1. 可以当时绑定多个事件
  2. self修饰符只自身触发
  3. once修饰符事件只执行一次
  4. passive修饰符提升滚动性能

事件修饰符

  1. stop, prevent, capture, self, once, passive

按键修饰符

  1. enter, tab, delete, esc, up, down, left, right

鼠标修饰符

  1. left, right, middle

精确修饰符

  1. exact
  2. @click.ctrl.exact只有按ctrl时再点击才会触发事件,不加exact,当ctrl结合其它键也会触发事件

表单修饰符

  1. lazy, number, trim,

Vue3相关原理

  1. toRefs原理:将proxy({name: ‘jack’})转换为{ name: proxy: ({value: ‘yang’}) }
  2. refs原理:将基础类型数据通过proxy代理,当数据发生变化时进行响应式更新proxy({value: ‘jack’})
  3. toRef:为初始化时未定义的属性定义一个响应式

Vue3监听

  1. watchEffect立即执行,相当于immediate,不需要传递监听内容
  2. watch惰性执行,首次不会执行,配置immediate可以实现非惰性

Vue3 minixs优先级

  1. 组件data, methods优先级高于 mixins data, methods
  2. 生命周期函数,先执行mixix里面,再执行组件的
  3. 自定义属性,组件属性优先于mixins
  4. 可自定义属性的合并策略,optionsMergeStrategies

Vue动画与过渡

  1. 动画是运动帧,从上到下,从左到右,弹跳等
  2. 过渡是从一个状态过渡到另一个状态
  3. Vue列表动画
  4. Vue组件动画
  5. Vue状态动画
  6. Vue单元素动画

Vue项目

  1. 组件name还有一个作用就是用于dev tools
  2. 项目合在一起写代码量少点,分开写未来扩展性更好
  3. 自己写toast
  4. 阻止Chrome自动填写密码:autocomplete=”new-password”
  5. 异步组件是谁实现的?webpack
  6. ?.使用
  7. template模板内少写JS逻辑
  8. 本地开发使用localhost,不要使用ip,以免影响热更新

登录JWT

  1. jwt:JSON Web Tokens
  2. 什么是jwt
  3. jwt解决了什么问题
  4. jwt原理
    1. 服务器认证后,生成一个JSON对象,后续通过json进行通信
  5. jwt数据结构
    1. image.png
    2. image.png
    3. image.png
    4. image.png
  6. jwt使用方式

    1. image.png

      Vue3与Vue2对比

  7. Vue3采用函数式编程,所以支持tree-shaking,不使用就不会打包

  8. Vue3采用TS开发,Vue2使用Flow开发
  9. 源码采用monorepo方式进行管理

    内部代码优化

  10. Vue3劫持数据采用proxy Vue2劫持数据采用defineProperty,有性能问题和缺陷

  11. Vue3中对模板编译进行了优化,编译时生成了Block tree,可以对子节点的动态节点进行收集,可以减少比较,并且采用了patchFlag标记动态节点
  12. Vue2 Diff算法在对比时是两棵树进行对比,Vue3是将动态节点收集成数组进行对比
  13. 如果使用JSX语法则无法模板优化,还是使用传统的两棵树Diff递归对比
  14. Vue3采用compositionApi进行组织功能,解决反复横跨,优化复用逻辑
  15. Vue3增加Fragment,Teleport,Suspense组件

    Vue3项目结构

  16. compiler-core:与平台无关的编译器核心

  17. compiler-dom:针对浏览器的编译模块
  18. compiler-sfc:针对单文件解析
  19. compiler-ssr:针对服务端渲染的编译模块
  20. reactivity:响应式系统
  21. ref-transform
  22. runtime-core:与平台无关的运行时核心(可以创建针对特定平台的运行时-自定义渲染器)
  23. runtime-dom:针对浏览器的运行时。包括DOM API,属性,事件处理等
  24. runtime-test:用于测试
  25. server-renderer:用于服务端渲染
  26. sfc-playground
  27. shared:多个包之间共享的内容
  28. size-check:用来测试代码体积
  29. template-explorer:用于调试编译器输出的开发工具
  30. vue-compat
  31. vue:完整版本,包括运行时和编译器
    1. 包含compiler-dom、compiler-core
      1. (dom基于core,相当于针对浏览器扩展了一些,dom是让template编译成render函数,如何不使用template,则可以不使用这个模块,只使用render函数开发)
    2. 包含runtime-core、runtime-dom、reactivity
      1. runtime-dom封装了浏览器操作DOM的API
      2. runtime-core封装了虚拟DOM的生成,如何调度的核心,不依赖于平台
      3. reactivity封装了响应式模块