Vue3 复习

60 阅读2分钟

ref 与 reactive

  1. 参数:ref 可以传基础类型和对象,传对象时底层调用的还是 reactive,reactive 只能传对象
  2. 访问:script 里访问数据时,ref 需要 .value,但 reactive 不用;template 时,ref 是直接定义的变量会解包,是对象属性则不会
  3. watch 监听:ref 传入对象的时候,默认不会开启深度监听,但 reactive 会
  4. 响应性:ref 重新分配一个对象或解构时不会失去响应性,reactive 会

watch 与 watchEffect

  1. 追踪项:watch 需要显示指定,watchEffect 自动追踪
  2. 清理:watch 需要去 beforeUnmounted 清理,watchEffect 可以返回清理函数
  3. 初始:watch 需要指定 immediate: true 才会初始时立即执行,watchEffect 不用
  4. 旧值:watch 有直接的旧值访问,watchEffect 没有

watch 与 computed

  1. 副作用:watch 可以执行副作用,但 computed 主要用于计算,不应该产生副作用
  2. 缓存:computed 会缓存结果,只有依赖项变化了才会重新计算
  3. 旧值:watch 在回调的第二个参数获取旧值,computed 在 getter 的第一个参数来获取计算属性返回的上一个值

v-if 与 v-for

v-if 优先级大于 v-for,所以 v-if 无法访问 v-for 作用域内的变量

v-if 与 v-show

v-if 底层是 dom 操作,初始为 false 则不会插入,所以适合变化不多的情况。v-show 是 display: none,dom 总是会被插入,可见性频繁变化时更优

v-model

v-bind + emit

  • 一个名为 modelValue 的 prop,本地 ref 的值与其同步
  • 一个名为 update:modelValue 的事件,当本地 ref 的值发生变更时触发
<input :value="props.modelValue" @input="emit('update:modelValue', $event.target.value)" />

Vue3 与 Vue2 的区别

  1. 响应式原理:vue2 采用 Object.defineProxy,只能监听特定属性的 getter 和 setter,导致对象新增属性时没有响应性。vue3 采用 proxy 代理,这就有了 reactive,但 proxy 只能代理对象,所以弄了一个 RefImpl 类,通过 set 和 get 标记 value 函数,导致每次都要 .value 去调这个函数
  2. fragment:vue3 的 template 可以有多个根元素,但 vue2 不行
  3. API风格:vue3 采用组合式 API,代码逻辑集中,vue2 选项式 API,同一逻辑的代码分散了
  4. 增加了 teleport 组件来转移 dom
  5. 生命周期的命名改变:
    • beforeCreate/created -> setup()

    • beforeMount -> onBeforeMount

    • mounted -> onMounted

    • beforeUpdate -> onBeforeUpdate

    • updated -> onUpdated

    • beforeDestroy -> onBeforeUnmount

    • destroyed -> onUnmounted

    • 异常捕获:errorCaptured -> onErrorCaptured

    • 新增被激活:onActivated

    • 新增不激活:onDeactivated

  6. setup() 语法糖:script 顶上写 setup,可以直接在模板里使用函数、变量、import 导入内容
  7. v-if 与 v-for:vue2 v-for优先,vue3 v-if优先,v-if 的条件将无法访问到 v-for 作用域内定义的变量别名
  8. diff 算法不同:vue2 采用双端算法 + 哈希,会比较每一个节点,不论是否动态;vue3 采用双端算法 + 最长递增子序列,有 patchFlag,只比较会发生变化的节点
  9. vue3 有更好的 TS 支持

响应式原理

diff 算法

插槽

父组件想要在子组件中插入内容时,可以使用插槽;子组件想传数据给父组件,可以使用作用域插槽;可以使用中括号来使用动态插槽名

默认插槽: 如果父组件没有提供内容,会显示 <slot> 的默认内容 "默认内容"<slot> 标签本身不会渲染成 DOM 元素,只渲染插入内容;一个子组件只能有一个默认插槽

具名插槽: template #name,将内容插入 name属性对应的插槽中

作用域插槽: 子组件可以把数据传递给父组件,父组件通过 作用域插槽 使用。作用域插槽也有名字;插槽传 props,外部使用 v-slot(简写#) 获取暴露出的 props 内容

组件通信方式

  1. props、emits:父子
  2. 插槽
  3. provide、inject:祖先后代
  4. 事件总线 EventBus
  5. 透传 $attrs
  6. 父组件 ref,子组件可以 defineExpose
  7. pinia
  8. v-model:props 与 emits 的语法糖