当前位置: 首页 > article >正文

vue-有关于TS与路由器

title: vue(TS)+路由器
date: 2025-01-28 12:00:00
tags:
  - 前端
categories:
  - 前端

Vue3-第二部分

这里是代码中出现TS的,后面是路由器

现在先上代码,步步分析。

eg1-props的使用

步步分析代码(先理解,再实践)

框架

image-20250128003823892

先分析main.ts

常规出现,就是创建与引入

// 引入createApp用于创建应用
import {createApp} from 'vue'
// 引入App根组件
import App from './App.vue'
​
createApp(App).mount('#app')

分析组件内的person.vue

模版部分
<template>
  <div class="person">
    <ul>
      <li v-for="p in list" :key="p.id">
        { {p.name} } -- { {p.age} }
      </li>
    </ul>
  </div>
</template>

功能说明:

1. 渲染数据列表

• list 是通过 props 传递给 Person 组件的。

• 使用 v-for 循环遍历 list 数组,动态生成 <li> 列表项。

• 每个 li 显示每个对象的 name 和 age。

2. 绑定唯一的 key:

• 使用 :key="p.id" 为每个列表项绑定唯一的 key,提高渲染效率。

脚本部分
<script lang="ts" setup name="Person">
  import { withDefaults } from 'vue'
  import { type Persons } from '@/types'
​
  // 接收list + 限制类型 + 限制必要性 + 指定默认值
  withDefaults(defineProps<{list?: Persons}>(), {
    list: () => [{ id: 'ausydgyu01', name: '康师傅·王麻子·特仑苏', age: 19 }]
  })
</script>

上面的import是什么?

一般是导入工具与类型

• withDefaults:

• 用于为 defineProps 定义的 props 设置默认值。它接收两个参数:

• defineProps 的返回值(包含 props 的类型约束)。

• 一个对象,用来指定每个 prop 的默认值。

• Persons:

• 从 @/types 导入的类型别名,表示一个由多个 person 对象组成的数组,符合以下结构:

也就是如果我要用到 prop的时候用

知识点解析:

1. defineProps:

• Vue 3 提供的 API,用于定义组件接收的 props。

• defineProps<{list?: Persons}>():

• 定义了一个可选的 list 属性,类型为 Persons(数组,每个元素是一个符合 PersonInter 的对象)。

2. withDefaults:

• 用来为可选 props(如 list?)设置默认值。

• 默认值为:

[{ id: 'ausydgyu01', name: '康师傅·王麻子·特仑苏', age: 19 }]

再分析index.ts

// 定义一个接口,用于限制person对象的具体属性
export interface PersonInter {
  id: string,
  name: string,
  age: number,
}
​
// 一个自定义类型
export type Persons = PersonInter[]

1. 接口 PersonInter:

• 定义了 person 对象的结构,强制要求每个对象包含以下属性:

• id:字符串,唯一标识。

• name:字符串,人员姓名。

• age:数字,人员年龄。

2. 类型别名 Persons:

• 定义了一个数组类型,数组的每个元素都必须符合 PersonInter 接口。

App.vue解析

<template>
  <!-- 务必看懂下面这一行代码 -->
  <!-- <h2 a="1+1" :b="1+1" c="x" :d="x" ref="qwe">测试</h2> -->
  
  <Person a="哈哈" />
</template>

静态属性:a = "1 + 1"是一个普通的字符串,直接作为属性值

动态属性:b = "1 + 1"是一个动态表达式,结果会被计算后作为属性值

ref="qwe",绑定DOM引用,可以在JavaScript中通过ref操作这个DOM元素

2. 子组件 <Person /> 的使用:

• <Person /> 是导入的子组件,代表 person.vue 文件。

• a="哈哈" 是传递给 <Person /> 的一个普通属性。

脚本部分

<script lang="ts" setup name="App">
  import Person from './components/Person.vue'
  import { reactive } from 'vue'
  import { type Persons } from '@/types'
​
  let x = 9
​
  let personList = reactive<Persons>([
    { id: 'asudfysafd01', name: '张三', age: 18 },
    { id: 'asudfysafd02', name: '李四', age: 20 },
    { id: 'asudfysaf)d03', name: '王五', age: 22 }
  ])
</script>

1. 引入 Person 组件:

• import Person from './components/Person.vue' 引入 person.vue,使得 <Person /能够在模板中使用。

  1. 定yi响应式数据:

  2. reactive 的作用:

    • 使得 personList 成为响应式数据。当 personList 或其内部的对象属性发生变化时,Vue 会自动更新视图。

整体逻辑总结

Index.ts 定义了personInter接口和Person类型,用来约束person数据结构

Person.vue 接收list作为props,通过withDefaults为list设置默认值

渲染list数据。动态生成列表

App.vue

定义一个响应式数据personalist,并可以通过props传递给pweson.vue

image-20250128010109534

vue2生命周期

<template>
  <div class="person">
    <h2>当前求和为:{ { sum } }</h2>
    <button @click="add">点我sum+1</button>
  </div>
</template>

功能说明:

1. 数据绑定:

• { { sum } } 用来动态展示变量 sum 的值。

• 每次点击按钮,sum 的值增加 1。

2. 事件绑定:

• @click="add":绑定按钮点击事件,触发 add 方法,更新 sum 的值。

<script lang="ts" setup name="Person">
  import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue'

  // 数据
  let sum = ref(0)

  // 方法
  function add() {
    sum.value += 1
  }

  // 创建
  console.log('创建')

  // 挂载前
  onBeforeMount(() => {
    // console.log('挂载前')
  })

  // 挂载完毕
  onMounted(() => {
    console.log('子---挂载完毕')
  })

  // 更新前
  onBeforeUpdate(() => {
    // console.log('更新前')
  })

  // 更新完毕
  onUpdated(() => {
    // console.log('更新完毕')
  })

  // 卸载前
  onBeforeUnmount(() => {
    // console.log('卸载前')
  })

  // 卸载完毕
  onUnmounted(() => {
    // console.log('卸载完毕')
  })
</script>

image-20250128011042599

app.vue

<template>
  <Person v-if="isShow" />
</template>

1. <Person v-if="isShow" /

• 条件渲染子组件 Person。

• 当 isShow 为 true 时,<Person / 会被挂载。

• 当 isShow 为 false 时,<Person /会被卸载。

脚本部分

<script lang="ts" setup name="App">
  import Person from './components/Person.vue'
  import { ref, onMounted } from 'vue'

  let isShow = ref(true)

  // 挂载完毕
  onMounted(() => {
    console.log('父---挂载完毕')
  })
</script>

功能解析:

1. 引入子组件:

• Person 是一个子组件,来自 ./components/Person.vue。

2. 响应式数据:

• let isShow = ref(true):定义了一个响应式布尔值 isShow,控制 <Person /> 的显示和隐藏。

3. 生命周期钩子:

• onMounted:在 App 组件挂载到 DOM 后执行。这里输出 父---挂载完毕,用于标记父组件挂载完成。

运行流程

  1. 父组件挂载(App

• isShow 默认为 true。

• <Person / 被挂载到 DOM 中。

• 控制台输出:

父---挂载完毕
创建
子---挂载完毕

. 子组件更新(Person

• 点击按钮时,sum.value 增加 1,触发子组件更新。

• 在更新阶段,执行以下生命周期钩子:

• onBeforeUpdate

• onUpdated

3. 子组件卸载(Person

• 如果将 isShow 设置为 false(例如通过交互),<Person /> 会被卸载。

• 卸载阶段执行:

• onBeforeUnmount

• onUnmounted

5. 总结

person.vue 的功能

• 通过按钮点击实现 sum 的动态更新。

• 使用 Vue 3 的生命周期钩子监控组件的各个阶段,包括挂载、更新、卸载。

app.vue 的功能

• 使用 v-if 控制子组件 Person 的挂载和卸载。

• 父组件负责管理子组件的存在与否,同时通过生命周期钩子记录父组件的挂载阶段。

生命周期运行示意图

1. 父组件挂载:

• onMounted -> 输出:父---挂载完毕

2. 子组件挂载:

• 创建

• onBeforeMount(未输出)

• onMounted -> 输出:子---挂载完毕

3. 子组件更新:

• onBeforeUpdate

• onUpdated

4. 子组件卸载:

• onBeforeUnmount

• onUnmounted

image-20250128012228275

对应页面

Eg2-hook自定义

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

<script lang="ts" setup name="Person">
  import useSum from '@/hooks/useSum'
  import useDog from '@/hooks/useDog'

  const {sum,add,bigSum} = useSum()
  const {dogList,getDog} = useDog()
</script>

<style scoped>
  .person {
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
  }
  button {
    margin: 0 5px;
  }
  li {
    font-size: 20px;
  }
  img {
    height: 100px;
    margin-right: 10px;
  }
</style>

这个是person.vue

在模版部分,

• 图片渲染:

• 使用 v-for 循环 dogList,通过动态绑定 src 和 key 属性渲染小狗图片。

在脚本部分

• 引入逻辑模块:

• 从 useSum.ts 中引入了 sum、add 和 bigSum,负责数值的处理。

• 从 useDog.ts 中引入了 dogList 和 getDog,负责图片列表的管理和 API 请求。

• 使用组合式 API:

• 通过解构的方式,将逻辑解耦到独立的模块中,提高代码的可复用性。

在useDog.ts模块

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

export default function () {
  // 数据
  let dogList = reactive([
    'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
  ])
  // 方法
  async function getDog() {
    try {
      let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
      dogList.push(result.data.message)
    } catch (error) {
      alert(error)
    }
  }
  // 钩子
  onMounted(() => {
    getDog()
  })
  // 向外部提供东西
  return { dogList, getDog }
}

功能分析

1. 响应式数据

• 使用 reactive 定义了图片列表 dogList,默认包含一张图片。

2. API 请求方法

• getDog 方法使用 Axios 请求 https://dog.ceo 提供的小狗图片 API。

• 将获取的图片 URL 推入 dogList 中。

• 通过 try-catch 捕获请求错误。

3. 生命周期钩子

• 在组件挂载时 (onMounted) 自动调用 getDog,预加载一张小狗图片。

关键点

• 合理使用 reactive 管理数组的响应式更新。

• 在组件加载时预先获取数据,优化用户体验。

在这里面有一个地方发送异步请求

zlet result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')

axios.get():

• 使用 axios 发起一个 HTTP GET 请求。

• 请求地址是 https://dog.ceo/api/breed/pembroke/images/random,这是一个提供随机小狗图片的 API。

• 返回的数据是一个包含 message 属性的 JSON 对象

await:

• await 暂停代码的执行,直到请求完成并返回结果。

• 返回值存储在 result 变量中,具体数据保存在 result.data 中。

在useSum.ts模块

import { ref, onMounted, computed } from 'vue'

export default function () {
  // 数据
  let sum = ref(0)
  let bigSum = computed(() => {
    return sum.value * 10
  })

  // 方法
  function add() {
    sum.value += 1
  }

  // 钩子
  onMounted(() => {
    add()
  })

  // 给外部提供东西
  return { sum, add, bigSum }
}

功能分析

1. 响应式数据

• 使用 ref 定义了单一响应式数据 sum。

• 使用 computed 定义了计算属性 bigSum,动态计算 sum 的 10 倍值。

2. 方法

• add 方法使 sum 增加 1。

3. 生命周期钩子

• 在 onMounted 中调用 add,在组件加载时使 sum 初始值为 1。

路由

在 Vue 3 中,路由管理通常通过 Vue Router 实现。路由的主要功能是实现页面的导航和组件的动态渲染。以下是关于路由的核心概念和代码实现的详细说明。

1. 什么是路由?

路由是一种通过 URL 映射组件或视图的方式。它允许用户在单页应用(SPA)中导航,而无需重新加载整个页面。

例如:

• /home 映射到 Home 组件。

• /about 映射到 About 组件。

image-20250128081820700

页面组件

<template>
  <div class="home">
    <img src="http://www.atguigu.com/images/index_new/logo.png" alt="">
  </div>
</template>

功能:展示一个居中的图片。

样式:通过 flex 布局将内容水平和垂直居中。

用途:作为首页内容。

<script setup lang="ts" name="Home">
</script>

作用

• 表示该组件使用 Vue 3 的 <script setup> 语法。

• lang="ts" 表示代码使用 TypeScript,增加类型安全。

• name="Home" 给组件命名为 Home,方便调试和递归调用。

样式部分

<style scoped>
  .home {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100%;
  }
</style>

作用

• 定义组件的样式。

• scoped 表示样式只作用于当前组件,不影响其他组件。

细节解析

• display: flex;:

• 使用 Flex 布局,使子元素容易居中对齐。

• justify-content: center;:

• 子元素水平居中。

• align-items: center;:

• 子元素垂直居中。

• height: 100%;:

• 根容器的高度设置为父级容器的 100%。

About.vue

<template>
  <div class="about">
    <h2>大家好,欢迎来到尚硅谷直播间</h2>
  </div>
</template>

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

</script>

<style scoped>
.about {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  color: rgb(85, 84, 84);
  font-size: 18px;
}
</style>

News.vue

<template>
  <div class="news">
    <ul>
      <li><a href="#">新闻001</a></li>
      <li><a href="#">新闻002</a></li>
      <li><a href="#">新闻003</a></li>
      <li><a href="#">新闻004</a></li>
    </ul>
  </div>
</template>

<script setup lang="ts" name="News">
  
</script>

<style scoped>
/* 新闻 */
.news {
  padding: 0 20px;
  display: flex;
  justify-content: space-between;
  height: 100%;
}
.news ul {
  margin-top: 30px;
  list-style: none;
  padding-left: 10px;
}
.news li>a {
  font-size: 18px;
  line-height: 40px;
  text-decoration: none;
  color: #64967E;
  text-shadow: 0 0 1px rgb(0, 84, 0);
}
</style>

路由配置

// 创建一个路由器,并暴露出去

// 第一步:引入createRouter
import {createRouter,createWebHistory} from 'vue-router'
// 引入一个一个可能要呈现组件
import Home from '@/components/Home.vue'
import News from '@/components/News.vue'
import About from '@/components/About.vue'

// 第二步:创建路由器
const router = createRouter({
  history:createWebHistory(), //路由器的工作模式(稍后讲解) 
  routes:[ //一个一个的路由规则
    {
      path:'/home',
      component:Home
    },
    {
      path:'/news',
      component:News
    },
    {
      path:'/about',
      component:About
    },
  ]
})

// 暴露出去router
export default router

createRouter

• 创建一个路由实例。

createWebHistory

• 使用 HTML5 的历史记录模式。

routes

• 定义路由规则,每条规则对应一个路径和组件。

应用入口

// 引入createApp用于创建应用
import {createApp} from 'vue'
// 引入App根组件
import App from './App.vue'
// 引入路由器
import router from './router'

// 创建一个应用
const app = createApp(App)
// 使用路由器
app.use(router)
// 挂载整个应用到app容器中
app.mount('#app')

App.vue

模版部分

<template>
  <div class="app">
    <h2 class="title">Vue路由测试</h2>
    <!-- 导航区 -->
    <div class="navigate">
      <RouterLink to="/home" active-class="xiaozhupeiqi">首页</RouterLink>
      <RouterLink to="/news" active-class="xiaozhupeiqi">新闻</RouterLink>
      <RouterLink to="/about" active-class="xiaozhupeiqi">关于</RouterLink>
    </div>
    <!-- 展示区 -->
    <div class="main-content">
      <RouterView></RouterView>
    </div>
  </div>
</template>

<RouterLink:

• Vue Router 提供的导航组件,类似于 HTML 的 <a> 标签。

• to="/home":指定点击该链接时跳转的路由路径。

• active-class="xiaozhupeiqi":定义激活时的样式类名,当链接的路由匹配当前路径时会自动应用。

• 导航链接功能:

• 首页:跳转到 /home 路由。

• 新闻:跳转到 /news 路由。

• 关于:跳转到 /about 路由。

在展示区

<div class="main-content">
  <RouterView></RouterView>
</div>

• <RouterView :

• Vue Router 提供的内置组件,用于渲染当前路由匹配的组件。

• 根据用户点击的导航链接,<RouterView会动态切换为对应的组件内容,例如 Home.vue、News.vue 或 About.vue。

脚本部分

<script lang="ts" setup name="App">
  import { RouterView, RouterLink } from 'vue-router'
</script>

逐行解析

(1) lang="ts"

• 表示当前脚本部分使用 TypeScript,增强类型安全。

• 允许对变量、函数等进行类型声明。

(2) setup

• 使用 Vue 3 的组合式 API 的语法糖。

• 在 <script setup中定义的变量和方法,可以直接在模板中使用,无需显式返回。

(3) name="App"

• 为当前组件指定名称为 App。

• 在开发者工具(如 Vue DevTools)中调试时,可以看到组件名称为 App,便于区分。

(4) 引入 Vue Router 的组件

import { RouterView, RouterLink } from 'vue-router'

• RouterLink:用于定义路由导航链接。

• RouterView:用于动态渲染路由匹配的组件。

样式部分

.title {
  text-align: center;
  word-spacing: 5px;
  margin: 30px 0;
  height: 70px;
  line-height: 70px;
  background-image: linear-gradient(45deg, gray, white);
  border-radius: 10px;
  box-shadow: 0 0 2px;
  font-size: 30px;
}
.navigate {
  display: flex;
  justify-content: space-around;
  margin: 0 100px;
}
.navigate a {
  display: block;
  text-align: center;
  width: 90px;
  height: 40px;
  line-height: 40px;
  border-radius: 10px;
  background-color: gray;
  text-decoration: none;
  color: white;
  font-size: 18px;
  letter-spacing: 5px;
}

image-20250128085015970

image-20250128085239563

image-20250128085251179

xiaozhupeiqi 激活后呈现的

image-20250128085312669

这个就是超链接<a的时候,未点击前呈现的

视频中没有讲这一部分,少了一个知识点的讲解就是routeLink->转换为<a标签

image-20250128085843036

image-20250128090039568

image-20250128090244976

Query 参数-路由

Header.ts

<template>
  <h2 class="title">Vue路由测试</h2>
</template>

<script setup lang="ts" name="Header">
  
</script>

<style scoped>
  .title {
    text-align: center;
    word-spacing: 5px;
    margin: 30px 0;
    height: 70px;
    line-height: 70px;
    background-image: linear-gradient(45deg, gray, white);
    border-radius: 10px;
    box-shadow: 0 0 2px;
    font-size: 30px;
  }
</style>

About.ts

<template>
  <div class="about">
    <h2>大家好,欢迎来到尚硅谷直播间</h2>
  </div>
</template>

<script setup lang="ts" name="About">
  import {onMounted,onUnmounted} from 'vue'

  onMounted(()=>{
    console.log('About组件挂载了')
  })
  onUnmounted(()=>{
    console.log('About组件卸载了')
  })
</script>

<style scoped>
.about {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  color: rgb(85, 84, 84);
  font-size: 18px;
}
</style>

image-20250128092207216

Detail.ts

<template>
  <ul class="news-list">
    <li>编号:{ { query.id } }</li>
    <li>标题:{ { query.title } }</li>
    <li>内容:{ { query.content } }</li>
  </ul>
</template>

<script setup lang="ts" name="About">
  import {toRefs} from 'vue'
  import {useRoute} from 'vue-router'
  let route = useRoute()
  let {query} = toRefs(route)


</script>

<style scoped>
  .news-list {
    list-style: none;
    padding-left: 20px;
  }

  .news-list>li {
    line-height: 30px;
  }
</style>

脚本部分

解析

(1) useRoute

定义

• useRoute 是 Vue Router 提供的组合式 API,用于获取当前路由对象。

作用

• 返回当前激活的路由信息,包括路径、参数、查询字符串等。

返回值

route 是一个响应式对象,包含当前路由的所有信息,例如:

{
  path: "/news",
  query: {
    id: "123",
    title: "Vue Router",
    content: "这是一个简单的示例"
  },
  params: { ... },
  ...
}

(2) toRefs

定义

• toRefs 是 Vue 的组合式 API,用于将响应式对象的属性转换为独立的响应式引用。

作用

将 route.query 转换为响应式引用,使得在模板中访问 query 的属性时,能够保持响应式更新。

代码作用

let { query } = toRefs(route)

(3) 数据流程

• useRoute() 获取当前路由信息。

• 通过 toRefs(route) 解构出 query,用于动态绑定数据。

Params

image-20250128094158019

image-20250128094312633

<template>
  <div class="news">
    <!-- 导航区 -->
    <ul>
      <li v-for="news in newsList" :key="news.id">
        <!-- 第一种写法 -->
        <!-- <RouterLink :to="`/news/detail/${news.id}/${news.title}/${news.content}`">{ {news.title} }</RouterLink> -->

        <!-- 第二种写法 -->
        <RouterLink 
          :to="{
            name:'xiang',
            params:{
              id:news.id,
              title:news.title,
              content:news.content
            }
          }"
        >
          { {news.title} }
        </RouterLink>
      </li>
    </ul>
    <!-- 展示区 -->
    <div class="news-content">
      <RouterView></RouterView>
    </div>
  </div>
</template>

<script setup lang="ts" name="News">
  import {reactive} from 'vue'
  import {RouterView,RouterLink} from 'vue-router'

  const newsList = reactive([
    {id:'asfdtrfay01',title:'很好的抗癌食物',content:'西蓝花'},
    {id:'asfdtrfay02',title:'如何一夜暴富',content:'学IT'},
    {id:'asfdtrfay03',title:'震惊,万万没想到',content:'明天是周一'},
    {id:'asfdtrfay04',title:'好消息!好消息!',content:'快过年了'}
  ])

</script>

<style scoped>
/* 新闻 */
.news {
  padding: 0 20px;
  display: flex;
  justify-content: space-between;
  height: 100%;
}
.news ul {
  margin-top: 30px;
  /* list-style: none; */
  padding-left: 10px;
}
.news li::marker {
  color: #64967E;
}
.news li>a {
  font-size: 18px;
  line-height: 40px;
  text-decoration: none;
  color: #64967E;
  text-shadow: 0 0 1px rgb(0, 84, 0);
}
.news-content {
  width: 70%;
  height: 90%;
  border: 1px solid;
  margin-top: 20px;
  border-radius: 10px;
}
</style>

这个是new.vue

image-20250128095252643

image-20250128095646602

Pinia

Count.vue

模版部分

<template>
  <div class="count">
    <h2>当前求和为:{ { sum } }</h2>
    <select v-model.number="n">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="add">加</button>
    <button @click="minus">减</button>
  </div>
</template>

• 使用 { { sum } } 动态绑定 sum 的值,显示当前的求和结果。

2. 选择操作数

• 使用 <select 元素,让用户选择一个数字(1、2 或 3)。

• 通过 v-model.number="n" 双向绑定选中的值到变量 n,并将其转换为数值。

  1. 加减操作

• 点击“加”按钮时调用 add 方法。

• 点击“减”按钮时调用 minus 方法。

脚本部分

<script setup lang="ts" name="Count">
  import { ref } from "vue";
  // 数据
  let sum = ref(1) // 当前求和
  let n = ref(1) // 用户选择的数字

  // 方法
  function add(){
    sum.value += n.value
  }
  function minus(){
    sum.value -= n.value
  }
</script>

1. ref 定义响应式数据

• sum:当前求和,初始值为 1。

• n:用户选择的数字,初始值为 1。

• 响应式数据会自动更新绑定到模板的内容。

2. 方法功能

• add:将选中的数字 n.value 加到 sum.value 上。

• minus:从 sum.value 中减去 n.value。

<script setup lang="ts" name="LoveTalk">
  import { reactive } from 'vue'
  import axios from "axios";
  import { nanoid } from 'nanoid'
  // 数据
  let talkList = reactive([
    {id:'ftrfasdf01',title:'今天你有点怪,哪里怪?怪好看的!'},
    {id:'ftrfasdf02',title:'草莓、蓝莓、蔓越莓,今天想我了没?'},
    {id:'ftrfasdf03',title:'心里给你留了一块地,我的死心塌地'}
  ])
  // 方法
  async function getLoveTalk(){
    // 发请求,下面这行的写法是:连续解构赋值+重命名
    let {data:{content:title} } = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
    // 把请求回来的字符串,包装成一个对象
    let obj = {id:nanoid(),title}
    // 放到数组中
    talkList.unshift(obj)
  }
</script>

在app.vue里面写

<template>
  <Count/>
  <br>
  <LoveTalk/>
</template>

<script setup lang="ts" name="App">
  import Count from './components/Count.vue'
  import LoveTalk from './components/LoveTalk.vue'
</script>
npm i pinia

image-20250128103405430

import {createApp} from 'vue'
import App from './App.vue'
// 第一步:引入pinia
import {createPinia} from 'pinia'

const app = createApp(App)
// 第二步:创建pinia
const pinia = createPinia()
// 第三步:安装pinia
app.use(pinia)
app.mount('#app')

image-20250128103603995

小菠萝出来啦!!!

存储+读取数据

创建一个store文件夹

Count.ts

import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{
  // 真正存储数据的地方
  state(){
    return {
      sum:6
    }
  }
})

Lovetalk.ts

import {defineStore} from 'pinia'

export const useTalkStore = defineStore('talk',{
  // 真正存储数据的地方
  state(){
    return {
      talkList:[
        {id:'ftrfasdf01',title:'今天你有点怪,哪里怪?怪好看的!'},
        {id:'ftrfasdf02',title:'草莓、蓝莓、蔓越莓,今天想我了没?'},
        {id:'ftrfasdf03',title:'心里给你留了一块地,我的死心塌地'}
      ]
    }
  }
})

修改数据

import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{
  // actions里面放置的是一个一个的方法,用于响应组件中的“动作”
  actions:{
    increment(value){
      console.log('increment被调用了',value)
      if( this.sum < 10){
        // 修改数据(this是当前的store)
        this.sum += value
      }
    }
  },
  // 真正存储数据的地方
  state(){
    return {
      sum:6,
      school:'atguigu',
      address:'宏福科技园'
    }
  }
})
import {defineStore} from 'pinia'
import axios from 'axios'
import {nanoid} from 'nanoid'

export const useTalkStore = defineStore('talk',{
  actions:{
    async getATalk(){
      // 发请求,下面这行的写法是:连续解构赋值+重命名
      let {data:{content:title} } = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
      // 把请求回来的字符串,包装成一个对象
      let obj = {id:nanoid(),title}
      // 放到数组中
      this.talkList.unshift(obj)
    }
  },
  // 真正存储数据的地方
  state(){
    return {
      talkList:[
        {id:'ftrfasdf01',title:'今天你有点怪,哪里怪?怪好看的!'},
        {id:'ftrfasdf02',title:'草莓、蓝莓、蔓越莓,今天想我了没?'},
        {id:'ftrfasdf03',title:'心里给你留了一块地,我的死心塌地'}
      ]
    }
  }
})

现在展开解释

整体功能

这段代码通过 Pinia 定义了一个 Store,用于管理一个情话列表 talkList,并提供了一个方法 getATalk 来向 API 请求新的情话并添加到 talkList 中。

1. 引入的依赖

import { defineStore } from 'pinia'
import axios from 'axios'
import { nanoid } from 'nanoid'

解析

1. defineStore:

• 从 pinia 中引入,用于定义一个新的 Store。

• Store 是状态管理的核心,用于存储和管理全局共享的状态。

2. axios:

• 用于发送 HTTP 请求。

• 这里通过 axios.get() 从 https://api.uomg.com/api/rand.qinghua 获取随机土味情话。

3. nanoid:

• 一个小型的 ID 生成工具。

• 用于为每条情话生成唯一的 ID,确保 talkList 中的每条情话都有一个独特的标识。

2. 定义 Store

export const useTalkStore = defineStore('talk', { ... })

解析

1. export const useTalkStore:

• 定义了一个 Store,命名为 useTalkStore。

• 这个名字的命名规则通常是 use 开头,以表明它是一个 Store。

2. defineStore('talk', {...}):

• 'talk' 是这个 Store 的唯一标识符,用于区分其他 Store。

• 第二个参数是 Store 的配置对象,包含 state 和 actions 等。

3. state:存储数据

state() {
  return {
    talkList: [
      { id: 'ftrfasdf01', title: '今天你有点怪,哪里怪?怪好看的!' },
      { id: 'ftrfasdf02', title: '草莓、蓝莓、蔓越莓,今天想我了没?' },
      { id: 'ftrfasdf03', title: '心里给你留了一块地,我的死心塌地' }
    ]
  }
}

解析

1. state:

• 一个函数,返回一个对象,这个对象定义了 Store 中的数据。

• 在这里,state 定义了一个情话列表 talkList。

2. talkList:

• 是一个数组,存储了情话的初始数据。

• 每条情话是一个对象,包含以下字段:

• id:情话的唯一标识符。

• title:情话的具体内容。

3. 响应式特性

• Pinia 的 state 是响应式的。

• 当 talkList 数据发生变化时,绑定到 talkList 的视图会自动更新。

4. actions:定义方法

actions: {
  async getATalk() {
    let { data: { content: title } } = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
    let obj = { id: nanoid(), title }
    this.talkList.unshift(obj)
  }
}

解析

1. actions:

• 定义了 Store 中的方法,通常用于处理复杂逻辑或修改状态。

• getATalk 是一个异步方法,用于从 API 获取新的情话并更新 talkList。

2. getATalk 的工作流程

发送请求

let { data: { content: title } } = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')

• 使用 axios.get() 发送请求,从 API 获取情话。

• 解构赋值提取 content 字段,并将其重命名为 title。

创建新对象

let obj = { id: nanoid(), title }

• 使用 nanoid() 生成一个唯一的 ID。

• 创建一个包含 id 和 title 的新情话对象。

更新 talkList:

this.talkList.unshift(obj)

• 使用 unshift 方法,将新情话添加到 talkList 的开头。

• 由于 talkList 是响应式的,更新数据后,绑定到 talkList 的 UI 会自动更新。


image-20250128104601061

1. storeToRefs 的使用

storeToRefs 是 Pinia 提供的一个工具函数,主要用于从 Store 中提取状态(state)和 Getter 的响应式引用,确保解构后不会丢失响应性。

import { storeToRefs } from 'pinia'

const store = useSomeStore()
const { stateProp, getterProp } = storeToRefs(store)

作用

• 将 state 和 getter 转换为响应式 ref。

• 解构 Store 中的属性时,防止响应性丢失。

2. getters 的使用

Pinia 的 getters 是类似于 Vuex 中的计算属性,用于对 state 的值进行派生计算。

  state: () => ({
    talkList: [
      { id: '1', title: '情话一' },
      { id: '2', title: '情话二' }
    ]
  }),
  getters: {
    talkCount: (state) => state.talkList.length // 返回情话总数
  }
})
import { useTalkStore } from '@/stores/talkStore'

const talkStore = useTalkStore()

// 直接访问 getter
console.log(talkStore.talkCount) // 输出情话总数

3. $subscribe 的使用

$subscribe 是 Pinia 提供的一个方法,用于监听 Store 中 state 和 action 的变化。

语法

store.$subscribe((mutation, state) => {
  console.log(mutation) // 包含 type 和 payload
  console.log(state)    // 当前状态
})

4. store 组合式写法

Pinia 支持组合式 API(Composition API)风格的 Store 定义。

export const useTalkStore = defineStore('talk', () => {
  const talkList = ref([
    { id: '1', title: '情话一' },
    { id: '2', title: '情话二' }
  ])

  const talkCount = computed(() => talkList.value.length)

  const addTalk = (id, title) => {
    talkList.value.push({ id, title })
  }

  return { talkList, talkCount, addTalk }
})
import { useTalkStore } from '@/stores/talkStore'

const talkStore = useTalkStore()

// 调用方法和访问属性
talkStore.addTalk('3', '情话三')
console.log(talkStore.talkCount) // 输出 3

image-20250128104929967


http://www.kler.cn/a/524463.html

相关文章:

  • ODP(OBProxy)路由初探
  • C++并发编程指南05
  • 数字化转型-工具变量(2024.1更新)-社科数据
  • 【深度学习】 UNet详解
  • 机器人抓取与操作经典规划算法(深蓝)——2
  • 【Linux笔记】Day4
  • android wifi 热点名称的默认配置
  • 企业SaaS(软件即服务)行业中AARRR
  • 搭建Spark分布式集群
  • 学习数据结构(2)空间复杂度+顺序表
  • 昆仑万维Java开发面试题及参考答案
  • 【linux三剑客】grep练习题
  • PETSc源码分析: Optimization Solvers
  • VLC-Qt: Qt + libVLC 的开源库
  • 小白一命速通JS中的windowglobal对象
  • Prompt提示词完整案例:让chatGPT成为“书单推荐”的高手
  • Spring项目部署到Docker
  • C# 9.0记录类型:解锁开发效率的魔法密码
  • 17、智能驾驶硬件架构安全设计一般原则
  • Linux学习笔记——用户管理
  • 【回溯+剪枝】找出所有子集的异或总和再求和 全排列Ⅱ
  • JUC--ConcurrentHashMap底层原理
  • 如何创建一个线程池
  • DeepSeek核心贡献:将SFT和RL统一的数学公式
  • C# INotifyPropertyChanged接口在list类型中的应用
  • 大一计算机的自学总结:异或运算