• Vu3笔记_02setup与常用的Composition API(组合式API)


    link

    vue3.x中文文档

    setup

    setup是Vue3.0中一个新的配置项,值的类型为一个函数。setup是所有Composition API(组合API)的“表演舞台 ”

    setup的执行时机

    setup函数在beforeCreate之前执行一次,this是undefined;也就是说在setup中不能使用this

    export default {
      setup () {
        console.log('this', this) // undefined
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    [1]定义数据和方法

    在vue2.x中数据需要定义在data中,方法需要定义在methods中。

    在vue3.x中数据和方法直接定义在setup中即可。

    那么哪些数据可以在模版中直接使用呢?

    setup函数返回值若是为一个对象,则该对象内的所有属性均可在模版中直接使用

    <template>
      <div class="test">{{ name }}</div>
    </template>
    <script>
    export default {
      setup () {
        const name = 'chaochao'
        return {
          name
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    setup函数返回值若是一个渲染函数,则该页面的内容为渲染函数的值而非模版中的内容了。

    <template>
      <div class="test">11111</div>
    </template>
    <script>
    export default {
      setup () {
        return ()=>{
           return h('div', 'chaochao')
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    tips: 模版中的内容被覆盖了!

    注意:setup不能是一个async函数,因为async函数的返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)

    兼容性

    vue3.0中可以使用vue2.x的data、methods配置项吗?

    在vue3.0中可以兼容之前的配置项,但是尽量不要与Vue2.x配置混用。若是混用:

    • Vue2.x配置项(data、methos、computed…)中可以访问到setup中的属性、方法;但在setup中不能访问到Vue2.x配置项中的属性和方法。
    • 如果有重名属性/方法, setup优先。
    响应式数据
    setup (){
      let 变量名 =return {
        变量名
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    直接通过上述语法声明变量,变量虽然可以在模版中使用,但是数据并不是响应式的,当数据更改时,vue并不会重新渲染数据;
    若是想要数据是响应式的需要借助 ref函数reactive函数 进行双向数据绑定。

    ref(组合API)
    作用

    ref函数的作用是 定义一个响应式的数据;推荐在定义简单数据类型时使用;

    语法
    let 变量名 = ref(initValue)
    
    • 1
    • 创建一个包含响应式数据的reference引用对象
    • JS中操作数据: 变量名.value
    • 模板中读取数据: 不需要.value,直接:{{变量名}}即可(内部做了封装,实际读取得是变量名.value)
    示例
    <template>
      <div class="hello">
        <h1>姓名:{{name}}h1>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    <script>
    import { ref } from 'vue'
    export default {
      setup () {
        let name = ref('chaochao')
        console.log('@@@', name) // reference对象,value属性值为真实的值
        return {
          name
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    本质
    • ref函数接收的数据可以是基本类型也可以是引用类型
    • 基本类型的数据:响应式依然是靠Object.defineProperty()getset完成的。->实现原理传送门
    • 对象类型的数据:内部会自动通过reactive函数转为代理对象
    reactive(组合API)
    作用

    reactive函数的作用是 定义一个引用类型的响应式数据(基本类型使用ref函数)

    语法
    const 代理对象= reactive(源对象)
    
    • 1
    • 接收一个对象/数组,返回一个Proxy实例对象
    • reactive定义的响应式数据是“深层次的”
    • 使用reactive方法实现双向绑定原理->传送门
    重新赋值失去响应式

    在Vue3中如果对一个reactive对象重新赋值,会导致失去响应式。

    <template>
      <div class="test">
        {{ info.name }}
        <br>
        {{ info.age }}
        <br>
        <button @click="editinfo">修改</button>
      </div>
    </template>
    <script>
    import { reactive } from 'vue'
    export default {
      setup () {
        let info = reactive({
          name:'chaochao',
          age:18
        })
        function editinfo () {
          info = reactive({
            name:'niuniu',
            age:20
          })
          console.log('info', info)
        }
        return {
          info,
          editinfo
        }
      }
    }
    </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

    上述示例中点击按钮页面没有任何变化(虽然打印的info数据发生了变化)

    这是因为reactive是使用了Proxy来实现响应式,而Proxy只能监听对象的属性访问和修改,而不能监听对象本身的赋值操作

    若是想要修改对象的值应该怎么做呢? 可以修改对象单个的属性

    // 此时点击按钮时页面内容随之改变
    function editinfo () {
      info.name = 'niuniu'
      info.age = 20
      console.log('info', info)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    但是很多情况下我们修改对象都是后端直接返回来的数据,字段很多,这样修改比较麻烦,可以使用ref来定义对象

    export default {
      setup () {
        let info = ref({
          name:'chaochao',
          age:18
        })
        function editinfo () {
          info.value = {
            name: 'niuniu',
            age: 20
          }
        }
        return {
          info,
          editinfo
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    因为修改ref对象修改的是value属性值,可以直接修改(数据还是响应式的)!

    对比ref与reactive
    • 从定义数据角度对比:
      • ref用来定义:基本类型数据。
      • reactive用来定义:对象/数组类型数据。
      • 备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象
    • 从原理角度对比:
      • ref通过Object.defineProperty()getset来实现响应式(数据劫持)。
      • reactive通过使用Proxy来实现响应式(数据劫持)。
    • 从使用角度对比:
      • ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value
      • reactive定义的数据:操作数据与读取数据:均不需要.value
    toRef

    传送门

    [2] 组件化开发

    组件化开发(vue2.x/vue3.x对比)

    [3] 生命周期函数

    配置项式生命周期+组合式API式生命周期

    tips: 个人感觉在3.x中2.x中的生命周期函数毫无用处->获取不到setup中的数据根本进行不了任何操作!

    [4] 侦听器

    [1]监听ref定义的1个响应式数据
    语法

    在vue3中侦听器被抽取为一个组合API,使用之前需要先引入

    <script>
    // [1]在vue3中 watch是一个组合式API,使用之前需要先引入
    import { watch } from 'vue';
    export default{
      setup(){
        // [2]开启watch侦听
        /*
          参数1:变量(监听变量),
          参数2:Function(逻辑代码)
          参数3:Object:配置项
          newVal: 该变量更改前的值
          oldVal:该变量更改后的值
        */
        watch(监听变量,(newVal,oldVal)=>{
          // 逻辑代码
        }, {
          // 配置项
        })
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    示例

    年龄:age
    按钮(点击年龄➕1)
    注:监听打印年龄

    <template>
      <h4>年龄:{{age}}</h4>
      <button @click="age++">点我年龄增加</button>
    </template>
    <script>
    // [1]在vue3中 watch是一个组合式API,使用之前需要先引入
    import { ref, watch } from 'vue';
    export default{
      setup(){
        let age = ref(18)
        watch(age,(newVal,oldVal)=>{
          console.log('@@@', newVal, oldVal)
        },{
          immediate:true
        })
        return {
          age
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    tips: 实际上监听的并不是18这个数值的变化,而是监听的ref实例对象的变化,只要是任意一个属性变化都会触发watch监听!

    [2]监听ref定义的多个响应式数据
    语法

    当监听多个ref定义的数据时,可以使用[1]中语法使用两个watch函数进行监听,也可以使用下列语法

       /*
          参数1:Array(监听变量),
          参数2:Function(逻辑代码)
          参数3:Object:配置项
          newVal: [变量1更改前的值,变量2更改前的值]
          oldVal:[变量1更改后的值,变量2更改后的值]
        */
       watch([变量1,变量2], (newVal,oldVal)=>{
            console.log('@@@', newVal, oldVal)
            // 逻辑代码
          },{
           // 配置项
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    [3]监听reactive所定义的一个响应式数据中所有的数据
    语法
    <script>
    // [1]在vue3中 watch是一个组合式API,使用之前需要先引入
    import { watch } from 'vue';
    export default{
      setup(){
        // [2]开启watch侦听
        /*
          参数1:变量(监听变量),
          参数2:Function(逻辑代码)
          参数3:Object:配置项
          newVal: 该变量更改前的值
          oldVal:该变量更改后的值
        */
        watch(监听变量,(newVal,oldVal)=>{
          // 逻辑代码
        }, {
          // 配置项
        })
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    与监听ref数据的区别
    • [1] 若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!
    • [2]若watch监视的是reactive定义的响应式数据,则强制开启了深度监视且无法关闭(deep:false失效)
    • [3] 若是数据很多存在效率问题(深度监听)
    [4]监听reactive所定义的响应式数据的某个属性
    语法
    <script>
    // [1]在vue3中 watch是一个组合式API,使用之前需要先引入
    import { watch } from 'vue';
    export default{
      setup(){
        // [2]开启watch侦听
        /*
          参数1:Function(监听变量),
          参数2:Function(逻辑代码)
          参数3:Object:配置项
          newVal: 该变量更改前的值
          oldVal:该变量更改后的值
        */
        watch(()=> 变量.属性,(newVal,oldVal)=>{
          // 逻辑代码
        }, {
          // 配置项
        })
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    [5] 监听reactive所定义的响应式数据的多个属性
    语法
    <script>
    // [1]在vue3中 watch是一个组合式API,使用之前需要先引入
    import { watch } from 'vue';
    export default{
      setup(){
        // [2]开启watch侦听
        /*
          参数1:Array(监听变量),
          参数2:Function(逻辑代码)
          参数3:Object:配置项
          newVal: [变量1更改前的值,变量2更改前的值]
          oldVal: [变量1更改后的值,变量2更改后的值]
        */
        watch([()=> 变量.属性,()=> 变量.属性],(newVal,oldVal)=>{
          // 逻辑代码
        }, {
          // 配置项
        })
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    示例
    <template>
     <h4>年龄:{{info.age}}</h4>
     <button @click="info.age++">点我年龄增加</button>
     <h4>sonplay:{{info.sonInfo.play.car}}</h4>
     <button @click="info.sonInfo.play.car+='~'">点我修改</button>
    </template>
    <script>
    // [1]在vue3中 watch是一个组合式API,使用之前需要先引入
    import { reactive, ref, watch } from 'vue';
    export default{
     setup(){
      
       let info =reactive({
         age:18,
         say:'hello',
         sonInfo:{
           age:2,
           play:{
             car:'汽车真好玩'
           }
         }
       })
       watch([()=> info.age,()=> info.sonInfo], (newVal,oldVal)=>{
           // 当点击 点我年龄增加 按钮时 会打印, 当点击 点我修改 时不会打印
           /*原因:
             只有监听reactive定义的对象的全部属性时才会强制开始深度监听
             当监听reactive定义的对象的某个属性时并没有开启强制刷新
             此时 deep:true还有效
             只要在配置项中进行配置 点击上述两个按钮的任意一个都会触发watch监听了!
           */
           console.log('@@@', newVal, oldVal)
         })
       return {
         info
       }
     }
    }
    </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
    总结
    • 监听一个值时,第一个参数传的是变量;
    • 监听多个值时,第一个参数传递的是数组,数组的每个元素是变量;
    • 当监听reactive对象的全部属性时,强制开启的深度监听且不可取消;
    • 监听时:监听的并不是实际数值的变化而是监听的ref对象/Proxy实例对象的变化!!!
    vue3中的侦听器-watchEffect
    • watch的套路是:既要指明监视的属性,也要指明监视的回调。

    • watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。

    • watchEffect有点像computed:

      • 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
      • 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
      //watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
      watchEffect(()=>{
          const x1 = sum.value
          const x2 = person.age
          console.log('watchEffect配置的回调执行了')
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

    [5] 计算属性

    语法

    在vue3中计算属性被抽取为一个组合API,使用之前需要先引入

    import {computed} from 'vue'
    export default {
      setup(){
        // computed的类型为一个函数
         
        // [1]在页面中使用->需要传入一个回调函数
        let res = computed(()=>{
          return xxx. // return 的值就是计算属性的值
    	})
    	
    	// [2]在页面中修改计算属性的值-> 去修改其他的值,就需使用get、set方法
    	let res = computed({
    	  get(){
    	    return xxx // return 的值就是计算属性的值
    	  },
    	  set(value){
    	    // 对其他值进行操作
    	  }
    	})
        return {
          res // 响应式的
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    示例

    下面以一个小例子说明vue3中计算属性的使用

    需求1

    姓:输入框
    名:输入框
    姓名:当用户输入姓、名时自动在此显示 姓 - 名 (实时改变)

    实现

    <template>
      姓:<input type="text" v-model="info.firstname">
      <br>
      名:<input type="text" v-model="info.lastname">
      <br>
      姓名:{{info.name}}
    </template>
    <script>
    // [1]在vue3中 computed是一个组合式API,使用之前需要先引入
    import { reactive, computed } from 'vue';
    export default{
      setup(){
        let info = reactive({
          firstname:'',
          lastname:''
        })
        // [2]使用计算属性
        info.name = computed(()=>{
          return `${info.firstname}-${info.lastname}`
        })
        return {
          info
        }
      }
    }
    </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

    姓:输入框
    名:输入框
    姓名:输入框
    注意:当用户输入姓、名时自动在此显示 姓 - 名 (实时改变) ; 当修改姓名时 姓、名输入框也要实时改变

    实现

    <template>
     姓:<input type="text" v-model="info.firstname">
     <br>
     名:<input type="text" v-model="info.lastname">
     <br>
     姓名:<input type="text" v-model="info.name">
    </template>
    <script>
    // [1]在vue3中 computed是一个组合式API,使用之前需要先引入
    import { reactive, computed } from 'vue';
    export default{
     setup(){
       let info = reactive({
         firstname:'',
         lastname:''
       })
       info.name = computed({
         get(){
           return `${info.firstname}-${info.lastname}`
         },
         set(value){
           const arr = value.split('-')
           info.firstname = arr[0]
           info.lastname = arr[1]
         }
       })
       return {
         info
       }
     }
    }
    </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

    在这里插入图片描述

    [6] hook

    概念
    • vue3.x中的hooks类似于vue2.x中的mixin类似
      • mixin(混入):本质是一个对象,将实例对象的配置项进行封装;
      • hook:本质是一个函数,把setup函数中使用的Composition API进行了封装
    • 自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂
    举例说明
    需求

    当用户点击页面时获取鼠标点击的点的坐标;

    实现1
    <template>
      <h1> 当前鼠标点击的坐标为point({{point.x}},{{point.y}})</h1>
    </template>
    <script>
    import { onBeforeUnmount, onMounted, reactive } from 'vue';
    
    export default{
      setup(){
        // 数据
        let point = reactive({
          x:0,
          y:0
        })
        
        // 方法
        function getpoint(event){
          point.x = event.pageX,
          point.y = event.pageY
        }
    
        // 生命周期
        onMounted(()=>{
          window.addEventListener('click', getpoint)
        })
        // 需要在页面注销时解除事件绑定,不然关闭当前页面之后点击页面还是会执行getpoint方法
        onBeforeUnmount(()=>{
          window.removeEventListener('click', getpoint)
        })
    
        return {
          point
        }
      }
    }
    </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

    在这里插入图片描述

    实现2-hook

    但是这个功能不只是在该组件被使用,在页面的其他组件中也使用到了;
    当然可以把代码复制过去,但是最简单的是将代码写在hook中,哪里使用在哪里引入

    hook文件 - usePoint

    import { onBeforeUnmount, onMounted, reactive } from 'vue';
    export default function savePoint(){
      // 数据
      let point = reactive({
        x:0,
        y:0
      })
          
      // 方法
      function getpoint(event){
        point.x = event.pageX,
        point.y = event.pageY
      }
      
      // 生命周期
      onMounted(()=>{
        window.addEventListener('click', getpoint)
      })
      onBeforeUnmount(()=>{
        window.removeEventListener('click', getpoint)
      })
    
      return point
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    组件

    <template>
      <h1> 当前鼠标点击的坐标为point({{point.x}},{{point.y}})</h1>
    </template>
    <script>
    import usePoint from '@/hooks/usePoint'
    export default{
      setup(){
        let point = usePoint()
        return {
          point
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    [7] 路由

    在vue3中创建路由实力化对象的方式与vue2相同,但是由于setup中不能使用this,因此在vue3中路由的跳转与访问还是有了一定的变化~
    在这里插入图片描述

    [8] vuex

    [1]获取store

    在这里插入图片描述

    [2]访问state

    在这里插入图片描述

    [9] ref获取dom

    vue2中获取dom

    在vue2中会通过以下方式获取dom

    • [1] 在dom元素绑定ref属性
        <div ref='box'>div>
      
      • 1
    • [2] 在js中通过this.$refs.box获取元素
    vue3中获取dom

    在vue3的setup中不能使用this,因此指定不能使用上述方式获取dom

    • 采用原生js获取dom(不可行)
        onMounted(()=>{
          console.log(11111, document.getElementById('box')) // null
        })
      
      • 1
      • 2
      • 3
      发现即使在dom渲染完毕,通过原生js也获取不到dom
    • 通过ref获取dom(可行)
        <div ref='box'>div>
      
      • 1
      <script setup>
      import { ref } from '@vue/reactivity';
      const box = ref()
      onMounted(()=>{
        console.log(1111,box.value) // 
      }) </script>
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      tips: 若是没有使用setup语法糖,需要将box变量return出去,否则将获取不到dom元素!

    通过ref获取组件的属性或方法

    组件的获取方式与dom元素的获取方式相同, 只要是在setup中 return出来的属性和方法都可以获取到

     const name = ref(null) // name与组件绑定的ref属性值一致
     name.value.属性值. // 获取指定属性
     name.value.方法名() // 调用指定方法
    
    • 1
    • 2
    • 3

    举例说明

    • 子组件
      <template>
        <div>{{ info.name }}div>
      template>
      
      <script>
      import { reactive } from 'vue'
      export default{
        setup(){
          const info = reactive({
            name:'chaochao',
            sex:'nv'
          })
          const name = 'niuniu'
          return{
            info
          }
        }
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
    • 父组件
        <template>
          <div>
             <test ref="box">test>
          
    template> <script setup> import { ref } from '@vue/reactivity'; const box = ref(null) onMounted(() => { console.log('box', box.value.info) // Proxy(Object) {name: 'chaochao', sex: 'nv'} console.log('box', box.value.name) // undefined }) script>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

[10] 获取this

虽然说在setup中获取不到this,但是在某些情况下又不得不使用this。

在vue3中, 存在getCurrentInstance方法获取当前组件的实例,等同于this

import { getCurrentInstance } from 'vue'

<script setup>
import { getCurrentInstance } from 'vue'
const {ctx, proxy} = getCurrentInstance()
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 其实ctx 与proxy 都是实例化对象,都可以获取到全局变量,但是~

    • ctx仅能在开发环境中使用,打包之后是拿不到的
    • proxy是能够在任何环境正常使用的!
  • 注意:虽然proxy能代表实例化对象,但是不要在setup中将proxy当作this使用(可以说是能不使用就不使用)

tips: getCurrentInstance 只能在 setup 或生命周期钩子中调用

[8]全局方法定义

vue2

在vue2.0中是将全局属性或方法挂在到Vue实力化对象的原型链上。

比如我们想添加一个全局属性,如下代码:

Vue.prototype.$pagehost = 'http://xxx'
  • 1

在组件中使用,仅需如下:

this.$pagehost // 'http://xxx'
  • 1
vue3

在vue3中是将数据添加在全局配置app.config.globalProperties中。

比如我们想添加一个全局属性,如下代码:

const app = createApp(App);
app.config.globalProperties.pagehost = 'http://xxx'
  • 1
  • 2

在组件中使用:

import { getCurrentInstance } from 'vue'
<script setup>
setup(){
  const {ctx, proxy} = getCurrentInstance()
  proxy.pagehost // 'http://xxx'
}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

setup语法糖

在vue3.2将setup封装为语法糖,将setup写在script标签上即可,语法如下:

<script setup>
...
</script>
  • 1
  • 2
  • 3

这样写之后呢,setup不再是一个函数了,没有return了,因此数据的导出等等都发生了一系列的变化,整理如下:

[1]data+methods:定义的数据和方法不需要return出去即可在模版中使用
<template>
  <div>
    {{ info.name }}
    <button @click="editname">点我修改namebutton>
  div>
template>

<script setup>
import { reactive } from 'vue'
const info = reactive({
  name:'chaochao',
  sex:'nv'
})
function editname(){
  info.name = 'niuniu'
}
script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

如上代码在运行之后在页面显示文本“chaochao”,在点击按钮“点我修改name”之后页面文本变为"niuniu"

[2]通过ref获取子组件的数据和方法(defineExpose)

通过模板 ref 或者 $parent 链获取到的是组件的公开实例。

使用