import { defineStore } from 'pinia'
import { usePostStore } from './post'
export const useAuthorStore = defineStore({
id: 'author',
state: () => ({
authors: []
getters: {
getPostAuthor: (state) => {
const postStore = usePostStore()
return state.authors.find((author) => author.id === postStore.post.userId)
actions: {
async fetchAuthors() {
this.authors = await fetch('https://xxx.com/users')
.then((response) => response.json())
这与 完全相同。我们再次导入并使用它在 getter 中提供所需的作者 ID。commentStore usePostStore getPostAuthor
就是这样。您会看到使用Pinia创建商店是多么容易,这是一个简单而优雅的解决方案。
现在,让我们看看如何在实践中使用商店。
在 Pinia 中创建视图和组件
在本节中,我们将创建必要的视图和组件,以应用我们刚刚创建的 Pinia 商店。让我们从所有帖子的列表开始。
请注意,我将 Pinia 与 Composition API 和语法结合使用。如果要改用选项 API,请查看本指南。<script setup>
创建帖子视图
在目录中,重命名为以下内容并将其内容替换为以下内容:views HomeView.vue PostsView.vue
<script setup>
import { RouterLink } from 'vue-router'
import { storeToRefs } from 'pinia'
import { usePostStore } from '../stores/post'
const { posts, loading, error } = storeToRefs(usePostStore())
const { fetchPosts } = usePostStore()
fetchPosts()
</script>
<template>
<p v-if="loading">Loading posts...</p>
<p v-if="error">{{ error.message }}</p>
<p v-if="posts" v-for="post in posts" :key="post.id">
<RouterLink :to="`/post/${post.id}`">{{ post.title }}</RouterLink>
<p>{{ post.body }}</p>
</main>
</template>
请注意,如果您收到已重命名文件的通知,请忽略它。
在这里,我们从邮政商店导入并提取所有必要的数据。
我们不能对状态属性和 getter 使用解构,因为它们会失去反应性。为了解决这个问题,Pinia提供了实用程序,该实用程序为每个属性创建一个ref。可以直接提取操作,而不会出现问题。storeToRefs
我们打电话来获取帖子。当使用组合 API 并在函数内部调用函数时,它等效于使用 Hook。因此,我们将在组件装载之前拥有帖子。fetchPosts() setup() created()
我们在模板中还有一系列指令。首先,如果加载是 ,则显示加载消息。然后,如果发生错误,我们会显示错误消息。v-if true
最后,我们循环访问帖子,并为每个帖子显示标题和正文。我们使用该组件向标题添加链接,以便当用户单击它时,他们将导航到单个帖子视图,稍后我们将创建该视图。RouterLink
现在,让我们修改该文件。打开它并将其内容替换为以下内容:router.js
import { createRouter, createWebHistory } from 'vue-router'
import PostsView from '../views/PostsView.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
path: '/',
name: 'posts',
component: PostsView
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')
export default router
在这里,我们导入 并将其用作第一个路由中的组件。我们还将名称从“主页”更改为“帖子”。PostsView.vue
测试帖子视图
好了,是时候测试我们到目前为止取得的成就了。运行应用 () 并在浏览器中查看结果:npm run dev
您可能会在控制台中收到一些 Vue 警告,以“未找到匹配项...”开头。这是因为我们尚未创建必要的组件,您可以安全地忽略它们。
如果帖子未显示,您可能还需要重新加载页面。
让我们继续创建单个帖子视图。关闭终端以避免任何不必要的错误消息。
创建单个帖子视图
在目录中,创建一个包含以下内容的文件:views PostView.vue
<script setup>
import { useRoute } from 'vue-router'
import { storeToRefs } from 'pinia'
import { useAuthorStore } from '../stores/author'
import { usePostStore } from '../stores/post'
import Post from '../components/Post.vue'
const route = useRoute()
const { getPostAuthor } = storeToRefs(useAuthorStore())
const { fetchAuthors} = useAuthorStore()
const { post, loading, error } = storeToRefs(usePostStore())
const { fetchPost } = usePostStore()
fetchAuthors()
fetchPost(route.params.id)
</script>
<template>
<p v-if="loading">Loading post...</p>
<p v-if="error">{{ error.message }}</p>
<p v-if="post">
<post :post="post" :author="getPostAuthor"></post>
</template>
在设置中,我们从作者存储中提取和从后期存储中提取必要的数据。我们还呼吁获取现有作者。getPostAuthor fetchAuthors fetchAuthors()
接下来,我们使用对象帮助提供的 ID 调用操作。这将更新,我们可以在模板中有效地使用它。fetchPost(route.params.id) route getPostAuthor
为了提供实际的帖子,我们使用一个组件,该组件需要两个道具:和。现在,让我们创建组件。post post author
创建组件post
在目录中,创建一个包含以下内容的文件:components Post.vue
<script setup>
import { RouterLink } from 'vue-router'
import { storeToRefs } from 'pinia'
import { useCommentStore } from '../stores/comment'
import Comment from '../components/Comment.vue'
defineProps(['post', 'author'])
const { getPostComments } = storeToRefs(useCommentStore())
const { fetchComments } = useCommentStore()
fetchComments()
</script>
<template>
<h2>{{ post.title }}</h2>
<p v-if="author">Written by: <RouterLink :to="`/author/${author.username}`">{{ author.name }}</RouterLink>
| <span>Comments: {{ getPostComments.length }}</span>
<p>{{ post.body }}</p>
<h3>Comments:</h3>
<comment :comments="getPostComments"></comment>
</template>
在这里,我们使用函数定义所需的 props,并从注释存储中提取必要的数据。然后,我们获取注释,以便可以正确更新。defineProps getPostComments
在模板中,我们首先显示帖子标题,然后在署名中,我们添加一个作者姓名,其中包含指向作者页面的链接和帖子中的评论数量。然后,我们在下面添加帖子正文和评论部分。
为了显示评论,我们将使用单独的组件,并将帖子评论传递给道具。comments
创建组件comment
在目录中,创建一个包含以下内容的文件:components Comment.vue
<script setup>
defineProps(['comments'])
</script>
<template>
<div v-for="comment in comments" :key="comment.id">
<h3>{{ comment.name }}</h3>
<p>{{ comment.body }}</p>
</template>
这很简单。我们定义道具并使用它来迭代帖子的评论。comments
在我们再次测试应用程序之前,请将以下内容添加到:router.js
import PostView from '../views/PostView.vue'
// ...
routes: [
// ...
{ path: '/post/:id', name: 'post', component: PostView },
再次运行应用。当您导航到单个帖子时,您应该会看到类似的视图:
现在是时候显示作者了。再次关闭终端。
创建作者视图
在目录中,将文件重命名为以下内容,并将内容替换为以下内容:views AboutView.vue AuthorsView.vue
<script setup>
import { RouterLink } from 'vue-router'
import { storeToRefs } from 'pinia'
import { useAuthorStore } from '../stores/author'
const { authors } = storeToRefs(useAuthorStore())
const { fetchAuthors } = useAuthorStore()
fetchAuthors()
</script>
<template>
<p v-if="authors" v-for="author in authors" :key="author.id">
<RouterLink :to="`/author/${author.username}`">{{ author.name }}</RouterLink>
</template>
在这里,我们使用作者存储来获取并让作者在模板中循环访问它们。对于每个作者,我们都会提供指向其页面的链接。
再次打开文件,并将“关于”页面的路由更改为以下内容:router.js
path: '/authors',
name: 'authors',
// 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/AuthorsView.vue')
在这里,我们将路径和名称分别更改为 和 ,并导入延迟加载。/authors authors AuthorsView.vue
再次运行应用。访问作者视图时,应会看到以下内容:
现在,让我们创建单个作者视图。再次关闭终端。
创建单个作者视图
在目录中,创建一个包含以下内容的文件:views AuthorView.vue
<script setup>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { storeToRefs } from 'pinia'
import { useAuthorStore } from '../stores/author'
import { usePostStore } from '../stores/post'
import Author from '../components/Author.vue'
const route = useRoute()
const { authors } = storeToRefs(useAuthorStore())
const { getPostsPerAuthor } = storeToRefs(usePostStore())
const { fetchPosts } = usePostStore()
const getAuthorByUserName = computed(() => {
return authors.value.find((author) => author.username === route.params.username)
fetchPosts()
</script>
<template>
<author
:author="getAuthorByUserName"
:posts="getPostsPerAuthor(getAuthorByUserName.id)">
</author>
</template>
在这里,为了找到当前作者是谁,我们使用他们的用户名从路由中获取它。因此,我们为此目的创建了一个计算;我们将和 props 传递给一个组件,我们现在将创建该组件。getAuthorByUserName author posts author
创建组件author
在目录中,创建包含以下内容的文件:components Author.vue
<script setup>
import { RouterLink } from 'vue-router'
defineProps(['author', 'posts'])
</script>
<template>
<h1>{{author.name}}</h1>
<p>{{posts.length}} posts written.</p>
<p v-for="post in posts" :key="post.id">
<RouterLink :to="`/post/${post.id}`">{{ post.title }}</RouterLink>
</template>
此组件显示作者姓名、作者撰写的帖子数以及帖子本身。
接下来,将以下内容添加到文件中:router.js
import AuthorView from '../views/AuthorView.vue'
// ...
routes: [
// ...
{ path: '/author/:username', name: 'author', component: AuthorView }
再次运行应用。转到作者视图时,应看到以下内容:
配置路由器
以下是最终文件的外观:router.js
import { createRouter, createWebHistory } from 'vue-router'
import PostsView from '../views/PostsView.vue'
import PostView from '../views/PostView.vue'
import AuthorView from '../views/AuthorView.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
path: '/',
name: 'posts',
component: PostsView
path: '/authors',
name: 'authors',
// 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/AuthorsView.vue')
{ path: '/post/:id', name: 'post', component: PostView },
{ path: '/author/:username', name: 'author', component: AuthorView },
export default router
现在,所有关于缺少资源/组件的 Vue 警告都应该消失了。
就是这样。我们成功地在一个相当复杂的应用程序中创建并使用了Pinia商店。
最后,让我们看看如何在 Vue devtools 中检查应用程序。
在接下来的屏幕截图中,我们打开了一个ID为2的帖子。以下是应用程序的路由在“路由”选项卡中的列出方式:
我们可以看到,我们创建的所有路由都在这里,并且单个帖子的路由处于活动状态,因为它当前正在使用中。
现在,让我们切换到“组件”选项卡,以便我们可以浏览帖子视图的应用程序组件树:
正如我们所看到的,该应用程序从两个组件开始,并在 中定义组件。然后,我们有单个帖子视图,后跟组件。最后,还有另一个注释组件。RouretLink RouterView App.vue post RouterLink
现在让我们看看商店,这是有趣的部分。Pinia 显示活动组件中使用的所有存储区。在我们的例子中,我们拥有所有三个,因为我们在打开单个帖子时都使用它们。
这是邮政商店:
我们可以看到Pinia显示了正确的打开的帖子。对于作者存储也是如此:
最后,注释存储显示注释:
同样,我们可以看到第一个注释的名称与浏览器中显示的名称匹配。所以,一切都如预期的那样工作。
现在,您知道了如何创建、使用和检查 Pinia 商店。
我对新的官方Vue状态管理工具非常满意。正如我们所看到的,它采用模块化设计,易于使用,占地面积小,最后但并非最不重要的是,它简单,灵活且功能强大。与Pinia一起创建商店真的很愉快。
在本教程中,我们构建了一个基本的博客引擎,其中包含Pinia提供的主要功能(状态,getters和操作)。当然,可以通过为作者、帖子和评论添加 CRUD 功能来进一步扩展该项目,但这超出了本教程的范围。
有关 Pinia 用法的更复杂和实际示例,您可以浏览 Directus 项目的代码。
最后,请务必查看Pinia文档,以了解更高级的使用方法。
完全按照用户的方式体验您的 Vue 应用
调试 Vue.js应用程序可能很困难,尤其是在用户会话期间有几十个甚至数百个突变时。如果你有兴趣在生产环境中监控和跟踪所有用户的 Vue 突变,请尝试 LogRocket。
https://logrocket.com/signup/
LogRocket就像一个用于Web和移动应用程序的DVR,记录Vue应用程序中发生的所有事情,包括网络请求,JavaScript错误,性能问题等等。您不必猜测问题发生的原因,而是可以汇总并报告问题发生时应用程序所处的状态。
LogRocket Vuex 插件将 Vuex 突变记录到 LogRocket 控制台,为您提供导致错误的原因以及问题发生时应用程序所处的状态的上下文。
现代化您的 Vue 应用程序调试方式 - 开始免费监控。
复杂的 Vue 3 状态管理变得简单 Pinia - LogRocket 博客 (blog-logrocket-com.translate.goog)
https://blog-logrocket-com.translate.goog/complex-vue-3-state-management-pinia/?_x_tr_sl=en&_x_tr_tl=zh-CN&_x_tr_hl=zh-CN&_x_tr_pto=sc
内容概要:操作系统实验,前端 vue3 + vite3 + pinia + ant design vue实现简易的生产者消费者模型,可以通过输入表单的形式手动调节生产者的消费速率和消费者的消费速率的形式,实现生产者消费者模型的可视化效果。
适宜人群: 本科阶段学习过vue,需要完成操作系统生产者消费者模型的可视化效果
能学到的知识:深入了解生产者消费者模型,熟悉vue3 的使用,了解typescript,pinia,vite3的使用效果。
阅读建议:此资源以开发简化版生产者消费者模型,不仅是代码编写实现也更注重内容上的需求分析和方案设计,所以在学习的过程要结合这些内容一起来实践,并调试对应的代码
运行环境要求: node.js
运行步骤:
执行以下命令:
npm install
npm run dev
打包命令:npm run build,生成的html文件可以使用live server 插件打开进行效果预览
- `Pinia` 是 `Vue` 的专属状态管理库,它允许你跨组件或页面共享状态。
- `Pinia` 是 `Vuex4` 的升级版,也就是 `Vuex5`
- `Pinia` 极大的简化了 `Vuex` 的使用,是 `Vue3` 的新的状态管理工具
- `Pinia` 对 `ts` 的支持更好,性能更优, 体积更小,无 `mutations`,可用于 `Vue2` 和 `Vue3`
- `Pinia` 支持 `Vue Devtools`、 模块热更新和服务端渲染
- `Pinia` 的官方地址为:[`h
Vue3引入pinia并模块化,如何在 vue3+TS 的项目中使用pinia进行模块化状态举个例子啊,在复杂的大型项目中呢,因为项目复杂所以数据必然多,如果不模块化管理,状态管理的数据可能都堆成山了。所以呢,咱们必须将这些数据进行模块化管理,最简单的是啥呢,比如用户相关的数据放在一个文件里,而系统相关的放在另一个文件里,这就是最简单的模块化。我们要聊的 Pinia 模块化也是同理,咱们来实际操作一把。最后总结一下,其实 Vue2 中 Vuex 同样也可以模块化管理,Vuex 是重量级的,更加适合大型项目。