Vue3学习(一)

组合式API

选项式api是将同一类选项放在一起,比如,所有data放在一起,methods放在一起。这种方式来说,各个功能上来说,各个功能的data和methods都混在一起了,比如功能1的data和功能2的data混在一起,功能1的methods和功能2的methods混在一起,就会显得很混乱,不易于维护。

组合式api是将同一类功能放在一起。比如功能1的data和功能1的methods放在一起,功能2的data和功能2的methods也放一起,按功能来组合。达到功能高内聚的效果,易于维护。

setup函数语法糖

原始的setup函数,要在函数中定义大量数据后,再将这些数据一个一个return返回

<script>
export default {
  setup () {
    console.log('setup执行了')
    console.log(this)
    // 定义数据和函数
    const msg = 'hi vue3'
    const say = () => {
      console.log(msg)
    }
 
    return { msg , say}
  }
}
</script>

数据多的情况下,看起来就会很乱,而且return语句中会很不好看,于是有了setup函数语法糖:

<script lang="ts" setup>
   
    let name = "二狗";
    let age = 20;
    let tel = "18888888888";
    let introduction = "一定要成为编程大牛";

function changeAge() {
    age += 1;
    console.log(age);
}

function showIntroduction() {
    introduction = "一定要成为编程大牛!!!";
    console.log(introduction);
}
</script>

这时的在script标签中的数据默认就当作全都return返回了。

响应式

ref

如果要让一个数据变成响应式的,就要让这个数据在定义的时候被ref函数包裹后再赋值给变量(要先从vue中引入ref函数)。这时的变量是一个RefImpl类型的了,要对原来的数据进行修改,要使用 变量.value 的方式,对这个value进行修改。

<script lang="ts" setup>
import { ref } from 'vue';

    let name = ref('张三')
    let age = ref(18)
    function changeName(){
        name.value = '二狗'
    }
    function addAge(){
        age.value++
    }
</script>

ref定义对象类型数据:(底层其实使用了reactive)

    let car2 = ref({brand:'宝马',price:100})
    function changePrice2(){
        car2.value.price += 20;
    }

    let chiikawa2 = ref([
        {id:1,name:'吉伊',color:'白馒头'},
        {id:2,name:'小八',color:'蓝裤衩头白猫'},
        {id:3,name:'小八',color:'黄色怪叫兔'}
    ])
    function change537_2(){
        chiikawa2.value[2].name = "乌萨奇"
    }

reactive

对象类型的数据,要包裹在reactive函数中再赋值给变量,此时的变量是一个代理对象,Proxy类型的。响应式后要更改对象的属性,就不是.value了,而是直接更改。

<script lang="ts" setup>
    import { ref, reactive } from 'vue';
    let car = reactive({brand:'奔驰',price:100})

    let chiikawa = reactive([
        {id:1,name:'吉伊',color:'白馒头'},
        {id:2,name:'小八',color:'蓝裤衩头白猫'},
        {id:3,name:'小八',color:'黄色怪叫兔'}
    ])

    function changePrice(){
        car.price += 20;
    }

    function change537(){
        chiikawa[2].name = "乌萨奇"
    }
</script>

reactive只能用来定义对象类型的响应式数据。

ref和reactive总结

  • ref创建的变量必须要用.value的方式去获取和修改数据
  • reactive重新分配一个新对象,会失去响应式,要想不失去响应式,可以使用Object.assign(变量名,新对象) 的方式,给目标变量一个新的对象值。
  • 若需要一个基本类型的响应式数据,必须使用ref,若需要一个响应式对象,层级不深,ref和reactive都可以,若需要一个响应式对象,且层级较深,推荐使用reactive。

toRefs和toRef

如果要将对象中的数据解构取出使用,就要使用toRefs和toRef函数。

    import { ref, reactive, toRefs ,toRef} from 'vue';
    let car = reactive({brand:'奔驰',price:100})

    let {brand,price} = toRefs(car)
    let nl = toRef(car,'brand')

提取单个属性值,使用toRef,提取多个属性值,使用toRefs

计算属性

定义:如果一个要用的数据,而是由已有的属性(data中的属性)计算得来,那么可以将其作为计算属性

计算属性的变量也是一个ref的值,只要参与计算属性的值的计算的某个变量发生了变化,计算属性的值也会实时更新。

<template>
  <div class="person">
    姓:<input type="text" v-model="firstName"><br>
    名:<input type="text" v-model="lastName"><br>
    全名:<span>{{fullName}}</span><br>
  </div>
</template>

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

    let firstName = ref('zhang')
    let lastName = ref('san')

    let fullName = computed(() => {
        return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '-' + lastName.value
    })
</script>

如果是要定义可读可写的计算属性:

     let fullName2 = computed({
        get(){
            return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '-' + lastName.value
        },
        set(val){ //val参数就是此计算属性新修改的值
            const x = val.split('-')
            firstName.value=x[0]
            lastName.value=x[1]
        }
    })

    function changeFullName(){
        fullName2.value = 'li-si'
    }

watch监视

监视即在发现数据发生变化的时候,要进行某些逻辑。

在vue3中,watch只能监视以下四种数据:

ref定义的数据、reactive定义的数据、函数返回一个值(getter)、一个包含上述内容的数组。

<template>
  <div>
    <h2>sum的值为:{{ sum }}</h2>
    <button @click="addSum">加一</button>
  </div>
</template>

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

    let sum = ref(0)
    function addSum(){
        sum.value++
    }
    //监视
    watch(sum,(newValue,oldValue)=>{
        console.log('sum变化了')
    })
</script>

如果想要解除监视,可以用一个变量接收watch返回的值,它返回的值是一个函数,当调用这个函数后,就会结束对应的监视。

    function addSum(){
        sum.value++
        if(sum.value >= 10){
            stop()
        }
    }
    //监视
    const stop = watch(sum,(newValue,oldValue)=>{
        console.log('sum变化了')
    })

监视对象类型的数据

若要监视对象类型的数据,通常要加入第三个参数,这个参数用于指定一些配置项,比如:是否深度监视(即检测到对象的属性的变化),是否在初始化的时候立即执行一次,等等。

<script lang="ts" setup>
  import { ref,watch } from 'vue';
    let person = ref({
        name:'张三',
        age:18
    })

    function changeName(){
        person.value.name += '~'
    }

    function changeAge(){
      person.value.age++
    }

    function changePerson(){
      person.value = {name:'李四',age:19}
    }

    watch(person,(newValue,oldValue)=>{    //要想设置为对监视的对象类型的数据的深度监视,要加配置项
      console.log('person变化了',newValue,oldValue)
    },{//第三个参数用于加其他配置项
      deep:true,//开启深度监视
      immediate:true//一来的时候先执行一次监视的函数中要执行的操作
    })
</script>

此处的oldValue如果是直接改整个对象,oldValue就是之前的对象值。如果改的是对象的属性,oldValue和newValue是同一个值,因为还是同一个对象。

如果是使用reactive定义的对象类型的数据,默认是自动开启深度监视的

<script lang="ts" setup>
  import { reactive,watch } from 'vue';
    let person = reactive({
        name:'张三',
        age:18
    })

    function changeName(){
        person.name += '~'
    }

    function changeAge(){
      person.age++
    }

    function changePerson(){
      Object.assign(person,{name:'李四',age:19})
    }

    watch(person,(newValue,oldValue)=>{ //reactive定义的对象类型的数据被监视的时候,默认是开启深度监视的
      console.log('person变化了',newValue,oldValue)
    })
</script>

如果只想监视对象的其中一个基本类型的属性,第一个参数写作一个getter函数,并且此时的监视,由于检测的是具体的属性,而不是对象。所以修改的时候,oldValue参数的值就是修改前的值

<script lang="ts" setup>
  import { reactive,watch } from 'vue';
    let person = reactive({
      name:'张三',
      age:18,
      car:{
        brand:'奔驰',
        color:'red'
      }
    })

    function changeName(){
      person.name += '~'
    }
    function changeAge(){
      person.age++
    }
    function changeCarBrand(){
      person.car.brand = '宝马'
    }
    function changeCarColor(){
      person.car.color = 'green'
    }
    function changeCar(){
      person.car = {brand:'迈巴赫',color:'black'}
    }

    watch(()=>{return person.age},(newValue,oldValue)=>{
      console.log('年龄变化为'+newValue+','+'旧值为'+oldValue)
    })
</script>

如果要监视的对象a的属性还是一个对象b,如果直接写该属性作为第一个参数,也可以监视到其对象b的属性值的变化。但是如果对象b的整个对象值发生变化的时候,不能监视到。

所以,建议此对象b的监视也写作getter函数的形式作为第一个参数。但是此时要监视对象b的属性值的变化,要使用深度监视,也就是加上第三个参数配置项中的deep为true

watch(()=>person.car,(newValue,oldValue)=>{
      console.log('person.car发生变化了',newValue,oldValue)
    },{deep:true})

如果要如此局部监视多个指定的属性,可以写作一个数组的方式

watch([()=>person.age,()=>person.car.color],(newValue,oldValue)=>{
      console.log('发生变化了',newValue,oldValue)
},{deep:true})

WathEffect监视

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

就是在函数中用到了那些数据,就检测那些数据,案例:

<template>
  <div class="person">
    <h2>需求:当水温达到60度,或者水位达到80cm的时候,给服务器发请求</h2>
    <h2>当前水温:{{ temp }}℃</h2>
    <h2>当前水位:{{ height }}cm</h2>
    <button @click="changeTemp">改变温度</button>
    <button @click="changeHeight">改变高度</button>
  </div>
</template>

<script lang="ts" setup>
    import {ref,watch, watchEffect} from 'vue';
    let temp = ref(10);
    let height = ref(0);

    function changeTemp(){
        temp.value += 10
    }

    function changeHeight(){
        height.value += 10
    }

    //watch实现
    watch([temp,height],(newValue)=>{
      let [newTemp,newHeight] = newValue
      if(newTemp >= 60 || newHeight >=80){
        console.log('给服务器发请求')
      }
    })

    //watchEffect实现
    watchEffect(()=>{
      if(temp.value >= 60 || height.value >= 80){
        console.log('给服务器发请求')
      }
    })
</script>

关于ref属性

  • 被用来给元素或子组件注册引用信息(id的替代者)
  • 引用在html标签上,获取到的是真实的DOM元素;应用在组件标签上,获取到的是组件的实例对象
  • 使用方式:
    • 在相应的标签上,给上ref属性。
    • 获取:let xxx = ref(),其中xxx指的是相应的标签的ref属性的属性值。
  • 但是获取到的组件实例对象默认是受保护的,要是想向外暴露对应的实例对象中的属性,就使用defineExpose函数在组件中将对指定的属性暴露出去:defineExpose({属性,属性,……})

关于props的使用

要是子组件的某个属性想要由父组件来决定,以达到更好的复用效果。就要使用props属性

定义props属性:

<template>
  <h2>
    {{ a }}
  </h2>
</template>

<script lang="ts" setup>
    import { defineProps } from 'vue';
    //接收a
    let x = defineProps(['a'])
    console.log(x)

</script>

在defineProps函数中,定义的属性可以直接由template引用(如上方的a),但是不能直接在script中使用,要用一个变量接收后再到script中使用

父组件:

<PropsLearning a="你好"></PropsLearning>

如果是想引用父组件中的某个变量,比如有一个变量let hello:string = ‘你好’,就要在相应的props属性前加上 : ,表示将属性值 ” ” 中的内容解析为表达式。

如果想要限制props的类型,可以使用泛型的方式,写法如下:

defineProps<{b:string}>()

如果想要让b可有也可无,就在b后面加上一个?,例:

defineProps<{b?:string}>()

如果还想让其在不传值的时候,有一个默认值,要引入withDefaults函数:

import { defineProps,withDefaults } from 'vue';

    // 定义组件的props,包括a和c+d,并设置c和d的默认值
    const props = withDefaults(defineProps<{
      a?: string; // 可选的字符串类型的prop
      c?: string; // 可选的字符串类型的prop
      d?: number; // 可选的数字类型的prop
    }>(), {
      c: 'hello', // 设置默认值
      d: 100, // 设置默认值
    });

如果要给默认值的属性是数组或者对象类型的,要使用箭头函数返回其要赋的值

Vue3生命周期

1、setup() : 开始创建组件,在 beforeCreate 和 created 之前执行,创建的是 data 和 method

2、onBeforeMount() : 组件挂载到节点上之前执行的函数;

3、onMounted() : 组件挂载完成后执行的函数;

4、onBeforeUpdate(): 组件更新之前执行的函数;

5、onUpdated(): 组件更新完成之后执行的函数;

6、onBeforeUnmount(): 组件卸载之前执行的函数;

7、onUnmounted(): 组件卸载完成后执行的函数;

8、onActivated(): 被包含在 <keep-alive> 中的组件,会多出两个生命周期钩子函数,被激活时执行;

9、onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行;

10、onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数。

自定义Hooks

hooks用于将功能分离出到相应的ts文件中,组件要引入相应的功能的时候,引入相应的hooks的ts文件即可,更符合高内聚低耦合的理念。

例:

组件:

用解构表达式将相应的ts文件中导出的内容引用到组件中。

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

<script lang="ts" setup>
    import useDogs from '@/hooks/useDogs';
    import useSum from '@/hooks/useSum';
    const {sum,add} = useSum()
    const {dogList,getDog} = useDogs()
</script>

<style>
    img{
        height: 100px;
        margin-right: 10px;
    }
</style>

hooks中的useDogs.ts:

ts数据要使用export导出,将要导出的数据封装为对象的形式return出去。

import { ref,reactive } from 'vue';
import axios from 'axios';

export default function(){
    //数据
    let dogList = reactive([
        '<https://images.dog.ceo/breeds/kombai/Kombai-indian-Dog.jpg>'
    ])
    //方法

    async function getDog(){
        try{
            let result = await axios.get('<https://dog.ceo/api/breeds/image/random>')
            dogList.push(result.data.message)
        }catch(error){
            alert(error)
        }
    }

    
    return {dogList,getDog}
}

hooks中的useSum.ts:

import { ref,reactive } from 'vue';
import axios from 'axios';
export default function(){
    //数据
    let sum = ref(0)
    //方法
    function add(){
        sum.value++
    }
    return {sum,add}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会敲代码的熊mao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值