2024-08-16
技术小刊
00

目录

计算属性和方法的区别,相同结果对于性能的差别
可写计算属性
侦听器 watch
即时回调的侦听器
一次性侦听器<3.4+>
watch vs. watchEffect
provide和inject 和响应式数据配合使用
如果你想确保提供的数据不能被注入方的组件更改,你可以使用 readonly() 来包装提供的值。
如果你正在构建大型的应用,请使用 Symbol 作注入名
异步组件 defineAsyncComponent
插件
KeepAlive
Teleport
Suspense - 实验性功能

SFC 英文 Single-File Component

  • 使用熟悉的 HTML、CSS 和 JavaScript 语法编写模块化的组件
  • 让本来就强相关的关注点自然内聚
  • 预编译模板,避免运行时的编译开销
  • 组件作用域的 CSS
  • 在使用组合式 API 时语法更简单
  • 通过交叉分析模板和逻辑代码能进行更多编译时优化
  • 更好的 IDE 支持,提供自动补全和对模板中表达式的类型检查
  • 开箱即用的模块热更新 (HMR) 支持

计算属性和方法的区别,相同结果对于性能的差别

  • 当包含响应式依赖对象的时候
  1. 若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的
  2. 不同之处在于计算属性值会基于其响应式依赖被缓存。
  3. 一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 <响应式依赖对象> 不改变,无论多少次访问 计算属性对象 都会立即返回先前的计算结果,而不用重复执行 getter 函数。
  4. 相比之下,方法调用总是会在重渲染发生时再次执行函数。

为什么需要缓存呢?想象一下我们有一个非常耗性能的计算属性 list,需要循环一个巨大的数组并做许多计算逻辑,并且可能也有其他计算属性依赖于 list。没有缓存的话,我们会重复执行非常多次 list 的 getter,然而这实际上没有必要!如果你确定不需要缓存,那么也可以使用方法调用。

可写计算属性

  • 计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 getter 和 setter 来创建:
js
<script setup> import { ref, computed } from 'vue' const firstName = ref('John') const lastName = ref('Doe') const fullName = computed({ // getter get() { return firstName.value + ' ' + lastName.value }, // setter set(newValue) { // 注意:我们这里使用的是解构赋值语法 [firstName.value, lastName.value] = newValue.split(' ') } }) </script>

侦听器 watch

即时回调的侦听器

  • watch 默认是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。举例来说,我们想请求一些初始数据,然后在相关状态更改时重新请求数据。
  • 我们可以通过传入 immediate: true 选项来强制侦听器的回调立即执行:
js
watch( source, (newValue, oldValue) => { // 立即执行,且当 `source` 改变时再次执行 }, { immediate: true } )

一次性侦听器<3.4+>

  • 每当被侦听源发生变化时,侦听器的回调就会执行。如果希望回调只在源变化时触发一次,请使用 once: true 选项。
js
watch( source, (newValue, oldValue) => { // 当 `source` 变化时,仅触发一次 }, { once: true } )

watch vs. watchEffect

  • watch 和 watchEffect 都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式:
  1. watch 只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。watch 会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。

  2. watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确。

provide和inject 和响应式数据配合使用

js
<!-- 在供给方组件内 --> <script setup> import { provide, ref } from 'vue' const location = ref('North Pole') function updateLocation() { location.value = 'South Pole' } provide('location', { location, updateLocation }) </script>
js
<!-- 在注入方组件 --> <script setup> import { inject } from 'vue' const { location, updateLocation } = inject('location') </script> <template> <button @click="updateLocation">{{ location }}</button> </template>

如果你想确保提供的数据不能被注入方的组件更改,你可以使用 readonly() 来包装提供的值。

js
<script setup> import { ref, provide, readonly } from 'vue' const count = ref(0) provide('read-only-count', readonly(count)) </script>

如果你正在构建大型的应用,请使用 Symbol 作注入名

但如果你正在构建大型的应用,包含非常多的依赖提供,或者你正在编写提供给其他开发者使用的组件库,建议最好使用 Symbol 来作为注入名以避免潜在的冲突。

  • 我们通常推荐在一个单独的文件中导出这些注入名 Symbol:
js
// keys.js export const myInjectionKey = Symbol()
js
// 在供给方组件中 import { provide } from 'vue' import { myInjectionKey } from './keys.js' provide(myInjectionKey, { /* 要提供的数据 */ });

异步组件 defineAsyncComponent

  • 在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。Vue 提供了 defineAsyncComponent 方法来实现此功能:
js
import { defineAsyncComponent } from 'vue' const AsyncComp = defineAsyncComponent(() => { return new Promise((resolve, reject) => { // ...从服务器获取组件 resolve(/* 获取到的组件 */) }) }) // ... 像使用其他一般组件一样使用 `AsyncComp`
  • ES 模块动态导入也会返回一个 Promise,所以多数情况下我们会将它和 defineAsyncComponent 搭配使用。
js
import { defineAsyncComponent } from 'vue' const AsyncComp = defineAsyncComponent(() => import('./components/MyComponent.vue') )

最后得到的 AsyncComp 是一个外层包装过的组件,仅在页面需要它渲染时才会调用加载内部实际组件的函数。它会将接收到的 props 和插槽传给内部组件,所以你可以使用这个异步的包装组件无缝地替换原始组件,同时实现延迟加载。

js
<script setup> import { defineAsyncComponent } from 'vue' const AdminPage = defineAsyncComponent(() => import('./components/AdminPageComponent.vue') ) </script> <template> <AdminPage /> </template>
  • 异步操作不可避免地会涉及到加载和错误状态,因此 defineAsyncComponent() 也支持在高级选项中处理这些状态:
js
const AsyncComp = defineAsyncComponent({ // 加载函数 loader: () => import('./Foo.vue'), // 加载异步组件时使用的组件 loadingComponent: LoadingComponent, // 展示加载组件前的延迟时间,默认为 200ms delay: 200, // 加载失败后展示的组件 errorComponent: ErrorComponent, // 如果提供了一个 timeout 时间限制,并超时了 // 也会显示这里配置的报错组件,默认值是:Infinity timeout: 3000 })

插件

插件 (Plugins) 是一种能为 Vue 添加全局功能的工具代码。

  • 一个插件可以是一个拥有 install() 方法的对象,也可以直接是一个安装函数本身。安装函数会接收到安装它的应用实例和传递给 app.use() 的额外选项作为参数:

  • 插件没有严格定义的使用范围,但是插件发挥作用的常见场景主要包括以下几种:

  1. 通过 app.component() 和 app.directive() 注册一到多个全局组件或自定义指令。

  2. 通过 app.provide() 使一个资源可被注入进整个应用。

  3. 向 app.config.globalProperties 中添加一些全局实例属性或方法

  4. 一个可能上述三种都包含了的功能库 (例如 vue-router)。

KeepAlive

它的功能是在多个组件间动态切换时缓存被移除的组件实例。

  1. KeepAlive 默认会缓存内部的所有组件实例,但我们可以通过 include 和 exclude prop 来定制该行为
  2. 我们可以通过传入 max prop 来限制可被缓存的最大组件实例数。KeepAlive 的行为在指定了 max 后类似一个 LRU 缓存:如果缓存的实例数量即将超过指定的那个最大数量,则最久没有被访问的缓存实例将被销毁,以便为新的实例腾出空间。

Teleport

它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。

Suspense - 实验性功能

用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:seek

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!