npm i pinia --save
import './assets/main.css' import { createApp } from 'vue' import App from './App.vue' //1. 导入 import { createPinia } from 'pinia' //2. 创建 const pinia = createPinia() const app = createApp(App) //3. 使用 app.use(pinia) app.mount('#app')
. 在默认示例的基础增加 msg
. 第一个参数 counter 是你的应用中 Store 的唯一 ID,Pinia 将用它来连接 store 和 devtools
. 第二个参数接收 option 对象或 setup 函数;setup 函数和组合式 API 类似,且功能更灵活
import { defineStore } from 'pinia' import { ref, computed } from 'vue' export const useCounterStore = defineStore('counter', ()=>{ //state - ref() const count = ref(0) const msg = ref('hi,there.') //getters - computed() const doubleCount = computed( () => count.value * 2 ) //action - function() const increment = () => count.value++ return { count, msg, doubleCount, increment } })
逻辑 - 引入仓库、创建仓库实例、使用仓库数据;创建仓库实例前无法使用
<script setup> import { useCounterStore } from '@/stores/counter'; const store = useCounterStore(); console.log('store', store); </script>
结构 - 渲染仓库数据;这里采用内联事件
<template> <div>{{ store.count }}</div> <div>{{ store.msg }}</div> <div>{{ store.doubleCount }}</div> <div @click="store.increment">store handle</div> </template>
let { count, increment } = counterStore;
<div>仓库数据 - {{ store.count }} - {{ count }}</div>
import { storeToRefs } from 'pinia'; let { count, increment } = storeToRefs(counterStore);
import { defineStore } from 'pinia' import { ref, computed } from 'vue' export const useGoodStore = defineStore('good', () => { const goods = ref([]) const isLoading = ref(false) const fetchGoods = async () => { isLoading.value = true let res = await fetch('http://127.0.0.1:3000/goods') let data = await res.json() goods.value = data isLoading.value = false } return { goods, isLoading, fetchGoods, } })
import { onMounted } from 'vue'; import { useGoodStore } from '@/stores/good'; const store = useGoodStore(); onMounted(() => { store.fetchGoods(); })
<div v-if="store.isLoading"> loading </div> <div v-else> // </div>
watch(() => goodStore.isLoading, (newVal, oldVal) => { if (newVal) { msg.value = '正在加载中...' } else { msg.value = '加载完成' } show.value = true; })
import { ref } from 'vue' import { defineStore } from 'pinia' export const useMenuStore = defineStore('menu', () => { const flag = ref(false) const switchFlag = () => { flag.value ? flag.value = false : flag.value = true } return { flag, switchFlag } })
主题切换/换肤/日夜模式
通过为 html 指定自定义属性实现 CSS 变量的更新达到切换效果
:root { --txt-color: #303133; --bg-color: #f1f1f1; --shadow-color: rgba(0, 0, 0, 0.1); } // 类形式 .data-theme { --txt-color: #f1f1f1; --bg-color: #131313; --shadow-color: rgba(255, 255, 255, 0.1); } // 属性形式 [data-theme="dark"] { --txt-color: #f1f1f1; --bg-color: #131313; --shadow-color: rgba(255, 255, 255, 0.1); }
import { defineStore } from 'pinia' import { ref, onMounted } from 'vue' export const useThemeStore = defineStore('theme', () => { const isDarkMode = ref(false); const toggleDarkMode = () => { isDarkMode.value = !isDarkMode.value; document.documentElement.setAttribute('data-theme', isDarkMode.value ? 'dark' : 'light'); }; return { isDarkMode, toggleDarkMode } })
import { useThemeStore } from '@/stores/theme'; const themeStore = useThemeStore();
<div class="theme-icon" @click="themeStore.toggleDarkMode"> <span v-if="themeStore.isDarkMode" class="iconfont icon-night-mode-fill"></span> <span v-else class="iconfont icon-daytime-mode-fill"></span> </div>