Vue3学习笔记(一)

目录

一:简介

二:使用vite创建vue项目

三:Vue3核心语法

四:setup

五:ref和reactive

六:toRefs和toRef

七:computed

八:watch

(1): 监视【ref】定义的【基本类型】数据

(2): 监视【ref】定义的【对象类型】数据

(3): 监视【reactive】定义的【对象类型】数据

(4): 监视【ref】或【reactive】定义的【对象类型】数据中的某个属性

(5): 监视上述的多个数据

九:watchEffect

十:ref

十一:props

十二:生命周期

十三:自定义hooks

ts相关


一:简介

在vue3中,编码风格进行了一些变化。

编码语言:JavaScript、TypeScript(推荐使用TypeScript)

编码风格:组合式API、选项式API(推荐使用组合式API)

简写形式:setup语法糖

性能提升:打包大小减少41%;初次渲染快55%,更新渲染快133%;内存减少54%。

源码升级:使用proxy代替defineProperty;重写虚拟dom的实现和Tree-Shaking。

二:使用vite创建vue项目

npm creat vue@latest

env.d.ts文件报错(飘红): 因为没有安装node_modules。这个文件的存在,是为了让ts去识别.txt等类型的文件

⚠️:vs code中Vue - Official 插件合并了TypeScript Vue Plugin (Volar)和 Vue Language Features (Volar) 这两个插件

Vite 项目中,index.html 是项目的入口文件,在项目最外层。

加载index.html后,Vite 解析 <script type="module" src="xxx"> 指向的JavaScript。

Vue3中是通过 createApp 函数创建一个应用实例。

三:Vue3核心语法

【OptionsAPI 与 CompositionAPI】

Vue2的API设计是Options(配置)风格的。

Vue3的API设计是Composition(组合)风格的。

Options API 的弊端:

Options类型的 API, 数据、方法、计算属性等, 是分散在: data、methods、computed中的, 若想新增或者修改一个需求, 就需要分别修改: data、methods、computed, 不便于维护和复用。

Composition API 的优势:

可以用函数的方式,更加优雅的组织代码,让相关功能的代码更加有序的组织在一起。

四:setup

setup是Vue3中一个新的配置项,同Vue2中的data,methods等为兄弟并列元素。

特点:setup函数返回的对象中的内容,可直接在模板中使用。
           setup中访问this是undefined。
           setup函数会在beforeCreate之前调用,它是“领先”所有钩子执行的。

注意⚠️:

  •         Vue2 的配置(data、methods......)中可以访问到setup中的属性、方法。
  •         但在setup中不能访问到Vue2的配置(data、methods......)。
  •         如果与Vue2冲突,则setup优先。

1:若返回一个对象:则对象中的:属性、方法等,在模板中均可以直接使用(重点关注)

<template>
    <div>人员信息</div>
    <ul>
        <li>姓名:{{ name }}</li>
        <li>年龄:{{ age }}</li>
        <li>地址:{{ adress }}</li>
        <br>
        <li>测试:{{ d }}</li>
        <li>测试:{{ e }}</li>
    </ul>
    <br>
    <div>
        <button @click = changeAge()>修改年龄</button>
        <button @click = showAdress()>显示地址</button>
    </div>
</template>

<script lang ='ts'>
export default{
    name:'thePerson',
    //vue2的写法 - 尽量不要与vue3混用
    data(){
        return{
            d: 123,
            e: this.name //可以使用vue3的数据
        }
    },
    setup(){
        console.log(this);  //undefined
        //注意:vue3可以使用vue2的数据。vue2不可以使用vue3的数据
        // console.log(this.d);  //报错-Cannot read properties of undefined (reading 'd')
        // 数据,原来写在data中(注意:此时的name、age、tel数据都不是响应式数据)
        let name = '章三';
        let age = 18;
        let adress = '北京市XXX';
        
        // 方法,原来写在methods中
        function changeAge(){
            //注意:此时这么修改name页面是不变化的
            age++;
            console.log(age)
        }
        function showAdress(){
            alert(adress);
        }
        
        // 返回一个对象,对象中的内容,模板中可以直接使用
        return {name,age,adress,changeAge,showAdress}
    }
}
</script>

2:setup若返回一个函数:则可以自定义渲染内容。

setup(){
  return ()=> '你好啊!'
}

3:setup语法糖

这个语法糖,可以让我们把setup独立出去。借助vite中的插件vite-plugin-vue-setup-extend,去指定组件名字。

1. 第一步:安装插件命令  ----  npm i vite-plugin-vue-setup-extend -D
2. 第二步:配置文件  ----  vite.config.ts

//vite.config.ts

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

export default defineConfig({
  plugins: [ VueSetupExtend() ]
})
<template>
    <div>人员信息</div>
    <ul>
        <li>姓名:{{ name }}</li>
        <li>年龄:{{ age }}</li>
        <li>地址:{{ adress }}</li>
    </ul>
    <br>
    <div>
        <button @click = chageAge()>修改年龄</button>
        <button @click = showAdress()>显示地址</button>
    </div>
</template>

<!-- 使用插件后 定义组件名称这块就可以简化了 -->
<!-- <script lang ='ts'>
export default{
    name:'thePerson'
}
</script> -->

<script lang ='ts' setup name='thePerson'>
    let name = '章三';
    let age = 18;
    let adress = '北京市XXX';
    
    function chageAge(){
        age++;
        console.log(age)
    }
    function showAdress(){
        alert(adress);
    }
</script>

五:ref和reactive

ref:

        作用: 定义响应式变量。

        语法: let xxx = ref(XXX)。

        返回值: 一个RefImpl的实例对象, 简称ref对象或ref, ref对象的value属性是响应式的。

        注意点:

                JS中操作数据需要: xxx.value, 但模板中不需要.value, 直接使用即可。

                对于let name = ref('张三')来说, name不是响应式的, name.value是响应式的。

        

        其实ref接收的数据可以是: 基本类型、对象类型。

        若ref接收的是对象类型, 内部其实也是调用了reactive函数。

reactive:

        作用: 定义一个响应式对象(基本类型不要用它, 要用ref, 否则报错)

        语法: let 响应式对象= reactive(源对象)。

        返回值: 一个Proxy的实例对象, 简称: 响应式对象。

        注意点: reactive定义的响应式数据是“深层次”的。

区别:

1. ref创建的变量必须使用.value(可以使用TypeScript Vue Plugin (Volar)插件自动添加.value)

2. reactive重新分配一个新对象, 会失去响应式(可以使用Object.assign去整体替换)

使用原则:

1. 若需要一个基本类型的响应式数据, 必须使用ref。

2. 若需要一个响应式对象, 层级不深, ref、reactive都可以。

3. 若需要一个响应式对象, 且层级较深, 推荐使用reactive。

<template>
    <div class="obj">
        <span>汽车数量{{ num }}</span>
        <button @click="changeCarNum()">汽车数量+1</button>
        <hr>

        <h2>汽车信息:一台{{ car.brand }}汽车,价值{{ car.price }}万</h2>
        <button @click="changeCarPrice()">修改汽车价格</button>
        <button @click="changeCar()">修改汽车信息</button>
        <hr>

        <h2>游戏列表:</h2>
        <ul>
            <li v-for="g in games" :key="g.id">{{ g.name }}</li>
        </ul>
        <button @click="changeFirstGame()">修改第一游戏</button>
        <hr>
        
        <h2>测试1: {{obj.a.b.c.d}}</h2>
        <button @click="deepTestReactive()">深层次数据测试-reactive</button>
        <h2>测试2: {{objRef.a.b.c.d}}</h2>
        <button @click="deepTestRef()">深层次数据测试-ref</button>
    </div>
</template>

<script lang ='ts' setup>
import {ref, reactive} from 'vue'

// 数据
let num = ref(0);
let car = reactive({ brand: '奔驰', price: 100 })
let games = ref([
  { id: 'game01', name: '英雄联盟' },
  { id: 'game02', name: '王者荣耀' },
  { id: 'game03', name: '开心消消乐' }
])
let obj = reactive({
  a:{
    b:{
      c:{
        d:666
      }
    }
  }
})
let objRef = ref({
  a:{
    b:{
      c:{
        d:666
      }
    }
  }
})

function changeCarNum(){
    //ref的数据必须使用value--报错信息:Must use `.value` to read or write the value wrapped by `ref()`.
    num.value += 1;
}

function changeCarPrice(){
    car.price += 10;
}

function changeCar(){
    // car = { brand: '小米', price: 25.9 }  //❌,不会变化。修改了之前的响应式绑定
    // car = reactive({ brand: '小米', price: 25.9 }) //❌,不会变化。 reactive重新分配一个新对象,会失去响应式(可以使用Object.assign去整体替换)

    //会变化,效率低
    // car.brand = '小米';
    // car.price = 25.9;

    //正解
    Object.assign(car,{ brand: '小米', price: 25.9 })
}

function changeFirstGame(){
    games.value[0].name = '刺激战场'

    // 如果使用reactive做响应式,写法为:games[0].name = '刺激战场';;
}

function deepTestReactive(){
    obj.a.b.c.d = 999;
}
function deepTestRef(){
    objRef.value.a.b.c.d = 888;
}

</script>

注意⚠️://reactive中的ref 已经进行了 拆包处理,不需要再次.value

let objRR = reactive({
    a:1,
    b:2,
    c:ref(3)
})

console.log(objRR.a) //1
console.log(objRR.b) //2
console.log(objRR.c) //3

六:toRefs和toRef

作用: 将一个响应式对象中的每一个属性, 转换为ref对象

备注: toRefs与toRef功能一致, 但toRefs可以批量转换。

<template>
    <div class="obj">
        <h2>汽车信息:一台{{ color }}的{{ car.brand }}汽车,价值{{ car.price }}万</h2>
        <button @click="changeCar()">修改汽车信息</button>
        <hr>
    </div>
</template>

<script lang ='ts' setup>
import {reactive, toRefs, toRef} from 'vue'

// 数据
let car = reactive({ brand: '奔驰', price: 100, color:'橄榄绿' });

//toRefs, toRef是为了让对象进行解构赋值之后仍然具有响应式的能力
//解构赋值 --  多个  --  toRefs
let {brand,price} =  toRefs(car);

//解构赋值 --  单个  --  toRef
let color = toRef(car,'color');

function changeCar(){
  //修改方式一
  // car.brand = '法拉利'
  // car.price += 10;

  //修改方式二
  brand.value = '法拉利'
  price.value += 10;

  //单一解构修改
  color.value = '霞光紫'
}

七:computed

作用:根据已有数据计算出新数据(和Vue2中的computed作用一致)。

有缓存

<template>
    <div class="person">
    姓:<input type="text" v-model="firstName"> <br>
    名:<input type="text" v-model="lastName"> <br>
    全名:<span>{{fullName}}</span> <br>
    <button @click="changeFullName">全名改为: 石昊</button>
  </div>
</template>

<script lang ='ts' setup>
import {ref, computed } from 'vue'

let firstName = ref('王');
let lastName = ref('林');

//计算属性 —— 只读不可写
// let fullName = computed(() => {
//     return firstName.value + lastName.value;
// })

//计算属性 —— 可读可写
let fullName = computed({
    get(){
        return firstName.value + '-' + lastName.value;
    },
    set(val){
        firstName.value = val.split('-')[0];
        lastName.value = val.split('-')[1];
    }
})

function changeFullName(){
    fullName.value = '石-昊';
}

</script>

八:watch

let watchRefObj = watch(
    // 被监视的数据,
    person,
    (newValue, oldValue)=>{
    console.log(监视回调);
    },{
    // 配置对象
    deep:true
    })

watch的第一个参数是:被监视的数据
watch的第二个参数是:监视的回调
watch的第三个参数是:配置对象(deep、immediate等等.....) 

        deep:深度监听

        immediate: 立即执行,首次加载就进行监听

作用: 监视数据的变化( 和Vue2中的watch作用一致 )

特点: Vue3中的watch只能监视以下四种数据:

  1. ref定义的数据。
  2. reactive定义的数据。
  3. 函数返回一个值( getter函数 )。
  4. 一个包含上述内容的数组。
(1): 监视【ref】定义的【基本类型】数据
<template>
    <h2>情况一: 监视【ref】定义的【基本类型】数据</h2>
    <div>当前求和为:{{sum}}</div>
    <button @click="changeSum()">点我sum+1</button>
    <hr>
</template>

<script lang ='ts' setup>
import {ref, reactive, watch } from 'vue'

// 情况一:监视【ref】定义的【基本类型】数据
//直接写数据名即可,监视的是其value值的改变。不需要 .value
let sum = ref(0);
function changeSum(){
    sum.value ++;
}
let stopwatch = watch(sum, (newValue, oldValue) => {
    console.log('新--' + newValue + '  *******  旧--' + oldValue);
    //超过5就停止监听
    if(newValue >= 5){
        stopwatch();
    }
})

</script>
(2): 监视【ref】定义的【对象类型】数据
<template>
    <h2>情况二: 监视【ref】定义的【对象类型】数据</h2>
    <div>姓名:{{ person.name }}</div>
    <div>年龄:{{ person.age }}</div>
    <button @click="changeName()">修改名字</button>
    <button @click="changeAge()">修改年龄</button>
    <button @click="changePerson()">修改整个人</button>
    <hr>

</template>

<script lang ='ts' setup>
import {ref, reactive, watch } from 'vue'

// 情况二: 监视【ref】定义的【对象类型】数据
// 若修改的是ref定义的对象中的属性, newValue 和 oldValue 都是新值, 因为它们是同一个对象。
// 若修改整个ref定义的对象, newValue 是新值,  oldValue 是旧值, 因为不是同一个对象了。
let person = ref({name:'石昊', age:18});
function changeName(){
    person.value.name += '~'
}
function changeAge(){
    person.value.age += 1
}
function changePerson(){
    person.value = {name:'王林',age:500}
}
//监视整个person对象,因为监视的是对象的地址值,导致不是同一个对象,会发生监听
//deep 会进行深度监听。 监听person下的name和age属性
let watchRefObj = watch(person, (newValue, oldValue)=>{
    console.log('新--' + newValue + '  *******  旧--' + oldValue);
},{deep:true})

//ref定义的类型,只能监听到ref本身
/*如果监听person.value.name会报错 -----  信息如下:
Invalid watch source:  石昊 A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.
*/ 
// let watchRefObjName = watch(person.value.name, (newValue, oldValue)=>{
//     console.log('新--' + newValue + '  *******  旧--' + oldValue);
// })


</script>
(3): 监视【reactive】定义的【对象类型】数据
<template>

    <h2>情况三: 监视【reactive】定义的【对象类型】数据</h2>
    <div>深度测试:{{obj.a.b.c}}</div>
    <button @click="test()">修改obj.a.b.c</button>
    <hr>

</template>

<script lang ='ts' setup>
import {ref, reactive, watch } from 'vue'

// 情况三: 监视【reactive】定义的【对象类型】数据
//默认开启了深度监视
let obj = reactive({
    a:{
        b:{
            c:666
        }
    }
})
function test(){
    obj.a.b.c = 999;
}
let testDeepWatch = watch(obj,(newValue, oldValue) => {
    console.log('新--' + newValue.a.b.c + '  *******  旧--' + oldValue.a.b.c);
})

</script>
(4): 监视【ref】或【reactive】定义的【对象类型】数据中的某个属性
(5): 监视上述的多个数据
<template>

    <h2>情况四: 监视【ref】或【reactive】定义的【对象类型】数据中的某个属性</h2>
    <div>姓名:{{ info.name }}</div>
    <div>年龄:{{ info.age }}</div>
    <div>汽车:{{ info.car.c1 }}、{{ info.car.c2 }}</div>
    <button @click="changeInfoName">修改名字</button>
    <button @click="changeInfoAge">修改年龄</button>
    <button @click="changeC1">修改第一台车</button>
    <button @click="changeC2">修改第二台车</button>
    <button @click="changeCar">修改整个车</button>
    <hr>

    <h2>情况五:监视上述的多个数据</h2>
    <div>直接监听情况四中的姓名, 年龄, 汽车</div>

</template>

<script lang ='ts' setup>
import {ref, reactive, watch } from 'vue'

// 情况四:监视【ref】或【reactive】定义的【对象类型】数据中的某个属性 
let info = reactive({
    name:'火灵儿',
    age:18,
    car:{
        c1:'奔驰',
        c2:'宝马'
    }
})

function changeInfoName(){
    info.name += '~'
}
function changeInfoAge(){
    info.age += 1
}
function changeC1(){
    info.car.c1 = '奥迪'
}
function changeC2(){
    info.car.c2 = '特斯拉'
}
function changeCar(){
    info.car = {c1:'小米',c2:'法拉利'}
}
//监听对象中的某个属性,若该属性是基本类型的,要写成函数式
let infoAgeWatch = watch(()=>info.age, (newValue, oldValue)=>{
    console.log('新--' + newValue + '  *******  旧--' + oldValue);
})
//监视对象中的某个属性,若该属性是对象类型的,可以直接写,也可写函数,更推荐写函数
/*注意:
    1:直接写 - info.car      修改对象的单一属性可触发监听,修改整体属性,不触发
    2:函数式 - ()=>info.car  修改对象的整体属性可触发监听,修改单一属性,不触发,使用深度监听deep可以解决这个问题
    */
let infoCarWatch = watch(()=>info.car, (newValue, oldValue)=>{
    console.log('新--' + JSON.stringify(newValue) + '  *******  旧--' + JSON.stringify(oldValue));
},{deep:true})


// 情况五:监视上述的多个数据
//监听数据类型为数组,打印值如此:火灵儿~,19,[object Object]
let moreDataWatch = watch([()=> info.name,()=> info.age, ()=>info.car], (newValue, oldValue)=>{
    console.log('多个数据变化:新--' + newValue + '  *******  旧--' + oldValue);
},{deep:true})

</script>

九:watchEffect

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

watch对比watchEffect

1. 都能监听响应式数据的变化,不同的是监听数据变化的方式不同

2. watch: 要明确指出监视的数据

3. watchEffect: 不用明确指出监视的数据(函数中用到哪些属性,自动监听)。

<template>
    <h1>需求: 水温达到80℃, 或水位达到30cm, 请求服务</h1>
    <h2>水温: {{temp}}</h2>
    <h2>水位: {{height}}</h2>
    <button @click="changePrice">水温+10</button>
    <button @click="changeSum">水位+6</button>
</template>

<script lang ='ts' setup>
import {ref, watchEffect } from 'vue'

let temp = ref(20);
let height = ref(0);

function changePrice(){
    temp.value += 10;
}
function changeSum(){
    height.value += 6;
}

//watchEffect不需要指明监听哪些属性,自动监视
let stopWtach = watchEffect(()=>{
    if(temp.value >= 80 || height.value >= 30){
        console.log('请求服务')
    }
    // 水温达到100,或水位达到50,取消监视
    if(temp.value === 100 || height.value === 50){
        console.log('清理了')
        stopWtach()
    }
})

</script>

十:ref

作用:用于注册模板引用。

1: 用在普通DOM标签上,获取的是DOM节点。

2: 用在组件标签上,获取的是组件实例对象。

defineExpose用来暴露组件内的数据(默认被保护)

//APP组件
<template>
  <theRefTag ref="title1"/>
  <button @click="showLog">父 - 点我打印</button>
</template>
<script setup lang="ts">

import theRefTag from './components/theRefTag.vue';
import {ref } from 'vue'

//1:用在普通html标签上是没有问题,获取的是DOM节点。
//2:用在组件标签上,是绑定的组件内的内容,获取的是组件实例对象。但是不可以直接看到,需要借助defineExpose来暴露内容
let title1 = ref();
function showLog(){
    console.log(title1.value)
}
</script>
//子组件 - theRefTag.vue
<template>
    <div ref = "title1">清明</div>
    <div ref = "title2">五一</div>
    <div ref = "title3">端午</div>
    <button @click="showLog">子 - 点我打印</button>
</template>

<script lang ='ts' setup>
import {ref, defineExpose} from 'vue'
//防止id名称在组件内混淆,引入的ref。只在本vue中生效
let title1 = ref();
let title2 = ref();
let title3 = ref();

function showLog(){
    console.log(title1.value)
}

// 借助defineExpose来暴露内容,将组件中的数据交给外部
defineExpose({title1,title2})

</script>

十一:props

用法:

* defineProps:接收 defineProps(数组类型):defineProps(['list','a'])

* <>:范式,用来限制类型:defineProps<{list:PersonList}>();

* withDefaults:指定默认值 withDefaults(类型,值:对象格式):

withDefaults(defineProps<{list:PersonList}>(), {

        list:()=>[{id:4,name:'云曦',sex:'女',age:18}]

})

//APP.vue
<template>
  <theTsInterface :list="personList" a="123"/>
</template>

<script setup lang="ts">
import { reactive } from 'vue';
import {type PersonList} from '@/types/person';

import theTsInterface from './components/theTsInterface.vue';

let personList = reactive<PersonList>([
    {id:1,name:'石昊',sex:'男',age:18},
    {id:2,name:'火灵儿',sex:'女',age:18},
    {id:3,name:'清漪',age:18}
])

</script>


//theTsInterface.vue
<template>
    <!-- <div>a:{{a}}</div> -->
    <ul>
        <li v-for="item in list" :key="item.id">
            {{item.name}}--{{item.age}}
        </li>
    </ul>
    
</template>

<script lang ='ts' setup>
import { PersonList } from '@/types/person';

//defineProps, withDefaults在vue3中属于宏方法,可以不引入直接使用
// import {defineProps, withDefaults} from 'vue'


// 第一种写法:仅接收。数组,可接受多个
// defineProps(['list','a'])

// 第二种写法:接收+限制类型
// 父组件只能传递自组件指定的类型
// defineProps<{list:PersonList}>();

// 第三种写法:接收+限制类型+指定默认值+限制必要性
/***
 * 注意
 * defineProps:接收 defineProps(数组类型)
 * <>:范式,用来限制类型
 * withDefaults:指定默认值 withDefaults(类型,值:对象格式)
*/
withDefaults(defineProps<{list:PersonList}>(), {
    list:()=>[{id:4,name:'云曦',sex:'女',age:18}]
})

</script>

十二:生命周期

概念:Vue组件实例在创建时要经历一系列的初始化步骤, 在此过程中Vue会在合适的时机, 调用特定的函数, 从而让开发者有机会在特定阶段运行自己的代码, 这些特定的函数统称为: 生命周期钩子,简单来说,就是vue自动调用对应的钩子函数。

创建阶段: setup(无需再次引入,直接创建)

挂载阶段: onBeforeMount、onMounted

更新阶段: onBeforeUpdate、onUpdated

卸载阶段: onBeforeUnmount、onUnmounted

//父组件 APP.vue
<template>
  <theRefTag ref="title1" v-if="showTag"></theRefTag>
  <button @click="showLog">父 - 点我打印</button>
</template>

<script setup lang="ts">
import { ref,reactive } from 'vue';
import theRefTag from './components/theRefTag.vue';

let title1 = ref();
let showTag = ref(true);
function showLog(){
    console.log(title1.value);
    showTag.value = !showTag.value;
}

</script>
//子组件theRefTag.vue
<template>
    <div ref = "title1">清明</div>
    <div ref = "title2">五一</div>
    <div v-if="showDuan">端午</div>
    <button @click="showLog">子 - 打印 并 显隐端午标签</button>

</template>

<script lang ='ts' setup>
import {ref, defineExpose} from 'vue'

import { onBeforeMount, onBeforeUnmount, onBeforeUpdate, onMounted, onUnmounted, onUpdated } from 'vue';

console.log('setup中即为生命周期 - 创建')

onBeforeMount(()=>{
    console.log('挂载之前');
})
onMounted(()=>{
    console.log('挂载完毕');
})
onBeforeUpdate(()=>{
    console.log('更新之前');
})
onUpdated(()=>{
    console.log('更新完毕');
})
onBeforeUnmount(()=>{
    console.log('卸载之前');
})
onUnmounted(()=>{
    console.log('卸载完毕');
})


//防止id名称在组件内混淆,引入的ref。只在本vue中生效
let title1 = ref();
let title2 = ref();

let showDuan = ref(true);

function showLog(){
    console.log(title1.value);

    showDuan.value = !showDuan.value;
}

// 借助defineExpose来暴露内容,将组件中的数据交给外部
defineExpose({title1,title2})

</script>

十三:自定义hooks

定义:本质是一个函数,把setup函数中使用的Composition API进行了封装,类似于vue2.x中的mixin。

优势:复用代码, 让setup中的逻辑更清楚易懂。每个功能点一个单独的ts文件。

  1. 可复用功能抽离为外部ts文件

  2. 文件名以use开头,形如:useSum

  3. 引用时将响应式变量或者方法显式解构暴露出来如:let {sum, add, bigAdd} = useSum();在setup函数解构出自定义hooks的变量和方法

注意⚠️:在hooks中依然可以使用生命周期钩子函数

//theHooks.vue
<template>
    <h2>当前求和为:{{sum}}</h2>
    <button @click="add">点我+1</button>
    <button @click="bigAdd">点我*10</button>
    <hr>
    <img v-for="(dog,index) in dogList" :key="index" :src="dog"> 
    <br>
    <button @click="getDog">再来一只狗</button>
</template>

<script lang ='ts' setup>
import {ref, defineExpose, reactive} from 'vue'
import axios,{AxiosError}  from 'axios'

import useSum from '../hooks/useSum'
import useDog from '../hooks/useDog'
let {sum, add, bigAdd} = useSum();
let {dogList,getDog} = useDog();

</script>

//useSum.ts
import {ref,onMounted} from 'vue'
export default function(){
    const sum = ref(1);
    function add(){
        sum.value ++;
    }
    function bigAdd(){
        sum.value *= 10;
    }
    //向外部暴露数据
    return {sum, add, bigAdd}
}

//useDog.ts
import { reactive } from "vue";
import axios, {AxiosError} from "axios";

//使用default,可以不用写方法名。不使用default,必须写方法名
export default function dog(){
    const dogList = reactive(['https://images.dog.ceo/breeds/pembroke/n02113023_1896.jpg'])

    //使用axios进行异步接口调用,使用try-catch进行接口失败处理
    //一个第三方接口,可以随机返回图片
    async function getDog(){
        try{
            const {data} = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
            console.log(data);
            // 维护数据
            dogList.push(data.message);
        }catch(error){
            // 处理错误
            const err = <AxiosError>error
            console.log(err.message)
        }
    }

    //必须将声明的变量或方法向外部暴露
    return {dogList, getDog}
}

ts相关

interface:自定义接口

<>: 范型

type:自定义类型

//theTsInterface.vue
<script lang ='ts' setup>
import {type PersonInter, type PersonList} from '../types/person';

let person:PersonInter = {id:1,name:'石昊',sex:'男',age:18}
console.log(person);

// 写法一:
//<PersonInter,XXX,XXX> 即为范型,可以有多个范型
// let personList:Array<PersonInter> = [
//     {id:1,name:'石昊',sex:'男',age:18},
//     {id:2,name:'火灵儿',sex:'女',age:18},
//     {id:3,name:'清漪',age:18}
// ]

// 写法二:
let personList:PersonList = [
    {id:1,name:'石昊',sex:'男',age:18},
    {id:2,name:'火灵儿',sex:'女',age:18},
    {id:3,name:'清漪',age:18}
]
console.log(personList);

</script>

//person.ts
//定义一个Person接口,用来限制person对象的具体属性
export interface PersonInter{
    id: number
    name: string,
    sex?: string,//可选属性
    age: number,
}

//自定义类型
export type PersonList = Array<PersonInter>
// 或者
// export type PersonList = PersonInter[]

  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值