Vue知识点查缺补漏

约定不等于承诺〃 2023-06-27 12:57 147阅读 0赞

对 Vue 框架中一些重要的特性、框架的原理进行整理汇总、有写的不对的或者不够充分的还望指教。


文章目录

      • SPA单页面
      • Vue—-单向数据流
      • Vue—-生命周期
      • v-if 与 v-show的区别
      • computed 与 watch的区别
      • Vue—-双向数据绑定原理
      • keep-alive
      • Vue—-组件间通信
      • Vuex
      • Vue—-SSR(服务端渲染)
      • vue-router
      • Vue—-虚拟DOM
      • Vue—-key的作用
      • Vue—-性能优化

SPA单页面

1、SPA( single-page application )是一种特殊的Web应用。它将所有的活动局限于一个Web页面中,仅在该Web页面初始化时加载相应的HTML、JavaScript、CSS。一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转,而是利用JavaScript动态的变换HTML(采用的是div切换显示和隐藏)以及利用路由机制,从而实现UI与用户的交互,避免页面的重新加载。

2、简单来说SPA的网页只有一个页面,而这个网页的实际方式要能够回应使用者所使用的各种装置并且赋值使用者在电脑上使用软件的体验,让使用者可以更容易和有效的使用网站。按照正常情况下,我们会在一个页面中链接到其他的很多个页面,进行页面的跳转,但是如果使用单页面应用的话,我们始终在一个页面中,通常使用a标签的描点来实现。

优点 :

  • 用户体验好、页面内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染
  • 基于上面一点,SPA 相对对服务器压力小
  • 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理

缺点 :

  • 初次加载耗时多 (首屏加载):为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;
  • 前进后退路由管理麻烦:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
  • SEO 比较差:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。

Vue—单向数据流

所有的 prop都使得其父子 prop之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

prop父组件传过来的原始数据,但是我们试图通过子组件 直接 去改变 父组件的数据(而不是通过发送事件的方式),这是不允许的,因为 Vue 是单向数据流 —— 也就是说, 数据总是从父组件传到子组件 ,子组件没有权利修改父组件传过来的数据, 只能请求 父组件对原始数据进行修改。

Vue—生命周期

Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、销毁等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,就是生命周期

vue生命周期详解图

异步请求调用???
可以在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。但是本人推荐在 created钩子函数中调用异步请求
why???

  • 能更快获取到服务端数据,减少页面 loading 时间
  • ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性

访问操作DOM???
在钩子函数 mounted 被调用前,Vue 已经将编译好的模板挂载到页面上,所以在 mounted 中可以访问操作 DOM。


v-if 与 v-show的区别

v-if真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器子组件适当地被销毁重建。同时它也是惰性的,渲染条件为,什么都不做。直到条件变成,才会开始渲染条件块。

v-show不管什么条件,元素是会被渲染,并且只是简单的基于css的 display属性 进行切换

so,出于性能考虑,需要经常切换或操作频繁的使用v-show,否则用 v-if


computed 与 watch的区别

computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。

应用场景 :

  • 进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算
  • 处理props或$emit的传值

watch: 更多的是观察的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作。

应用场景 :

  • 在数据变化时执行异步开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
  • 监听props,$emit或当前组件的值执行异步操作

Vue—双向数据绑定原理

vue.js 采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

  • 数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
  • 指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
  • Watcher,作为连接ObserverCompile的桥梁,能够订阅收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图

MVVM


keep-alive

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态避免重新渲染。

  • 一般结合路由和动态组件一起使用,用于缓存组件
  • 提供 includeexclude 属性,两者都支持字符串正则表达式include表示只有名称匹配的组件会被缓存exclude表示任何名称匹配的组件都不会被缓存 ,其中 exclude的优先级比 include
  • 对应两个钩子函数 activateddeactivated,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated

Vue—组件间通信

Vue 组件间通信主要指以下 3 类通信:父子组件通信兄弟组件通信隔代组件通信

1 、props / $emit—适用于父子组件通信

  • 父组件的数据需要通过 props 把数据传给子组件
  • 子组件向父组件传递数据就需要通过$emit()再通过里传递的事件来传递数据。子组件可以通过 $emit()触发父组件中的自定义事件。

2 、ref 与 $parent / $children—适用于父子组件通信

  • ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
  • $parent / $children:访问父 / 子实例

3 、EventBus ($emit / $on)—适用于父子、隔代、兄弟组件通信

  • 通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。

4 、$attrs/$listeners—适用于隔代组件通信

  • $attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外 ),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 inheritAttrs 选项一起使用。
  • $listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件

5 、provide / inject—适用于隔代组件通信

  • 祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。 provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。

6 、Vuex—适用于父子、隔代、兄弟组件通信

  • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  • 改变 store 中的状态的唯一途径就是显式地提交 mutation。这样使得我们可以方便地跟踪每一个状态的变化。

Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理(它采用集中式存贮管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化)。每一个 Vuex 应用的核心就是 store(仓库)。store 基本上就是一个容器,它包含着你的应用中大部分的状态 state

Vuex的五大核心属性: State、Getter、Mutations、Actions、Module

  • State : 存储数据/状态,在根实例注册store,用this.$store来访问,对应的data是响应式的,从store读取数据,若发生变化,组件对应更新。
  • Getter : store的计算属性,返回值根据依赖缓存,只有当依赖发生变化才会被重新计算
  • Mutations : 更改vuex的store中状态的唯一方法就是提交mutations同步操作)。
  • Actions : 含任意异步操作,通过提交mutations间接改变状态。
  • Module : 将store分割模块,允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。

vuex

由于传参的方法对于多层嵌套的组件会非常繁琐,并且对于兄弟组件间的状态传递也无能为力。我们经常用父子组件直接引用通过事件变更/同步状态,这样导致后期代码维护花销太大。
所以要把组件的共享状态抽取出来,以一个全局的单例模式管理,在这种模式下,不管在任意组件任意位置都能获取状态触发行为。另外通过定义隔离状态管理中的各种概念,后续的代码会更结构化易维护


Vue—SSR(服务端渲染)

Vue.js是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记”激活”为客户端上完全可交互的应用程序。即:SSR 大致的意思就是vue在客户端将标签渲染成的整个html片段的工作在服务端完成,服务端形成的html片段直接返回给客户端这个过程就叫做服务端渲染

优点 :

  • 利于SEO: 因为SPA页面的内容是通过Ajax获取,而搜索引擎爬取工具并不会等待Ajax异步完成后再抓取页面内容,所以在SPA中是抓取不到页面通过Ajax获取到的内容;而SSR是直接由服务端返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面。
  • 页面内容显示快(首屏加载更快): SPA会等待所有vue编译后的js文件都下载完成后,才开始进行页面的渲染,文件下载等需要一定的时间等,所以首屏渲染需要一定的时间;SSR直接由服务端渲染好页面直接返回显示无需等待下载js文件再去渲染等,所以SSR更快的内容显示。

缺点 :

  • 开发条件限制: 例如服务端渲染只支持beforCreatecreated两个钩子函数,这会导致一些外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行;并且与可以部署在任何静态文件服务器上的完全静态单页面应用程序SPA不同,服务端渲染应用程序,需要处于Node.js server运行环境。
  • 服务器负载:在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加大量占用 CPU 资源 (CPU-intensive - CPU 密集),因此如果你预料在高流量环境 (high traffic) 下使用,请准备相应的服务器负载,并明智地采用缓存策略

ssr


vue-router

前端路由的核心:改变试图的同时不会向服务器端发起请求。

vue-router的路由模式是 hashhistory、abstract

看源码如下:

  1. switch (mode) {
  2. case 'history':
  3. this.history = new HTML5History(this, options.base)
  4. break
  5. case 'hash':
  6. this.history = new HashHistory(this, options.base, this.fallback)
  7. break
  8. case 'abstract':
  9. this.history = new AbstractHistory(this, options.base)
  10. break
  11. default:
  12. if (process.env.NODE_ENV !== 'production') {
  13. assert(false, `invalid mode: ${ mode}`)
  14. }
  15. }

hash: 使用 URL hash值来作路由。支持所有浏览器(包括不支持 HTML5 History API 的浏览器)

history: 依赖 HTML5 History API和服务器配置。具体可以查看 HTML5 History 模式。

abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。


主要说说 hash 和 history

  • hash:

    之前前端路由的实现是基于 location.hash来实现的。其原理很简单,location.hash的值就是 URL#后面的内容。

    hash路由模式的实现主要有几个特性:

    • URLhash值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送
    • hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换
    • 可以通过 a 标签,并设置 href 属性,当用户点击这个标签后,URLhash 值会发生改变;或者使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值。
    • 可以使用 hashchange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)
  • history:

    利用了 HTML5 History Interface 中新增的 pushState()replaceState() 方法。(需要特定浏览器支持
    这两个方法应用于浏览器的历史记录栈,在当前已有的 backforwardgo 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求

    history路由模式的实现主要有几个特性:

    • pushStaterepalceState 两个 API 来操作实现 URL 的变化
    • 可以使用 popstate 事件来监听 url 的变化,从而对页面进行跳转(渲染)
    • history.pushState()history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面跳转(渲染)

可以说,hash和history模式都属于浏览器自身的特性,vue-router只是利用这两个特性(通过调用浏览器提供的接口)来实现前端路由

注:history不怕前进,不怕后退,就怕刷新(f5)。 所以要想玩好history,后端必须做到路由全覆盖处理,前端配置404页面,这样就不至于一刷新就404.


Vue—虚拟DOM

虚拟 DOM 的实现原理主要包括以下 3 部分:

  • JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象
  • diff 算法 — 比较两棵虚拟 DOM 树的差异
  • patch 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。

优点:

  • 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限。
  • 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟DOM数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率。
  • 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染weex 开发等等。

缺点:

  • 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。

Vue—key的作用

key 是为 Vuevnode唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速。

看源码

  1. function createKeyToOldIdx (children, beginIdx, endIdx) {
  2. let i, key
  3. const map = { }
  4. for (i = beginIdx; i <= endIdx; ++i) {
  5. key = children[i].key
  6. if (isDef(key)) map[key] = i
  7. }
  8. return map
  9. }

更准确:
因为带key就不是就地复用了,在sameNode函数 a.key === b.key对比中可以避免就地复用的情况。所以会更加准确。

更快速:
利用key的唯一性生成map对象来获取对应节点,比遍历方式更快。主要是为了提升diff【同级比较】的效率。自己想一下自己要实现前后列表的diff,如果对列表的每一项增加一个key,即唯一索引,那就可以很清楚的知道两个列表谁少了谁没变。而如果不加key的话,就只能一个个对比了。


Vue—性能优化

代码层面的优化

  • v-ifv-show 区分使用场景
  • computedwatch 区分使用场景
  • v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
  • 长列表性能优化
  • 事件的销毁
  • 图片资源懒加载
  • 路由懒加载
  • 第三方插件的按需引入
  • 优化无限列表性能
  • 服务端渲染 SSR or 预渲染

Webpack 层面的优化

  • Webpack 对图片进行压缩
  • 减少 ES6 转为 ES5 的冗余代码
  • 提取公共代码
  • 模板预编译
  • 提取组件的 CSS
  • 优化 SourceMap
  • 构建结果输出分析
  • Vue 项目的编译优化

基础的 Web 技术的优化

  • 开启 gzip 压缩
  • 浏览器缓存
  • CDN 的使用
  • 使用 Chrome Performance 查找性能瓶颈

发表评论

表情:
评论列表 (有 0 条评论,147人围观)

还没有评论,来说两句吧...

相关阅读

    相关 TechBits | HTTP

    前言 对于 HTTP 协议的了解,一直停留在它是一种通信协议,用于帮助客户端和服务端之间的传送多种类型的数据,并在客户端上进行展示。但是对于其中有些字段倒是没有过多理解,

    相关 java

    最近有个需求要把项目发布在weblogic12c服务器中,按照网上的教程对springboot项目进行改造后,陆续遇到了几个问题: 1.weblogic报错:afu.com