一、v-model 参数的用法
1、Vue2.x 的 .sync
在一个包含 title prop 的组件中,我们可以用以下方法表达对其赋新值的意图
普通写法:
this.$emit('update:title', newTitle)
<text-document v-bind:title="doc.title" v-on:update:title="doc.title = $event" > </text-document>
.sync 修饰符(简写):
<text-document v-bind:title.sync="doc.title"></text-document>
2、Vue3.x的 v-model:title=“xxx”
若要更改 model 名称,而不是更改组件内的 model 选项,那么可以将一个 arguments 传递给 model
<ChildComponent v-model:title="pageTitle"></ChildComponent> <!-- 是以下的简写 --> <ChildComponent :title="pageTitle" @update:title="pageTitle = $event"></ChildComponent>
示例:
index.vue 父组件
<template> <p>{{ name }} {{ age }}</p> <UserInfo v-model:name="name" v-model:age="age" > </UserInfo> </template> <script> import { reactive, toRefs } from 'vue' import UserInfo from './UserInfo.vue'; export default { name: 'VModel', components: {UserInfo}, setup() { const state = reactive({ name: '杂货铺', age: '20' }) return toRefs(state) } }; </script>
UserInfo.vue 子组件
- v-bind 绑定属性的 value
- 监听 input 框内值的更新
<template> <input :value="name" @input="$emit('update:name', $event.target.value)"> <input :value="age" @input="$emit('update:age', $event.target.value)"> </template> <script> export default { name: 'UserInfo', props: { name: String, age: String } }; </script>
二、watch 和 watchEffect 的区别
- 两者都可监听 data 属性变化
- watch 需要明确监听哪个属性
- watchEffect 会根据其中的属性,自动监听其变化
1、watch 监听(vue2.x)
(1)示例:watch 监听 值 的变化
- 第一个参数是要监听的属性
- 第二个参数是新旧值
- 第三个参数是初始化之前就监听(可选参数)
<template> <p>watch vs watchEffect</p> <p>{{ numberRef }}</p> </template> <script> import { ref, toRefs, watch} from 'vue' export default { name: 'Watch', setup() { // 定义值类型 const numberRef = ref(100) // watch 监听 watch(numberRef, (newNumber, oldNumber) => { console.log('ref watch', newNumber, oldNumber); }) // 定时器,修改 numberRef 的值,用于监听 setTimeout(() => { numberRef.value = 200 }, 1000) return { numberRef, } } }; </script>
watch 监听可选的第三个参数
immediate: true // 初始化之前就监听,可选
(2)示例:watch 监听 对象 的变化
<template> <p>watch vs watchEffect</p> <p>{{ name }} {{ age }}</p> </template> <script> import { reactive, toRefs, watch} from 'vue' export default { name: 'Watch', setup() { const state = reactive({ name: '杂货铺', age: 21 }) watch( // 第一个参数,确定要监听哪个属性 () => state.age, // 第二个参数,回调函数 (newAge, oldAge) => { console.log('state watch', newAge, oldAge); }, // 第三个参数,配置项,可选 { immediate: true, // 初始换之前就监听,可选 deep: true // 深度监听 } ) setTimeout(() => { state.age = 25 }, 3000) setTimeout(() => { state.name = '前端杂货铺' }, 5000) return { ...toRefs(state) } } }; </script>
2、watchEffect 监听(Vue3.x)
示例:watchEffect 监听对象变化
<template> <p>watch vs watchEffect</p> <p>{{ name }} {{ age }}</p> </template> <script> import { reactive, toRefs, watchEffect} from 'vue' export default { name: 'Watch', setup() { const state = reactive({ name: '杂货铺', age: 21 }) // 初始化时,一定会执行一次(收集要监听的数据) watchEffect(() => { console.log('hello watchEffect'); }) // 监听 state.name watchEffect(() => { console.log('state.name', state.name); }) // 监听 state.age watchEffect(() => { console.log('state.age', state.age); }) setTimeout(() => { state.age = 25 }, 1500) setTimeout(() => { state.name = '前端杂货铺' }, 3000) return { ...toRefs(state) } } }; </script>
3、watch 和 watchEffect 的区别
- 两者都可监听 data 属性变化
- watch 需要明确监听哪个属性
- watchEffect 会根据其中的属性,自动监听其变化
三、在 setup 中如何获取组件实例
- 在 setup 和其他 Composition API 中没有 this
- 可通过 getCurrentInstance 获取当前实例
- 若使用 Options API 可照常使用 this
示例:使用 getCurrentInstance 获取当前实例
<template> <p>setup中获取组件实例</p> </template> <script> import { getCurrentInstance, onMounted } from 'vue'; export default { name: 'GetInstance', data() { return { x: 1 } }, setup() { // Composition API 没有 this => undefined console.log('this1', this); // 获取当前实例 const instance = getCurrentInstance() console.log('instance', instance); // 挂载完成 => 通过 instance.data.x 获取 x 的值 onMounted(() => { // 挂载完也没有 this => undefined console.log('this in onMounted', this); console.log('x', instance.data.x); }) }, // vue2.x 中有 this,能直接取到值 mounted() { console.log('this2', this); console.log('x', this.x); } }; </script>
四、Vue3 为何比 Vue2 快
- Proxy 响应式
- PatchFlag
- hoistStatic
- cacheHandler
- SRR 优化
- tree-shaking
1、PatchFlag
- 编译模板时,动态节点做标记
- 标记,分为不同的类型,如 TEXT PROPS
- diff 算法时,可以区分静态节点,以及不同类型的动态节点
测试地址:PatchFlag测试
Vue2.x 与 Vue3.x diff 算法的部分区别:
出处:https://coding.imooc.com/lesson/419.html#mid=41996
2、hoistStatic
- 将静态节点的定义,提升到父作用域,缓存起来
- 多个相邻的静态节点,会被合并起来
- 典型的拿空间换时间的优化策略
Options 打开 hoistStatic:
3、cacheHandler
- 缓存事件
4、SSR 优化
- 静态节点直接输出,绕过了 vdom
- 动态节点,还是需要动态渲染
5、tree shaking
- 编译时,根据不同的情况,引入不同的 API
需要什么就引入什么:
五、Vite 为何启动快?
- 开发环境使用 ES6 Module,无需打包 —— 非常快
- 生产环境使用 rollup,并不会快很多
示例:ES Module 在浏览器中的使用
print.js 文件
export default function (a, b) { console.log(a, b) }
add.js 文件
import print from './print.js' export default function add(a, b) { print('print', 'add') return a + b }
test.html
- script 标签中要使用 type="module"
- 导入所需文件
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ES Module demo</title> </head> <body> <p>基本演示</p> <script type="module"> import add from './src/add.js' const res = add(1, 2) console.log('add res', res) </script> </body> </html>
六、Composition API 和 React Hooks 对比
- 前者 setup 只会被调用一次,而后者函数会被多次调用
- 前者无需 useMemo useCallback,因为 setup 只调用一次
- 前者无需顾虑调用顺序,而后者需要保证 hooks 的顺序一致
不积跬步无以至千里 不积小流无以成江海
点个专注不迷路,持续更新中…