如何使用Vue、GraphQL和Apollo客户端构建博客
介绍
在本文中,您将构建一个使用 GraphQL 服务器的博客。 我们将使用 Apollo 客户端和 Vue 构建博客应用程序。
先决条件
要完成本教程,您需要:
- Node.js 安装在本地,您可以按照【X57X】如何安装Node.js 并创建本地开发环境【X126X】进行。
- MySQL在本地安装并运行,您可以按照如何安装MySQL来完成。
本教程假设您了解 JavaScript 并熟悉 Vue 和 GraphQL。
本教程已使用 Node v14.4.0、npm
v6.14.5、MySQL v14.14、@adonisjs/cli
v4.0.12、@vue/cli
v4.4.6、[X120X ] v2.5.2、graphql
v15.1.0 和 apollo-client
v2.6.10。
创建 GraphQL 服务器
您可以获取 GraphQL 服务器,以便您可以按照教程进行操作。
克隆存储库后,导航到 GraphQL 服务器项目目录:
cd adonis-graphql-server
安装所需的软件包:
npm install
将 .env.example
复制到 .env
:
cp .env.example .env
根据需要编辑 .env
文件,以便数据库信息为您正在运行的 MySQL 数据库提供正确的凭据。 DB_USER
和 DB_PASSWORD
可能需要更改。
为 Adonis 生成密钥:
npx @adonisjs/cli key:generate
迁移数据库配置:
npx @adonisjs/cli migration:run
启用 CORS
GraphQL 服务器是用 AdonisJS 构建的。 AdonisJS 提供了一个包,我们可以使用它来处理我们 API 上的跨域资源共享 (CORS)。 默认情况下,AdonisJS 上的 CORS 是关闭的,所以我们需要启用它。
为了在 AdonisJS 应用上启用 CORS,我们在 config/cors.js
中将 origin
设置为 true
,如下所示:
配置/cors.js
origin: true
克隆的 GraphQL 服务器已经启用了 CORS,但值得一提的是。
启动 GraphQL 服务器
由于我们的博客应用程序将使用 GraphQL 服务器,因此我们需要启动服务器并使其在本教程的其余部分保持运行。
要开始,请确保您位于 GraphQL 服务器项目目录中并运行以下命令:
npx @adonisjs/cli serve --dev
这将启动 GraphQL 服务器并保持运行。
本教程的其余部分假设您已经启动了 GraphQL 服务器并且它正在运行。
处理完这些,让我们开始构建我们的博客应用程序。
第 1 步——创建一个 Vue 应用程序
我们将首先使用 Vue CLI 创建一个新的 Vue 应用程序:
npx -p @vue/cli -p @vue/cli-init vue init webpack graphql-blog-app
注意: 现代 Vue 项目可以利用:
npx @vue/cli create graphql-blog-app
系统将提示您有关您的项目的问题。 以下是所做的一些选择。 对于本教程,安装 vue-router
很重要:
? Project name graphql-blog-app ? Project description A Vue.js project ? Vue build standalone ? Install vue-router? Yes ? Use ESLint to lint your code? Yes ? Pick an ESLint preset Standard ? Set up unit tests No ? Setup e2e tests with Nightwatch? No ? Should we run `npm install` for you after the project has been created? (recommended) npm
这将创建一个名为 graphql-blog-app
的新 Vue 应用程序并安装其依赖项。
导航到新创建的目录:
cd graphql-blog-app
通过在终端中运行以下命令,可以随时在浏览器中运行和查看该应用程序:
npm start
第 2 步 — 安装软件包
创建应用程序后,我们可以继续安装必要的包来构建我们的 GraphQL 博客应用程序:
npm install --save vue-apollo graphql apollo-client apollo-link apollo-link-context apollo-link-http apollo-cache-inmemory graphql-tag
让我们快速浏览每个包:
vue-apollo
:VueJS 的 Apollo/GraphQL 集成。 我们安装了最新版本的插件,允许我们使用 Apollo 客户端 2.0 附带的所有强大功能。graphql
:GraphQL for JavaScript 的参考实现。apollo-client
:一个功能齐全、生产就绪的缓存 GraphQL 客户端,适用于每个服务器或 UI 框架。apollo-link
:用于修改 GraphQL 请求的控制流和获取 GraphQL 结果的标准接口。apollo-link-context
:用于为您的操作设置上下文,供后续链中的其他链接使用。apollo-link-http
:用于使用 HTTP fetch 通过网络获取 GraphQL 结果。apollo-cache-inmemory
:Apollo Client 2.0 的缓存实现。graphql-tag
:解析 GraphQL 查询的 JavaScript 模板文字标签。
第 3 步 — 设置 Vue Apollo
接下来,让我们使用这些包。 我们将首先创建一个 ApolloClient
实例并安装 VueApollo
插件。 打开 src/main.js
并添加以下代码:
src/main.js
// ... import { ApolloClient } from 'apollo-client' import { HttpLink } from 'apollo-link-http' import { InMemoryCache } from 'apollo-cache-inmemory' import VueApollo from 'vue-apollo' const httpLink = new HttpLink({ // URL to graphql server, you should use an absolute URL here uri: 'http://localhost:3333/graphql' }) // create the apollo client const apolloClient = new ApolloClient({ link: httpLink, cache: new InMemoryCache() }) // install the vue plugin Vue.use(VueApollo)
我们使用 GraphQL 服务器的 URL (http://localhost:3333/graphql
) 创建一个新的 httpLink
实例。 然后我们使用上面创建的 httpLink
创建一个 Apollo 客户端,并指定我们想要一个内存缓存。 最后,我们安装 Vue Apollo 插件。
接下来,让我们创建一个我们将在根组件上指定的 apolloProvider
对象:
src/main.js
// ... const apolloProvider = new VueApollo({ defaultClient: apolloClient }) // update Vue instance by adding `apolloProvider` /* eslint-disable no-new */ new Vue({ el: '#app', router, apolloProvider, template: '<App/>', components: { App } })
我们使用默认客户端创建的 apolloClient
创建 Vue Apollo 插件的新实例。 最后,我们通过将 apolloProvider
对象添加到我们的 Vue 实例中来使用它,就像我们使用 Vue 路由器一样。
第 4 步 - 添加布尔玛
出于本教程的目的,我们将使用 Bulma CSS。 所以,让我们添加它。 打开index.html
更新如下:
索引.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>GraphQL Blog App</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css"> </head> <body> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
我们在这个内容交付网络 (CDN) 上引用了 Bulma。
第 5 步 — 删除未使用的代码
我们在创建 Vue 应用程序时附带了一些文件和代码,我们不会在本教程中使用它们。 让我们删除它们,这样它们就不会干扰我们的应用程序。
删除 HelloWorld
组件并从 src/router/index.js
中删除其所有引用。
第 6 步 - 创建主布局
该博客将在其页面中使用通用布局。 在这种情况下,让我们定义一个所有页面都将使用的布局。 为此,请打开 src/App.vue
并更新如下:
src/App.vue
<template> <div id="app"> <nav class="navbar is-primary" role="navigation" aria-label="main navigation"> <div class="container"> <div class="navbar-brand"> <router-link class="navbar-item" to="/">Blog App</router-link> <button class="button navbar-burger"> <span></span> <span></span> <span></span> </button> </div> </div> </nav> <router-view/> </div> </template> <script> export default { name: 'app' } </script>
我们添加一个所有页面都将使用的标题。
第 7 步 - 创建用户注册页面
用户应该能够注册我们的博客应用程序。 我们将创建一个 SignUp
组件来处理它。 因此,在 src/components
中创建一个新的 Admin
文件夹。 所有与管理员相关的组件都将在此文件夹内创建。
在我们创建 SignUp
组件之前,让我们创建一个专用文件来保存我们所有的 GraphQL 查询和突变。 我们将直接在 src
中创建这个文件。 在 src
中创建一个 graphql.js
文件并将以下代码粘贴到其中:
src/graphql.js
import gql from 'graphql-tag' export const SIGNUP_MUTATION = gql` mutation SignupMutation($username: String!, $email: String!, $password: String!) { createUser( username: $username, email: $email, password: $password ) { id username email } } `
这是 GraphQL 突变,它将处理在我们的 GraphQL 服务器上创建新用户。 它需要用户的用户名、电子邮件和密码。 这些变量将从 SignUp
组件传递。
接下来,让我们创建 SignUp
组件。 在 Admin
文件夹中,创建一个 SignUp.vue
文件并将以下代码粘贴到其中:
src/components/Admin/SignUp.vue
<template> <section class="section"> <div class="columns"> <div class="column is-4 is-offset-4"> <h2 class="title has-text-centered">Signup</h2> <form method="POST" @submit.prevent="signup"> <div class="field"> <label class="label">Username</label> <p class="control"> <input type="text" class="input" v-model="username" /> </p> </div> <div class="field"> <label class="label">E-Mail Address</label> <p class="control"> <input type="email" class="input" v-model="email" /> </p> </div> <div class="field"> <label class="label">Password</label> <p class="control"> <input type="password" class="input" v-model="password" /> </p> </div> <p class="control"> <button class="button is-primary is-fullwidth is-uppercase">SignUp</button> </p> </form> </div> </div> </section> </template> <script> import { SIGNUP_MUTATION } from '@/graphql' export default { name: 'SignUp', data () { return { username: '', email: '', password: '' } }, methods: { signup () { this.$apollo .mutate({ mutation: SIGNUP_MUTATION, variables: { username: this.username, email: this.email, password: this.password } }) .then(response => { // redirect to login page this.$router.replace('/login') }) } } } </script>
该组件呈现一个表单供用户注册。 提交表单后,将调用 signup
方法。 在 signup
方法中,我们使用 this.$apollo
上可用的 mutate
方法(来自 Vue Apollo 插件)。 我们使用之前创建的 SIGNUP_MUTATION
突变并传递必要的变量。 一旦注册过程成功(即用户已创建),我们将用户重定向到登录页面(我们将很快创建)。
添加注册路线
打开src/router/index.js
,添加如下代码:
src/路由器/index.js
// ... import SignUp from '@/components/Admin/SignUp' // ... export default new Router({ routes: [ // add these inside the `routes` array { path: '/signup', name: 'SignUp', component: SignUp } ] })
现在,当我们访问 /signup
路由时,我们应该会看到如下图所示的注册表单:
第 8 步 - 创建用户登录页面
让我们添加用户登录的功能。 就像我们对用户注册所做的那样,让我们首先创建 GraphQL 突变。 将以下代码添加到 src/graphql.js
:
src/graphql.js
export const LOGIN_MUTATION = gql` mutation LoginMutation($email: String!, $password: String!) { login( email: $email, password: $password ) } `
这个 GraphQL 突变处理用户登录到我们的 GraphQL 服务器。 它需要用户的电子邮件和密码。
接下来,在 Admin
文件夹中,创建一个 LogIn.vue
文件并将以下代码粘贴到其中:
src/components/Admin/LogIn.vue
<template> <section class="section"> <div class="columns"> <div class="column is-4 is-offset-4"> <h2 class="title has-text-centered">Login</h2> <form method="POST" @submit.prevent="login"> <div class="field"> <label class="label">E-Mail Address</label> <p class="control"> <input type="email" class="input" v-model="email" /> </p> </div> <div class="field"> <label class="label">Password</label> <p class="control"> <input type="password" class="input" v-model="password" /> </p> </div> <p class="control"> <button class="button is-primary is-fullwidth is-uppercase">Login</button> </p> </form> </div> </div> </section> </template> <script> import { LOGIN_MUTATION } from '@/graphql' export default { name: 'LogIn', data () { return { email: '', password: '' } }, methods: { login () { this.$apollo .mutate({ mutation: LOGIN_MUTATION, variables: { email: this.email, password: this.password } }) .then(response => { // save user token to localstorage localStorage.setItem('blog-app-token', response.data.login) // redirect user this.$router.replace('/admin/posts') }) } } } </script>
该组件呈现一个简单的表单供用户登录。 提交表单后,将调用 login
方法。 在 login
方法中,我们使用了 mutate
方法。 我们使用之前创建的 LOGIN_MUTATION
突变并传递必要的变量。 一旦登录过程成功,我们将从我们的 GraphQL 服务器获取的令牌保存到 localStorage 并重定向用户。
添加登录路由
打开src/router/index.js
,添加如下代码:
src/路由器/index.js
// ... import LogIn from '@/components/Admin/LogIn' // ... export default new Router({ routes: [ // ... // add these inside the `routes` array { path: '/login', name: 'LogIn', component: LogIn } ] })
现在当我们访问 /login
路由时,我们应该看到我们的登录表单,如下图所示:
第 9 步 - 创建菜单组件
在我们开始充实博客的管理部分之前,让我们创建一个 Menu
组件,它将用作侧边栏导航菜单。 在 Admin
文件夹中,创建一个 Menu.vue
文件并将以下代码粘贴到其中:
src/components/Admin/Menu.vue
<template> <aside class="menu"> <p class="menu-label">Post</p> <ul class="menu-list"> <li> <router-link to="/admin/posts/new">New Post</router-link> </li> <li> <router-link to="/admin/posts">Posts</router-link> </li> </ul> <p class="menu-label">User</p> <ul class="menu-list"> <li> <router-link to="/admin/users">Users</router-link> </li> </ul> </aside> </template>
这会呈现指向我们博客应用程序的一些管理部分的链接。
第 10 步 — 创建用户列表页面
在管理部分,我们希望能够看到已创建的用户列表。 为此,我们创建了一个 Users
组件。 但首先,让我们编写 GraphQL 查询来获取所有创建的用户。 将以下代码添加到 src/graphql.js
:
src/graphql.js
export const ALL_USERS_QUERY = gql` query AllUsersQuery { allUsers { id username email } } `
这个 GraphQL 查询从我们的 GraphQL 服务器获取所有用户。
接下来,让我们创建 Users
组件。 在 Admin
文件夹中,创建一个 Users.vue
文件并将以下代码粘贴到其中:
src/components/Admin/Users.vue
<template> <section class="section"> <div class="container"> <div class="columns"> <div class="column is-3"> <Menu/> </div> <div class="column is-9"> <h2 class="title">Users</h2> <table class="table is-striped is-narrow is-hoverable is-fullwidth"> <thead> <tr> <th>Username</th> <th>Email</th> <th></th> </tr> </thead> <tbody> <tr v-for="user in allUsers" :key="user.id"> <td>{{ user.username }}</td> <td>{{ user.email }}</td> <td> <router-link :to="`/admin/users/${user.id}`">View</router-link> </td> </tr> </tbody> </table> </div> </div> </div> </section> </template> <script> import Menu from '@/components/Admin/Menu' import { ALL_USERS_QUERY } from '@/graphql' export default { name: 'Users', components: { Menu }, data () { return { allUsers: [] } }, apollo: { // fetch all users allUsers: { query: ALL_USERS_QUERY } } } </script>
我们使用之前创建的 Menu
组件。 然后我们定义我们的数据,一旦从我们的 GraphQL 服务器获取数据,这些数据就会被填充。 在 apollo
对象中,我们添加 GraphQL 查询以获取所有用户。 这利用了我们在上面创建的 ALL_USERS_QUERY
。 需要注意的是,我们的数据名称(本例中为 allUsers
)必须与 GraphQL 查询中使用的名称相同(本例中为 allUsers
)。 一旦 allUsers
填充了来自我们 GraphQL 服务器的数据,我们就会通过遍历用户数组在表格中显示用户。 我们还添加了一个链接来查看每个用户的详细信息。
添加用户路由
打开src/router/index.js
,添加如下代码:
src/路由器/index.js
// ... import Users from '@/components/Admin/Users' // ... export default new Router({ routes: [ // ... // add these inside the `routes` array { path: '/admin/users', name: 'Users', component: Users } ] })
现在,当我们访问 /admin/users
路由时,我们应该会看到如下图所示的用户列表:
第 11 步 - 创建用户详细信息页面
在最后一节中,我们添加了一个链接来查看用户详细信息。 现在,让我们实现它。 将以下代码添加到 src/graphql.js
:
src/graphql.js
export const USER_QUERY = gql` query UserQuery($id: Int!) { user(id: $id) { id username email posts { id } } } `
这个 GraphQL 查询通过用户的 ID 从我们的 GraphQL 服务器获取用户。 它将用户的 ID 作为参数。 用户 ID 将从 UserDetails
组件传递。
接下来,让我们创建 UserDetails
组件。 在 Admin
文件夹中,创建一个 UserDetails.vue
文件并将以下代码粘贴到其中:
src/components/Admin/UserDetails.vue
<template> <section class="section"> <div class="container"> <div class="columns"> <div class="column is-3"> <Menu/> </div> <div class="column is-9"> <h2 class="title">User Details</h2> <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label">Username</label> </div> <div class="field-body"> <div class="field"> <p class="control"> <input class="input is-static" :value="user.username" readonly /> </p> </div> </div> </div> <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label">Email Address</label> </div> <div class="field-body"> <div class="field"> <p class="control"> <input class="input is-static" :value="user.email" readonly /> </p> </div> </div> </div> <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label">Number of posts</label> </div> <div class="field-body"> <div class="field"> <p class="control"> <input class="input is-static" :value="user.posts.length" readonly /> </p> </div> </div> </div> </div> </div> </div> </section> </template> <script> import Menu from '@/components/Admin/Menu' import { USER_QUERY } from '@/graphql' export default { name: 'UserDetails', components: { Menu }, data () { return { user: '', id: this.$route.params.id } }, apollo: { // fetch user by ID user: { query: USER_QUERY, variables () { return { id: this.id } } } } } </script>
我们显示指定用户的用户名、电子邮件和创建的帖子数。 USER_QUERY
接受我们要查看其详细信息的用户的 ID。 用户 ID 是从路由参数中获取的。 也就是说,给定 /admin/users/12
,12 是特定用户的 ID。 我们需要一种方法将此 ID 传递给我们的查询。 为此,我们通过定义返回包含用户 ID 的对象的 variables
函数来使用 反应参数 。
添加用户详细信息路由
打开src/router/index.js
,添加下面的代码。 这条路线应该低于所有以前的路线:
src/路由器/index.js
// ... import UserDetails from '@/components/Admin/UserDetails' // ... export default new Router({ routes: [ // ... // add these inside the `routes` array { path: '/admin/users/:id', name: 'UserDetails', component: UserDetails, props: true } ] })
我们现在应该能够查看特定的用户详细信息:
第 12 步 — 授权用户
只有经过身份验证的用户才能添加新帖子。 因此,我们需要一种方法来传递带有用户令牌的 Authorization
标头以及添加新帖子的请求,这将表示用户实际上可以添加新帖子。 使用 apollo-link-context
,我们可以轻松做到这一点。 打开 src/main.js
并添加以下代码:
src/main.js
// ... import { setContext } from 'apollo-link-context' // ... const authLink = setContext((_, { headers }) => { // get the authentication token from localstorage if it exists const token = localStorage.getItem('blog-app-token') // return the headers to the context so httpLink can read them return { headers: { ...headers, authorization: token ? `Bearer ${token}` : null } } }) // ... // update apollo client as below const apolloClient = new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache() })
首先,我们导入 apollo-link-context
。 然后我们利用它创建一个 authLink
从本地存储中获取用户令牌并返回包含授权标头的标头。 最后,我们在 Apollo 客户端中使用了 authLink
。
现在,授权标头将与向我们的 GraphQL 服务器发出的所有请求一起发送。
第 13 步 - 创建新帖子页面
帖子是任何博客的核心。 用户应该能够添加新帖子。 同样,我们将首先创建 GraphQL 突变以向我们的博客添加新帖子。 将以下代码添加到 src/graphql.js
:
src/graphql.js
export const ADD_POST_MUTATION = gql` mutation AddPostMutation($title: String!, $content: String!) { addPost( title: $title, content: $content ) { id slug title content user { id username email } } } `
这种突变采用我们想要添加到 GraphQL 服务器的帖子的标题和内容。
接下来,在 Admin
文件夹中创建一个 AddPost
组件并将以下代码粘贴到其中:
src/components/Admin/AddPost.vue
<template> <section class="section"> <div class="container"> <div class="columns"> <div class="column is-3"> <Menu/> </div> <div class="column is-9"> <h2 class="title">Add Post</h2> <form method="post" @submit.prevent="addPost"> <div class="field"> <label class="label">Title</label> <p class="control"> <input class="input" v-model="title" placeholder="Post title" /> </p> </div> <div class="field"> <label class="label">Content</label> <p class="control"> <textarea class="textarea" rows="10" v-model="content" placeholder="Post content" ></textarea> </p> </div> <p class="control"> <button class="button is-primary">Add Post</button> </p> </form> </div> </div> </div> </section> </template> <script> import Menu from '@/components/Admin/Menu' import { ADD_POST_MUTATION, ALL_POSTS_QUERY } from '@/graphql' export default { name: 'AddPost', components: { Menu }, data () { return { title: '', content: '' } }, methods: { addPost () { this.$apollo .mutate({ mutation: ADD_POST_MUTATION, variables: { title: this.title, content: this.content }, update: (store, { data: { addPost } }) => { // read data from cache for this query const data = store.readQuery({ query: ALL_POSTS_QUERY }) // add new post from the mutation to existing posts data.allPosts.push(addPost) // write data back to the cache store.writeQuery({ query: ALL_POSTS_QUERY, data }) } }) .then(response => { // redirect to all posts this.$router.replace('/admin/posts') }) } } } </script>
该组件呈现一个用于添加新帖子的表单。 它使用 ADD_POST_MUTATION
传递给它必要的变量。 由于 Apollo 客户端缓存(在我们的例子中是在内存中)它查询,所以我们需要一种方法来在我们执行突变操作时更新缓存。 请注意,有一个 update
函数,我们通过将新添加的帖子添加到缓存中来更新商店。 首先,我们从缓存中获取与查询匹配的数据 (ALL_POSTS_QUERY
),然后将新帖子添加到 allPosts
数组中。 最后,我们将新数据写回缓存。 成功添加帖子后,我们将重定向到帖子列表(我们将很快创建)。
添加 Add Post 路由
打开src/router/index.js
,添加如下代码:
src/路由器/index.js
// ... import AddPost from '@/components/Admin/AddPost' // ... export default new Router({ routes: [ // ... // add these inside the `routes` array { path: '/admin/posts/new', name: 'AddPost', component: AddPost } ] })
用户现在应该可以添加新帖子了:
第 14 步 - 显示所有帖子
我们将首先通过将以下代码添加到 src/graphql.js
来创建 GraphQL 查询:
src/graphql.js
export const ALL_POSTS_QUERY = gql` query AllPostsQuery { allPosts { id title slug user { username } } } `
这个 GraphQL 查询从我们的 GraphQL 服务器获取所有帖子。
接下来,在 Admin
文件夹中创建一个 Posts
组件,并将以下代码粘贴到其中:
src/components/Admin/Posts.vue
<template> <section class="section"> <div class="container"> <div class="columns"> <div class="column is-3"> <Menu/> </div> <div class="column is-9"> <h2 class="title">Posts</h2> <table class="table is-striped is-narrow is-hoverable is-fullwidth"> <thead> <tr> <th>Title</th> <th>User</th> <th></th> </tr> </thead> <tbody> <tr v-for="post in allPosts" :key="post.id" > <td>{{ post.title }}</td> <td>{{ post.user.username }}</td> </tr> </tbody> </table> </div> </div> </div> </section> </template> <script> import Menu from '@/components/Admin/Menu' import { ALL_POSTS_QUERY } from '@/graphql' export default { name: 'Posts', components: { Menu }, data () { return { allPosts: [] } }, apollo: { // fetch all posts allPosts: { query: ALL_POSTS_QUERY } } } </script>
我们使用之前创建的 Menu
组件。 然后我们定义我们的数据,一旦从我们的 GraphQL 服务器获取数据,这些数据就会被填充。 在 apollo
对象中,我们添加 GraphQL 查询以获取所有用户。 这利用了我们在上面创建的 ALL_USERS_QUERY
。 需要注意的是,我们的数据名称(本例中为 allUsers
)必须与 GraphQL 查询中使用的名称相同(本例中为 allUsers
)。 一旦 allUsers
填充了来自我们 GraphQL 服务器的数据,我们就会通过遍历用户数组在表格中显示用户。 我们还添加了一个链接来查看每个用户的详细信息。
添加帖子路线
打开src/router/index.js
,添加如下代码:
src/路由器/index.js
// ... import Posts from '@/components/Admin/Posts' // ... export default new Router({ routes: [ // ... // add these inside the `routes` array { path: '/admin/posts', name: 'Posts', component: Posts } ] })
现在,当我们访问 /admin/posts
路由时,我们应该会看到如下图所示的帖子列表:
第 15 步 — 创建博客主页
博客主页将显示创建的所有帖子的列表,就像在显示帖子部分中一样。 事实上,主页将使用与显示帖子完全相同的 GraphQL。 只有主页的标记会有所不同。 在 src/components
内部创建一个 Home
组件,并在其中添加以下代码:
src/components/Home.vue
<template> <section class="section"> <div class="columns"> <div class="column is-6 is-offset-3"> <h1 class="title">Latest Posts</h1> <h3 v-for="post in allPosts" :key="post.id" class="title is-5" > <router-link :to="post.slug"> {{ post.title }} </router-link> </h3> </div> </div> </section> </template> <script> import { ALL_POSTS_QUERY } from '@/graphql' export default { name: 'Home', data () { return { allPosts: [] } }, apollo: { // fetch all posts allPosts: { query: ALL_POSTS_QUERY } } } </script>
正如我们所见,JavaScript 部分与 Posts
组件的部分相同。 只是不同的标记。 我们循环遍历帖子数组并显示与其 slug 链接的每个帖子的标题。
添加主路由
打开src/router/index.js
,添加如下代码:
src/路由器/index.js
// ... import Home from '@/components/Home' // ... export default new Router({ routes: [ // ... // add these inside the `routes` array { path: '/', name: 'Home', component: Home } ] })
访问 /
路由,我们应该看到我们的博客主页,如下图所示:
第 16 步 - 创建单个帖子页面
最后要添加的是查看特定帖子的能力。 将以下代码添加到 src/graphql.js
:
src/graphql.js
export const POST_QUERY = gql` query PostQuery($slug: String!) { post(slug: $slug) { id title slug content user { id username email } } } `
此查询通过其 slug 获取帖子。 它需要获取帖子的 slug 作为参数。
接下来,在 src/components
内部创建一个 SinglePost
组件,并在其中添加以下代码:
src/components/SinglePost.vue
<template> <section class="section"> <div class="columns"> <div class="column is-6 is-offset-3"> <router-link class="button is-link is-small" to="/">Back Home</router-link> <h1 class="title"> {{ post.title }} </h1> <div class="content"> {{ post.content }} </div> </div> </div> </section> </template> <script> import { POST_QUERY } from '@/graphql' export default { name: 'SinglePost', data () { return { post: '', slug: this.$route.params.slug } }, apollo: { // fetch post by slug post: { query: POST_QUERY, variables () { return { slug: this.slug } } } } } </script>
我们显示帖子标题及其内容以及返回主页的链接。 JavaScript 部分遵循用于显示用户详细信息的实现。 在这种情况下,我们从路由参数中获取 post slug。
添加查看帖子路线
打开src/router/index.js
,添加如下代码:
src/路由器/index.js
// ... import SinglePost from '@/components/SinglePost' // ... export default new Router({ routes: [ // ... // add these inside the `routes` array { path: '/:slug', name: 'SinglePost', component: SinglePost, props: true } ] })
注意:这条路线应该是路线数组中的最后一条路线。
我们现在应该可以查看单个帖子:
结论
在本教程中,我们了解了如何使用 GraphQL、Apollo 客户端和 VueJS 构建博客应用程序。 我们还看到了如何将我们的前端应用程序连接到 GraphQL 服务器。
本教程的 完整代码可在 GitHub 上找到。