如何使用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 上找到。