ref 与 reactive
- 参数:ref 可以传基础类型和对象,传对象时底层调用的还是 reactive,reactive 只能传对象
- 访问:script 里访问数据时,ref 需要 .value,但 reactive 不用;template 时,ref 是直接定义的变量会解包,是对象属性则不会
- watch 监听:ref 传入对象的时候,默认不会开启深度监听,但 reactive 会
- 响应性:ref 重新分配一个对象或解构时不会失去响应性,reactive 会
watch 与 watchEffect
- 追踪项:watch 需要显示指定,watchEffect 自动追踪
- 清理:watch 需要去 beforeUnmounted 清理,watchEffect 可以返回清理函数
- 初始:watch 需要指定 immediate: true 才会初始时立即执行,watchEffect 不用
- 旧值:watch 有直接的旧值访问,watchEffect 没有
watch 与 computed
- 副作用:watch 可以执行副作用,但 computed 主要用于计算,不应该产生副作用
- 缓存:computed 会缓存结果,只有依赖项变化了才会重新计算
- 旧值: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 的区别
- 响应式原理:vue2 采用 Object.defineProxy,只能监听特定属性的 getter 和 setter,导致对象新增属性时没有响应性。vue3 采用 proxy 代理,这就有了 reactive,但 proxy 只能代理对象,所以弄了一个 RefImpl 类,通过 set 和 get 标记 value 函数,导致每次都要 .value 去调这个函数
- fragment:vue3 的 template 可以有多个根元素,但 vue2 不行
- API风格:vue3 采用组合式 API,代码逻辑集中,vue2 选项式 API,同一逻辑的代码分散了
- 增加了 teleport 组件来转移 dom
- 生命周期的命名改变:
-
beforeCreate/created -> setup()
-
beforeMount -> onBeforeMount
-
mounted -> onMounted
-
beforeUpdate -> onBeforeUpdate
-
updated -> onUpdated
-
beforeDestroy -> onBeforeUnmount
-
destroyed -> onUnmounted
-
异常捕获:errorCaptured -> onErrorCaptured
-
新增被激活:onActivated
-
新增不激活:onDeactivated
-
- setup() 语法糖:script 顶上写 setup,可以直接在模板里使用函数、变量、import 导入内容
- v-if 与 v-for:vue2 v-for优先,vue3 v-if优先,
v-if的条件将无法访问到v-for作用域内定义的变量别名 - diff 算法不同:vue2 采用双端算法 + 哈希,会比较每一个节点,不论是否动态;vue3 采用双端算法 + 最长递增子序列,有 patchFlag,只比较会发生变化的节点
- vue3 有更好的 TS 支持
响应式原理
diff 算法
插槽
父组件想要在子组件中插入内容时,可以使用插槽;子组件想传数据给父组件,可以使用作用域插槽;可以使用中括号来使用动态插槽名
默认插槽:
如果父组件没有提供内容,会显示 <slot> 的默认内容 "默认内容",<slot> 标签本身不会渲染成 DOM 元素,只渲染插入内容;一个子组件只能有一个默认插槽
具名插槽: template #name,将内容插入 name属性对应的插槽中
作用域插槽: 子组件可以把数据传递给父组件,父组件通过 作用域插槽 使用。作用域插槽也有名字;插槽传 props,外部使用 v-slot(简写#) 获取暴露出的 props 内容
组件通信方式
- props、emits:父子
- 插槽
- provide、inject:祖先后代
- 事件总线 EventBus
- 透传 $attrs
- 父组件 ref,子组件可以 defineExpose
- pinia
- v-model:props 与 emits 的语法糖