3.0 特性

... 2022-11-17 About 4 min

# 3.0 特性

# 生命周期

// 3.0中 只有卸载的生命周期的改变了名称,其他的没有变。
beforeDestroy ---> beforeUnmount
destroyed ---> unmounted


// 在 setup 函数中导入生命周期函数需一致加 on 前缀。
// setup 导入生命函数实例

setup -> beforeCreate 
      -> beforeCreated

beforeMount ---> onBeforeMount 
mounted ---> onMounted

beforeUpdate ---> onBeforeUpdate
updated ---> onUpdated

beforeUnMount ---> onBeforeUnmount
unmounted ---> onUnmounted

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# v-model

// 2.x
<input v-model="msg" placeholder="请输入内容" />
// 底层实现。
<input :value={value} @input="value = $event.target.value" placeholder="请输入内容">

<script>
// 在 2.0 中 可以通过 model 配置项来改变 value 绑定的值, 默认值是 value
export default {
    model: {
        value: 'value',
        event: 'input'
    },
    props: {
        value: String
    }
}
</script>

// 3.x
<input v-model:text="value" placeholder="请输入内容" />
// 底层实现。
<input :value={value} @update:text="value = $event.target.value" placeholder="请输入内容" />

<script>
// 在 3.0 值移除了 model 配置项,如需更改在 v-model 后面传递要修改的 prop 名。
export default {
    props: {
        text: String
    }
}
</script>

// 注意点:在 3.x 中 .sync 移除了。合并到 v-model冒号绑定的值一起了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

参考链接 (opens new window)

# ref

3.x 中创建值类型数据为响应式。


<template>
    <div>{{ count }}</div>
</template>

<script lang="ts">
import { ref } from 'vue'
export default {
    setup() {
        // 通过 ref 创建的数据,返回的格式是 { value: 0 }。
        // 在 setup 中使用中需通过 .value 形式使用。模板中使用 count 不用 .value 形式,vue 会帮我们 .value。
        const count = ref(0) 
        // 修改了 count 的值,页面使用到时,自动改变 count。
        count.value = 333 

        return {
            count
        }
    }
}
</script>

// 注意点:
// ref 也可以接受对象或者数组参数,返回格式就是 { value: 对象或数组 }。
// ref 创建的数据本质上还是通过 reactive 函数包裹然后再 value 中接受传过来的参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# toRef

3.x 中将响应式对象中的某个属性转换成 ref 的形式,两者之间修改值都会改变,并触发响应式

<template>
  <div>{{ nameRef }}</div>
</template>

<script lang="ts">
import { reactive, toRef } from 'vue'
  export default {
      setup() {
          const state = reactive({
              name: 123 
          })

          const nameRef = toRef(state, 'name')

          setTimeout(() => {
              state.name = 222 // nameRef会改变
              nameRef.value = 333 // state.name 会改变
          }, 1500)

          return {
              nameRef
          }
      }
  }
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# toRefs

3.x 中将响应式对象的全部属性转换成 ref 形式,两者之间修改值都会改变,并触发响应式

<template>
 <div>{{ ageRef }}</div>
</template>

<script lang="ts">
 import { reactive, toRefs } from 'vue'
  export default {
      setup() {
        const state = reactive({
            age: 20
        })

        const stateRef = toRefs(state)

        setTimeout(() => {
            state.age = 30 // stateRef.age会改变
            stateRef.age = 50 // state.age 会改变
        }, 1500)

        return stateRef
      }
  }
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# reactive

3.x 中创建引用类型数据的响应式

<template>
 <div class="list">
    <div v-for="(item, index) in countData" :key="index">{{ item }}</div>
 </div>
</template>

<script lang="ts">
import { reactive } from 'vue'
export default {
    setup() {
      // 通过 reactive 创建的数据,返回的格式就是传过来的格式。
      // 在使用中不需要 .value 形式。 
      const countData = reactive({
          list: []
      })

      countData.list = [{a: 1, b: 2, c: 3}]

      return {
          countData
      }
    }
}
</scrip>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# watch

监听某个数据的变化,初始化时不会触发,并且要指定监听的数据。

<template>
  <span>{{ numRef }}</span>
</template>

<script lang="ts">
import { watch, ref, reactive } from 'vue'
   export default {
       setup() {
          // 监听多个数据 watch 第一个参数传数组 [newRef, numRef]
          // 监听 ref 数据
          const numRef = ref(0)
          watch(
              numRef, 
              (newVal, oldVal) => {
                 console.log(newVal)
              }, 
              { 
                  deep: true
              }
          )

          setTimeout(() => numRef.value = 5, 1500)


          // 监听 reactive 数据
          const state = reactive({
              num: 0,
              age: 10
          })
          watch(
              () => state.num,
              (newVal, oldVal) => {
                  console.log(newVal)
              },
              {
                  deep: true
              }
          )

          setTimeout(() => state.num = 5, 1500)
       }
   }
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# watchEffect

对传入的回调函数里面的数据进行监听,并会在初始化时触发,进行收集依赖。


<template>
  <span>{{ numRef }}}</span>
</template>

<script>
import { watchEffect, ref, reactive } from 'vue'
 export default {
     setup() {
       const numRef = ref(0)
       const state = reactive({
           age: 0,
           num: 10
       })
       // 初始化时会触发回调函数
       watchEffect(() => {
           if (numRef.value === 3) {
               console.log('watchEffect执行了', numRef.value)
           }
       })

       setTimeout(() => numRef.value = 3, 1500)
     }
 }
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 响应式

在 2.x 中 Vue 实现响应式是通过 Object.defineProtry 函数来劫持 data 中数据的获取和改变,并在其中订阅依赖和发布依赖来触发页面上数据的改变。他的缺点是不能监听新增和删除的操作,只有通过 Vue.set 和 Vue.delete 函数来触发响应式。

在 3.x 中 Vue,通过 new Proxy 函数来劫持。这个函数可以监听到新增和删除的操作。并且他还有更多的方法如:get, set, deleteProto 等来监听数据。但他本身是 ES6 才出现的,所以在 IE 浏览器不是兼容的。

# Vue3 比 Vue2 快在那些方面(体积小)

  1. PatchFlag 在编译时对节点进行标记,区分静态文本节点和动态节点。在 diff 算法比对中,如果是静态文本节点就不对对比,直接对比动态节点。
  2. hoistStatic 将静态节点的定义,提升到父级作用域,进行缓存。多个相邻的静态节点,会被合并起来。
  3. cacheHandler 将节点的事件进行缓存,下次如果有事件,直接取缓存的事件。
  4. SSR优化 针对静态节点直接编译成字符串形式,不走 Vdom 流程。
  5. tree-shaking 针对模板中使用的指令,或其他东西,引入对应的 API, 从而减少体积。
Last update: November 17, 2022 07:05
Contributors: Skr