Vue3学后总结

90 阅读6分钟

Vue3学后总结

1. setup

1.1 为什么使用setup

在vue2中我们需要在script中写方法(method)、数据(data)等等,这样会给我们的项目维护带来很大的不便,这时vue3中的setup就给我们带来了很大的便利。

1.2 使用

根据官方文档:

setup() 钩子是在组件中使用组合式 API 的入口,通常只在以下情况下使用:

  1. 需要在非单文件组件中使用组合式 API 时。
  2. 需要在基于选项式 API 的组件中集成基于组合式 API 的代码时。

其余情况我们都要用这种语法:

<script setup></script>

使用setup的语法糖时不需要加export default{},来主动暴露,也不需要再调用setup()函数再在里面写代码,更不需要return{}作为返回值暴露给模板。我们可以用代码来直观感受一下。

<script>
import { ref } from 'vue'export default {
  setup() {
    const count = ref(0)
​
    return {
      count
    }
  }
}
</script>
<script setup>import {ref} from 'vue'const count = ref(0)
​
</script>

可以很直观的看出使用setup会让我们的代码看上去更加简洁明了,更能体现出vue3更加轻量级的特点。

2. ref函数

2.1定义

接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性 .value。

通俗来说就是ref函数返回一个包含get和set方法的对象,而且是一个可响应的对象。

2.2 如何使用ref

2.2.1 基本用法

首先我们要定义一个量,并且用ref响应式来接收

const count = ref(0)
console.log(count.value) // 0
​
count.value++
console.log(count.value) // 1

2.2.2 如何操作ref中的值

使用ref函数返回的对象其实是一个RefImpl对象并不是一个value,我们还是通过代码来分析一下。

let name = ref("zs")
console.log(name)

当我们直接打印name时在浏览器控制台中返回的是一个

并非是一个'zs'也就是我们上面所说的RefImpl对象,里面有个属性value,value里的值才是’zs‘,所以如果我们想要直接获取这个值,我们必须这样写:

let name = ref("zs")
console.log(name.value)

image-20221105112408005.png 这时控制台打印的只有zs这两个字母啦。

3. reactive函数

3.1 定义

接收一个普通对象然后返回该普通对象的响应式代理。

注意:虽然reactive和ref都是响应式,但是reactive只能用来返回一个对象类型数据,而ref可以用来返回基本类型数据,当然ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象。

3.2 如何使用reactive

reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。

3.2.1 基本用法

let person = reactive({
  name:'zs',
  age:20,
  job:{
    type:'设计经理',
    salary:'30k',
    a:{
      b:{
        c:666
      }
    }
  },
  hobby:['吃饭','睡觉','打豆豆']
})
    console.log(person)
    console.log(person.name)//zs
    console.log(person.job.type)//设计经理
    console.log(person.job.a.b.c)//666

通过浏览器控制台我们可以观察到reactive返回的是一个Proxy对象

image-20221105113933313.png

并且reactive获取值的时候并不需要像ref一样,在属性后加value。因此reative在操作person对象里的属性时也就比ref更加的容易。

4. computed

4.1 传入getter函数

传入一个 getter 函数,返回一个默认不可手动修改的 ref 对象。

let person = reactive({
  firstName:'张',
  lastName: '三'
})
person.fullName = computed(()=>{
  return person.firstName+"-"+person.lastName
})
person.fullName = "1"+person.fullName//error

如果你修改就会在浏览器控制台中报以下错误。

image-20221105125452609.png

4.2 传入一个get和set函数

或者传入一个拥有 get 和 set 函数的对象,创建一个可手动修改的计算状态。

let person = reactive({
  firstName:'张',
  lastName: '三'
})
person.fullName = computed({
  get(){
    return person.firstName+"-"+person.lastName
  },
  set(value){
    const nameArr = value.split('-')
    person.firstName = nameArr[0]
​
    person.lastName = nameArr[1]
  }
})
    person.fullName = "1"+person.fullName// 1张-三

5. watch监听

5.1 监听ref

<template>
 <h2>当前求和为:{{sum}}</h2>
 <button @click="sum++">点我+1</button>
</template><script setup>
let sum = ref(0)
 watch(sum,(newValue,oldValue)=>{
      console.log('sum变了',newValue,oldValue)
    },{immediate:true})
</script>

{immediate:true}即刚打开网页就开始监听,无论你是否点击+1。如图第一条即是{immediate:true}所展示出来的效果,而后面两条数据则是监听才有的效果。

image-20221105133703484.png

5.2 监听ref所定义的多个响应式数据

<template>
  <h2>当前求和为:{{sum}}</h2>
  <button @click="sum++">点我+1</button>//1
  <br>
  <button @click="msg+='!'">你好啊:</button>
  <h2>{{msg}}</h2>//你好啊!
</template><script setup>
let sum = ref(0)
let msg = ref('你好啊')
watch([sum,msg],(newValue,oldValue)=>{
  console.log('sum或msg变了',newValue,oldValue)
​
},{immediate:true})
</script>

5.3 监视reactive所定义的一个响应式数据的全部属性

<template>
<h2>姓名:{{person.name}}</h2>
  <h2>年龄:{{person.age}}</h2>
  <button @click="person.name+='qwq'">修改姓名</button>//zsqwq
  <button @click="person.age+=1">增长年龄</button>//20
  <h2>薪水:{{person.job.j1.salary}}k</h2>//20k
  <button @click="person.job.j1.salary++">增长薪水</button>21k
</template><script setup>
 let person = reactive({
      name:"zs",
      age:19,
      job:{
        j1:{
          salary:20
        }
      }
    })
    
watch(person,(newValue,oldValue)=>{
  console.log('person变了',newValue,oldValue)
},{immediate:true})
</script>

5.4 监听reactive所定义的一个响应式数据中的某个属性

watch(()=>person.age,(newValue,oldValue)=>{
  console.log('person变了',newValue,oldValue)
})

此时监听person.age的属性,只要age变了就会监听到

5.5 监听reactive所定义的一个响应式数据中的某些属性

watch([()=>person.age,()=>person.name],(newValue,oldValue)=>{
  console.log('age或name变了',newValue,oldValue)
})

因为监听内容只能填一个的关系,这里巧妙的用了数组的方法来同时监听person.age和person.name这样只要age或者name变了我们都可以监听到。

5.6 特殊情况

let person = reactive({
      name:"pp",
      age:19,
      job:{
        j1:{
          salary:20
        }
      }
    })
    
watch(()=>person.job,(newValue,oldValue)=>{
  console.log("薪水变了",newValue,oldValue)
},{deep:true})

这里如果不用{deep:true}是监听不到salary的变化的,但是情况一的话不用deep就可以监视的到salary的变化,也是感觉很神奇。以我的理解可能是因为监听person的话自动开启深度监听,而job为person中的一个属性,默认不开启深度监听吧。如果有懂的大佬希望能来指正。

5.7 注意事项

1、使用watch监听reactive所定义的一个响应式数据时时,无法获取oldValue,只能监听到新数据。

6. watchEffect

6.1 定义

立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。

即watchEffect是立即执行,在加载页面时主动执行。

6.2 基本用法

watchEffect(()=>{
  sum.value
  console.log("watchEffect所指定的回调执行了")
})

我们可以看出watchEffect只需要传递一个回调函数,在加载中收集依赖,所以我们只要在内部写出我们需要指定要监听的数据就行。

7. watch和watchEffect的异同

异:

  1. 执行时机:watchEffect是立即执行的,在页面加载时会主动执行一次,来收集依赖;而watch是惰性地执行副作用,它不会立即执行,但可以配置 {immediate:true},使其主动触发。
  2. 参数不同:watchEffect只需要传递一个回调函数,不需要传递监听的数据,它会在页面加载时主动执行一次,来收集依赖;而watch至少要有两个参数,第三个参数是配置项可以根据需求来配置,第一个参数是监听的数据,第二个参数是回调函数。
  3. 结果不同:watchEffect和watch监听reactive的时候一样都获取不到更改前的值,而watch可以同时获取更改前和更改后的值。

同:

watch 与 watchEffect 在手动停止侦听、清除副作用 (将 onInvalidate 作为第三个参数传递给回调)、刷新时机和调试方面有相同的行为。

学习中遇到的BUG

1、未使用驼峰命名时template会报错如图:

image-20221103111140958.png

而且报错的时候是因为我用了setup的语法糖,没使用语法糖的时候没有报错。

后来看报错原因是因为我没有用驼峰命名法来命名我的文件,按照网上的方式在vue.config.js中加上 lintOnSave:false 即:

module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave:false
})

加完之后发现仍然报错不知道是什么原因,后来无奈只能修改了文件名为驼峰命名的方式。