Bootstrap

Vue3基础知识

1.vue3简单介绍

1.1 vue3的优势

在这里插入图片描述

1.2 vue3 VS vue2

需求:点击按钮,使数值+1

  1. vue2
<script>
export defaule{
	data(){
		return{
			count:0
        }
   },
   methods:{
   addCount(){
	    this.count++
   }
 }
}
</script>
  1. vue3
<script setup>
import {ref} from 'vue'
const count=ref(0)  //声明数据,声明一个0
const addCount=()=>count.value++
</script>

2.使用create-vue搭建vue3项目

2.1 认识create-vue

create-vue是Vue官方新的脚手架工具,底层切换到了vite(下一代构建工具),为开发提供极速响应。

2.2 使用create-vue创建项目

2.2.1 前提环境条件

已安装16.0或更高版本的Node.js

node -v

2.2.2 创建一个Vue应用

npm init vue@latest    //这一指令将会安装并执行create-vue

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

3.熟悉项目目录和关键文件

在这里插入图片描述
main.js
在这里插入图片描述
在这里插入图片描述

4.组合式API

4.1 组合式API - setup选项

组合式API:可理解成一系列函数,通过调用这些函数来书写逻辑;
setup选项:组合式API的入口,只有写setup,才可以写组合式API函数
在这里插入图片描述
setup选项中写代码的特点
在这里插入图片描述
setup中的内容需要return:setup中可定义变量、函数,但这些都需要return,后面模板中才可以使用

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

<!--setup
 1.执行时机比beforeCreate还要早
 2.setup函数中,获取不到this(this是undefined)
 3.数据和函数,需要在setup最后return,才能在模板中应用
问题:每次都要对setup中的数据或函数进行return 太麻烦?
解决:直接在script标签中加个setup语法糖,如<script setup>后,不用再写return返回setup中的数据或函数
 4.通过setup语法糖简化代码
-->

<!--<script>
export default {
  setup() {
    // console.log("setup函数",this)
    //  数据
    const message = "hello vue3"
    //  函数
    const logMessage = () => {
      console.log(message)
    }
    return {
      message,
      logMessage
    }
  },
  beforeCreate() {
    console.log("beforeCreate函数")
  }
}
</script>-->
<!--setup语法糖简化-->
<script setup>
//  数据
const message = "hello vue3"
//  函数
const logMessage = () => {
  console.log(message)
}
</script>

<template>
  <div>{{ message }}</div>
  <button @click="logMessage">按钮</button>
</template>
<style scoped>
</style>

4.2 组合式API - reactive和ref函数

4.2.1 reactive() 处理对象类型数据

作用:接收对象类型数据的参数传入并返回一个响应式的对象;
在这里插入图片描述

4.2.2 ref() 处理简单类型或对象类型的数据

作用:接收简单类型或对象类型的数据传入并返回一个响应式的对象;
在这里插入图片描述

<!--
1.reactive():接收一个对象类型的数据,返回一个响应式的对象
问题:reactive是接收一个对象类型的数据,如果是简单类型的数据,应该怎么办?
解决:使用ref()函数处理简单类型数据

2.ref():接收一个简单类型 或 复杂类型,返回一个响应式的对象
  本质:是再原有传入数据的基础上,外层包了一层,包成了复杂类型
  底层:包成复杂类型之后,再借助reactive()实现响应式
  注意:
    1.在script脚本中访问数据,需要通过.value;
    2.在template模板中访问数据,不需要加.value(帮我们扒了一层)
  推荐:以后声明数据,统一使用ref=>统一了编码规范
-->
<script setup>
//1.reactive()
/*import {reactive} from "vue";
const state = reactive({
  count: 100
})
const setCount = () => {
  state.count++
}*/

//2.ref()
import {ref} from "vue";

const count=ref(0)
// console.log(count.value)
const addCount=()=>{
  count.value++
}
const subCount=()=>{
  count.value--
}

</script>
<template>
  <div>
    <div>{{ count }}</div>
    <button @click="addCount">+1</button>
    <button @click="subCount">-1</button>
  </div>
</template>
<style scoped>
</style>

4.3 组合式API - computed计算属性函数

计算属性基本思想和Vue2的完全一致,组合式API下的计算属性只是修改了写法;
在这里插入图片描述

<!--
computed:计算属性基本思想和Vue2的完全一致,组合式API下的计算属性只是修改了写法;
-->
<script setup>
//基本语法:
//const 计算属性 = computed(()=>{return 计算返回的结果})
import {computed,ref} from "vue";
//声明数据
const list = ref([1, 2, 3, 4, 5, 6, 7, 8])
//基于list派生一个计算属性,要求从list中过滤出>2
const computedList = computed(() => {
  return list.value.filter(item => item > 2)
})
//定义修改数组的方法
const addFn = (() => {
  list.value.push(888)
})
</script>
<template>
  <div>
    <div>原始数据:{{ list }}</div>
    <div>计算后的数据:{{ computedList }}</div>
    <button type="button" @click="addFn">修改</button>
  </div>
</template>
<style scoped>
</style>

4.4 组合式API - watch

在这里插入图片描述
1.基础使用 - 侦听单个数据
在这里插入图片描述

<script setup>
//1.导入watch函数
import {ref,watch} from "vue";
//声明数据
const count = ref(0)
//2.调用watch侦听变化
//基本语法:
//watch(ref对象,回调函数),该watch侦听的作用,一旦count值发生变化,后面的回调函数就会自动执行
watch(count,(newValue,oldValue)=>{
  console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
})
</script>
  1. 基础使用 - 侦听多个数据
    在这里插入图片描述
<script setup>
//(2)侦听多个数据
import {ref, watch} from 'vue'

const count = ref(0)
const name = ref('cp')
const updateCount=()=>{
  count.value++
}
const updateName=()=>{
  name.value="沪漂豫姑娘~"
}
//ref多个对象用数组包裹
watch([count, name], ([newCount, newName], [oldCount, oldName]) => {
  console.log(`count或name变化了`, [newCount, newName], [oldCount, oldName])
})
</script>
<template>
  <div>
    <div>{{ count }}</div>
    <button @click="updateCount"><span>+1</span></button>
    <div>{{ name }}</div>
    <button @click="updateName">改昵称</button>
  </div>
</template>
<style scoped>
</style>
  1. 额外参数 - immediate 在这里插入图片描述
<script>
//(3)immediate 立刻执行
import {ref, watch} from "vue";

const count = ref(0)
const name = ref('张三')
const updateCount=()=>{
  count.value++
}
const updateName=()=>{
  name.value="沪漂豫姑娘~"
}
watch(count, (newValue,oldValue) => {
  console.log(newValue,oldValue)
}, {
  immediate: true
})
</script>
  1. 额外参数 - deep
<script>
//(4)deep 深度监视,默认的watch进行的是浅层监视,但如果需要监视复杂对象中的子属性数据的变化,可使用deep监视
//如果 const ref1=ref(简单类型),可以直接监视
//如果 const ref2=ref(复杂类型),监视不到复杂类型内部数据的变化(如果对象内部属性数据发生变化,但监视不到)
import {ref, watch} from "vue";

const userInfo = ref({
  name: 'zs',
  age: 18
})
const setUserInfo = () => {
  // 修改了userInfo.value修改了对象的地址,才能监视到
  // userInfo.value={name:'豫姑娘~',age:19}

  userInfo.value.age++
}
watch(userInfo, (newValue) => {
  console.log(newValue)
}, {
  deep: true
})
</script>
  1. 精确侦听对象中的某个属性
    在这里插入图片描述
<script>
// 需求:在不开启deep的前提下,侦听age的变化,只有age变化时才执行回调
import {ref, watch} from "vue";

const userInfo = ref({
  name: 'zs',
  age: 18
})
const setUserInfo = () => {
  // 修改了userInfo.value修改了对象的地址,才能监视到
  // userInfo.value={name:'豫姑娘~',age:19}
  userInfo.value.age++
  // userInfo.value.name="沪漂~"
}
watch(
    () => userInfo.value.age,  //监听对象中的指定属性,固定写法
    (newValue,oldValue) => console.log(newValue,oldValue))
</script>

注意:
(1)作为watch函数的第一个参数,ref对象需要添加.value吗?
答:不需要,第一个参数就是传ref对象
(2)watch只能侦听单个数据吗?
答:单个或多个
(3)不开启deep,直接监视 复杂类型,修改属性能触发回调吗?
答:不能,默认是浅层监听(只可以监听简单类型的数据,不可以监听对象类型的数据)
(4)不开启deep,精确侦听对象的某个属性?
答:可以把第一个参数写成函数的写法,返回要监听的具体属性;

4.5组合式API - 生命周期函数

在这里插入图片描述

<!--组合式API - 生命周期函数
-->
<script setup>
//beforeCreate 和 created 的相关代码
//一律放到setup中执行
import {onMounted} from "vue";

const getList = () => {
  setTimeout(() => {
    console.log('发送请求,获取数据')
  }, 2000)
}
//一进入页面,就会发送该请求
getList()

//如果有些代码需要在mounted生命周期中执行
onMounted(()=>{
  console.log('mounted生命周期函数 - 逻辑1')
})

//写成函数的调用方式,可以调用多次,并不会冲突,而是按照顺序依次执行
onMounted(()=>{
  console.log('mounted生命周期函数 - 逻辑2')
})

</script>
<template>

</template>
<style scoped>
</style>

4.6 组合式API - 父子通信

4.6.1 父传子

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

  1. 父组件 (App.vue)
<!--组合式API - 父子通信
(1)组合式API - 父传子
  基本思想:
  1)父组件中给子组件绑定属性(给子组件,添加属性的方式传值);
  2)子组件内部通过props选项接收(在子组件,通过props接收);
-->
<script setup>
import {ref} from 'vue'
//局部组件(导入进来就可以使用)
import SonCom from "@/components/son-com.vue"

const money = ref(100)

const getMoney = () => {
  money.value += 10
}
</script>
<template>
  <div>
    <h3>父组件 - {{ money }}
      <button @click="getMoney">挣钱</button>

    </h3>
    <!--  给子组件,添加属性的方式传值-->
    <!--  :money="money将数据动态的传入给子组件-->
    <SonCom car="宝马车" :money="money"></SonCom>
  </div>
</template>
<style scoped>
</style>
  1. 子组件 (son-com.vue)
<script setup>
//子组件(06.组件式API - 父传子)
//注意:
//(1)由于写了 setup,所以无法直接配置props选项,此处需要借助于“ 编译器宏 ”函数defineProps(),接收子组件传递的数据
//(2)在脚本(script)中,调用父组件传过来的数据props,需要props.属性名进行使用,而在模板(template)中使用父组件传过来的数据props,可以直接使用(不用加props前缀)

const props=defineProps({
//  在此处写配置项,接收父组件穿过来的数据
  car: String,
  money: Number
})
//  使用props.属性名使用父组件传过来的数据
console.log(props.car)
console.log(props.money)
</script>

<template>
<!--  直接使用父组件传过来props中的数据-->
<div class="son">子组件 - {{car}} - {{money}}</div>
</template>

<style scoped>
.son{
  border: 1px solid #000;
  padding: 30px;
}
</style>

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/11d9c459aee44230b65fa8fdf58fdfbb.png

4.6.2 子传父

在这里插入图片描述

  1. App.vue
<!--组合式API - 父子通信
(1)组合式API - 子传父
  基本思想:
    1)在子组件内部,通过emit方法触发事件(emit是通过编译器宏获取);
    2)在父组件中,给子组件标签通过@绑定事件(通过@进行监听);


-->
<script setup>
import {ref} from 'vue'
//局部组件(导入进来就可以使用)
import SonCom from "@/components/son-com.vue"

const money = ref(100)

const getMoney = () => {
  money.value += 10
}
//监听子组件发出的请求后,做出的处理函数
const changeFn=(newMoney)=>{
  money.value=newMoney
}
</script>
<template>
  <div>
    <h3>父组件 - {{ money }}
      <button @click="getMoney">挣钱</button>

    </h3>
    <!--  给子组件,添加属性的方式传值-->
    <!--  :money="money将数据动态的传入给子组件-->
    <!--  @changeMoney="changeFn":是监听事件-->
    <SonCom
        @changeMoney="changeFn"
        car="宝马车"
        :money="money"></SonCom>
  </div>
</template>
<style scoped>
</style>
  1. 子组件 (son-com.vue)
<script setup>
//子组件(06.组件式API - 父传子)
//注意:
//(1)由于写了 setup,所以无法直接配置props选项,此处需要借助于“ 编译器宏 ”函数defineProps(),接收子组件传递的数据
//(2)在脚本(script)中,调用父组件传过来的数据props,需要props.属性名进行使用,而在模板(template)中使用父组件传过来的数据props,可以直接使用(不用加props前缀)

const props=defineProps({
//  在此处写配置项,接收父组件穿过来的数据
  car: String,
  money: Number
})
//定义emit事件
const emit=defineEmits(["changeMoney"])
//  使用props.属性名使用父组件传过来的数据
console.log(props.car)
console.log(props.money)

//子传父
const buy=()=>{
//  需要emit触发事件(emit是通过defineProps编译器宏定义,如编译器定义的changeMoney)
//  直接使用编译器定义的事件,后面是传入的值,例如:5
emit("changeMoney",5)
}
</script>

<template>
<!--  直接使用父组件传过来props中的数据-->
<div class="son">子组件 - {{car}} - {{money}}
<button @click="buy">花钱</button>
</div>
</template>

<style scoped>
.son{
  border: 1px solid #000;
  padding: 30px;
}
</style>

在这里插入图片描述

4.7 组合式API - 模板引用

在这里插入图片描述
vue3中的模板引用
在这里插入图片描述
在这里插入图片描述

  1. test-com.vue
<script setup>
const count=999

const sayHi=()=>{
  console.log("hello")
}
//默认情况下,在setup语法糖下组件内部的属性和方法是不开放给父组件访问的
// 可通过defineExpose编译宏指定哪些数据和方法允许访问
//通过defineExpose编译宏指定的数据和方法,在父组件中导入该子组件后就可以直接使用defineExpose指定的数据和方法
defineExpose({
  count,
  sayHi
})
</script>
<template>
  <div>
    测试组件 - {{count}}
  </div>
</template>
<style scoped>
</style>
  1. App.vue
<!--组合式API - 模板引用
//模板引用(可以获取dom,也可以获取组件)
 通过ref表示获取真实的dom对象或组件实例对象
 1.调用ref函数生成一个ref对象;
 2.通过ref标识绑定ref对象到标签;
 3.通过ref对象,value即可访问到绑定元素(必须在渲染完成后,才可以拿到);

-->
<script setup>
//导入子组件,在该组件中可以使用导入的子组件中的defineExpose中的属性和方法
import TestCom from "@/components/test-com.vue"
import {onMounted, ref} from 'vue'

//模板引用(可以获取dom,也可以获取组件)
//1.调用ref函数生成一个ref对象
const inp = ref(null)

//生命周期钩子 onMounted
onMounted(() => {
  console.log('页面打开自动聚焦')
  inp.value.focus()  //一进页面就聚焦
  // clickFn()
})
const clickFn = () => {
  console.log("点击按钮,进行聚焦")
  inp.value.focus()
}

//-----------------------------
const testRef=ref(null)
const getCom=()=>{
  console.log(testRef.value.count)
  // console.log(testRef.value.sayHi())
  testRef.value.sayHi()
}
</script>
<template>
  <div>
    <!--  2.通过ref标识绑定ref对象-->
    <!--  <h1 ref="inp">我是dom标签h1</h1>-->
    <input ref="inp" type="text">
    <button @click="clickFn">点击聚焦输入框</button>
  </div>
  <TestCom ref="testRef"></TestCom>
  <button @click="getCom">获取组件</button>
</template>
<style scoped>
</style>

在这里插入图片描述

4.8 组合式API - provide 和 inject

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

1.顶部组件(APP.vue)

<!--
组合式API - provide和inject
跨层传递普通数据
1.顶层组件通过provide函数提供数据;
2.底层组件通过inject函数获取数据
-->
<script setup>
import {onMounted, provide, ref} from 'vue'
import CenterCom from "@/components/center-com.vue"
//1.跨层传递普通数据
provide("theme-color",'pink')
//2.跨层传递复杂数据
provide('userInfo',{
  name:'豫姑娘~',
  age:18
})
//3.跨层传递响应式数据
const count=ref(100)
provide("count",count)

//4.跨层传递函数=>给子孙后代传递可以修改数据的方法
provide("changeCount",(num)=>{
  count.value=count.value+num
})
</script>
<template>
  <div>
    <h1>顶层组件</h1>
    <CenterCom></CenterCom>
  </div>
</template>
<style scoped>
</style>
  1. 中间组件(center-com.vue)
<script setup>
import centerCom from "@/components/bottom-com.vue"
</script>
<template>
<div>
  <h2>中间组件</h2>
  <center-com></center-com>
</div>
</template>

<style scoped>
</style>
  1. 底部组件(bottom-com.vue)
<script setup>
import {inject} from "vue";

const color = inject('theme-color')
const userInfo = inject("userInfo")
const count = inject("count")
//祖先组件传入的修改数据的方法
const changeCount = inject("changeCount")
const clickFn = (num) => {
  changeCount(num)
}
</script>
<template>
  <div>
    <h3>底部组件</h3>
    <p>普通数据:{{ color }}</p>
    <p>复杂数据:{{ userInfo.name }}------{{ userInfo.age }}</p>
    <p>响应式数据count:{{ count }}</p>
    <button @click="clickFn(100)">+100</button>
  </div>
</template>

<style scoped>
</style>

5.vue3新特性

5.1 defineOptions

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

在script标签中使用defineOptions编译器方法给组件命名
<script setup>
defineOptions({
  //给组件命名
  name:'RegisterIndex'
})
</script>

给views/login/index.vue对应组件重新命名

<script setup>
defineOptions({
  //给组件命名
  name:'RegisterIndex'
})
</script>
<template>

</template>

<style scoped>
</style>

5.2 defineModel

在这里插入图片描述

  1. APP.vue
<!--
vue3新特性 - defineModel
-->
<script setup>
import inputCom from '@/components/input-com.vue'
import {ref} from "vue";

const txt = ref('vue3新特性,defineModel')

</script>
<template>
  <div>
    <inputCom v-model="txt"></inputCom>
    {{ txt }}
  </div>
</template>
<style scoped>
</style>
  1. input-com.vue(input-com-copy.vue简写)
<script setup>
import {defineModel} from "vue";
//vue3新特性
const modelValue = defineModel()
</script>
<template>
  <div>
    <input type="text"
           :value="modelValue"
           @input="e=>modelValue=e.target.value">
  </div>
</template>

<style scoped>
</style>
  1. input-com-copy.vue
<script setup>
defineOptions({
  name:"input-com",
  //接收modelValue传入的数据
  modelValue:String
})
//使用defineEmits定义当前emit方法
const emit=defineEmits(['update:modelValue'])
</script>
<template>
<div>
  <input type="text"
         :value="modelValue"
         @input="e=>emit('update:modelValue',e.target.value)">
</div>
</template>

<style scoped>
</style>
  1. vite.config.js
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue({
      script:{
        defineModel:true   //声明使用defineModel
      }
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

6.Pinia快速入门

6.1 什么是Pinia?

在这里插入图片描述

6.2 手动将Pinia添加到项目中?

将Pinia添加到项目中的整体步骤:
(1)新建一个vue3项目;
在这里插入图片描述
(2)在项目中安装pinia;

npm install pinia  //在项目中安装pinia

(3)在main.js中导入pinia;
(4)在各组件中使用;

  1. main.js

import {createApp} from 'vue'
import {createPinia} from 'pinia'
import App from './App.vue'

const pinia=createPinia()  //创建Pinia实例
const app=createApp(App)  //创建根实例
app.use(pinia)   //pinia插件的安装配置
app.mount('#app')   //视图的挂载
  1. App.vue
<script setup>
import Son1Com from "@/components/son1-com.vue"
import Son2Com from "@/components/son2-com.vue"
</script>
<template>
  <div>
    <h1>App.vue根组件 - 0</h1>
    <Son1Com></Son1Com>
    <Son2Com></Son2Com>
  </div>
</template>

<style scoped>
</style>
  1. son1-com.vue
<script setup>
defineProps({
  name:"Son1Com"
})
</script>
<template>
<div>son1Com - 0 - <button>+</button></div>
</template>

<style scoped>

</style>
  1. son2-com.vue
<script setup>
defineOptions({
  name:"son2Com"
})
</script>
<template>
<div>Son2Com - 0 - <button>-</button></div>
</template>

<style scoped>

</style>

6.3 Pinia基本语法

Pinia基础使用 - 计数器案例
1). 定义store;
2). 组件使用store;

  1. App.vue
<script setup>
import Son1Com from "@/components/son1-com.vue"
import Son2Com from "@/components/son2-com.vue"

//使用store中仓库的值
import {useCounterStore} from "@/store/count.js"
const countStore = useCounterStore()  //获取store中的对象
const countStoreCount=countStore.count   //获取store中对象的值
const countStoreMsg=countStore.msg   //获取store对象中的值
</script>
<template>
  <div>
    <h1>App.vue根组件 - 0</h1>
    <h2>{{countStoreCount}} --- {{countStoreMsg}}</h2>
    <Son1Com></Son1Com>
    <Son2Com></Son2Com>
  </div>
</template>

<style scoped>
</style>
  1. store/count.js(store仓库,该仓库中的数据可以提供给多个组件使用)
import {defineStore} from "pinia";
import {ref,computed} from 'vue'

//定义store仓库数据(多组件可以共享的数据)
// defineStore(仓库的唯一标识(参数1),()=>{...}(参数2))

/**
 * useCounterStore  基于该名使用仓库中的值
 * export  导出
 * @type {StoreDefinition<"counter", _ExtractStateFromSetupStore<{msg: Ref<UnwrapRef<string>>, count: Ref<UnwrapRef<number>>}>, _ExtractGettersFromSetupStore<{msg: Ref<UnwrapRef<string>>, count: Ref<UnwrapRef<number>>}>, _ExtractActionsFromSetupStore<{msg: Ref<UnwrapRef<string>>, count: Ref<UnwrapRef<number>>}>>}
 */
//  1.创建仓库,基于useCounterStore就可以获取函数,进而使用该仓库中的值
export const useCounterStore = defineStore("counter", () => {

//    声明数据 state - count
    const count = ref(100)

//    声明操作数据的方法 action(普通函数)
    const addCount = () => {
        count.value++
    }
    const subCount = () => {
        count.value--
    }
//    声明基于数据派生的的计算属性 getters(computed)
    const double = computed(() =>
        count.value * 2
    )


//    声明数据 state - msg
    const msg = ref("hello pinia")

    return {
        count,     //count属性
        double,    //计算属性
        addCount,  //方法1
        subCount,  //方法2
        msg
    }
})
  1. son1-com.vue(调用count.js仓库中的数据)
<script setup>
defineProps({
  name:"Son1Com"
})
import {useCounterStore} from "@/store/count.js";
const countStore=useCounterStore()  //获取仓库中的数据对象
const count=countStore.count  //获取仓库对象中的值
const msg=countStore.msg
const double=countStore.double
</script>
<template>
<!--  注意:当在js脚本中将对象中的属性分离出来时,在修改原对象中的值时,无法修改分离出的对象属性值不被修改-->
<div>son1Com(获取js模块中分离出的对象中的各属性值)
  - {{count}} -{{msg}} - {{double}}
  - <button @click="countStore.addCount">+</button></div>
<div>son1Com(直接根据对象引用其中的值)
  - {{countStore.count}} -{{countStore.msg}} - {{countStore.double}}
  - <button @click="countStore.subCount">-</button></div>
</template>

<style scoped>
</style>

6.4 Pinia - action异步写法

在这里插入图片描述

  1. store/channel.js(仓库数据)
import {defineStore} from 'pinia'
import axios from "axios";
import {ref} from 'vue'

//仓库变量的命名(use+仓库名+Store)
export const useChannelStore=defineStore("channel",()=>{
//    声明数据
    const channelList=ref([])
//    声明操作数据的方法
    const getList=async ()=>{
    //    支持异步({data:{data}}是解构返回的数据)
        const {data:{data}}=await axios.get("http://geeek.itheima.net/v1_0/channels")
        channelList.value=data.channels
        console.log(data.channels)
    }
//    声明getters相关
//    返回数据及方法
    return {
        channelList,
        getList
    }
})
  1. App.vue(引用channel.js中的数据)
<script setup>
import Son1Com from "@/components/son1-com.vue"
import Son2Com from "@/components/son2-com.vue"

//使用store中仓库的值
import {useCounterStore} from "@/store/count.js"
import {useChannelStore} from "./store/channel.js"
const countStore = useCounterStore()  //获取store中的counter对象
const channelStore=useChannelStore()  //获取store中的channel对象

const countStoreCount=countStore.count   //获取store中对象的值
const countStoreMsg=countStore.msg   //获取store对象中的值
</script>
<template>
  <div>
    <h1>App.vue根组件 - 0</h1>
    <h2>{{countStoreCount}} --- {{countStoreMsg}}</h2>
    <Son1Com></Son1Com>
    <Son2Com></Son2Com>
    <hr>
    <button @click="channelStore.getList()">获取频道数据</button>
    <ul>
      <li v-for="item in channelStore.channelList">新闻</li>
      <li>音乐</li>
    </ul>
  </div>
</template>

<style scoped>
</style>

6.5 Pinia - storeToRefs方法

App.vue

<script setup>
//导入storeToRefs方法,避免直接解构会失去响应式
import {storeToRefs} from 'pinia'
import Son1Com from "@/components/son1-com.vue"
import Son2Com from "@/components/son2-com.vue"

//使用store中仓库的值
import {useCounterStore} from "@/store/count.js"
import {useChannelStore} from "./store/channel.js"
const countStore = useCounterStore()  //获取store中的counter对象
const channelStore=useChannelStore()  //获取store中的channel对象

//此时,直接解构,不处理,数据会丢失响应式(希望解构后仍保持响应式)
// const {count,msg} = counterStore
//使用storeToRefs保持解构后数据的响应式
/**
 * 对数据的解构处理
 */
const {count,msg} = storeToRefs(countStore)
const {channelList} = storeToRefs(channelStore)
/**
 * 对方法的解构处理
 */
const {getList} = channelStore

// const countStoreCount=countStore.count   //获取store中对象的值
// const countStoreMsg=countStore.msg   //获取store对象中的值
</script>
<template>
  <div>
    <h1>App.vue根组件 - 0</h1>
    <h2>{{count}} --- {{msg}}</h2>
    <Son1Com></Son1Com>
    <Son2Com></Son2Com>
    <hr>
    <button @click="getList">获取频道数据</button>
    <ul>
      <li v-for="item in channelList" :key="item.id">新闻</li>
      <li>音乐</li>
    </ul>
  </div>
</template>

<style scoped>
</style>

6.6 Pinia - 持久化

在对数据进行处理之后,保持着最新的数据,即使刷新页面,其数据也保持处理后的值。
(内部原理:修改数据时,将修改后的数据存放到本地,刷新页面时,首先从本地查询)
在这里插入图片描述
在这里插入图片描述(1)在main.js中导入持久化插件

//导入持久化插件
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

(2)在main.js中使用持久化插件

app.use(pinia.use(piniaPluginPersistedstate))   //pinia插件的安装配置

(3)在仓库中对数据进行持久化操作
defineStore(仓库的唯一标识(参数1),()=>{…}(参数2),导入的持久化(piniaPluginPersistedstate):true(开启当前模块数据的持久化))

//  1.创建仓库,基于useCounterStore就可以获取函数,进而使用该仓库中的值
export const useCounterStore = defineStore("counter", () => {
//    声明数据 state - count
    const count = ref(100)
//    声明操作数据的方法 action(普通函数)
    const addCount = () => {
        count.value++
    }
    const subCount = () => {
        count.value--
    }
//    声明基于数据派生的的计算属性 getters(computed)
    const double = computed(() =>
        count.value * 2
    )
//    声明数据 state - msg
    const msg = ref("hello pinia")
    return {
        count,     //count属性
        double,    //计算属性
        addCount,  //方法1
        subCount,  //方法2
        msg
    }
}, {
    piniaPluginPersistedstate: true  //开启当前模块的持久化
})
  1. main.js

import {createApp} from 'vue'
import {createPinia} from 'pinia'
import App from './App.vue'
//导入持久化插件
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia=createPinia()  //创建Pinia实例
const app=createApp(App)  //创建根实例
app.use(pinia.use(piniaPluginPersistedstate))   //pinia插件的安装配置
app.mount('#app')   //视图的挂载
  1. count.js
import {defineStore} from "pinia";
import {computed, ref} from 'vue'

//定义store仓库数据(多组件可以共享的数据)
// defineStore(仓库的唯一标识(参数1),()=>{...}(参数2),导入的持久化(piniaPluginPersistedstate):true(开启当前模块的持久化))

/**
 * useCounterStore  基于该名使用仓库中的值
 * export  导出
 * @type {StoreDefinition<"counter", _ExtractStateFromSetupStore<{msg: Ref<UnwrapRef<string>>, count: Ref<UnwrapRef<number>>}>, _ExtractGettersFromSetupStore<{msg: Ref<UnwrapRef<string>>, count: Ref<UnwrapRef<number>>}>, _ExtractActionsFromSetupStore<{msg: Ref<UnwrapRef<string>>, count: Ref<UnwrapRef<number>>}>>}
 */
//  1.创建仓库,基于useCounterStore就可以获取函数,进而使用该仓库中的值
export const useCounterStore = defineStore("counter", () => {
//    声明数据 state - count
    const count = ref(100)
//    声明操作数据的方法 action(普通函数)
    const addCount = () => {
        count.value++
    }
    const subCount = () => {
        count.value--
    }
//    声明基于数据派生的的计算属性 getters(computed)
    const double = computed(() =>
        count.value * 2
    )
//    声明数据 state - msg
    const msg = ref("hello pinia")
    return {
        count,     //count属性
        double,    //计算属性
        addCount,  //方法1
        subCount,  //方法2
        msg
    }
}, {
    // piniaPluginPersistedstate: true  //开启当前模块的持久化
    piniaPluginPersistedstate: {
        key:'piniaData' ,  //key是持久化数据往本地存放时的key值(本地存储的唯一标识),此时key作为键值,持久化数据作为值
        paths:['count']   //指定持久化数据(对模块中特定数据进行持久化)(无此项则表示对该模块中的数据全部进行持久化)
    }
})

在这里插入图片描述

;