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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/961549.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【AI编辑器】字节跳动推出AI IDE——Trae,专为中文开发者深度定制

目录 一、背景 二、核心特性 2.1 AI驱动的代码自动生成 2.2 智能问答与代码补全 2.3 多语言支持 2.4 插件与扩展 三、架构 四、下载使用 4.1 下载与安装 4.2 界面与配置 五、应用实践 5.1 快速生成代码 5.2 智能问答与调试 5.3 团队协作与代码审查 六、与Cursor…

(done) ABI 相关知识补充:内核线程切换、用户线程切换、用户内核切换需要保存哪些寄存器?

由于操作系统和编译器约定了 ABI&#xff0c;如下&#xff1a; 编译器在对 C 语言编译时&#xff0c;会自动 caller 标注的寄存器进行保存恢复。保存的步骤通常发生在进入函数的时候&#xff0c;恢复的步骤通常发生在从函数返回的时候。 内核线程切换需要保存的寄存器&#…

把本地搭建的hexo博客部署到自己的服务器上

配置远程服务器的git 安装git 安装依赖工具包 yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel安装编译工具 yum install -y gcc perl-ExtUtils-MakeMaker package下载git&#xff0c;也可以去官网下载了传到服务器上 wget https://www.ke…

71-《颠茄》

颠茄 颠茄&#xff0c;别名&#xff1a;野山茄、美女草、别拉多娜草&#xff0c;拉丁文名&#xff1a;Atropa belladonna L.是双子叶植物纲、茄科、颠茄属多年生草本&#xff0c;或因栽培为一年生&#xff0c;根粗壮&#xff0c;圆柱形。茎下部单一&#xff0c;带紫色&#xff…

二次封装的方法

二次封装 我们开发中经常需要封装一些第三方组件&#xff0c;那么父组件应该怎么传值&#xff0c;怎么调用封装好的组件原有的属性、插槽、方法&#xff0c;一个个调用虽然可行&#xff0c;但十分麻烦&#xff0c;我们一起来看更简便的方法。 二次封装组件&#xff0c;属性怎…

计算机组成原理(2)王道学习笔记

数据的表示和运算 提问&#xff1a;1.数据如何在计算机中表示&#xff1f; 2.运算器如何实现数据的算术、逻辑运算&#xff1f; 十进制计数法 古印度人发明了阿拉伯数字&#xff1a;0&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6&#…

npm启动前端项目时报错(vue) error:0308010C:digital envelope routines::unsupported

vue 启动项目时&#xff0c;npm run serve 报下面的错&#xff1a; error:0308010C:digital envelope routines::unsupported at new Hash (node:internal/crypto/hash:67:19) at Object.createHash (node:crypto:133:10) at FSReqCallback.readFileAfterClose [as on…

「 机器人 」仿生扑翼飞行器中的“被动旋转机制”概述

前言 在仿生扑翼飞行器的机翼设计中,模仿昆虫翼的被动旋转机制是一项关键技术。其核心思想在于:机翼旋转角度(攻角)并非完全通过主动伺服来控制,而是利用空气动力和惯性力的作用,自然地实现被动调节。以下对这种设计的背景、原理与优势进行详细说明。 1. 背景:昆虫的被动…

防御保护第一次实验:安全策略配置

一、实验拓扑 二、实验要求 三、需求分析 1.创建两个vlan 2.在ENSP中配置基于时间的ACL实现对于办公区PC访问OA Server的时间限制&#xff08;工作日早8到晚6&#xff09;。 3.通过配置基于MAC地址的ACL来实现对于生产区PC访问Web Server的限制&#xff08;除PC3外不能访问&am…

[权限提升] Windows 提权 — 系统内核溢出漏洞提权

关注这个框架的其他相关笔记&#xff1a;[内网安全] 内网渗透 - 学习手册-CSDN博客 0x01&#xff1a;系统内核溢出漏洞提权介绍 注意&#xff1a;提权很容易让电脑蓝屏&#xff0c;所以如果是测试的话&#xff0c;提权前最好做好系统备份。 溢出漏洞就像是往杯子里装水 —— 如…

Dest1ny漏洞库:用友 U8 Cloud ReleaseRepMngAction SQL 注入漏洞(CNVD-2024-33023)

大家好&#xff0c;今天是Dest1ny漏洞库的专题&#xff01;&#xff01; 会时不时发送新的漏洞资讯&#xff01;&#xff01; 大家多多关注&#xff0c;多多点赞&#xff01;&#xff01;&#xff01; 0x01 产品简介 用友U8 Cloud是用友推出的新一代云ERP&#xff0c;主要聚…

在线课堂小程序设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

【Linux权限】—— 于虚拟殿堂,轻拨密钥启华章

欢迎来到ZyyOvO的博客✨&#xff0c;一个关于探索技术的角落&#xff0c;记录学习的点滴&#x1f4d6;&#xff0c;分享实用的技巧&#x1f6e0;️&#xff0c;偶尔还有一些奇思妙想&#x1f4a1; 本文由ZyyOvO原创✍️&#xff0c;感谢支持❤️&#xff01;请尊重原创&#x1…

Qt Designer and Python: Build Your GUI

1.install pyside6 2.pyside6-designer.exe 发送到桌面快捷方式 在Python安装的所在 Scripts 文件夹下找到此文件。如C:\Program Files\Python312\Scripts 3. 打开pyside6-designer 设计UI 4.保存为simple.ui 文件&#xff0c;再转成py文件 用代码执行 pyside6-uic.exe simpl…

【Rust自学】15.7. 循环引用导致内存泄漏

说句题外话&#xff0c;这篇文章真心很难&#xff0c;有看不懂可以在评论区问&#xff0c;我会尽快作答的。 喜欢的话别忘了点赞、收藏加关注哦&#xff08;加关注即可阅读全文&#xff09;&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω…

[免费]基于Python的Django博客系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的基于Python的Django博客系统&#xff0c;分享下哈。 项目视频演示 【免费】基于Python的Django博客系统 Python毕业设计_哔哩哔哩_bilibili 项目介绍 随着互联网技术的飞速发展&#xff0c;信息的传播与…

乐优商城项目总结

文章目录 项目简介微服务集群1.enreka注册中心2. zuul网关3. 公共工具类4. 商品微服务5. 文件上传微服务6. 搜索微服务7. 页面静态化微服务8. 用户微服务9. 短信微服务10. 认证微服务11. 购物车微服务12. 订单微服务项目最大的收获项目遇到的问题 项目简介 乐优商城是一个全品…

基于django的智能停车场车辆管理深度学习车牌识别系统

完整源码项目包获取→点击文章末尾名片&#xff01;

【开源免费】基于Vue和SpringBoot的在线文档管理系统(附论文)

本文项目编号 T 038 &#xff0c;文末自助获取源码 \color{red}{T038&#xff0c;文末自助获取源码} T038&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

双层Git管理项目,github托管显示正常

双层Git管理项目&#xff0c;github托管显示正常 背景 在写React项目时&#xff0c;使用Next.js,该项目默认由git托管。但是我有在项目代码外层记笔记的习惯&#xff0c;我就在外层使用了git托管。 目录如下 code 层内也有.git 文件&#xff0c;对其托管。 我没太在意&…