vue3(下)

生命周期

概念:Vue组件实例在创建时要经历一系列的初始化步骤,在此过程中Vue会在合适的时机,调用特定的函数

Vue2的生命周期

  • 生命周期整体分为四个阶段,分别是:创建、挂载、更新、销毁

  • 创建阶段:beforeCreatecreated

    挂载阶段:beforeMountmounted

    更新阶段:beforeUpdateupdated

    销毁阶段:beforeDestroydestroyed

Vue3的生命周期

  • 生命周期整体分为四个阶段,分别是:创建、挂载、更新、卸载

  • 创建阶段:setup

    挂载阶段:onBeforeMountonMounted

    更新阶段:onBeforeUpdateonUpdated

    卸载阶段:onBeforeUnmountonUnmounted

    • 停止语句-> debugger

    • 销毁在父里用 v-show=变量名 (false)隐藏 || v-if(false)连同结构一起删

  • 常用的钩子:onMounted(挂载完毕)、onUpdated(更新完毕)、onBeforeUnmount(卸载之前)

自定义hook

本质是一个函数,把setup函数中使用的Composition API进行了封装。

自定义hook的优势:复用代码, 让setup中的逻辑更清楚易懂。

在.ts另外写一个 引入、用函数封装的{对象,方法},必须暴露出去export default 默认暴露,后面直接跟一个值

如果只是export 后面跟着的是一个函数必须起名export default function(){}

调用:先引入,后调用(主文件中......vue)

<script setup lang="ts">
  import useSum from './hooks/useSum'
  import useDog from './hooks/useDog'
	
  let {sum,increment,decrement} = useSum()
  let {dogList,getDog} = useDog()
</script>

请求方法(重点单词async await axios try catch)

axios 只会请求正确的接口,if接口错误会什么都没有。必须得先引入


import {reactive,onMounted} from 'vue'
import axios,{AxiosError} from 'axios'

async try await catch捕捉错误并提示


async function getDog(){
    try {
      // 发请求
      let {data} = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
      // 维护数据
      dogList.push(data.message)
    } catch (error) {
      // 处理错误
      const err = <AxiosError>error
      console.log(err.message)
    }
  }

路由

基本切换效果

//创建一个路由器并暴露出去(引入+创建)
import {createRouter,createWebHistory} from 'vue-router'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import About from '@/pages/About.vue'

//创建路由器
const router = createRouter({
	history:createWebHistory(),//路由器的工作模式
    //路由:对象们[{path:'路径',component:'组件'}...{}]
	routes:[
		{
			path:'/home',
			component:Home
		},
		{
			path:'/about',
			component:About
		}
	]
})
//暴露
export default router

main.ts代码(操作,路由参与代码)

import router from './router/index'

//App根组件的使用

//创建一个应用

//使用路由器

app.use(router)

//挂载整个应用到app容器中

app.mount('#app')

使用App.vue

引入路由器后在html里 <RouterView></RouterView> import {RouterLink,RouterView} from 'vue-router'

路由器工作模式

history模式

优点:URL更加美观,不带有#,更接近传统的网站URL

缺点:后期项目上线,需要服务端配合处理路径问题,否则刷新会有404错误。


const router = createRouter({
    history:createWebHistory(), //history模式
    /******/
})

hash模式

优点:兼容性更好,因为不需要服务器端处理路径。

缺点:URL带有#不太美观,且在SEO优化方面相对较差。


const router = createRouter({
    history:createWebHashHistory(), //hash模式
    /******/
})

4.5. 【to的两种写法】


<!-- 第一种:to的字符串写法 -->
<router-link active-class="active" to="/home">主页</router-link>
​
<!-- 第二种:to的对象写法 -->
<router-link active-class="active" :to="{path:'/home'}">Home</router-link>
ink>

嵌套路由

  1. 编写News的子路由:Detail.vue

  2. 配置路由规则,使用children配置项:

跳转路由:


<!--简化前:需要写完整的路径(to的字符串写法) -->
<router-link to="/news/detail">跳转</router-link>
​
<!--简化后:直接通过名字跳转(to的对象写法配合name属性) -->
<router-link :to="{name:'guanyu'}">跳转</router-l

路由的props配置

作用:让路由组件更方便的收到参数(可以将路由参数作为props传给组件)

props的对象写法,作用:把对象中的每一组key-value作为props传给Detail组件
  props:{a:1,b:2,c:3}, 
// props的布尔值写法,作用:把收到了每一组params参数,作为props传给Detail组件
  props:true
  //在vue里直接调用 defineProps(['id','title','content'])
// props的函数写法,作用:把返回的对象中每一组key-value作为props传给Detail组件
  props(route){
    return route.query

replace属性

  1. 作用:控制路由跳转时操作浏览器历史记录的模式。

  2. 浏览器的历史记录有两种写入方式:分别为pushreplace

    • push是追加历史记录(默认值)。

    • replace是替换当前记录。

  3. 开启replace模式:

  4. <template> 里的Routerlink 后

    
    <RouterLink replace .......>News</RouterLink>

编程式导航

路由组件的两个重要的属性:$route$router变成了两个hooksto

重定向

  1. 作用:将特定的路径,重新定向到已有路由。

  2. 具体编码:

    
    {
        path:'/',
        redirect:'/about'
    }

pinia

准备一个效果

存储+读取数据

  1. Store是一个保存:状态业务逻辑 的实体,每个组件都可以读取写入它。

  2. 它有三个概念:stategetteraction,相当于组件中的: datacomputedmethods

  3. 具体编码:src/store/count.ts

    // 引入defineStore用于创建store
    import {defineStore} from 'pinia'
    ​
    // 定义并暴露一个store
    export const useCountStore = defineStore('count',{
      // 动作
      actions:{},
      // 状态(真正储存数据的地方)
      state(){
        return {
          sum:6
        }
      },
      // 计算
      getters:{}
    })

修改数据

  1. 第一种修改方式,直接修改

    ​ const countStore=useCountStore()

    
    countStore.sum = 666
  2. 第二种修改方式:批量修改($patch)

    
    countStore.$patch({
      sum:999,
      school:'atguigu'
    })
  3. 第三种修改方式:借助action修改(action中可以编写一些业务逻辑)

    ​ actions里面放置的是一个一个的犯法,用于响应组件中的“动作”

    
    import { defineStore } from 'pinia'
    ​
    export const useCountStore = defineStore('count', {
      /*************/
      actions: {
        //加
        increment(value:number) {
          if (this.sum < 10) {
            //操作countStore中的sum
            this.sum += value
          }
        },
        //减
        decrement(value:number){
          if(this.sum > 1){
            this.sum -= value
          }
        }
      },
      /*************/
    })
  4. 组件中调用action即可

    
    // 使用countStore
    const countStore = useCountStore()
    ​
    // 调用对应action
    countStore.incrementOdd(n.value)

getters

  1. 概念:当state中的数据,需要经过处理后再使用时,可以使用getters配置。

  2. 追加getters配置。

 getters:{
    bigSum:(state):number => state.sum *10,
    upperSchool():string{
      return this. school.toUpperCase()
    }
  }
  1. 组件中读取数据:

    
    const {increment,decrement} = countStore
    let {sum,school,bigSum,upperSchool} = storeToRefs(countStore)

$subscribe

通过 store 的 $subscribe() 方法侦听 state 及其变化


talkStore.$subscribe((mutate,state)=>{
  console.log('LoveTalk',mutate,state)
  localStorage.setItem('talk',JSON.stringify(talkList.value))
})

store组合式写法

export const useTalkStore = defineStore('talk',()=>{
  // talkList就是state
  const talkList = reactive(
    JSON.parse(localStorage.getItem('talkList') as string) || []
  )

  // getATalk函数相当于action
  async function getATalk(){
    // 发请求,下面这行的写法是:连续解构赋值+重命名
    let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
    // 把请求回来的字符串,包装成一个对象
    let obj = {id:nanoid(),title}
    // 放到数组中
    talkList.unshift(obj)
  }
  return {talkList,getATalk}

组件通信

Vue3组件通信和Vue2的区别:

  • 移出事件总线,使用mitt代替。

  • vuex换成了pinia

  • .sync优化到了v-model里面了。

  • $listeners所有的东西,合并到$attrs中了。

  • $children被砍掉了。

props

概述:props是使用频率最高的一种通信方式,常用与 :父 ↔ 子

  • 父传子:属性值是非函数

  • 子传父:属性值是函数

父组件:


<template>
  <div class="father">
    <h3>父组件,</h3>
        <h4>我的车:{{ car }}</h4>
        <h4>儿子给的玩具:{{ toy }}</h4>
        <Child :car="car" :getToy="getToy"/>
  </div>
</template>
​
<script setup lang="ts" name="Father">
    import Child from './Child.vue'
    import { ref } from "vue";
    // 数据
    const car = ref('奔驰')
    const toy = ref()
    // 方法
    function getToy(value:string){
        toy.value = value
    }
</script>

子组件


<template>
  <div class="child">
    <h3>子组件</h3>
        <h4>我的玩具:{{ toy }}</h4>
        <h4>父给我的车:{{ car }}</h4>
        <button @click="getToy(toy)">玩具给父亲</button>
  </div>
</template>
​
<script setup lang="ts" name="Child">
    import { ref } from "vue";
    const toy = ref('奥特曼')
    
    defineProps(['car','getToy'])
</script>
  1. 概述:自定义事件常用于:子 => 父。

  2. 注意区分好:原生事件、自定义事件。

  • 原生事件:

    • 事件名是特定的(clickmosueenter等等)

    • 事件对象$event: 是包含事件相关信息的对象(pageXpageYtargetkeyCode

  • 自定义事件:

    • 事件名是任意名称

    • <strong style="color:red">事件对象$event: 是调用emit时所提供的数据,可以是任意类型!!!</strong >

  1. 示例:

    
    <!--在父组件中,给子组件绑定自定义事件:-->
    <Child @send-toy="toy = $event"/>
    ​
    <!--注意区分原生事件与自定义事件中的$event-->
    <button @click="toy = $event">测试</button>
    
    //子组件中,触发事件:
    this.$emit('send-toy', 具体数据)

概述:与消息订阅与发布(pubsub)功能类似,可以实现任意组件间通信。

v-model

  1. 概述:实现 父↔子 之间相互通信。

  2. 前序知识 —— v-model的本质

    
    <!-- 使用v-model指令 -->
    <input type="text" v-model="userName">
    ​
    <!-- v-model的本质是下面这行代码 -->
    <input 
      type="text" 
      :value="userName" 
      @input="userName =(<HTMLInputElement>$event.target).value"
    >
  3. 组件标签上的v-model的本质::moldeValueupdate:modelValue事件。

    
    <!-- 组件标签上使用v-model指令 -->
    <AtguiguInput v-model="userName"/>
    ​
    <!-- 组件标签上v-model的本质 -->
    <AtguiguInput :modelValue="userName" @update:model-value="userName = $event"/>

    AtguiguInput组件中:

    
    <template>
      <div class="box">
        <!--将接收的value值赋给input元素的value属性,目的是:为了呈现数据 -->
            <!--给input元素绑定原生input事件,触发input事件时,进而触发update:model-value事件-->
        <input 
           type="text" 
           :value="modelValue" 
           @input="emit('update:model-value',$event.target.value)"
        >
      </div>
    </template>
    ​
    <script setup lang="ts" name="AtguiguInput">
      // 接收props
      defineProps(['modelValue'])
      // 声明事件
      const emit = defineEmits(['update:model-value'])
    </script>

$attrs

  1. 概述:$attrs用于实现当前组件的父组件,向当前组件的子组件通信(祖→孙)。

  2. 具体说明:$attrs是一个对象,包含所有父组件传入的标签属性。

  3. 注意:$attrs会自动排除props中声明的属性(可以认为声明过的 props 被子组件自己“消费”了)


vue3(下)
http://localhost:8090//archives/di-yi-zhou-kao-he-yu-dao-de-wen-ti
作者
文伊仪
发布于
2024年11月24日
许可协议