Vue3魔法手册 作者 张天禹 013_pinia

043_对pinia的理解

pinia 官网
复制代码
https://pinia.vuejs.org/zh/

集中式状态(数据)管理

复制代码
react ====> redux
vue2  ====> vuex
vue3  ====> pinia

嵌套组件

集中式状态(数据)管理除redux,vuex,pinia等以外,还包括github.com上的第三方库,其实有很多都能做集中式状态管理,什么叫集中式,简单来说,就是把所有要管理的数据放在一个容器里面,放在一个地方,这就叫集中式状态(数据)管理,跟他相对应的一个概念叫做分布式。

当我们开发的时候,可能有一个根组件叫App,当我们的应用越来越复杂,功能越来越多的时候,就会出现非常多的组件,甚至组件之间还会嵌套,随你编写的应用越来越多,很有可能会出现这个模样,比如1号组件和2号组件要共享一下数据,1号组件为登录组件,用户登录成功之后,会存储用户的信息,而2号组件是属于抽奖页面,比如说今天是双11,有一个双11抽奖页面,用户点击这个组件进去之后,要求就是抽奖页面,要呈现用户的头像,要展示用户的用户名,其实就是一号组件与二号组件要共享一下数据,这时候你再考虑到用 pinia集中式状态管理,老师我们用了集中式,那这样比如3号组件,4号组件都不往他们里面写数据,一切数据都交给 pinia 管理,这是不合理的,官方说了如下一句话:

你要将那些共享的数据交给集中式管理,而不是组件自身的数据。

官网举例说比如一个元素的可见性,你鼠标一点,他就显示,再一点就隐藏,其实你完全可以将该数据交给组件自身,比如4号组件的数据为isShow,他一会儿显示(true),一会儿隐藏(false),其实你没有必要大动干戈的将数据交给pinia,大家都用该数据时,你才考虑集中式状态管理,这就是为什么要用pinia以及对pinia的理解。

App.vue 备份

复制代码
<template>
  <div class="app">
    标题
    <Header></Header>
    导航区
    <div class="navigate">
      第一种: to的字符串写法
      <RouterLink to="/home" active-class="active">首页</RouterLink>
      <RouterLink to="/news" active-class="active">新闻</RouterLink>
      <RouterLink to="/about" active-class="active">关于</RouterLink>
      第二种: to的对象写法 path跳转
      <RouterLink :to="{path:'/home'}" active-class="active">首页</RouterLink>
      <RouterLink :to="{path:'/news'}" active-class="active">新闻</RouterLink>
      <RouterLink :to="{path:'/about'}" active-class="active">关于</RouterLink>
      第三种: to的对象写法 名字跳转
      <RouterLink replace :to="{name:'home'}" active-class="active">首页</RouterLink>
      <RouterLink replace :to="{name:'news'}" active-class="active">新闻</RouterLink>
      <RouterLink replace :to="{name:'about'}" active-class="active">关于</RouterLink>
    </div>
    展示区
    <div class="main-content">
      占位符,此处将来要展示不同的组件内容
      <RouterView></RouterView>
      此处以后可能要展示各种组件内容,到底展示哪个组件,取决于路由的匹配结果
    </div>
  </div>
</template>

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

<style scoped>
	/*App*/
  .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;
  }

  .navigate a.active {
    background-color: #64967E;
    color: #ffc268;
    font-weight: 900;
    text-shadow: 0 0 1px black;
    font-family: 微软雅黑;
  }

  .main-content {
    margin: 0 auto;
    margin-top: 30px;
    border-radius: 10px;
    width: 90%;
    height: 400px;
    border: 1px solid;
  }
</style>

044_准备一个效果

多个组件共享数据,才考虑用 pinia,接下来我们准备这些做一个效果来看看。

笔记

两个组件

最少两个组件,才能聊出共享

一个组件保存求和的值,一个组件保存着获取一句土味情话

name="App" 这个name是用来定义当前组件名字的,如果你不写,他就会去寻找文件名作为组件名

安装 npm install -D sass-embedded

n为用户选择的数据

当点击2时,2此时为字符串,字符串和数字是不会相加的

只有一上来时,你写的那个初始值,他才是数字,所有用户的输入他默认处理都是字符串,那问题如何让他变成数字呢?有如下三种方式:

1, 在 value 前添加 冒号,红色的都是表达式,一执行就是数字1,2,3

2, 最正统的做法是在 v-model.number="n" 这添加number

3, 在方法里面添加Number() 包裹一下就可以了

安装 npm i axios
土味情话网站,后端已经解决跨域问题
复制代码
https://api.uomg.com/api/rand.qinghua?format=json

https://api.vvhan.com/api/love

在数组前面添加数据使用unshift()方法

在数组后面添加数据使用push()方法!

打印不是目的,我们要将这句话塞到浏览器上

生成id的第三方库 有两个比较常用 uuid nanoid

复制代码
安装
npm i nanoid
npm i uuid

引入 nanoid
import { nanoid } from 'nanoid';

使用
id: nanoid()

点击一个他就来一个

_准备一个效果 实现代码如下

复制代码
1, src/App.vue
<template>
  <Count />
  <br>
  <LoveTalk />
  <!-- <div class="app">
    标题
    <Header></Header>
    导航区
    <div class="navigate">
      第一种: to的字符串写法
      <RouterLink to="/home" active-class="active">首页</RouterLink>
      <RouterLink to="/news" active-class="active">新闻</RouterLink>
      <RouterLink to="/about" active-class="active">关于</RouterLink>
      第二种: to的对象写法 path跳转
      <RouterLink :to="{path:'/home'}" active-class="active">首页</RouterLink>
      <RouterLink :to="{path:'/news'}" active-class="active">新闻</RouterLink>
      <RouterLink :to="{path:'/about'}" active-class="active">关于</RouterLink>
      第三种: to的对象写法 名字跳转
      <RouterLink replace :to="{name:'home'}" active-class="active">首页</RouterLink>
      <RouterLink replace :to="{name:'news'}" active-class="active">新闻</RouterLink>
      <RouterLink replace :to="{name:'about'}" active-class="active">关于</RouterLink>
    </div>
    展示区
    <div class="main-content">
      占位符,此处将来要展示不同的组件内容
      <RouterView></RouterView>
      此处以后可能要展示各种组件内容,到底展示哪个组件,取决于路由的匹配结果
    </div>
  </div> -->
</template>

<script setup lang="ts" name="App">
  import Count from '@/components/Count.vue';
  import LoveTalk from '@/components/LoveTalk.vue';
</script>

<!-- <script setup lang="ts" name="App">
  import { RouterView,RouterLink } from 'vue-router';
  import Header from '@/components/Header.vue';
</script> -->

<style scoped>
	/*
  .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;
  }

  .navigate a.active {
    background-color: #64967E;
    color: #ffc268;
    font-weight: 900;
    text-shadow: 0 0 1px black;
    font-family: 微软雅黑;
  }

  .main-content {
    margin: 0 auto;
    margin-top: 30px;
    border-radius: 10px;
    width: 90%;
    height: 400px;
    border: 1px solid;
  }
    */
</style>





2, src/components/Count.vue

<template>
    <div class="count">
        <h2>当前求和为: {{ sum }}</h2>
        <select v-model="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>

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

    // 数据
    let sum = ref(1) // 当前求和
    let n = ref(1)   // 用户选择的数字

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

<style lang="scss" scoped>
    .count {
        background-color: skyblue;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    select,button {
        margin: 0 5px;
        height: 25px;
    }
</style>








3, src/components/LoveTalk.vue
<template>
    <div class="talk">
        <button @click="getLoveTalk">获取一句土味情话</button>
        <ul>
            <li v-for="talk in talkList" :key="talk.id">{{ talk.title }}</li>
        </ul>
    </div>
</template>

<script setup lang="ts" name="LoveTalk">
import axios from 'axios';
import { reactive } from 'vue';
import { nanoid } from 'nanoid';

// 数据
let talkList = reactive([
    {id: 'zg01', title: '今天你有点怪,哪里怪,怪好看的'},
    {id: 'zg02', title: '草莓,蓝莓,樱桃,今天想我没有'},
    {id: 'zg03', title: '心里给你留了一块地,想放点啥就放点啥'},
]);

// 方法  发送请求获取一句土味情话
async function getLoveTalk() {
    // 发送请求获取一句土味情话 连续两次结构加重命名
    // let result = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')

    let {data: {content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')
    // console.log(result.data.content);
    // 把请求回来的数据字符串,包装成对象,添加到数组中
    // let obj = {id: nanoid(), title: result.data.content};
    let obj = {id: nanoid(), title};// title: title触发对象的简写形式直接写title就可以了
    // console.log(obj);
    // 添加到数组中
    talkList.unshift(obj);  // 添加到数组开头位置
    // talkList.push({id: nanoid(), title: result.data.content});// 添加到数组末尾位置

}
</script>

<style scoped>
.talk {
    background-color: orange;
    padding: 10px;   
    border-radius: 10px;
    box-shadow: 0 0 10px; 
}
</style>

045_搭建pinia环境

安装 npm i pinia

安装pinia结束后,你要去一个地方,编写一段代码,固定的,不允许换位置,接下来我们将pinia的时候,无论是文件夹的划分,还是命名,还是写法,我们都完全遵循官方的规范。
首先,回到src/main.ts里面,
复制代码
// 第一步 引入 pinia
import {createPinia} from 'pinia'

// 第二 创建 pinia
const pinia = createPinia()

// 第三步 安装 pinia  就是将 pinia 挂载到应用上
app.use(pinia)

_搭建pinia环境 实现代码如下

复制代码
1, src/App.vue
<template>
  <Count />
  <br>
  <Dog />
  <!-- <div class="app">
    标题
    <Header></Header>
    导航区
    <div class="navigate">
      第一种: to的字符串写法
      <RouterLink to="/home" active-class="active">首页</RouterLink>
      <RouterLink to="/news" active-class="active">新闻</RouterLink>
      <RouterLink to="/about" active-class="active">关于</RouterLink>
      第二种: to的对象写法 path跳转
      <RouterLink :to="{path:'/home'}" active-class="active">首页</RouterLink>
      <RouterLink :to="{path:'/news'}" active-class="active">新闻</RouterLink>
      <RouterLink :to="{path:'/about'}" active-class="active">关于</RouterLink>
      第三种: to的对象写法 名字跳转
      <RouterLink replace :to="{name:'home'}" active-class="active">首页</RouterLink>
      <RouterLink replace :to="{name:'news'}" active-class="active">新闻</RouterLink>
      <RouterLink replace :to="{name:'about'}" active-class="active">关于</RouterLink>
    </div>
    展示区
    <div class="main-content">
      占位符,此处将来要展示不同的组件内容
      <RouterView></RouterView>
      此处以后可能要展示各种组件内容,到底展示哪个组件,取决于路由的匹配结果
    </div>
  </div> -->
</template>

<script setup lang="ts" name="App">
  import Count from '@/components/Count.vue';
  import Dog from '@/components/Dog.vue';
</script>

<!-- <script setup lang="ts" name="App">
  import { RouterView,RouterLink } from 'vue-router';
  import Header from '@/components/Header.vue';
</script> -->

<style scoped>
	/*
  .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;
  }

  .navigate a.active {
    background-color: #64967E;
    color: #ffc268;
    font-weight: 900;
    text-shadow: 0 0 1px black;
    font-family: 微软雅黑;
  }

  .main-content {
    margin: 0 auto;
    margin-top: 30px;
    border-radius: 10px;
    width: 90%;
    height: 400px;
    border: 1px solid;
  }
    */
</style>





2, src/main.ts
// 引入 createApp 用于创建应用
import {createApp} from 'vue'

// 引入 App根组件
import App from './App.vue'

// 第一步 引入 pinia
import {createPinia} from 'pinia'

// 引入路由器
// import router from './router'

// 创建一个应用
const app = createApp(App)

// 第二 创建 pinia
const pinia = createPinia()

// 第三步 安装 pinia  就是将 pinia 挂载到应用上
app.use(pinia)
// app.use(createPinia()) // 也可以这样写,等同于上面的写法 简写写法

// 使用路由器
// app.use(router)

// 挂载整个应用到 app 容器中
app.mount('#app')







3, src/components/Count.vue
<template>
    <div class="count">
        <h2>当前求和为: {{ sum }}</h2>
        <select v-model="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>

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

    // 数据
    let sum = ref(1) // 当前求和
    let n = ref(1)   // 用户选择的数字

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

<style lang="scss" scoped>
    .count {
        background-color: skyblue;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    select,button {
        margin: 0 5px;
        height: 25px;
    }
</style>









4, src/components/Dog.vue
<template>
    <div class="dog">
        <img v-for="(dog,index) in dogList" :key="index" :src="dog" alt="">
		<br>
		<button @click="getDog">再来一只小狗</button>
    </div>
</template>

<script setup lang="ts" name="Dog">
    import { reactive } from 'vue'
    import axios from 'axios'

    // 数据
    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)
        }
    }
</script>



<style scoped>
    .dog {
        background-color: pink;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    button {
		margin: 0 5px;
	}

	li {
		font-size: 20px;
	}

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

046_存储+读取数据

5.3 [存储+读取数据]
复制代码
1, Store是一个保存: 状态,业务逻辑 的实体,每个组件都可以读取,写入他。
2, 他有三个概念: state,getter,action,相当于组件中的: data,computed和methods。
3, 具体编码: src/store/count.ts
// 引入 defineStore 用于创建 store
import {defineStore} from 'pinia'

// 定义并暴露一个 store
export const useCountStore = defineStore('count',{
	// 动作
	actions: {},
	// 状态
	state() {
		return {
			sum:6
		}
	},
	getters: {}
})

笔记

在 src 目录下创建 store

store就是pinia的具体体现

store就是pinia落地的东西 store就是pinia里面的总经理

在 store 目录下创建 count.ts 有人也用 Count.ts,这也是可以的

总之你取名就是要让人知道你在里面存储的是什么

看到红色你就应该捕获到该项目用到pinia

而且都是跟计数相关的内容

当你在store目录下看到 user.ts 这里面肯定是跟用户相关的数据

我们去count.ts建立一个属于count的小仓库 存储count相关的数据

复制代码
import {defineStore} from 'pinia'

const useCountStore = defineStore('count',{
    // 配置对象
    state:()=>{
        return {
            count:0
        }
    },
    actions:{
        increment(){this.count++},//这里的this指向的是当前store的实例对象,可以直接操作里面的数据
        decrement(){this.count--}
    },
    getters:{
        doubleCount:state=>{return state.count*2}
    }
})

代码解释:
defineStore('参数1',{参数2})
参数1: 相当于他的id值,这个名跟文件名保持一致,
参数2: 写一个配置对象

state: 状态(数据),官方要求这里必须写成一个函数

这里用 export 实现分别暴露

此时你拥有了一个pinia下在state下存储count 的组织架构

count.ts里面就是一个仓库,只要是跟统计相关的(和,差,乘,除,开根后的结果等)都可以存储到这里

代码-效果

countStore 是reactive所定义的一个响应式对象

$state 就是我们刚才在 count.ts 文件中配置的state

如果你自己定义的ref,撤包了,你必须使用 'xxx.value'格式获取数据

如果你是在 reactive里面包裹的ref(),他就直接给你撤包了解除来了,c后面就不需要'.value'

由于sum是包裹在reactive()整个蓝色里面的,所以此时的sum就不需要.value了

由于 countStore 返回的是响应式对象数据,所以可以直接访问里面的数据和方法 不需要解构赋值,也不需要.value访问

直接拿到state中的数据了

复制代码
import { ref,reactive } from 'vue'
    import { useCountStore } from '@/store/count'

    // 引入store中的数据和方法
    const countStore = useCountStore()
    // 由于 countStore 返回的是响应式对象数据,所以可以直接访问里面的数据和方法,
    // 不需要解构赋值,也不需要.value访问
    console.log('@@@',countStore.sum)

还有一种方式,可以从$state里面去拿到state的数据,这种方式在编程式开发中用得很多

复制代码
import { ref,reactive } from 'vue'
    import { useCountStore } from '@/store/count'

    // 引入store中的数据和方法
    const countStore = useCountStore()
    // 由于 countStore 返回的是响应式对象数据,所以可以直接访问里面的数据和方法,
    // 不需要解构赋值,也不需要.value访问 第一种拿到sum数据的方式
    // console.log('@@@',countStore.sum) // 响应式对象数据,可以直接访问里面的数据和方法
    console.log('@@@',countStore.$state.sum)  

第三种方式 拿到 state 中的数据

复制代码
import { ref,reactive,computed } from 'vue'
import { useCountStore } from '@/store/count'

// 引入store中的数据和方法
const countStore = useCountStore()

// 第三种拿到sum数据的方式
let sum = computed(()=>{
    return countStore.sum
})
console.log('@@@',countStore.$state.sum)  

因为我们定义了 countStore,所以我们可以直接拿到state中的sum数据

此时state中的sum数据可以读出来了

pinia 主体

count 是pinia里面的小分类

src/store/dog.ts

复制代码
import {defineStore} from 'pinia'

export const useDogStore = defineStore('dog',{ // 配置对象
    // 真正存储数据的地方
    state:()=>{
        return {
            dogList:[
                'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
            ]
        }
    }
})

src/store/count.ts

复制代码
import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{ // 配置对象
    // 真正存储数据的地方
    state:()=>{
        return {
            sum: 8
        }
    }
})

src/store/loveTalk.ts

复制代码
import {defineStore} from 'pinia'

export const useTalkStore = defineStore('talk',{ // 配置对象
    // 真正存储数据的地方
    state:()=>{
        return {
            talkList:[
                {id: 'zg01', title: '今天你有点怪,哪里怪,怪好看的'},
                {id: 'zg02', title: '草莓,蓝莓,樱桃,今天想我没有'},
                {id: 'zg03', title: '心里给你留了一块地,想放点啥就放点啥'},
            ]
        }
    }
})

定义仓库: useTalkStore ,分类ID: 'talk',数据: talkList

src/components/loveTalk.vue

复制代码
<template>
    <div class="talk">
        <button @click="getLoveTalk">获取一句土味情话</button>
        <ul>
            <li v-for="talk in talkList" :key="talk.id">{{ talk.title }}</li>
        </ul>
    </div>
</template>

<script setup lang="ts" name="LoveTalk">
import axios from 'axios';
import { reactive } from 'vue';
import { nanoid } from 'nanoid';

// 数据
// let talkList = reactive([
//     {id: 'zg01', title: '今天你有点怪,哪里怪,怪好看的'},
//     {id: 'zg02', title: '草莓,蓝莓,樱桃,今天想我没有'},
//     {id: 'zg03', title: '心里给你留了一块地,想放点啥就放点啥'},
// ]);

// 方法  发送请求获取一句土味情话
async function getLoveTalk() {
    // 发送请求获取一句土味情话 连续两次结构加重命名
    // let result = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')

    // 1. let {data: {content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')
    // console.log(result.data.content);
    // 把请求回来的数据字符串,包装成对象,添加到数组中
    // let obj = {id: nanoid(), title: result.data.content};
    // 2. let obj = {id: nanoid(), title};// title: title触发对象的简写形式直接写title就可以了
    // console.log(obj);
    // 添加到数组中
    // 3. talkList.unshift(obj);  // 添加到数组开头位置
    // talkList.push({id: nanoid(), title: result.data.content});// 添加到数组末尾位置

}
</script>

<style scoped>
.talk {
    background-color: orange;
    padding: 10px;   
    border-radius: 10px;
    box-shadow: 0 0 10px; 
}
</style>

count与dog都已经安装了

_存储+读取数据 实现代码如下:

复制代码
1, src/App.vue
<template>
  <Count />
  <br>
  <Dog />
  <!-- <div class="app">
    标题
    <Header></Header>
    导航区
    <div class="navigate">
      第一种: to的字符串写法
      <RouterLink to="/home" active-class="active">首页</RouterLink>
      <RouterLink to="/news" active-class="active">新闻</RouterLink>
      <RouterLink to="/about" active-class="active">关于</RouterLink>
      第二种: to的对象写法 path跳转
      <RouterLink :to="{path:'/home'}" active-class="active">首页</RouterLink>
      <RouterLink :to="{path:'/news'}" active-class="active">新闻</RouterLink>
      <RouterLink :to="{path:'/about'}" active-class="active">关于</RouterLink>
      第三种: to的对象写法 名字跳转
      <RouterLink replace :to="{name:'home'}" active-class="active">首页</RouterLink>
      <RouterLink replace :to="{name:'news'}" active-class="active">新闻</RouterLink>
      <RouterLink replace :to="{name:'about'}" active-class="active">关于</RouterLink>
    </div>
    展示区
    <div class="main-content">
      占位符,此处将来要展示不同的组件内容
      <RouterView></RouterView>
      此处以后可能要展示各种组件内容,到底展示哪个组件,取决于路由的匹配结果
    </div>
  </div> -->
</template>

<script setup lang="ts" name="App">
  import Count from '@/components/Count.vue';
  import Dog from '@/components/Dog.vue';
</script>

<!-- <script setup lang="ts" name="App">
  import { RouterView,RouterLink } from 'vue-router';
  import Header from '@/components/Header.vue';
</script> -->

<style scoped>
	/*
  .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;
  }

  .navigate a.active {
    background-color: #64967E;
    color: #ffc268;
    font-weight: 900;
    text-shadow: 0 0 1px black;
    font-family: 微软雅黑;
  }

  .main-content {
    margin: 0 auto;
    margin-top: 30px;
    border-radius: 10px;
    width: 90%;
    height: 400px;
    border: 1px solid;
  }
    */
</style>





2, src/main.ts
// 引入 createApp 用于创建应用
import {createApp} from 'vue'

// 引入 App根组件
import App from './App.vue'

// 第一步 引入 pinia
import {createPinia} from 'pinia'

// 引入路由器
// import router from './router'

// 创建一个应用
const app = createApp(App)

// 第二 创建 pinia
const pinia = createPinia()

// 第三步 安装 pinia  就是将 pinia 挂载到应用上
app.use(pinia)
// app.use(createPinia()) // 也可以这样写,等同于上面的写法 简写写法

// 使用路由器
// app.use(router)

// 挂载整个应用到 app 容器中
app.mount('#app')






3, src/components/Dog.vue
<template>
    <div class="dog">
        <img v-for="(dog,index) in dogStore.dogList" :key="index" :src="dog" alt="">
		<br>
		<button @click="getDog">再来一只小狗</button>
    </div>
</template>

<script setup lang="ts" name="Dog">
    import { reactive } from 'vue'
    import axios from 'axios'
    import {useDogStore} from '@/store/dog.ts'

    const dogStore = useDogStore()


    // 数据
    // 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)
        // }
    }
</script>



<style scoped>
    .dog {
        background-color: pink;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    button {
		margin: 0 5px;
	}

	li {
		font-size: 20px;
	}

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





4, src/components/LoveTalk.vue
<template>
    <div class="talk">
        <button @click="getLoveTalk">获取一句土味情话</button>
        <ul>
            <li v-for="talk in talkStore.talkList" :key="talk.id">{{ talk.title }}</li>
        </ul>
    </div>
</template>

<script setup lang="ts" name="LoveTalk">
import axios from 'axios';
import { reactive } from 'vue';
import { nanoid } from 'nanoid';
import {useTalkStore} from '@/store/loveTalk.ts'

const talkStore = useTalkStore()
// console.log('@',talkStore)


// 数据
// let talkList = reactive([
//     {id: 'zg01', title: '今天你有点怪,哪里怪,怪好看的'},
//     {id: 'zg02', title: '草莓,蓝莓,樱桃,今天想我没有'},
//     {id: 'zg03', title: '心里给你留了一块地,想放点啥就放点啥'},
// ]);

// 方法  发送请求获取一句土味情话
async function getLoveTalk() {
    // 发送请求获取一句土味情话 连续两次结构加重命名
    // let result = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')

    // 1. let {data: {content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')
    // console.log(result.data.content);
    // 把请求回来的数据字符串,包装成对象,添加到数组中
    // let obj = {id: nanoid(), title: result.data.content};
    // 2. let obj = {id: nanoid(), title};// title: title触发对象的简写形式直接写title就可以了
    // console.log(obj);
    // 添加到数组中
    // 3. talkList.unshift(obj);  // 添加到数组开头位置
    // talkList.push({id: nanoid(), title: result.data.content});// 添加到数组末尾位置

}
</script>

<style scoped>
.talk {
    background-color: orange;
    padding: 10px;   
    border-radius: 10px;
    box-shadow: 0 0 10px; 
}
</style>





5, src/components/Count.vue
<template>
    <div class="count">
        <h2>当前求和为: {{ countStore.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>

<script setup lang="ts" name="Count">
    import { ref,reactive,computed } from 'vue'
    import { useCountStore } from '@/store/count'

    // 引入store中的数据和方法
    const countStore = useCountStore()
    // 由于 countStore 返回的是响应式对象数据,所以可以直接访问里面的数据和方法,
    // 不需要解构赋值,也不需要.value访问
    // 以下三种方式都可以拿到state中的数据
    // 第一种拿到sum数据的方式
    // console.log('@@@',countStore.sum) // 响应式对象数据,可以直接访问里面的数据和方法
    // 第二种拿到sum数据的方式
    // console.log('@@@',countStore.$state.sum)  // 响应式对象数据,可以直接访问里面的数据和方法
    // 第三种拿到sum数据的方式
    // let sum = computed(()=>{
    //     return countStore.sum
    // })
    // console.log('@@@',countStore.$state.sum)  



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

    let x = ref(4)

    console.log(obj.a)
    console.log(obj.b)
    console.log(obj.c)  // 撤包了 不需要.value访问,直接访问即可
    console.log(x.value) // 需要.value访问

    */


    // 数据
    let n = ref(1)   // 用户选择的数字

    // 方法
    function add() {
    }
    function minus() {
    }
</script>

<style lang="scss" scoped>
    .count {
        background-color: skyblue;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    select,button {
        margin: 0 5px;
        height: 25px;
    }
</style>








6, src/store/dog.ts
import {defineStore} from 'pinia'

export const useDogStore = defineStore('dog',{ // 配置对象
    // 真正存储数据的地方
    state:()=>{
        return {
            dogList:[
                'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
            ]
        }
    }
})






7, src/store/loveTalk.ts
import {defineStore} from 'pinia'

export const useTalkStore = defineStore('talk',{ // 配置对象
    // 真正存储数据的地方
    state:()=>{
        return {
            talkList:[
                {id: 'zg01', title: '今天你有点怪,哪里怪,怪好看的'},
                {id: 'zg02', title: '草莓,蓝莓,樱桃,今天想我没有'},
                {id: 'zg03', title: '心里给你留了一块地,想放点啥就放点啥'},
            ]
        }
    }
})





8, src/store/count.ts

import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{ // 配置对象
    // 真正存储数据的地方
    state:()=>{
        return {
            sum: 8
        }
    }
})

047_修改数据(三种方式)

5.4 [修改数据(三种方式)]
复制代码
1, 第一种修改方式,直接修改
countStore.sum = 666

2, 第二种修改方式: 批量修改
countStore.$patch({
	sum:999,
	school:'atguigu'
})

3, 第三种方式: 借助actions修改(actions中可以编写一些业务逻辑)
import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{
	/********/
	actions: {
		// 加
		increment(value:number) {
			if(this.sum<10) {
				// 操作 useCountStore 中的sum
				this.sum += value
			}
		}
	},
})

笔记

代码-效果

完整的碎片: 绿色框里面的内容

发生3次改变

Mouse: 鼠标事件

Keyboard: 键盘事件

Components: 组件上相关事件

actions 第三种修改数据方式

count.ts 是存储跟计数相关的小仓库

执行 代码-效果

你能在 actions对象里面访问到 state 吗?肯定不可以,这是一个作用域的问题

底层帮你维护好了一个this,我们先输出一个this,看看里面都有什么

this.$state

给我们程序员用的基本都是设计为$开头

获取数据有两种方法 this.sum和$state.sum

要做一些极限的限制,你需要这样写

这样也可以实现限制

商品订单的操作 秒杀 参与活动 中奖 抽奖等

设计订单逻辑处理actions,这样就涉及到代码复用了

_修改数据(三种方式) 实现代码如下

复制代码
1, src/components/Count.vue
<template>
    <div class="count">
        <h2>当前求和为: {{ countStore.sum }}</h2>
        <h3>欢迎来到: {{ countStore.school }},坐落于: {{ countStore.address }}</h3>
        <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>

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

    // 引入 useCountStore
    import { useCountStore } from '@/store/count'

    // 使用useCountStore,得到一个专门保存 count 相关的 store 实例对象 countStore
    const countStore = useCountStore()

    // 由于 countStore 返回的是响应式对象数据,所以可以直接访问里面的数据和方法,
    // 不需要解构赋值,也不需要.value访问
    // 以下三种方式都可以拿到state中的数据
    // 第一种拿到sum数据的方式
    // console.log('@@@',countStore.sum) // 响应式对象数据,可以直接访问里面的数据和方法
    // 第二种拿到sum数据的方式
    // console.log('@@@',countStore.$state.sum)  // 响应式对象数据,可以直接访问里面的数据和方法
    // 第三种拿到sum数据的方式
    // let sum = computed(()=>{
    //     return countStore.sum
    // })
    // console.log('@@@',countStore.$state.sum)  



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

    let x = ref(4)

    console.log(obj.a)
    console.log(obj.b)
    console.log(obj.c)  // 撤包了 不需要.value访问,直接访问即可
    console.log(x.value) // 需要.value访问

    */


    // 数据
    let n = ref(1)   // 用户选择的数字

    // 方法
    function add() {
        // 响应式对象数据,可以直接访问里面的数据和方法
        // 不需要解构赋值,也不需要.value访问
        // countStore.sum += n.value 

        // 第一种修改数据的方式
        // countStore.sum += 1
        // countStore.school = '尚硅谷'
        // countStore.address = '北京'

        // 第二种批量修改数据的方式
        // countStore.$patch({
        //     sum: countStore.sum + 1,
        //     school: '尚硅谷',
        //     address: '北京'
        // })

        // 第三种修改数据的方式
        countStore.increment(n.value)
    }
    function minus() {
    }
</script>

<style scoped>
    .count {
        background-color: skyblue;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    select,button {
        margin: 0 5px;
        height: 25px;
    }
</style>







2, src/components/Dog.vue
<template>
    <div class="dog">
        <img v-for="(dog,index) in dogStore.dogList" :key="index" :src="dog" alt="">
		<br>
		<button @click="getDog">再来一只小狗</button>
    </div>
</template>

<script setup lang="ts" name="Dog">
    import { reactive } from 'vue'
    import axios from 'axios'
    import {useDogStore} from '@/store/dog.ts'

    const dogStore = useDogStore()


    // 数据
    // 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)
        // }
    }
</script>



<style scoped>
    .dog {
        background-color: pink;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    button {
		margin: 0 5px;
	}

	li {
		font-size: 20px;
	}

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




3, src/store/count.ts
import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{ // 配置对象
    // actions里面放置一个一个的动作方法,用于响应式组件中的"动作(比如要加,要减)" 用来修改数据
    actions: {
        increment(value:number) { // 修改数据
            console.log('increment被调用了',value)
            // 如何修改数据 有两种方式修改数据 使用 this.sum 或者使用this.$state.sum 都可以修改数据
            // console.log(this.$state.sum)
            // console.log(this.sum) // 8 拿到sum的值 8
            // this 是当前的store实例对象,this.sum 就是访问store里面的数据,this.sum++ 就是修改数据
            
            if (this.sum < 10) {
                this.sum += value;
            }       
            // this.sum++
        }
    },
    // 真正存储数据的地方
    state:()=>{
        return {
            sum: 8,
            school: 'atguigu',
            address: '宏福科技园'
        }
    }
})




4, src/store/dog.ts
import {defineStore} from 'pinia'

export const useDogStore = defineStore('dog',{ // 配置对象
    // 真正存储数据的地方
    state:()=>{
        return {
            dogList:[
                'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
            ]
        }
    }
})

048_storeToRefs

5.5 [storeToRefs]
复制代码
1, 借助 storeToRefs将store中的数据转为ref对象,方便在模板中使用。
2, 注意: pinia提供的storeToRefs只会将数据做转换, 而vue的toRefs会转换store中所有数据和方法。

1, src/components/Count.vue
<template>
	<div class="count">
		<h2>当前求和为: {{sum}}</h2>
	</div>
</template>

<script setup lang="ts" name="Count">
	import {useCountStore} from '@/store/count'
	/*引入 storeToRefs */
	import {storeToRefs} from 'pinia'
	
	/*得到countStore */
	const countStore = useCountStore()
	/*使用storeToRefs转换countStore,随后解构*/
	const {sum} = storeToRefs(countStore)
</script>

笔记

这句绿色代码确实把数据拿出来了,可数据丢失了响应式

添加 toRefs(countStore) 数据还真变成了响应式,实际开发中是不会用toRefs() 来包裹stroe的数据

打印一下,发现他把store身上所有的数据,方法等都变成了ref响应式数据

我们只需要将school,sum等数据包裹一下就可以了,increment是方法,不需要包裹

所以我们不能用toRefs()来包裹 store里面的存储库,如何解决这个问题呢?我们可以在pinia中引入 storeToRefs来解决这个问题

复制代码
1, 引入 storeToRefs 引入 useCountStore
import { useCountStore } from '@/store/count'
import { storeToRefs } from 'pinia'

2,使用
const countStore = useCountStore()
const {sum,school,address} = storeToRefs(countStore)

可以完美解决数据解构赋值问题

总结:

storeToRefs() 只关注 store里面的数据,不关注store里面的方法

_storeToRefs 实现代码如下:

复制代码
1, src/components/Dog.vue
<template>
    <div class="dog">
        <img v-for="(dog,index) in dogList" :key="index" :src="dog" alt="">
		<br>
		<button @click="getDog">再来一只小狗</button>
    </div>
</template>

<script setup lang="ts" name="Dog">
    import {useDogStore} from '@/store/dog.ts'
    import { storeToRefs } from 'pinia';

    const dogStore = useDogStore()
    const {dogList} = storeToRefs(dogStore)



    // 数据
    // let dogList = reactive([
    //     'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
    // ])

    // 方法
    async function getDog() {
        dogStore.addDog()
        // try {
        //     let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
        //     dogList.push(result.data.message)
        // } catch (error) {
        //     alert(error)
        // }
    }
</script>



<style scoped>
    .dog {
        background-color: pink;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    button {
		margin: 0 5px;
	}

	li {
		font-size: 20px;
	}

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





2, src/components/Count.vue
<template>
    <div class="count">
        <h2>当前求和为: {{ sum }}</h2>
        <h3>欢迎来到: {{ school }},坐落于: {{ address }}</h3>
        <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>

<script setup lang="ts" name="Count">
    import { ref,reactive,computed,toRefs } from 'vue'
    import { storeToRefs } from 'pinia'

    // 引入 useCountStore
    import { useCountStore } from '@/store/count'

    // 使用useCountStore,得到一个专门保存 count 相关的 store 实例对象 countStore
    const countStore = useCountStore()
    // 使用storeToRefs只会关注store中的数据,不会对方法进行ref包裹 解构赋值,可以直接访问里面的数据和方法
    const {sum,school,address} = storeToRefs(countStore)
    // console.log('!!!',storeToRefs(countStore))

    // const {sum,school,address} = toRefs(countStore)
    // console.log('!!!',toRefs(countStore))




    // 由于 countStore 返回的是响应式对象数据,所以可以直接访问里面的数据和方法,
    // 不需要解构赋值,也不需要.value访问
    // 以下三种方式都可以拿到state中的数据
    // 第一种拿到sum数据的方式
    // console.log('@@@',countStore.sum) // 响应式对象数据,可以直接访问里面的数据和方法
    // 第二种拿到sum数据的方式
    // console.log('@@@',countStore.$state.sum)  // 响应式对象数据,可以直接访问里面的数据和方法
    // 第三种拿到sum数据的方式
    // let sum = computed(()=>{
    //     return countStore.sum
    // })
    // console.log('@@@',countStore.$state.sum)  



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

    let x = ref(4)

    console.log(obj.a)
    console.log(obj.b)
    console.log(obj.c)  // 撤包了 不需要.value访问,直接访问即可
    console.log(x.value) // 需要.value访问

    */


    // 数据
    let n = ref(1)   // 用户选择的数字

    // 方法
    function add() {
        // 响应式对象数据,可以直接访问里面的数据和方法
        // 不需要解构赋值,也不需要.value访问
        // countStore.sum += n.value 

        // 第一种修改数据的方式
        // countStore.sum += 1
        // countStore.school = '尚硅谷'
        // countStore.address = '北京'

        // 第二种批量修改数据的方式
        // countStore.$patch({
        //     sum: countStore.sum + 1,
        //     school: '尚硅谷',
        //     address: '北京'
        // })

        // 第三种修改数据的方式
        countStore.increment(n.value)
    }
    function minus() {
        countStore.decrement(n.value)
        // countStore.sum -= n.value
    }
</script>

<style scoped>
    .count {
        background-color: skyblue;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    select,button {
        margin: 0 5px;
        height: 25px;
    }
</style>








3, src/components/LoveTalk.vue
<template>
    <div class="talk">
        <button @click="getLoveTalk">获取一句土味情话</button>
        <ul>
            <li v-for="talk in talkList" :key="talk.id">{{ talk.title }}</li>
        </ul>
    </div>
</template>

<script setup lang="ts" name="LoveTalk">
import {useTalkStore} from '@/store/loveTalk.ts'
import { storeToRefs } from 'pinia';

const talkStore = useTalkStore()
const { talkList } = storeToRefs(talkStore)

// console.log('@',talkStore)


// 数据
// let talkList = reactive([
//     {id: 'zg01', title: '今天你有点怪,哪里怪,怪好看的'},
//     {id: 'zg02', title: '草莓,蓝莓,樱桃,今天想我没有'},
//     {id: 'zg03', title: '心里给你留了一块地,想放点啥就放点啥'},
// ]);

// 方法  发送请求获取一句土味情话
function getLoveTalk() {
    talkStore.getAddTalk()
}

//async function getLoveTalk() {
    // 发送请求获取一句土味情话 连续两次结构加重命名
    // let result = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')

    // 1. let {data: {content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')
    // console.log(result.data.content);
    // 把请求回来的数据字符串,包装成对象,添加到数组中
    // let obj = {id: nanoid(), title: result.data.content};
    // 2. let obj = {id: nanoid(), title}; // title: title触发对象的简写形式直接写title就可以了
    // console.log(obj);
    // 添加到数组中
    // 3. talkList.unshift(obj);  // 添加到数组开头位置
    // talkList.push({id: nanoid(), title: result.data.content});// 添加到数组末尾位置

//}
</script>

<style scoped>
.talk {
    background-color: orange;
    padding: 10px;   
    border-radius: 10px;
    box-shadow: 0 0 10px; 
}
</style>






4, src/store/dog.ts
import {defineStore} from 'pinia'
import axios from 'axios'

export const useDogStore = defineStore('dog',{ // 配置对象
    actions:{
        async addDog(){
            // this.dogList.push(url)
            try {
                let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
                this.dogList.push(result.data.message)
            } catch (error) {
                alert(error)
            }
        }
    },
    // 真正存储数据的地方
    state:()=>{
        return {
            dogList:[
                'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
            ]
        }
    }
})





5, src/store/count.ts
import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{ // 配置对象
    // actions里面放置一个一个的动作函数或者方法,用于响应式组件中的"动作(比如要加,要减)" 用来修改数据
    actions: {
        increment(value:number) { // 修改数据
            // 1, console.log('increment被调用了',value)
            // 2, console.log(this)
            // 如何修改数据 有两种方式修改数据 使用 this.sum 或者使用this.$state.sum 都可以修改数据
            // console.log(this.$state.sum) // 8 拿到sum的值 8
            // console.log(this.sum) // 8 拿到sum的值 8
            // this 是当前的store实例对象,this.sum 就是访问store里面的数据,this.sum++ 就是修改数据
            
            if (this.sum < 10) {
                this.sum += value;
            }
        },
        decrement(value:number) {
            console.log('decrement被调用了',value)
            if (this.sum > 0) {
                this.sum -= value;
            }
        },
        reset() {
            // 重置数据
            this.sum = 0;
            this.school = '北京大学';
        }
    },
    // 真正存储数据的地方
    state:()=>{
        return {
            sum: 6,
            school: 'atguigu',
            address: '宏福科技园'
        }
    }
})





6, src/store/loveTalk.ts
import {defineStore} from 'pinia'
import axios from 'axios';
import { nanoid } from 'nanoid';

export const useTalkStore = defineStore('talk',{ // 配置对象
    actions:{
        async getAddTalk() {
            let {data: {content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')
            let obj = {id: nanoid(), title}; // 生成一个唯一的ID,用于唯一标识对话内容
            this.talkList.unshift(obj);  // 添加到数组开头位置,实现最新对话在最上方显示的效果
        }

        // // 添加一个对话
        //  addTalk(title:string){ // 添加对话
        //     const talk = {id: Date.now().toString(), title}
        //     this.talkList.push(talk)
        // },
        // // 删除对话
        // delTalk(id:string){ // 根据ID删除对话
        //     const index = this.talkList.findIndex((item)=> item.id === id)
        //     if(index !== -1) {
        //         this.talkList.splice(index, 1)
        //     }
        // },
        // // 清空对话
        // clearTalk(){ // 清空所有对话
        //     this.talkList = []
        // }
    },
    // 真正存储数据的地方
    state:()=>{
        return {
            talkList:[
                {id: 'zg01', title: '今天你有点怪,哪里怪,怪好看的'},
                {id: 'zg02', title: '草莓,蓝莓,樱桃,今天想我没有'},
                {id: 'zg03', title: '心里给你留了一块地,想放点啥就放点啥'},
            ]
        }
    }
})

049_getters的使用

有一天你对pinia里面的数据不满意时,就可以追加 getters,vuex里面也有getters.
5.6 [getters]
复制代码
1, 概念: 当 state 中的数据,需要经过处理后再使用时,可以使用getters配置。
2, 追加 gettere 配置
// 引入 defineStore 用于创建 store
import {defineStore} from 'pinia'

// 定义并暴露一个 store
export const useCountStore = defineStore('count',{
	// 动作
	actions: {
		/******/
	},
	// 状态
	state() {
		return {
			sum: 1,
			school: 'atguigu'
		}
	},
	// 计算
    getters: {
    	bigSum: state => state.sum*10,
        // bigSum:(state):number => state.sum*10,
        upperSchool():string{
        	return this.school.toUpperCase()
        }
    }
})

笔记

050_$subscribe的使用

这节课我们来说一下订阅,他可以让你监视state里面数据极其变化。
5.7 [$subscribe]
复制代码
通过 store 的 $subscribe() 方法侦听 state 极其变化
talkStore.$subscribe((mutate,state)=>{
	console.log('LoveTalk',mutate,state)
	localStorage.setItem('talk',JSON.stringify(talkList.value))
})

笔记

代码-效果

代码-效果

发现一个尴尬的情况: localStore 里面存储的都是字符串,如果你传的不是字符串,底层会调用toString(),如果一个数据里面都是对象,调用了toString()必定是[object Object],[object Object]...所以你要真想存储,我们就得使用 JSON.stringify(state.talkList)此时飘红就解决了

代码如下:

复制代码
localStorage.setItem('talkList',JSON.stringify(state.talkList))
代码的意思: 我要存储数组,并且要打成字符串的形式

存储数组且打成字符串的形式

能存储到本地,我们就可以办大事了,可以实现刷新不丢失数据

初始值的时候,不要写死这三个,那怎么办?我们存储什么就去拿什么localStorage.getItem('talk'),但是你光拿不行,

光拿是很危险的,就变成了如下如图所示的点...,你有这么多数据吗?不是的,而是你这么拿的话,拿出来的是一个字符串,字符串一旦参与v-for遍历,就变成了如下如图所示的点...

所以说,你拿出来的那一堆数据要将他转换一下,当时你把字符串存储进去的,你现在就得把字符串转换回来,使用 JSON.parse(localStorage.getItem('talkList') as string) || []

代码-效果

你有可能取不出来,类型有问题,

我们可以使用 as string 直接断言,他就是一个能取出来的字符串

此时上面的代码还是不完善,有可能人家第一次使用你家的网站,key里面可能没有任何东西,你可以刷新,他什么都没有,但是你如果点击按钮,立马报错,你不能从null身上读取 unshift()

因为你把null交给 JSON.parse()解析完成后还是null,

你点击按钮就是添加,此时就是 null.unshift,你是不是在null身上读取unshift,所以你就有问题了。

如何处理,我们可以写或者一个空数组,就可以解决 null.unshift问题,你里面有数据我们就解析,没有就使用空数组

效果如下,完美解决问题

_$subscribe和getters的使用 实现代码如下

复制代码
1, src/components/Dog.vue
<template>
    <div class="dog">
        <img v-for="(dog,index) in dogList" :key="index" :src="dog" alt="">
		<br>
		<button @click="getDog">再来一只小狗</button>
    </div>
</template>

<script setup lang="ts" name="Dog">
    import {useDogStore} from '@/store/dog.ts'
    import { storeToRefs } from 'pinia';

    const dogStore = useDogStore()
    const {dogList} = storeToRefs(dogStore)
    dogStore.$subscribe((mutate,state)=>{
        console.log('dogStore里面保存的数据发生变化了',mutate,state)
        // 持久化存储数据到本地存储中
        // localStorage.setItem('dogList',state.dogList)
        localStorage.setItem('dogList',JSON.stringify(state.dogList))
    })



    // 数据
    // let dogList = reactive([
    //     'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
    // ])

    // 方法
    async function getDog() {
        dogStore.addDog()
        // try {
        //     let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
        //     dogList.push(result.data.message)
        // } catch (error) {
        //     alert(error)
        // }
    }
</script>



<style scoped>
    .dog {
        background-color: pink;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    button {
		margin: 0 5px;
	}

	li {
		font-size: 20px;
	}

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





2, src/components/Count.vue
<template>
    <div class="count">
        <h2>当前求和为: {{ sum }},放大10倍: {{ bigSum }}</h2>
        <h3>欢迎来到: {{ school }},坐落于: {{ address }},大写: {{upperSchool}}</h3>
        <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>

<script setup lang="ts" name="Count">
    import { ref,reactive,computed,toRefs } from 'vue'
    import { storeToRefs } from 'pinia'

    // 引入 useCountStore
    import { useCountStore } from '@/store/count'

    // 使用useCountStore,得到一个专门保存 count 相关的 store 实例对象 countStore
    const countStore = useCountStore()
    // 使用storeToRefs只会关注store中的数据,不会对方法进行ref包裹 解构赋值,可以直接访问里面的数据和方法
    const {sum,school,address,bigSum,upperSchool} = storeToRefs(countStore)
    // console.log('!!!',storeToRefs(countStore))

    // const {sum,school,address} = toRefs(countStore)
    // console.log('!!!',toRefs(countStore))




    // 由于 countStore 返回的是响应式对象数据,所以可以直接访问里面的数据和方法,
    // 不需要解构赋值,也不需要.value访问
    // 以下三种方式都可以拿到state中的数据
    // 第一种拿到sum数据的方式
    // console.log('@@@',countStore.sum) // 响应式对象数据,可以直接访问里面的数据和方法
    // 第二种拿到sum数据的方式
    // console.log('@@@',countStore.$state.sum)  // 响应式对象数据,可以直接访问里面的数据和方法
    // 第三种拿到sum数据的方式
    // let sum = computed(()=>{
    //     return countStore.sum
    // })
    // console.log('@@@',countStore.$state.sum)  



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

    let x = ref(4)

    console.log(obj.a)
    console.log(obj.b)
    console.log(obj.c)  // 撤包了 不需要.value访问,直接访问即可
    console.log(x.value) // 需要.value访问

    */


    // 数据
    let n = ref(1)   // 用户选择的数字

    // 方法
    function add() {
        // 响应式对象数据,可以直接访问里面的数据和方法
        // 不需要解构赋值,也不需要.value访问
        // countStore.sum += n.value 

        // 第一种修改数据的方式
        // countStore.sum += 1
        // countStore.school = '尚硅谷'
        // countStore.address = '北京'

        // 第二种批量修改数据的方式
        // countStore.$patch({
        //     sum: countStore.sum + 1,
        //     school: '尚硅谷',
        //     address: '北京'
        // })

        // 第三种修改数据的方式
        countStore.increment(n.value)
    }
    function minus() {
        countStore.decrement(n.value)
        // countStore.sum -= n.value
    }
</script>

<style scoped>
    .count {
        background-color: skyblue;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    select,button {
        margin: 0 5px;
        height: 25px;
    }
</style>








3, src/components/LoveTalk.vue
<template>
    <div class="talk">
        <button @click="getLoveTalk">获取一句土味情话</button>
        <ul>
            <li v-for="talk in talkList" :key="talk.id">{{ talk.title }}</li>
        </ul>
    </div>
</template>

<script setup lang="ts" name="LoveTalk">
import {useTalkStore} from '@/store/loveTalk.ts'
import { storeToRefs } from 'pinia';

const talkStore = useTalkStore()
const { talkList } = storeToRefs(talkStore)
talkStore.$subscribe((mutate,state)=>{
    console.log('talkStore保存的数据变化了',mutate,state)
    // 浏览器的本地存储,持久化数据保存到本地存储中
    localStorage.setItem('talkList',JSON.stringify(state.talkList))
})
// talkStore.$subscribe((mutation, state) => {
//     if (mutation.type === 'getAddTalk') {
//         console.log('数据更新了', state)
//     }
// })

// console.log('@',talkStore)


// 数据
// let talkList = reactive([
//     {id: 'zg01', title: '今天你有点怪,哪里怪,怪好看的'},
//     {id: 'zg02', title: '草莓,蓝莓,樱桃,今天想我没有'},
//     {id: 'zg03', title: '心里给你留了一块地,想放点啥就放点啥'},
// ]);

// 方法  发送请求获取一句土味情话
function getLoveTalk() {
    talkStore.getAddTalk()
}

//async function getLoveTalk() {
    // 发送请求获取一句土味情话 连续两次结构加重命名
    // let result = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')

    // 1. let {data: {content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')
    // console.log(result.data.content);
    // 把请求回来的数据字符串,包装成对象,添加到数组中
    // let obj = {id: nanoid(), title: result.data.content};
    // 2. let obj = {id: nanoid(), title}; // title: title触发对象的简写形式直接写title就可以了
    // console.log(obj);
    // 添加到数组中
    // 3. talkList.unshift(obj);  // 添加到数组开头位置
    // talkList.push({id: nanoid(), title: result.data.content});// 添加到数组末尾位置

//}
</script>

<style scoped>
.talk {
    background-color: orange;
    padding: 10px;   
    border-radius: 10px;
    box-shadow: 0 0 10px; 
}
</style>




4, src/store/dog.ts
import {defineStore} from 'pinia'
import axios from 'axios'

export const useDogStore = defineStore('dog',{ // 配置对象
    actions:{
        async addDog(){
            // this.dogList.push(url)
            try {
                let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
                this.dogList.push(result.data.message)
            } catch (error) {
                alert(error)
            }
        }
    },
    // 真正存储数据的地方
    state:()=>{
        return {
            dogList:JSON.parse(localStorage.getItem('dogList') as string)||[]
            // 2, dogList:JSON.parse(localStorage.getItem('dogList') as string||'[]'),
            // 3, dogList:localStorage.getItem('dogList')?JSON.parse(localStorage.getItem('dogList')!):[]
            // dogList:[
            //     'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
            // ]
        }
    }
})




5, src/store/count.ts
import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{ // 配置对象
    // actions里面放置一个一个的动作函数或者方法,用于响应式组件中的"动作(比如要加,要减)" 用来修改数据
    actions: {
        increment(value:number) { // 修改数据
            // 1, console.log('increment被调用了',value)
            // 2, console.log(this)
            // 如何修改数据 有两种方式修改数据 使用 this.sum 或者使用this.$state.sum 都可以修改数据
            // console.log(this.$state.sum) // 8 拿到sum的值 8
            // console.log(this.sum) // 8 拿到sum的值 8
            // this 是当前的store实例对象,this.sum 就是访问store里面的数据,this.sum++ 就是修改数据
            
            if (this.sum < 10) {
                this.sum += value;
            }
        },
        decrement(value:number) {
            console.log('decrement被调用了',value)
            if (this.sum > 0) {
                this.sum -= value;
            }
        },
        reset() {
            // 重置数据
            this.sum = 0;
            this.school = '北京大学';
        }
    },
    // 真正存储数据的地方
    state:()=>{
        return {
            sum: 6,
            school: 'atguigu',
            address: '宏福科技园'
        }
    },
    getters: {
        // 计算属性
        bigSum:state => state.sum * 10,
        // bigSum(state) {
        //     return state.sum * 10; // 计算属性,返回一个新的值
        // },
        upperSchool():string {
            console.log('@@@@',this);
            // return state.school.toUpperCase();
            return this.school.toUpperCase(); // 计算属性,返回一个新的值
        },
        // 计算属性,返回一个新的值
        // ...... 其他的计算属性
    }
})





6, src/store/loveTalk.ts
import {defineStore} from 'pinia'
import axios from 'axios';
import { nanoid } from 'nanoid';

export const useTalkStore = defineStore('talk',{ // 配置对象
    actions:{
        async getAddTalk() {
            let {data: {content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')
            let obj = {id: nanoid(), title}; // 生成一个唯一的ID,用于唯一标识对话内容
            this.talkList.unshift(obj);  // 添加到数组开头位置,实现最新对话在最上方显示的效果
        }

        // // 添加一个对话
        //  addTalk(title:string){ // 添加对话
        //     const talk = {id: Date.now().toString(), title}
        //     this.talkList.push(talk)
        // },
        // // 删除对话
        // delTalk(id:string){ // 根据ID删除对话
        //     const index = this.talkList.findIndex((item)=> item.id === id)
        //     if(index !== -1) {
        //         this.talkList.splice(index, 1)
        //     }
        // },
        // // 清空对话
        // clearTalk(){ // 清空所有对话
        //     this.talkList = []
        // }
    },
    // 真正存储数据的地方
    state:()=>{
        return {
            talkList:JSON.parse(localStorage.getItem('talkList') as string) || []
            // 2, talkList:JSON.parse(localStorage.getItem('talkList') as string || '[]')
            // 3, talkList:localStorage.getItem('talkList') ? JSON.parse(localStorage.getItem('talkList')!) : []
            // talkList:[
            //     {id: 'zg01', title: '今天你有点怪,哪里怪,怪好看的'},
            //     {id: 'zg02', title: '草莓,蓝莓,樱桃,今天想我没有'},
            //     {id: 'zg03', title: '心里给你留了一块地,想放点啥就放点啥'},
            // ]
        }
    }
})

051_store组合式写法

红色的是一个对象,绿色的是选项===>选项式写法

组合式写法

绿色框里面相当于setup函数

_store组合式写法 实现代码如下

复制代码
1, src/components/Dog.vue
<template>
    <div class="dog">
        <img v-for="(dog,index) in dogList" :key="index" :src="dog" alt="">
		<br>
		<button @click="getDog">再来一只小狗</button>
    </div>
</template>

<script setup lang="ts" name="Dog">
    import {useDogStore} from '@/store/dog.ts'
    import { storeToRefs } from 'pinia';

    const dogStore = useDogStore()
    const {dogList} = storeToRefs(dogStore)
    dogStore.$subscribe((mutate,state)=>{
        console.log('dogStore里面保存的数据发生变化了',mutate,state)
        // 持久化存储数据到本地存储中
        // localStorage.setItem('dogList',state.dogList)
        localStorage.setItem('dogList',JSON.stringify(state.dogList))
    })



    // 数据
    // let dogList = reactive([
    //     'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
    // ])

    // 方法
    async function getDog() {
        dogStore.addDog()
        // try {
        //     let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
        //     dogList.push(result.data.message)
        // } catch (error) {
        //     alert(error)
        // }
    }
</script>



<style scoped>
    .dog {
        background-color: pink;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    button {
		margin: 0 5px;
	}

	li {
		font-size: 20px;
	}

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





2, src/components/Count.vue
<template>
    <div class="count">
        <h2>当前求和为: {{ sum }},放大10倍: {{ bigSum }}</h2>
        <h3>欢迎来到: {{ school }},坐落于: {{ address }},大写: {{upperSchool}}</h3>
        <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>

<script setup lang="ts" name="Count">
    import { ref,reactive,computed,toRefs } from 'vue'
    import { storeToRefs } from 'pinia'

    // 引入 useCountStore
    import { useCountStore } from '@/store/count'

    // 使用useCountStore,得到一个专门保存 count 相关的 store 实例对象 countStore
    const countStore = useCountStore()
    // 使用storeToRefs只会关注store中的数据,不会对方法进行ref包裹 解构赋值,可以直接访问里面的数据和方法
    const {sum,school,address,bigSum,upperSchool} = storeToRefs(countStore)
    // console.log('!!!',storeToRefs(countStore))

    // const {sum,school,address} = toRefs(countStore)
    // console.log('!!!',toRefs(countStore))




    // 由于 countStore 返回的是响应式对象数据,所以可以直接访问里面的数据和方法,
    // 不需要解构赋值,也不需要.value访问
    // 以下三种方式都可以拿到state中的数据
    // 第一种拿到sum数据的方式
    // console.log('@@@',countStore.sum) // 响应式对象数据,可以直接访问里面的数据和方法
    // 第二种拿到sum数据的方式
    // console.log('@@@',countStore.$state.sum)  // 响应式对象数据,可以直接访问里面的数据和方法
    // 第三种拿到sum数据的方式
    // let sum = computed(()=>{
    //     return countStore.sum
    // })
    // console.log('@@@',countStore.$state.sum)  



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

    let x = ref(4)

    console.log(obj.a)
    console.log(obj.b)
    console.log(obj.c)  // 撤包了 不需要.value访问,直接访问即可
    console.log(x.value) // 需要.value访问

    */


    // 数据
    let n = ref(1)   // 用户选择的数字

    // 方法
    function add() {
        // 响应式对象数据,可以直接访问里面的数据和方法
        // 不需要解构赋值,也不需要.value访问
        // countStore.sum += n.value 

        // 第一种修改数据的方式
        // countStore.sum += 1
        // countStore.school = '尚硅谷'
        // countStore.address = '北京'

        // 第二种批量修改数据的方式
        // countStore.$patch({
        //     sum: countStore.sum + 1,
        //     school: '尚硅谷',
        //     address: '北京'
        // })

        // 第三种修改数据的方式
        countStore.increment(n.value)
    }
    function minus() {
        countStore.decrement(n.value)
        // countStore.sum -= n.value
    }
</script>

<style scoped>
    .count {
        background-color: skyblue;
        padding: 10px;   
        border-radius: 10px;
        box-shadow: 0 0 10px; 
    }
    select,button {
        margin: 0 5px;
        height: 25px;
    }
</style>









3, src/components/LoveTalk.vue
<template>
    <div class="talk">
        <button @click="getLoveTalk">获取一句土味情话</button>
        <ul>
            <li v-for="talk in talkList" :key="talk.id">{{ talk.title }}</li>
        </ul>
    </div>
</template>

<script setup lang="ts" name="LoveTalk">
import {useTalkStore} from '@/store/loveTalk.ts'
import { storeToRefs } from 'pinia';

const talkStore = useTalkStore()
const { talkList } = storeToRefs(talkStore)
talkStore.$subscribe((mutate,state)=>{
    console.log('talkStore保存的数据变化了',mutate,state)
    // 浏览器的本地存储,持久化数据保存到本地存储中
    localStorage.setItem('talkList',JSON.stringify(state.talkList))
})
// talkStore.$subscribe((mutation, state) => {
//     if (mutation.type === 'getAddTalk') {
//         console.log('数据更新了', state)
//     }
// })

// console.log('@',talkStore)


// 数据
// let talkList = reactive([
//     {id: 'zg01', title: '今天你有点怪,哪里怪,怪好看的'},
//     {id: 'zg02', title: '草莓,蓝莓,樱桃,今天想我没有'},
//     {id: 'zg03', title: '心里给你留了一块地,想放点啥就放点啥'},
// ]);

// 方法  发送请求获取一句土味情话
function getLoveTalk() {
    talkStore.getAddTalk()
}

//async function getLoveTalk() {
    // 发送请求获取一句土味情话 连续两次结构加重命名
    // let result = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')

    // 1. let {data: {content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')
    // console.log(result.data.content);
    // 把请求回来的数据字符串,包装成对象,添加到数组中
    // let obj = {id: nanoid(), title: result.data.content};
    // 2. let obj = {id: nanoid(), title}; // title: title触发对象的简写形式直接写title就可以了
    // console.log(obj);
    // 添加到数组中
    // 3. talkList.unshift(obj);  // 添加到数组开头位置
    // talkList.push({id: nanoid(), title: result.data.content});// 添加到数组末尾位置

//}
</script>

<style scoped>
.talk {
    background-color: orange;
    padding: 10px;   
    border-radius: 10px;
    box-shadow: 0 0 10px; 
}
</style>





4, src/store/dog.ts
import {defineStore} from 'pinia'
import axios from 'axios'

// 1, 组合式API写法 函数写法
import { reactive } from 'vue'
export const useDogStore = defineStore('dog',()=>{
    // dogList相当于state, 相当于data
    const dogList = reactive(JSON.parse(localStorage.getItem('dogList') as string)||[])

    // addDog相当于actions, 相当于methods
    async function addDog(){
        try {
            let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
            dogList.push(result.data.message)
        } catch (error) {
            alert(error)
        }
    }

    // 3, 暴露出去的属性, 相当于computed
    return {dogList,addDog}
})



// 2, 选项式API写法 配置对象写法
// export const useDogStore = defineStore('dog',{ // 配置对象
//     actions:{
//         async addDog(){
//             // this.dogList.push(url)
//             try {
//                 let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
//                 this.dogList.push(result.data.message)
//             } catch (error) {
//                 alert(error)
//             }
//         }
//     },
//     // 真正存储数据的地方
//     state:()=>{
//         return {
//             dogList:JSON.parse(localStorage.getItem('dogList') as string)||[]
//             // 2, dogList:JSON.parse(localStorage.getItem('dogList') as string||'[]'),
//             // 3, dogList:localStorage.getItem('dogList')?JSON.parse(localStorage.getItem('dogList')!):[]
//             // dogList:[
//             //     'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
//             // ]
//         }
//     }
// })





5, src/store/count.ts
import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{ // 配置对象
    // actions里面放置一个一个的动作函数或者方法,用于响应式组件中的"动作(比如要加,要减)" 用来修改数据
    actions: {
        increment(value:number) { // 修改数据
            // 1, console.log('increment被调用了',value)
            // 2, console.log(this)
            // 如何修改数据 有两种方式修改数据 使用 this.sum 或者使用this.$state.sum 都可以修改数据
            // console.log(this.$state.sum) // 8 拿到sum的值 8
            // console.log(this.sum) // 8 拿到sum的值 8
            // this 是当前的store实例对象,this.sum 就是访问store里面的数据,this.sum++ 就是修改数据
            
            if (this.sum < 10) {
                this.sum += value;
            }
        },
        decrement(value:number) {
            console.log('decrement被调用了',value)
            if (this.sum > 0) {
                this.sum -= value;
            }
        },
        reset() {
            // 重置数据
            this.sum = 0;
            this.school = '北京大学';
        }
    },
    // 真正存储数据的地方
    state:()=>{
        return {
            sum: 6,
            school: 'atguigu',
            address: '宏福科技园'
        }
    },
    getters: {
        // 计算属性
        bigSum:state => state.sum * 10,
        // bigSum(state) {
        //     return state.sum * 10; // 计算属性,返回一个新的值
        // },
        upperSchool():string {
            console.log('@@@@',this);
            // return state.school.toUpperCase();
            return this.school.toUpperCase(); // 计算属性,返回一个新的值
        },
        // 计算属性,返回一个新的值
        // ...... 其他的计算属性
    }
})






6, src/store/loveTalk.ts
import {defineStore} from 'pinia'
import axios from 'axios';
import { nanoid } from 'nanoid';

// 1, 组合式API写法 函数写法 
import { reactive } from 'vue'
export const useTalkStore = defineStore('talk',()=>{
    // talkList相当于state,相当于组件的data属性
    const talkList = reactive(
        JSON.parse(localStorage.getItem('talkList') as string) || []
    )
    
    // getAddTalk()函数相当于action
    async function getAddTalk() {
        let {data: {content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')
        let obj = {id: nanoid(), title}; // 生成一个唯一的ID,用于唯一标识对话内容
        talkList.unshift(obj);  // 添加到数组开头位置,实现最新对话在最上方显示的效果
    }
    return {talkList, getAddTalk}
})

// 2, 选项式API写法 配置对象写法
// export const useTalkStore = defineStore('talk',{ // 配置对象
//     actions:{
//         async getAddTalk() {
//             let {data: {content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json&charset=utf-8')
//             let obj = {id: nanoid(), title}; // 生成一个唯一的ID,用于唯一标识对话内容
//             this.talkList.unshift(obj);  // 添加到数组开头位置,实现最新对话在最上方显示的效果
//         }

//         // // 添加一个对话
//         //  addTalk(title:string){ // 添加对话
//         //     const talk = {id: Date.now().toString(), title}
//         //     this.talkList.push(talk)
//         // },
//         // // 删除对话
//         // delTalk(id:string){ // 根据ID删除对话
//         //     const index = this.talkList.findIndex((item)=> item.id === id)
//         //     if(index !== -1) {
//         //         this.talkList.splice(index, 1)
//         //     }
//         // },
//         // // 清空对话
//         // clearTalk(){ // 清空所有对话
//         //     this.talkList = []
//         // }
//     },
//     // 真正存储数据的地方
//     state:()=>{
//         return {
//             talkList:JSON.parse(localStorage.getItem('talkList') as string) || []
//             // 2, talkList:JSON.parse(localStorage.getItem('talkList') as string || '[]')
//             // 3, talkList:localStorage.getItem('talkList') ? JSON.parse(localStorage.getItem('talkList')!) : []
//             // talkList:[
//             //     {id: 'zg01', title: '今天你有点怪,哪里怪,怪好看的'},
//             //     {id: 'zg02', title: '草莓,蓝莓,樱桃,今天想我没有'},
//             //     {id: 'zg03', title: '心里给你留了一块地,想放点啥就放点啥'},
//             // ]
//         }
//     }
// })
相关推荐
哆啦A梦15881 小时前
Vue3魔法手册 作者 张天禹 014_组件通信
前端·vue.js·typescript
木斯佳1 小时前
前端八股文面经大全:有赞前端一面二面HR面(2026-1-13)·面经深度解析
前端·状态模式
VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue养老院管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
码云数智-园园2 小时前
Vue 3 + TypeScript 企业级项目架构实战:从0到1打造可维护的前端工程体系
前端·vue.js·typescript
CappuccinoRose2 小时前
CSS 语法学习文档(十五)
前端·学习·重构·渲染·浏览器
Marshall1512 小时前
DC-SDK 实战指南:基于 Cesium 的三维数字孪生大屏开发 前言 在当今数字孪生、智慧城市等领域的开发中,三维地图可视化已经成为核心需求。
前端
少云清3 小时前
【UI自动化测试】5_web自动化测试 _元素操作和元素信息获取
前端·web自动化测试
lyyl啊辉3 小时前
2. Vue数据双向绑定
前端·vue.js
CappuccinoRose4 小时前
CSS 语法学习文档(十七)
前端·css·学习·布局·houdini·瀑布流布局·csspaintingapi