[Pinia] 基本範例
TL;DR
Pinia起手式範例
參考資料
相關連結
- Pinia | Official
安裝Pinia
如果在使用Vite時已經有勾選要使用Pinia,則會自動安裝並且匯入
./src/main.js
import './assets/main.scss'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router/index.js'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
如果尚未安裝可以使用:
npm install pinia --save
接著按照上述Vite所產生的程式碼將Pinia給匯入到app中。
建立一個Store
如果使用Vite建立Pinia環境,則會自動在./src/stores
創建一隻counter.js
的檔案。
資料夾名稱
在使用Pinia時,因為會會準備許多支檔案,所以在命名時建議使用複數(stores)
因為counter.js
是使用Composition API的範例,我們另外建立一支user.js
的store示範。
./src/stores/user.js
import { defineStore } from "pinia";
// defineStore有兩個參數。1.Store名稱;2.屬性參數
export default defineStore('User Store',{
// 對應Data,這邊可以直接使用箭頭函式撰寫
// 同()=>{return{name:'wei}}
state:()=>({
name:'wei',
wallet:300
}),
// 對應Computed
getters:{
// 變數名稱state不是固定的,但是取state比較直觀。
getUserName:(state)=>`我的名字是${state.name}`
},
// 對應Methods
actions:{
updateName(){
this.name='weiwei'
}
}
})
state
:對應Vue元件的data
getters
:對應Vue元件的computed
actions
:對應Vue元件的methods
將Store匯入元件
以下新增一支PiniaPractice.vue的檔案,並且掛載在先前範例中的newPage下:
- PiniaPractice.vue
- index.js
- NewPage.vue
./src/views/PiniaPractice.vue
<template>
{{ name }} / {{ getUserName }} / {{ wallet }}
<br>
<button type="button" class="btn btn-primary" @click="updateName">更新名稱</button>
</template>
<script>
import userStore from '@/stores/user.js'
import { mapState, mapActions } from 'pinia';
export default {
data() {
return {
}
},
methods: {
...mapActions(userStore,['updateName'])
},
computed: {
// 展開,並且帶入兩個參數。分別為1.Sotre;2.要帶入的state,getters
...mapState(userStore, ['name', 'getUserName', 'wallet'])
}
}
</script>
./src/router/index.js
import { createRouter, createWebHashHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('../views/AboutView.vue')
},
{
path: '/newpage',
name: '新增頁面',
component: () => import('../views/NewPage.vue'),
children: [
{
path: 'a',
name: '新增頁面內的元件A',
component: () => import('../components/ComponentA.vue')
},
{
path: 'b',
name: '新增頁面內的元件B',
component: () => import('../components/ComponentB.vue')
},
// {
// path: 'routerNavigation',
// component: ()=> import('@/views/RouterNavigation.vue')
// },
{
path: 'routerNavigation',
component: () => import('@/views/RouterNavigation.vue')
},
{
path: 'dynamicRouter/:id',
component: () => import('@/views/DynamicRouter.vue')
},
{
path: 'dynamicRouterByProps/:id',
component: () => import('@/views/DynamicRouterByProps.vue'),
props: (route) => {
console.log('route:', route)
return {
id: route.params.id
}
}
},
{
path: 'namedview',
name: 'namedview',
component: () => import('@/views/NamedView.vue'),
children: [
{
path: 'c2a',
components: {
left: () => import('@/components/ComponentC.vue'),
right: () => import('@/components/ComponentA.vue')
}
},
{
path: 'a2b',
components: {
left: () => import('@/components/ComponentA.vue'),
right: () => import('@/components/ComponentB.vue')
}
}
]
},
{
path: 'pinia',
component: () => import('@/views/PiniaPractice.vue')
},
]
},
// {
// path:'/newPage/:pathMatch(.*)*',
// redirect:{
// name:'about'
// }
// },
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/NotFound.vue')
}
]
const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL),
linkActiveClass: 'active',
routes: routes,
scrollBehavior(to, from, savedPosition) {
console.log(to, from, savedPosition)
if (to.fullPath.match('newPage')) {
return {
top: 0
}
}
return {
top: 0
}
}
})
export default router
<template>
<div class="container">
<div class="row py-3">
<div class="col-3">
<div class="list-group">
<RouterLink :to="{ name: '新增頁面內的元件A' }" class="list-group-item list-group-item-action" aria-current="true">
元件A
</RouterLink>
<RouterLink to="/newpage/b" class="list-group-item list-group-item-action">
元件B
</RouterLink>
<RouterLink to="/newpage/namedview/c2a" class="list-group-item list-group-item-action">
C to A
</RouterLink>
<RouterLink to="/newpage/namedview/a2b" class="list-group-item list-group-item-action">
A to B
</RouterLink>
<RouterLink to="/newpage/dynamicRouter/81a0b89d11fb45c2" class="list-group-item list-group-item-action">
DynamicRouter
</RouterLink>
<RouterLink to="/newpage/dynamicRouterByProps/81a0b89d11fb45c2" class="list-group-item list-group-item-action">
DynamicRouter
</RouterLink>
<RouterLink to="/newpage/routernavigation" class="list-group-item list-group-item-action">
RouterNavigation
</RouterLink>
<RouterLink to="/newpage/pinia" class="list-group-item list-group-item-action">
PiniaPractice
</RouterLink>
</div>
</div>
<div class="col-9">
<RouterView></RouterView>
</div>
</div>
</div>
</template>
<script>
export default {
components: {
}
}
</script>
跨元件傳遞狀態
今天將HomeView.vue
內將Store內的user.js
給匯入 縱使是兩個不同的頁面,因為都是取自Store所提供的變數,所以當在PiniaPractice.vue
頁面點擊按鈕改變name的名稱時,HomeView.vue
頁面的name也會同時改變。
Homeview.vue
程式碼
Homeview.vue
程式碼<template>
<div class="home">
<h2>home</h2>
<p>{{ name }}</p>
</div>
</template>
<script>
import userStore from '@/stores/user.js'
import { mapState, mapActions } from 'pinia';
export default {
data() {
return {
}
},
methods: {
...mapActions(userStore,['updateName'])
},
// Pinia匯入的狀態只能存放在Computed內?
computed: {
// 展開,並且帶入兩個參數。分別為1.Sotre;2.要帶入的state,getters
...mapState(userStore, ['name', 'getUserName', 'wallet'])
}
}
</script>
<style scoped>
.home {
min-height: 100vh;
}
</style>