【Vue3(八)】


前言

一、示例效果

实现如下效果:
在这里插入图片描述
创建两个组件,在App.vue里引入

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

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


import LoveTalk from "@/components/LoveTalk.vue";
import Count from "@/components/Count.vue";
</script>
<style scoped>

</style>


计算组件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>
      <option value="4">4</option>
    </select>
    <button @click="add"></button>
    <button @click="minus"></button>
  </div>
</template>

<script lang="ts" setup 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>
<style scoped>
.count{
  background-color: aquamarine;
  padding: 10px;
  border-radius: 10px;
  box-shadow: 0 0 10px
}
select,button{
  margin:0 5px;
  height: 25px;
}
</style>


在土味情话的组件LoveTalk.vue里,要npm i nanoid

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

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

let talkList = reactive([
    {id:'001',title:'你今天有点怪,怪好看的'},
  {id:'002',title:'草莓,蓝莓,蔓越莓,今天想我没'},
  {id:'003',title:'心里留了一块地'}
  ])

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

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


二、搭建pinia环境

vue2用vuex,vue3用pinia,都是集中式状态(数据)管理
先下载npm i pinia,在main.ts里引入pinia,创建pinia,安装pinia
main.ts


// 引入createApp用于创建应用,相当于花盆
import { createApp } from 'vue'

// 引入App根组件放在应用
// @ts-ignore  用于告诉TypeScript编译器忽略某个特定错误或警告
import App from './App.vue'

// 第一步:引入pinia
// @ts-ignore

import { createPinia } from 'pinia';



// 创建一个应用
const app = createApp(App)
// 第二步:创建pinia
const pinia = createPinia();
// 第三步:安装pinia
app.use(pinia)

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



三、存储+读取数据

在src下新建store文件,新建count.ts和lovetalk.ts分别存放相关内容数据。在ts文件里引入defineStore,将定义的方法暴露出去
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:'001',title:'你今天有点怪,怪好看的'},
                {id:'002',title:'草莓,蓝莓,蔓越莓,今天想我没'},
                {id:'003',title:'心里留了一块地'}

            ]
        }
    }
})

在相关组件里引入ts文件定义的方法并使用

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

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

const countStore = useCountStore()

// 以下两种方式都可拿到state中数据
// console.log('@@@',countStore.sum)
// console.log('@@@',countStore.$state.sum)

// // 若ref在reactive里,则被拆包,打印时不用加.value;若自己定义的,需要.value
// let obj = reactive({
//   a:1,
//   b:2,
//   c:ref(3)
// })
// let x = ref(9)
// console.log(obj.a)
// console.log(obj.b)
// console.log(obj.c)
// console.log(x.value)

// 数据

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

function add(){


}
function minus(){

}


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


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

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

const talkStore = useTalkStore()


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

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


在这里插入图片描述
在这里插入图片描述

四、修改数据

添加学校和地址,实现修改功能
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>
      <option value="4">4</option>
    </select>
    <button @click="add"></button>
    <button @click="minus"></button>
  </div>
</template>

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

const countStore = useCountStore()


// 数据

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

function add(){
  // 第一种修改方式
  // countStore.sum += 1
  // countStore.school = 'school'
  // countStore.address = '未知'

  // 第二种修改方式,针对数据多的情况,批量修改
  // countStore.$patch({
  //   sum:888,
  //   school: '北京大学',
  //   address: '北京'
  // })

  // 第三种修改方式
  countStore.increment(n.value)


}
function minus(){

}

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


以下是第一种修改方法和第二种修改方法的区别
在这里插入图片描述
在这里插入图片描述
第三种方法需要在count.ts添加actions

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:'清华',
            address:'北京'

        }
    }
})

五、storeToRefs

想要变成响应式,就要以下操作,注意toref()和storeToRefs()区别
在这里插入图片描述
在这里插入图片描述

代码如下(示例):

六、getters的使用

当state中的数据,需要经过处理后再使用时,可以使用getters配置
在count.ts文件里添加getters

import {defineStore} from "pinia";

export const useCountStore = defineStore('count',{
    // actions里面放置的是一个一个的方法,用于响应组件中动作
    actions:{
        increment(value:number){
            console.log('increment被调用了',value)
            if (this.sum < 10){
                // 修改数据(this是当前的store)
                this.sum += value
            }
        }
    },
    // 真正存储数据的地方
    state(){
        return {
            sum:1,
            school:'qinghua',
            address:'北京'

        }
    },
    getters:{
        // 使用this就不能使用箭头函数
        bigSum:state => {
            return state.sum *10
        },
        upperSchool(state){
            return this.school.toUpperCase()

        }
    }
})

若不写state参数,就要upperSchool():string{}
在这里插入图片描述

七、$subsccribe的使用

LoveTalk.vue

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

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

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

talkStore.$subscribe((mutate,state)=>{
  console.log('talkStore里面保存的数据发生了变化',mutate,state)
  // 浏览器本地存储,localStorage底层传的都是字符串,若传的不是字符串,会调用toString
  localStorage.setItem('talkList',JSON.stringify(state.talkList))

})

 function getLove(){
  talkStore.getATalk()

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


lovetalk.ts

import {defineStore} from "pinia";
import axios from "axios";
import {nanoid} from "nanoid";


export  const useTalkStore = defineStore('talk',{
    actions:{
         async getATalk(){
            // let result = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
            // 发请求,下面这行写法是:连续解构赋值+重命名
              let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
            // console.log(result.data)
            // 把请求回来的字符串,包装成一个对象
               let obj = {id:nanoid(),title}
            // let obj = {id:nanoid(),title:result.data.content}
            // console.log(obj)
            // 放到数组中
            this.talkList.unshift(obj)
        }
    },
    // 真正存储数据的地方
    state(){
        return {
            // 数据不丢失
            talkList:JSON.parse(localStorage.getItem('talkList')as string) || []
        }
    }
})

在这里插入图片描述

八、store组合式写法

在这里插入图片描述
在这里插入图片描述
组合式记得return

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值