文章

【若依】18、Vue3和Vue2的差异

Vue3 中可以原封不动的使用 Vue2 中的方法(Options API)。 但是 Vue3 中提供了一些语法糖。

变量定义

例如 Vue2 中,我们定义变量,可以按照如下方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
  <div>
    <h1>Hello Vue3</h1>
    <div></div>
  </div>
</template>

<script>
export default {
  name: "Test01",
  data() {
    return {
      msg: "hello yueyazhui"
    }
  }
}
</script>

<style lang='scss' scoped>

</style>

以上代码,在 Vue3 中,可以按照如下方式来写:

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
<template>
  <div>
    <h1>Hello Vue3</h1>
    <div></div>
    <input type="text" v-model="msg">
  </div>
</template>

<script>
import {ref} from 'vue'

export default {
  name: "Test02",
  /**
   * Vue2 中定义的各种变量、方法、生命周期钩子函数等等,现在统一都在 setup 中进行定义
   * 
   * 所有定义的变量、方法等,都需要返回之后才可以使用
   */
  setup() {
    // 直接这样写,这个变量不是响应式数据
    // let msg = "hello yueyazhui"
    let msg = ref("hello yueyazhui")
    return {msg}
  }
}
</script>

<style lang='scss' scoped>

</style>

两个要点:

  1. 变量定义,需要用到 ref 函数,该函数,直接从 vue 中导入,否则直接定义的变量不具备响应式的特性。
  2. 所有定义的变量、方法等,都需要 return,不 return,用不了。

    方法定义

    在 Vue2 中,我们一般是将方法定义在 methods 节点中,但是在 Vue3 中,我们将方法定义在 setup 方法中,尤其要注意,方法定义完成之后,必须要返回方法名,否则方法用不了。 ```vue

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
如上,像定义一个变量一样去定义方法,方法定义完成之后,一定要返回。
### 钩子函数
在 Vue2 中,定义钩子函数,直接定义对应的方法名即可:
```vue
<template>
  <div>
    <h1>Hello Vue3</h1>
    <div></div>
  </div>
</template>

<script>
export default {
  name: "Test01",
  data() {
    return {
      msg: "hello yueyazhui"
    }
  },
  mounted() {
    console.log('---Vue2 mounted()---')
  }
}
</script>

<style lang='scss' scoped>

</style>

但是,在 Vue3 中,由于所有的东西都是在 setup 中定义的,包括钩子函数。 Vue3 中定义钩子函数:

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
<template>
  <div>
    <h1>Hello Vue3</h1>
    <div></div>
    <input type="text" v-model="msg">
    <div><button @click="handleLogin('yue', '123')">登录</button></div>
  </div>
</template>

<script>
import {ref, onMounted} from 'vue'

export default {
  name: "Test02",
  /**
   * Vue2 中定义的各种变量、方法、生命周期钩子函数等等,现在统一都在 setup 中进行定义
   * 
   * 所有定义的变量、方法等,都需要返回之后才可以使用
   */
  setup() {
    // 直接这样写,这个变量不是响应式数据
    // let msg = "hello yueyazhui"
    let msg = ref("hello yueyazhui")
    const handleLogin = (username, password) => {
      console.log('username', username)
      console.log('password', password)
    }
    // 调用钩子函数,并传入回调函数
    // 注意:钩子函数不需要返回
    onMounted(() => {
      console.log('---Vue3 onMounted()---')
    })
    return {msg, handleLogin}
  }
}
</script>

<style lang='scss' scoped>

</style>
  • 首先从 vue 中导入钩子函数。
  • 在 setup 方法中去定义钩子函数的逻辑。
  • 在 return 中,不需要返回钩子函数。

钩子函数对照:

Vue2 Vue3
beforeCreate onBeforeCreate
created onCreated
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated OnUpdated
beforeUnmount OnBeforeUnmount
unmounted OnUnmounted
activated OnActivated
deactivated OnDeactivated
errorCapture OnErrorCapture
renderTracked OnRenderTracked
renderTriggered OnRenderTriggered

computed 属性

计算属性和钩子函数比较类似,计算属性使用步骤:

  1. 从 vue 中导入计算属性函数。
  2. 定义计算属性。
  3. 在 return 中返回计算属性值。 ```vue
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
45
46
47
48
49
50
51
计算属性更新的例子:
```vue
<template>
  <div>
    <h1>Hello Vue3</h1>
    <div></div>
    <input type="text" v-model="msg">
    <div><button @click="handleLogin('yue', '123')">登录</button></div>
    <div></div>
  </div>
</template>

<script>
import {ref, onMounted, computed} from 'vue'

export default {
  name: "Test02",
  /**
   * Vue2 中定义的各种变量、方法、生命周期钩子函数等等,现在统一都在 setup 中进行定义
   * 
   * 所有定义的变量、方法等,都需要返回之后才可以使用
   */
  setup() {
    // 直接这样写,这个变量不是响应式数据
    // let msg = "hello yueyazhui"
    let msg = ref("hello yueyazhui")
    let num = ref(99)
    const handleLogin = (username, password) => {
      console.log('username', username)
      console.log('password', password)
      num.value++
    }
    // 调用钩子函数,并传入回调函数
    // 注意:钩子函数不需要返回
    onMounted(() => {
      console.log('---Vue3 onMounted()---')
    })
    // 通过计算属性去定义一个变量
    // 注意:计算属性需要返回
    const currentTime = computed(() => {
      num.value
      return Date.now()
    })
    return {msg, handleLogin, currentTime, num}
  }
}
</script>

<style lang='scss' scoped>

</style>

由于生成计算属性 currentTime 依赖 num 变量,所以当 num 变量发生变化的时候,计算属性会自动更新,否则计算属性将一直使用缓存中的数据(num 没有发生变化的情况)。 另外还有一点,就是定义的变量入 num、msg 等 ,在 HTML 节点中,直接使用 num、msg,但是如果是在方法中操作这些变量,则一定要使用 num.value 或者 msg.value 去操作这些变量。

watch 函数

Vue3 中,watch 函数的写法:

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
45
46
47
48
49
50
51
52
53
<template>
  <div>
    <h1>Hello Vue3</h1>
    <div></div>
    <input type="text" v-model="msg">
    <div><button @click="handleLogin('yue', '123')">登录</button></div>
    <div></div>
  </div>
</template>

<script>
import {ref, onMounted, computed, watch} from 'vue'

export default {
  name: "Test02",
  /**
   * Vue2 中定义的各种变量、方法、生命周期钩子函数等等,现在统一都在 setup 中进行定义
   * 
   * 所有定义的变量、方法等,都需要返回之后才可以使用
   */
  setup() {
    // 直接这样写,这个变量不是响应式数据
    // let msg = "hello yueyazhui"
    let msg = ref("hello yueyazhui")
    let num = ref(99)
    const handleLogin = (username, password) => {
      console.log('username', username)
      console.log('password', password)
      num.value++
    }
    // 调用钩子函数,并传入回调函数
    // 注意:钩子函数不需要返回
    onMounted(() => {
      console.log('---Vue3 onMounted()---')
    })
    // 通过计算属性去定义一个变量
    // 注意:计算属性需要返回
    const currentTime = computed(() => {
      num.value
      return Date.now()
    })
    watch(num, (newValue, oldValue) => {
      console.log('newValue', newValue)
      console.log('oldValue', oldValue)
    })
    return {msg, handleLogin, currentTime, num}
  }
}
</script>

<style lang='scss' scoped>

</style>
  1. 先从 vue 中导入 watch 函数。
  2. 在 setup 中去监控变量,第一个参数是要监控的变量,第二个参数则是一个回调函数,回调函数的参数就是所监控变量值的变化。

    ref 和 reactive

    ```vue

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
一般来说,我们通过 ref 来定义一个变量,一般都是原始数据类型,例如 String、Number、BigInt、Boolean 等,通过 reactive 来定义一个对象。
如上面的案例所示,定义了 book 对象之后,接下来的访问中,通过 book.xxx 就可以访问到 book 中的属性值了。
但是,假设我们在定义的时候,定义的是 book 对象,但是我们访问的时候,却希望能够直接按照属性来访问,此时可以直接展开变量,但是,如果直接通过三个点去展开变量,会导致变量的响应式特点失效,此时,我们可以通过 toRefs 函数,让变量恢复响应式的特点:
```vue
<template>
  <div>
    <h1>Hello Vue3</h1>
    <div></div>
    <!-- <div></div>
    <div></div> -->
    <div></div>
    <div></div>
    <div><button @click="updateBookInfo">更改图书信息</button></div>
  </div>
</template>

<script>
import {ref, reactive, toRefs} from 'vue'

export default {
  name: "Test03",
  setup() {
    let num = ref(99)
    let book = reactive({
      name: '燕倾天下',
      author: '天下归元'
    })
    const updateBookInfo = () => {
      book.name = '扶摇'
    }
    return {num, ...toRefs(book), updateBookInfo}
  }
}
</script>

<style lang='scss' scoped>

</style>

总结:

  1. ref 定义原始数据类型;reactive 定义对象。
  2. 如果用到了对象展开,那么需要用到 toRefs 函数将对象中的属性变为响应式。
  3. 在 vue3 中,定义的变量、函数等等,在使用的时候,都不需要 this。

    setup

  4. 写的时候,容易忘记返回变量或者方法等等。
  5. 写法有点臃肿。 ```vue

``` 现在,就直接在 script 节点中,增加 setup 属性,然后 script 节点中定义的变量名、方法名等等,默认就会自动返回,我们只需要定义即可。

本文由作者按照 CC BY 4.0 进行授权