pinia的基本使用实现官网的todoList
main.js
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { createPinia } from 'pinia'
createApp(App).use(createPinia()).mount('#app')
store/index.js or store/todoList.js
// => todoList.js
import { defineStore } from "pinia";
export default defineStore("todoList", {
state: () => ({
todos: [],
filter: "all", //finished unfinished
nextId: 0,
}),
actions: {
addTodo(text) {
this.todos.push({
id: this.nextId++,
text,
isFinished: false,
});
},
toggleTodo(id) {
this.todos = this.todos.map((todo) => {
if (todo.id === id) {
todo.isFinished = !todo.isFinished;
}
return todo;
});
},
removeTodo(id) {
this.todos = this.todos.filter((todo) => todo.id !== id);
},
},
getters: {
finishTodos(state) {
return state.todos.filter((todo) => todo.isFinished);
},
unFinishTodos(state) {
return state.todos.filter((todo) => !todo.isFinished);
},
filterTodos(state) {
switch (this.filter) {
case "all":
return this.todos;
case "finished":
return this.finishTodos;
case "unFinished":
return this.unFinishTodos;
}
},
},
});
//=> index.js
import useTodoListStore from "./todoList";
export { useTodoListStore };
组件书写,目录如下
// =>index.vue
<template>
<div>
<todo-tab></todo-tab>
<todo-form></todo-form>
<Todos></Todos>
</div>
</template>
<script setup>
import TodoTab from './TodoTab.vue';
import TodoForm from './TodoForm.vue';
import Todos from './Todos.vue';
</script>
<style scoped></style>
// => TodoTab.vue
<template>
<div>
<a
href="javascript:;"
:class="{ active: todoListStore.filter === 'all' }"
@click="setFilter('all')"
>All</a>
<a
href="javascript:;"
:class="{ active: todoListStore.filter === 'finished' }"
@click="setFilter('finished')"
>Finished</a>
<a
href="javascript:;"
:class="{ active: todoListStore.filter === 'unFinished' }"
@click="setFilter('unFinished')"
>UnFinished</a>
</div>
</template>
<script setup>
import { useTodoListStore } from "../../store";
const todoListStore = useTodoListStore();
const setFilter = (filter) => todoListStore.$patch({ filter });
</script>
<style scoped>
.active {
text-decoration: none;
color: black;
}
a {
margin-right: 15px;
}
</style>
//=> TodoForm.vue
<template>
<div>
<input type="text" placeholder="输入点内容" v-model.trim="inputRef" />
<button @click="addTodo">增加</button>
</div>
</template>
<script setup>
import { ref } from "vue";
import { useTodoListStore } from "../../store";
const todoListStore = useTodoListStore();
const inputRef = ref("");
const addTodo = () => {
if(!inputRef.value) return;
todoListStore.addTodo(inputRef.value);
inputRef.value = "";
};
</script>
// => Todos.vue
<template>
<div>
<div v-for="item of todoListStore.filterTodos">
<input
type="checkbox"
:checked="item.isFinished"
@click="todoListStore.toggleTodo(item.id)"
/>
<span :class="{ finished: item.isFinished }">{{ item.text }}</span>
<button @click="todoListStore.removeTodo(item.id)">Delete</button>
</div>
</div>
</template>
<script setup>
import { useTodoListStore } from "../../store";
const todoListStore = useTodoListStore();
</script>
<style scoped>
.finished {
text-decoration: line-through;
}
</style>
App.vue
<template>
<div>
<todo-list />
</div>
</template>
<script setup>
import TodoList from './components/TodoList/index.vue';
</script>
效果图如下:
pinia的核心实现
目录如下
- 实现 createPinia
- 实现 defineStore
- api中的patch方法
createPinia.js
import { reactive } from "vue";
import { patch } from "./api";
// => 创建pinia
export default () => {
// 1.数据变成响应式的
const piniaStore = reactive({});
// 2.能被use的基础
function install(app) {
// 3.用渗透的方式传递数据
app.provide("setSubStore", setSubStore);
}
function setSubStore(name, store) {
if (!piniaStore[name]) {
// =>相当于 {} => obj[name] = {xxx}
piniaStore[name] = store;
piniaStore[name].$patch = patch;
}
return piniaStore;
}
return {
install,
};
};
api.js
// => value 是一个对象 如果在这个里面的话修改值
export function patch(value) {
const store = this;
for(let key in value) {
store[key] = value[key];
}
}
defineStore.js
import { computed, inject, reactive, toRef, ref } from "vue";
export default (name, {
state,
getters,
actions
}) => {
const store = {};
// => 处理 store
if(state && typeof state === 'function') {
const _state = state();
store.$state = reactive(_state);
// console.log(store.$state)
// => 把state上的属性放到 store上
for(let key in _state) {
store[key] = toRef(store.$state, key);
// store[key] = ref(store.$state[key]);
}
}
// => 处理 actions
if(actions && Object.keys(actions).length > 0) {
for(let method in actions) {
store[method] = actions[method];
}
}
// => 处理getters 使用computed进行处理
if(getters && Object.keys(getters).length > 0) {
for(let getter in getters) {
store[getter] = computed(getters[getter].bind(store.$state, store.$state));
store.$state[getter] = store[getter];
}
}
// 返回一个函数
return () => {
// =>获取到 createPinia 渗透下来的方法进行注册 模块
const setSubStore = inject("setSubStore");
const piniaStore = setSubStore(name, reactive(store));
return piniaStore[name];
}
}
index.js
import createPinia from "./createPinia";
import defineStore from "./defineStore";
export { createPinia, defineStore };
- 实现的效果如上面的结果一直
- 构造出来的格式如下: