Vue3+vite+Ts+pinia—第二章 setup

1,539 阅读6分钟

2.1 setup概述

        setup是Vue3中一个新的配置项,值是一个函数,它是Composition API表演的舞台,组件中所用到的:数据、方法、计算属性、监视......等等,均配置在setup中。

2.1.1 setup写数据

        在Vue2中,数据是写在data里,在setup里直接使用变量定义,然后return返回,模板即可读取该变量。

        Vue2:

<template>
  <div class="person">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
  </div>
</template>

<script>
  export default {
    name:'Person',
    data() {
      return {
        name: '张三'
        age: 18
        tel: '13888888888'
      }
    }
  }
</script>

        Vue3:

<template>
  <div class="person">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
  </div>
</template>

<script lang="ts">
  export default {
    name:'Person',
    setup(){
      let name = '张三'
      let age = 18
      let tel = '13888888888'

      return {name,age,tel}
    }
  }
</script>

2.1.2 setup写方法

        在Vue2中,方法是写在methods里,在setup里可以直接写function,同样需要return返回,模板就能识别该方法。

        Vue2:

<template>
    <div class="person">
      <h2>姓名:{{name}}</h2>
      <h2>年龄:{{age}}</h2>
      <button @click="changeName">修改名字</button>
      <button @click="changeAge">修改年龄</button>
      <button @click="showTel">查看联系方式</button>
    </div>
  </template>
  
  <script>
    export default {
      name:'Person',
      data(){
        return {
          name:'张三',
          age:18,
          tel:'13888888888'
        }
      },
      methods:{
        // 修改姓名
        changeName(){
          this.name = 'zhang-san'
        },
        // 修改年龄
        changeAge(){
          this.age += 1
        },
        // 展示联系方式
        showTel(){
          alert(this.tel)
        }
      }
    }
  </script>

        Vue3:

<template>
  <div class="person">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="showTel">查看联系方式</button>
  </div>
</template>

<script lang="ts">
  export default {
    name:'Person',
    setup(){
      let name = '张三'
      let age = 18
      let tel = '13888888888'
      
      // 方法
      function changeName() {
        name = 'zhang-san'
      }
      function changeAge() {
        age += 1
      }
      function showTel() {
        alert(tel)
      }

      // 将数据、方法交出去,模板中才可以使用
      return {name,age,tel,changeName,changeAge,showTel}
    }
  }
</script>

        注意1:此时的数据并不是响应式的,也就是说变量的值改变了,并没有同步刷新视图。

        关于响应式的问题,可以参考# Vue3+vite+Ts+pinia—第三章 ref-reactive-toRefs-toRef

71ff0d0f-482a-43c3-8b89-861743c5ac7f.gif

        注意2:在setup里,是没有this作用域的,也就是说在setup里不能用this。

<script lang="ts">
  export default {
    name:'Person',
    setup(){
      console.log(this);
      ......
    }
  }
</script>

image.png

2.1.3 setup执行时机

        在Vue2中,在所有生命周期中最早执行的是beforeCreate,而setup执行时机比beforeCreat更快。

export default {
  name:'Person',
  beforeCreate(){
    console.log('beforeCreate')
  },
  setup(){
    console.log('setup')
  }
}

image.png

2.1.4 代码示例

2.2 setup的返回值

        一般来说,setup返回的是一个对象,里面包含着定义的变量和方法,给模板使用。但它也可以返回一个函数,它可以直接指定渲染的内容,覆盖掉<template>模板的内容,也就是说,你可以在函数里写页面。

<template>
  <div class="person">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="showTel">查看联系方式</button>
  </div>
</template>

<script lang="ts">
  export default {
    name:'Person',
    setup(){
      ......

      return () => '哈哈'
    }
  }
</script>

image.png

2.3 setup与OptionsAPI

        学完setup会产生以下几个问题:

        1、setup与data、methods有什么关系呢?

        2、setup与data、methods这些传统的配置项可否同时写,以谁为主?

        3、setup可否读取data的变量?又或者data、methods可否读取setup变量?

        实际上按正常开发Vue3而言,是不应该出现这些问题的,因为用了Vue3就不应该再用data、methods,但由于Vue3又是支持Vue2的语法,这样就难免在开发过程中,有开发者既写Vue2也写Vue3语法,混着来写。因此这些概念就必须得弄明白。

2.3.1 setup与data、methods并存

        虽然在setup定义了数据和方法,但如果此时也写了data和methods,Vue3一样能识别。

<template>
  <div class="person">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="showTel">查看联系方式</button>
    <hr>
    <h2>测试1:{{a}}</h2>
    <button @click="b">测试</button>
  </div>
</template>

<script lang="ts">
  export default {
    name:'Person',
    data(){
      return {
        a:100
      }
    },
    methods:{
      b(){
        console.log('b')
      }
    },
    setup(){
      let name = '张三'
      let age = 18
      let tel = '13888888888'
      
      // 方法
      function changeName() {
        name = 'zhang-san'
      }
      function changeAge() {
        age += 1
      }
      function showTel() {
        alert(tel)
      }
      return {name,age,tel,changeName,changeAge,showTel}
    }
  }
</script>

image.png

        说明无论是数据还是方法,写在setup或者data、methods都是可以的,只是不推荐在Vue3再使用旧语法而已。

2.3.2 setup与data的关系

        setup与data之间能否相互通信?答案是setup不能读取data变量,但data可以读取setup变量。在Vue3中,setup是最快执行的函数,因此在data定义之前,setup变量已经存在。反过来setup是不能读data变量的,在setup执行的时候,data变量还没开始定义。

<template>
  <div class="person">
    ......
    <h2>测试1:{{a}}</h2>
    <h2>测试2:{{c}}</h2>
    <button @click="b">测试</button>
  </div>
</template>

<script lang="ts">
  export default {
    name:'Person',
    data(){
      return {
        a:100,
        c:this.name
      }
    },
    methods:{
      b(){
        console.log('b')
      }
    },
    setup(){
      let name = '张三'
      let age = 18
      let tel = '13888888888'
      
      ......
    }
  }
</script>

image.png

2.3.3 示例代码

2.4 setup语法糖

        因为使用setup函数,它是必须要return返回的,这样模板才可以读取。但是随着变量和方法越来越多,那么要return的东西就越多,而且还会存在忘记return的情况。

2.4.1 <script>标签添加setup

        在<script>标签添加setup的作用是,它里面的内容就相当于setup(){}函数一样,而且还帮我们return返回,非常方便,这里举一个最简单的例子对比一下:

        1、setup函数写法

<script lang="ts">
  export default {
    name:'Person',
    setup(){
      let a = 666
      return {a}
    }
  }
</script>

        2、<script>加setup

<script lang="ts">
  export default {
    name:'Person'
  }
</script>
<script setup>
  let a = 666
</script>

image.png

        此时它会报一个错误,说<script>与<script setup>必须是相同的语言类型,因为现在存在两个<script>,一个加了lang="ts",而setup的<script>没加,这里只需在setup的<script>也加上lang="ts"即可。

<script lang="ts">
  export default {
    name:'Person'
  }
</script>
<script lang="ts" setup>
  let a = 666
</script>

2.4.2 两个<script>合二为一

        现在还存在一个问题,就是现在虽然把setup抽离到另一个<script>,但之前的<script>用来配置组件名的,这个倒不能随便合并在一起,因为<script>配置了setup就意味着它里面的是setup函数的内容,不能在里面写export default这些东西。

        删掉没有setup的<script>标签是没问题的,程序仍然能正常运行:

<template>
  <div class="person">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <h2>地址:{{address}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="showTel">查看联系方式</button>
  </div>
</template>

<script lang="ts" setup>
  let name = '张三'
  let age = 18
  let tel = '13888888888'
  let address = '北京昌平区宏福苑·宏福科技园'

  // 方法
  function changeName() {
    name = 'zhang-san'
  }
  function changeAge() {
    age += 1
  }
  function showTel() {
    alert(tel)
  }
</script>

image.png

        但如果此时想改变组件名就麻烦了,在Vue中组件名是读取你配置的name属性,现在删掉了就等于没有配置name属性,那就读取文件名作为组件名。

image.png

image.png

        此时如果想给组件改名,除非是修改文件名,显然这个是不能随便改的。除此之外,我们还可以借助vite中的插件简化:

        1、npm i vite-plugin-vue-setup-extend -D

        2、vite.config.ts

import { defineConfig } from 'vite'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'

export default defineConfig({
  plugins: [ VueSetupExtend() ]
})

        3、在<scrpit>标签添加name属性

            <script setup lang="ts" name="Person234">

image.png

        当然改组件名的情况并不是很多,但是如果一些公司规范是所有组件的文件名都叫index.vue,在外面包裹一个组件业务名,如下图所示,此时修改组件名就比较有用。

image.png

2.4.3 示例代码