docs: Add Chinese Doc (#329)

* docs: structure of Chinese doc

* docs: translate root page to Chinese

* docs: translate pages in `/guide` and `/guid/apollo` to Chinese

* docs: translate pages in `/api` and `/migration` to Chinese

- fix some words in completed pages

* docs: translate pages in `/guide/components` to Chinese

* docs: fix some words

* docs: keep Chinese version up to date

* docs: Chinese version up to date

* docs: fix some words

* docs: fix some words
This commit is contained in:
高英健
2018-09-08 21:53:04 +08:00
committed by Guillaume Chau
parent c2f9b416e2
commit 906975e45b
27 changed files with 2877 additions and 89 deletions
+200 -89
View File
@@ -1,104 +1,215 @@
module.exports = {
title: 'Vue Apollo',
description: '🚀 Integrate GraphQL in your Vue.js apps!',
base: '/vue-apollo/',
serviceWorker: true,
head: [
['link', { rel: 'icon', href: '/favicon.png' }],
],
locales: {
'/': {
lang: 'en-US',
title: 'Vue Apollo',
description: '🚀 Integrate GraphQL in your Vue.js apps!',
},
'/zh-cn/': {
lang: 'zh-CN',
title: 'Vue Apollo',
description: '🚀 在你的 Vue.js 应用中集成 GraphQL',
}
},
themeConfig: {
repo: 'Akryum/vue-apollo',
docsDir: 'docs',
editLinks: true,
lastUpdated: 'Last Updated',
nav: [
{
text: 'Guide',
link: '/guide/',
locales: {
'/': {
selectText: 'Languages',
label: 'English',
lastUpdated: 'Last Updated',
nav: [
{
text: 'Guide',
link: '/guide/',
},
{
text: 'API Reference',
link: '/api/',
},
{
text: 'Migration',
link: '/migration/',
},
{
text: 'CLI plugin',
link: 'https://github.com/Akryum/vue-cli-plugin-apollo',
},
{
text: 'Patreon',
link: 'https://www.patreon.com/akryum',
},
],
sidebarDepth: 3,
sidebar: {
'/guide/': [
'',
'installation',
{
title: 'Basic Usage',
collapsable: false,
children: [
'apollo/',
'apollo/queries',
'apollo/mutations',
'apollo/subscriptions',
'apollo/pagination',
],
},
{
title: 'Components',
collapsable: false,
children: [
'components/',
'components/query',
'components/mutation',
'components/subscribe-to-more',
],
},
{
title: 'Advanced topics',
collapsable: false,
children: [
'multiple-clients',
'ssr',
'local-state',
'testing',
],
},
],
'/api/': [
{
title: 'Vue Apollo',
collapsable: false,
children: [
'apollo-provider',
'dollar-apollo',
'ssr',
],
},
{
title: 'Smart Apollo',
collapsable: false,
children: [
'smart-query',
'smart-subscription',
],
},
{
title: 'Apollo Components',
collapsable: false,
children: [
'apollo-query',
'apollo-subscribe-to-more',
'apollo-mutation',
],
},
],
'/migration/': [''],
},
},
{
text: 'API Reference',
link: '/api/',
'/zh-cn/': {
selectText: '选择语言',
label: '简体中文',
editLinks: true,
lastUpdated: '上次更新时间',
nav: [
{
text: '指南',
link: '/zh-cn/guide/',
},
{
text: 'API 参考',
link: '/zh-cn/api/',
},
{
text: '迁移',
link: '/zh-cn/migration/',
},
{
text: 'CLI 插件',
link: 'https://github.com/Akryum/vue-cli-plugin-apollo',
},
{
text: '赞助作者',
link: 'https://www.patreon.com/akryum',
},
],
sidebarDepth: 3,
sidebar: {
'/zh-cn/guide/': [
'',
'installation',
{
title: '基本使用',
collapsable: false,
children: [
'apollo/',
'apollo/queries',
'apollo/mutations',
'apollo/subscriptions',
'apollo/pagination',
],
},
{
title: '组件',
collapsable: false,
children: [
'components/',
'components/query',
'components/mutation',
'components/subscribe-to-more',
],
},
{
title: '进阶',
collapsable: false,
children: [
'multiple-clients',
'ssr',
'local-state',
'testing',
],
},
],
'/zh-cn/api/': [
{
title: 'Vue Apollo',
collapsable: false,
children: [
'apollo-provider',
'dollar-apollo',
'ssr',
],
},
{
title: 'Smart Apollo',
collapsable: false,
children: [
'smart-query',
'smart-subscription',
],
},
{
title: 'Apollo 组件',
collapsable: false,
children: [
'apollo-query',
'apollo-subscribe-to-more',
'apollo-mutation',
],
},
],
'/zh-cn/migration/': [''],
},
},
{
text: 'Migration',
link: '/migration/',
},
{
text: 'CLI plugin',
link: 'https://github.com/Akryum/vue-cli-plugin-apollo',
},
{
text: 'Patreon',
link: 'https://www.patreon.com/akryum',
},
],
sidebarDepth: 3,
sidebar: {
'/guide/': [
'',
'installation',
{
title: 'Basic Usage',
collapsable: false,
children: [
'apollo/',
'apollo/queries',
'apollo/mutations',
'apollo/subscriptions',
'apollo/pagination',
],
},
{
title: 'Components',
collapsable: false,
children: [
'components/',
'components/query',
'components/mutation',
'components/subscribe-to-more',
],
},
{
title: 'Advanced topics',
collapsable: false,
children: [
'multiple-clients',
'ssr',
'local-state',
'testing',
],
},
],
'/api/': [
{
title: 'Vue Apollo',
collapsable: false,
children: [
'apollo-provider',
'dollar-apollo',
'ssr',
],
},
{
title: 'Smart Apollo',
collapsable: false,
children: [
'smart-query',
'smart-subscription',
],
},
{
title: 'Apollo Components',
collapsable: false,
children: [
'apollo-query',
'apollo-subscribe-to-more',
'apollo-mutation',
],
},
],
'/migration/': [''],
},
},
}
+20
View File
@@ -0,0 +1,20 @@
---
home: true
heroImage: /logo.png
actionText: 由此起步 →
actionLink: /zh-cn/guide/
features:
- title: 自动更新
details: 无需考虑更新 UI 或重新获取查询的问题!
- title: 模板内组件
details: 通过 Apollo 组件声明式地使用 Apollo
- title: 支持 SSR
details: 在渲染 HTML 页面之前在服务端运行你的查询
footer: LICENCE ISC - Created by Guillaume CHAU (@Akryum)
---
<p style="text-align: center;">
<a href="https://www.patreon.com/akryum" target="_blank">
<img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Become a Patreon">
</a>
</p>
+7
View File
@@ -0,0 +1,7 @@
# API 参考
欢迎查看 API 参考!
::: warning Work-in-Progress
如果你发现缺少了某些东西,请创建一个代码合并请求!
:::
+23
View File
@@ -0,0 +1,23 @@
# ApolloMutation 组件
## Props
- `mutation`GraphQL 查询(由 `graphql-tag` 转换)
- `variables`GraphQL 变量对象
- `optimisticResponse`:详见 [乐观 UI](https://www.apollographql.com/docs/react/features/optimistic-ui.html)
- `update`:详见 [变更后更新缓存](https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-mutation-options-update)
- `refetchQueries`:详见 [变更后重新获取查询](https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-mutation-options-refetchQueries)
- `clientId`:用于解析使用的 Apollo 客户端(在 ApolloProvider 中定义)
- `tag`:字符串,HTML 标签名(默认值:`div`);如果是 `undefined`,该组件将成为无渲染组件(内容不会被包装在标签中)
## 作用域插槽 props
- `mutate(options = undefined)`:调用变更的函数。你可以重载变更的选项(例如:`mutate({ variables: { foo: 'bar } })`
- `loading`:布尔值,表明请求正在进行中
- `error`:最后一次变更调用的最终错误
- `gqlError`:第一个 GraphQL 错误(如果有)
## 事件
- `done(resultObject)`
- `error(errorObject)`
+47
View File
@@ -0,0 +1,47 @@
# ApolloProvider
## 构造函数
```js
const apolloProvider = new VueApollo({
// 支持多客户端
// 在查询中使用 'client' 选项
// 或在 apollo 定义中使用 '$client'
clients: {
a: apolloClientA,
b: apolloClientB,
},
// 默认客户端
defaultClient: apolloClient,
// 'apollo' 对象的默认定义
defaultOptions: {
// 详见 'apollo' 的定义
// 例如:默认查询选项
$query: {
loadingKey: 'loading',
fetchPolicy: 'cache-and-network',
},
},
// 查看所有查询的加载状态
// 详见 '智能查询 > 选项 > watchLoading'
watchLoading (isLoading, countModifier) {
loading += countModifier
console.log('Global loading', loading, countModifier)
},
// 所有智能查询和订阅的全局错误处理函数
errorHandler (error) {
console.log('Global error handler')
console.error(error)
},
})
```
在你的 Vue 应用程序中使用 apollo provider
```js
new Vue({
el: '#app',
apolloProvider,
render: h => h(App),
})
```
+33
View File
@@ -0,0 +1,33 @@
# ApolloQuery 组件
## Props
- `query`GraphQL 查询(由 `graphql-tag` 转换)
- `variables`GraphQL 变量对象
- `fetchPolicy`:详见 [apollo fetchPolicy](https://www.apollographql.com/docs/react/basics/queries.html#graphql-config-options-fetchPolicy)
- `pollInterval`:详见 [apollo pollInterval](https://www.apollographql.com/docs/react/basics/queries.html#graphql-config-options-pollInterval)
- `notifyOnNetworkStatusChange`:详见 [apollo notifyOnNetworkStatusChange](https://www.apollographql.com/docs/react/basics/queries.html#graphql-config-options-notifyOnNetworkStatusChange)
- `context`:详见 [apollo context](https://www.apollographql.com/docs/react/basics/queries.html#graphql-config-options-context)
- `skip`:布尔值,禁用查询获取
- `clientId`:用于解析使用的 Apollo 客户端(在 ApolloProvider 中定义)
- `deep`:布尔值,使用深度 Vue 侦听器
- `tag`:字符串,HTML 标签名(默认值:`div`);如果是 `undefined`,该组件将成为无渲染组件(内容不会被包装在标签中)
- `debounce`:对重新获取查询结果的防抖毫秒数(例如当变量更改时)
- `throttle`:对重新获取查询结果的节流毫秒数(例如当变量更改时)
## 作用域插槽
- `result`Apollo 查询结果
- `result.data`:查询返回的数据
- `result.loading`:布尔值,表明请求正在进行中
- `result.error`:当前结果的最终错误
- `result.networkStatus`:详见 [apollo networkStatus](https://www.apollographql.com/docs/react/basics/queries.html#graphql-query-data-networkStatus)
- `query`:与组件关联的智能查询
- `isLoading`:智能查询加载状态
- `gqlError`:第一个 GraphQL 错误(如果有)
- `times`:结果被更新的次数
## 事件
- `result(resultObject)`
- `error(errorObject)`
@@ -0,0 +1,7 @@
# ApolloSubscribeToMore 组件
## Props
- `document`:包含订阅的 GraphQL 文档。
- `variables`:将自动更新订阅变量的对象。
- `updateQuery`:可以根据需要更新查询结果的函数。
+23
View File
@@ -0,0 +1,23 @@
# Dollar Apollo
这是添加到任何使用 Apollo 的组件中的 Apollo 管理器。它可以在一个组件内通过 `this.$apollo` 访问到。
## 属性
- `vm`:关联的组件。
- `queries`:组件的智能查询的数组。
- `subscriptions`:组件的智能订阅的数组。
- `client`:组件当前使用的 Apollo 客户端。
- `provider`:注入的 [Apollo Provider](./apollo-provider.md)。
- `loading`:是否至少有一个查询正在加载。
- `skipAllQueries`:(setter) 布尔值,用于暂停或取消暂停所有智能查询。
- `skipAllSubscriptions`:(setter) 布尔值,用于暂停或取消暂停所有智能订阅。
- `skipAll`:(setter) 布尔值,用于暂停或取消暂停所有智能查询和智能订阅。
## 方法
- `query`:执行一个查询(详见 [查询](../guide/apollo/queries.md))。
- `mutate`:执行一个变更(详见 [变更](../guide/apollo/mutations.md))。
- `subscribe`:标准的 Apollo 订阅方法(详见 [订阅](../guide/apollo/subscriptions.md))。
- `addSmartQuery`:手动添加一个智能查询(不推荐使用)。
- `addSmartSubscription`:添加一个智能订阅(详见 [订阅](../guide/apollo/subscriptions.md))。
+246
View File
@@ -0,0 +1,246 @@
# 智能查询
在组件的 `apollo` 定义中声明的每个查询(不以 `$` 字符开头)都会创建一个智能查询对象。
## 选项
- `query`:GraphQL 文档(可以是一个文件或一个 `gql` 字符串)。
- `variables`:对象或返回对象的响应式函数。每个键将用 `'$'` 映射到 GraphQL 文档中,例如 `foo` 将变为 `$foo`
- `throttle`:变量更新节流时间(毫秒)。
- `debounce`:变量更新防抖时间(毫秒)。
- `update(data) {return ...}` 用来自定义设置到 vue 属性中的值,例如当字段名称不匹配时。
- `result(ApolloQueryResult)` 是收到结果时调用的钩子(更多参见 [ApolloQueryResult](https://github.com/apollographql/apollo-client/blob/master/packages/apollo-client/src/core/types.ts) 的文档)。
- `error(error)` 是有错误时调用的钩子。`error` 是一个具有 `graphQLErrors` 属性或 `networkError` 属性的 Apollo 错误对象。
- `loadingKey` 将更新你传递的值所对应的组件数据属性。你应该在组件的 `data()` 钩子中将此属性初始化为 `0` 。当查询正在加载时,此属性将增加 1;当不再加载时,它将减去 1。这样,该属性可以表示当前正在加载中的查询的计数器。
- `watchLoading(isLoading, countModifier)` 是一个在查询的加载状态发生变化时调用的钩子。`countModifier` 参数当查询正在加载时等于 `1`,不再加载时为 `-1`
- `manual` 是一个禁用自动属性更新的布尔值。如果使用它,你需要指定一个 `result` 回调函数(参见下面的示例)。
- `deep` 是一个在 Vue 侦听器上使用 `deep: true` 的布尔值。
- `subscribeToMore`:一个或一组 [subscribeToMore 选项](../guide/apollo/subscriptions.md#subscribetomore) 对象。
- `prefetch` 是一个布尔值或函数来确定是否应该预取查询。详见 [服务端渲染](../guide/ssr.md)。
示例:
```js
// Apollo 具体选项
apollo: {
// 带参数的高级查询
// vue 会侦听 'variables' 方法
pingMessage: {
query: gql`query PingMessage($message: String!) {
ping(message: $message)
}`,
// 响应式参数
variables() {
// 在这里使用 vue 的响应式属性
return {
message: this.pingInput,
}
},
// 变量:深度对象侦听
deep: false,
// 我们使用自定义更新回调,因为字段名称不匹配
// 默认情况下,将使用 'data' 结果对象上的 'pingMessage' 属性
// 考虑到 apollo 服务端的工作方式,我们知道结果是在 'ping' 属性中
update(data) {
console.log(data)
// 返回的值将更新 vue 属性 'pingMessage'
return data.ping
},
// 可选结果钩子
result({ data, loading, networkStatus }) {
console.log("We got some result!")
},
// 错误处理
error(error) {
console.error('We\'ve got an error!', error)
},
// 加载状态
// loadingKey 是数据属性的名称
// 在查询正在加载时将递增,不再加载时递减
loadingKey: 'loadingQueriesCount',
// 当加载状态发生变化时会调用 watchLoading
watchLoading(isLoading, countModifier) {
// isLoading 是一个布尔值
// countModifier 为 1 或 -1
},
},
},
```
如果你使用 `ES2015``update` 也可以这样写:
```js
update: data => data.ping
```
手动模式示例:
```js
{
query: gql`...`,
manual: true,
result ({ data, loading }) {
if (!loading) {
this.items = data.items
}
},
}
```
## 属性
### Skip
你可以使用 `skip` 来暂停或停止暂停:
```js
this.$apollo.queries.users.skip = true
```
### loading
查询是否正在加载中:
```js
this.$apollo.queries.users.loading
```
## 方法
### refresh
停止并重新启动查询:
```js
this.$apollo.queries.users.refresh()
```
### start
开始查询:
```js
this.$apollo.queries.users.start()
```
### stop
停止查询:
```js
this.$apollo.queries.users.stop()
```
### fetchMore
为分页加载更多数据:
```js
this.page++
this.$apollo.queries.tagsPage.fetchMore({
// 新的变量
variables: {
page: this.page,
pageSize,
},
// 用新数据转换之前的结果
updateQuery: (previousResult, { fetchMoreResult }) => {
const newTags = fetchMoreResult.tagsPage.tags
const hasMore = fetchMoreResult.tagsPage.hasMore
this.showMoreEnabled = hasMore
return {
tagsPage: {
__typename: previousResult.tagsPage.__typename,
// 合并标签列表
tags: [...previousResult.tagsPage.tags, ...newTags],
hasMore,
},
}
},
})
```
### subscribeToMore
使用 GraphQL 订阅来订阅更多数据:
```js
// 我们需要在重新订阅之前取消订阅
if (this.tagsSub) {
this.tagsSub.unsubscribe()
}
// 在查询上订阅
this.tagsSub = this.$apollo.queries.tags.subscribeToMore({
document: TAG_ADDED,
variables: {
type,
},
// 变更之前的结果
updateQuery: (previousResult, { subscriptionData }) => {
// 如果我们在没有做操作的情况下已经添加了标签
// 这可能是由 addTag 变更上的 `updateQuery` 导致
if (previousResult.tags.find(tag => tag.id === subscriptionData.data.tagAdded.id)) {
return previousResult
}
return {
tags: [
...previousResult.tags,
// 添加新的标签
subscriptionData.data.tagAdded,
],
}
},
})
```
### refetch
重新获取查询,可选择使用新变量:
```js
this.$apollo.queries.users.refetch()
// 使用新变量
this.$apollo.queries.users.refetch({
friendsOf: 'id-user'
})
```
### setVariables
更新查询中的变量,如果发生了改变则重新获取查询。要强制重新获取,请使用 `refetch`
```js
this.$apollo.queries.users.setVariables({
friendsOf: 'id-user'
})
```
### setOptions
更新 Apollo [watchQuery](https://www.apollographql.com/docs/react/api/apollo-client.html#ApolloClient.watchQuery) 选项并重新获取:
```js
this.$apollo.queries.users.setOptions({
fetchPolicy: 'cache-and-network'
})
```
### startPolling
使用轮询启动自动更新(这意味着每隔 `x` ms 进行重新获取):
```js
this.$apollo.queries.users.startPolling(2000) // ms
```
### stopPolling
停止轮询:
```js
this.$apollo.queries.users.stopPolling()
```
+47
View File
@@ -0,0 +1,47 @@
# 智能订阅
每个在组件中的 `apollo.$subscribe` 选项中声明的订阅都会创建一个智能订阅对象。
## 选项
- `query`:GraphQL 文档(可以是一个文件或一个 `gql` 字符串)。
- `variables`:对象或返回对象的响应式函数。每个键将用 `'$'` 映射到 GraphQL 文档中,例如 `foo` 将变为 `$foo`
- `throttle`:变量更新节流时间(毫秒)。
- `debounce`:变量更新防抖时间(毫秒)。
- `result(data)` 是收到结果时调用的钩子。
## 属性
### Skip
你可以使用 `skip` 来暂停或停止暂停:
```js
this.$apollo.subscriptions.users.skip = true
```
## 方法
### refresh
停止并重新启动查询:
```js
this.$apollo.subscriptions.users.restart()
```
### start
开始查询:
```js
this.$apollo.subscriptions.users.start()
```
### stop
停止查询:
```js
this.$apollo.subscriptions.users.stop()
```
+55
View File
@@ -0,0 +1,55 @@
# ApolloSSR
## 用法
详见 [SSR 指南](../guide/ssr.md).
## 方法
### prefetchAll
预取所有队列中的组件定义,并在所有对应的 apollo 数据准备就绪时返回已解决的(resolved) promise。
```js
await ApolloSSR.prefetchAll (apolloProvider, componentDefs, context)
```
`context` 作为参数传递给智能查询中的 `prefetch` 选项。它可能包含路由和 store。
### getStates
将 apollo store 状态作为 JavaScript 对象返回。
```js
const states = ApolloSSR.getStates(apolloProvider, options)
```
`options` 的默认值是:
```js
{
// 每个 apollo 客户端状态的 key 的前缀
exportNamespace: '',
}
```
### exportStates
将 apollo store 状态作为字符串内的 JavaScript 代码返回。该代码可以直接注入到页面 HTML 的 `<script>` 标签中。
```js
const js = ApolloSSR.exportStates(apolloProvider, options)
```
`options` 的默认值是:
```js
{
// 全局变量名
globalName: '__APOLLO_STATE__',
// 变量设置到的全局对象
attachTo: 'window',
// 每个 apollo 客户端状态的 key 的前缀
exportNamespace: '',
}
```
+47
View File
@@ -0,0 +1,47 @@
# 简介
::: danger
本文档关联的版本仅支持 Apollo 2.x。查看支持 Apollo 1.x 的旧版本,请点击 [这里](https://github.com/Akryum/vue-apollo/tree/apollo-1).
:::
这个库通过声明式查询将 [apollo](https://www.apollographql.com/) 集成到你的 [Vue](http://vuejs.org) 组件中。兼容 Vue 1.0+ 和 2.0+。[在线演示](https://jsfiddle.net/Akryum/oyejk2qL/)
## 赞助商
<p style="text-align: center; font-size: 24px; color: #9999A5;">
&lt;在这里加入你的 logo&gt;
</p>
## Become a sponsor
你的公司是否使用了 vue-apollo 或 vue-cli-plugin-apollo 来构建出色的应用程序?加入资助者并成为赞助商,在此文档中添加你的 logo!在 Patreon 上支持我,将节省我用于谋生的工作时间,从而能够在如 vue-apollo 一样的免费开源软件上工作更多!谢谢!
<p style="text-align: center;">
<a href="https://www.patreon.com/akryum" target="_blank">
<img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Become a Patreon">
</a>
</p>
## 什么是 GraphQL
[GraphQL](https://graphql.org/) 是一个旨在简化前端和后端之间通信的规范。它主要由服务端的 schema 语言和客户端的查询语言组成。
## 什么是 Apollo?
[Apollo](https://www.apollographql.com/) 是通过社区力量帮助你在应用中使用 GraphQL 的一套工具。它的 [客户端](https://www.apollographql.com/client) 和 [服务端](https://www.apollographql.com/server) 都非常有名。Apollo 由 [Meteor 开发团队](https://www.meteor.io/) 开发和支持。
## 链接
[<img src="https://assets-cdn.github.com/favicon.ico" alt="icon" width="16" height="16"/> Vue-cli 插件](https://github.com/Akryum/vue-cli-plugin-apollo)
[<img src="https://assets-cdn.github.com/favicon.ico" alt="icon" width="16" height="16"/> 更多 vue-apollo 示例](https://github.com/Akryum/vue-apollo-example)
[<img src="https://assets-cdn.github.com/favicon.ico" alt="icon" width="16" height="16"/> Apollo graphql server 示例](https://github.com/Akryum/apollo-server-example)
[<img src="http://graphql.cn/favicon.ico" alt="icon" width="16" height="16"/> GraphQL 中文文档](http://graphql.cn/)
[<img src="https://www.howtographql.com/static/howtographql.d1a2e5b4.svg" alt="icon" width="16" height="16"/> How to GraphQL](https://www.howtographql.com/vue-apollo/0-introduction/)
[<img src="https://conf.vuejs.org/img/logo-48.png" alt="icon" width="16" height="16"/> VueConf 2017 演示](https://github.com/Akryum/vueconf-2017-demo) &amp; [讲义](http://slides.com/akryum/graphql#/)
[<img src="https://assets-cdn.github.com/favicon.ico" alt="icon" width="16" height="16"/> Devfest 峰会示例](https://github.com/Akryum/devfest-nantes-2017)(包括许多特性,如 SSR、OAuth、实时更新、Apollo Engine 等)
+132
View File
@@ -0,0 +1,132 @@
# 在 Vue 组件中使用 Apollo
要在你的 Vue 组件中声明 apollo 查询,只需添加一个 `apollo` 对象:
```js
new Vue({
apollo: {
// Apollo 的具体选项
},
})
```
在你的每个 vue 组件中,你都可以通过 `this.$apollo.provider.defaultClient``this.$apollo.provider.clients.<key>`(用于 [多客户端](../multiple-clients.md))来访问 [apollo-client](https://www.apollographql.com/docs/react/) 实例。
## 查询(Queries
为每个你需要通过 Apollo 的查询结果提供数据的 Vue 属性,在 `apollo` 对象中添加一个对应属性。
```js
import gql from 'graphql-tag'
export default {
apollo: {
// 简单的查询,将更新 'hello' 这个 vue 属性
hello: gql`query { hello }`,
},
}
```
更多细节请查看 [查询](./queries.md) 一章。
## 变更(Mutations
使用 `this.$apollo.mutate` 发送变更语句:
```js
methods: {
async addTag() {
// 调用 graphql 变更
const result = await this.$apollo.mutate({
// 查询语句
mutation: gql`mutation ($label: String!) {
addTag(label: $label) {
id
label
}
}`,
// 参数
variables: {
label: this.newTag,
},
})
}
}
```
更多细节请查看 [变更](./mutations.md) 一章。
## 特殊选项
`apollo` 对象中的特殊选项以 `$` 开头表示。
- `$skip` 用于禁用所有查询和订阅(后文详述)
- `$skipAllQueries` 用于禁用所有查询(后文详述)
- `$skipAllSubscriptions` 用于禁用所有订阅(后文详述)
- `$deep` 用于当为以上的属性提供函数时,通过 `deep: true` 进行监听
- `$error` 用于捕获默认处理函数中的错误(详见智能查询的 `error` 高级选项)
- `$query` 用于将默认选项应用于组件中的所有查询
示例:
```vue
<script>
export default {
data () {
return {
loading: 0,
}
},
apollo: {
$query: {
loadingKey: 'loading',
},
query1: { ... },
query2: { ... },
},
}
</script>
```
你可以在 apollo provider 中为 `apollo` 定义一套默认选项。例如:
```js
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
defaultOptions: {
// 将应用于组件中的所有查询的 apollo 选项
$query: {
loadingKey: 'loading',
fetchPolicy: 'cache-and-network',
},
},
})
```
## 全部跳过
你可以使用 `skipAllQueries` 禁用组件的所有查询,使用 `skipAllSubscriptions` 禁用所有订阅,或是使用 `skipAll` 将两者全部禁用:
```js
this.$apollo.skipAllQueries = true
this.$apollo.skipAllSubscriptions = true
this.$apollo.skipAll = true
```
你也可以在组件的 `apollo` 选项中声明这些属性。它们可以是布尔值:
```js
apollo: {
$skipAll: true
}
```
或是响应式函数:
```js
apollo: {
$skipAll () {
return this.foo === 42
}
}
```
+121
View File
@@ -0,0 +1,121 @@
# 变更
变更是在你的 apollo 服务端更改你的数据状态的查询。
使用 `this.$apollo.mutate()` 来发送一个 GraphQL 变更。
想要了解更多信息,请访问 [apollo 文档](https://www.apollographql.com/docs/react/api/apollo-client.html#ApolloClient.mutate)。有一个以变更为重点的 [示例应用](https://github.com/Akryum/vue-apollo-todos),你可以看看。
::: warning
你不应当在 variables 中发送 `__typename` 字段,因此不建议直接发送 Apollo 结果对象。
:::
```js
methods: {
addTag() {
// 保存用户输入以防止错误
const newTag = this.newTag
// 将其清除以尽早更新用户页面
this.newTag = ''
// 调用 graphql 变更
this.$apollo.mutate({
// 查询语句
mutation: gql`mutation ($label: String!) {
addTag(label: $label) {
id
label
}
}`,
// 参数
variables: {
label: newTag,
},
// 用结果更新缓存
// 查询将先通过乐观响应、然后再通过真正的变更结果更新
update: (store, { data: { newTag } }) => {
// 从缓存中读取这个查询的数据
const data = store.readQuery({ query: TAGS_QUERY })
// 将变更中的标签添加到最后
data.tags.push(newTag)
// 将数据写回缓存
store.writeQuery({ query: TAGS_QUERY, data })
},
// 乐观 UI
// 将在请求产生时作为“假”结果,使用户界面能够快速更新
optimisticResponse: {
__typename: 'Mutation',
addTag: {
__typename: 'Tag',
id: -1,
label: newTag,
},
},
}).then((data) => {
// 结果
console.log(data)
}).catch((error) => {
// 错误
console.error(error)
// 恢复初始用户输入
this.newTag = newTag
})
},
},
```
## 服务端示例
```js
export const schema = `
type Tag {
id: Int
label: String
}
type Query {
tags: [Tag]
}
type Mutation {
addTag(label: String!): Tag
}
schema {
query: Query
mutation: Mutation
}
`
// 假数据生成器
import faker from 'faker'
// 生成一些标签
var id = 0
var tags = []
for (let i = 0; i < 42; i++) {
addTag(faker.random.word())
}
function addTag(label) {
let t = {
id: id++,
label,
}
tags.push(t)
return t
}
export const resolvers = {
Query: {
tags(root, args, context) {
return tags
},
},
Mutation: {
addTag(root, { label }, context) {
console.log(`adding tag '${label}'`)
return addTag(label)
},
},
}
```
+95
View File
@@ -0,0 +1,95 @@
# 使用 `fetchMore` 实现分页
*[这里](https://github.com/Akryum/apollo-server-example/blob/master/schema.js#L21) 是服务端的一个简单示例。*
有时候你的数据集非常大,你想分块加载它。
使用智能查询上的 `fetchMore()` 方法来加载更多数据。
::: warning
不要忘记将 `__typename` 包含到新结果中。
使用 `variables()` 时不要更改返回的初始变量,否则列表数据将丢失。
:::
示例:
```vue
<template>
<div id="app">
<h2>Pagination</h2>
<div class="tag-list" v-if="tagsPage">
<div class="tag-list-item" v-for="tag in tagsPage.tags">
{{ tag.id }} - {{ tag.label }} - {{ tag.type }}
</div>
<div class="actions">
<button v-if="showMoreEnabled" @click="showMore">Show more</button>
</div>
</div>
</div>
</template>
<script>
import gql from 'graphql-tag'
const pageSize = 10
export default {
name: 'app',
data: () => ({
page: 0,
showMoreEnabled: true,
}),
apollo: {
// Pages
tagsPage: {
// GraphQL 查询
query: gql`query tagsPage ($page: Int!, $pageSize: Int!) {
tagsPage(page: $page, size: $pageSize) {
tags {
id
label
type
}
hasMore
}
}`,
// 初始变量
variables: {
page: 0,
pageSize,
},
},
},
methods: {
showMore() {
this.page ++
// 获取更多数据并转换原始结果
this.$apollo.queries.tagsPage.fetchMore({
// 新的变量
variables: {
page: this.page,
pageSize,
},
// 用新数据转换之前的结果
updateQuery: (previousResult, { fetchMoreResult }) => {
const newTags = fetchMoreResult.tagsPage.tags
const hasMore = fetchMoreResult.tagsPage.hasMore
this.showMoreEnabled = hasMore
return {
tagsPage: {
__typename: previousResult.tagsPage.__typename,
// 合并标签列表
tags: [...previousResult.tagsPage.tags, ...newTags],
hasMore,
},
}
},
})
},
},
}
</script>
```
+401
View File
@@ -0,0 +1,401 @@
# 查询
为每个你需要通过 Apollo 的查询结果提供数据的 Vue 属性,在 `apollo` 对象中添加一个对应属性。每一个属性都将创建一个智能查询。
## 简单查询
使用 `gql` 编写你的 GraphQL 查询:
```js
import gql from 'graphql-tag'
```
直接将 [gql](https://github.com/apollographql/graphql-tag) 查询作为值:
```js
apollo: {
// 简单的查询,将更新 'hello' 这个 vue 属性
hello: gql`{hello}`,
},
```
接下来你可以通过 `this.$apollo.queries.<name>` 访问这个查询。
你可以在 vue 组件的 `data` 钩子中初始化属性:
```js
data () {
return {
// 初始化你的 apollo 数据
hello: '',
},
},
```
在服务端添加相应的 schema 和解析器:
```js
export const schema = `
type Query {
hello: String
}
schema {
query: Query
}
`
export const resolvers = {
Query: {
hello(root, args, context) {
return "Hello world!"
},
},
}
```
更多信息请访问 [apollo 文档](https://www.apollographql.com/docs/apollo-server/)。
接下来你可以在 vue 组件中正常使用属性:
```vue
<template>
<div class="apollo">
<h3>Hello</h3>
<p>
{{hello}}
</p>
</div>
</template>
```
## 带参数的查询
你可以通过在对象中声明 `query``variables` 将变量(读取参数)添加到 `gql` 查询中:
```js
// Apollo 具体选项
apollo: {
// 带参数的查询
ping: {
// gql 查询
query: gql`query PingMessage($message: String!) {
ping(message: $message)
}`,
// 静态参数
variables: {
message: 'Meow',
},
},
},
```
你可以在这个对象中使用 apollo 的 `watchQuery` 中的选项,比如:
- `fetchPolicy`
- `pollInterval`
- ...
更多细节请查看 [apollo 文档](https://www.apollographql.com/docs/react/api/apollo-client.html#ApolloClient.watchQuery)。
例如,你可以像这样添加 `fetchPolicy` apollo 选项:
```js
apollo: {
// 带参数的查询
ping: {
query: gql`query PingMessage($message: String!) {
ping(message: $message)
}`,
variables: {
message: 'Meow'
},
// 在这里加入其他选项
fetchPolicy: 'cache-and-network',
},
},
```
同样的,你可以在 vue 组件中初始化属性:
```js
data () {
return {
// 初始化你的 apollo 数据
ping: '',
}
},
```
在服务端添加相应的 schema 和解析器:
```js
export const schema = `
type Query {
ping(message: String!): String
}
schema {
query: Query
}
`
export const resolvers = {
Query: {
ping(root, { message }, context) {
return `Answering ${message}`
},
},
}
```
然后在你的 vue 组件中使用它:
```vue
<template>
<div class="apollo">
<h3>Ping</h3>
<p>
{{ ping }}
</p>
</div>
</template>
```
## 加载状态
你可以通过 `$apollo.loading` 属性显示加载状态:
```vue
<div v-if="$apollo.loading">Loading...</div>
```
或者针对这个特定的 `ping` 查询:
```vue
<div v-if="$apollo.queries.ping.loading">Loading...</div>
```
## 用函数作为选项
你可以使用将在创建组件时被调用一次的函数,并且它必须返回选项对象:
```js
// Apollo 具体选项
apollo: {
// 带参数的查询
ping () {
// 它将在创建组件时被调用一次
// 必须返回选项对象
return {
// gql 查询
query: gql`query PingMessage($message: String!) {
ping(message: $message)
}`,
// 静态参数
variables: {
message: 'Meow',
},
}
},
},
```
::: tip
同样适用于 [订阅](./subscriptions.md)。
:::
## 响应式查询定义
你可以使用函数定义 `query` 选项。这将自动更新 graphql 查询的定义:
```js
// 特定标签可以是随机标签或最后添加的标签
featuredTag: {
query () {
// 这里你可以用'this' 访问组件实例
if (this.showTag === 'random') {
return gql`{
randomTag {
id
label
type
}
}`
} else if (this.showTag === 'last') {
return gql`{
lastTag {
id
label
type
}
}`
}
},
// 为 'featuredTag' 这个组件属性赋值
update: data => data.randomTag || data.lastTag,
},
```
::: tip
同样适用于 [订阅](./subscriptions.md)。
:::
## 响应式参数
使用函数使 vue 属性能够响应式的提供给参数:
```js
// Apollo 具体选项
apollo: {
// 带参数的查询
ping: {
query: gql`query PingMessage($message: String!) {
ping(message: $message)
}`,
// 响应式参数
variables() {
// 在这里使用 vue 响应式属性
return {
message: this.pingInput,
}
},
},
},
```
在每次参数更改时,将重新获取查询,例如:
```vue
<template>
<div class="apollo">
<h3>Ping</h3>
<input v-model="pingInput" placeholder="Enter a message" />
<p>
{{ping}}
</p>
</div>
</template>
```
## 跳过查询
如果查询被跳过,它将被禁用且结果将不再被更新。你可以使用 `skip` 选项:
```js
// Apollo 具体选项
apollo: {
tags: {
// GraphQL 查询
query: gql`query tagList ($type: String!) {
tags(type: $type) {
id
label
}
}`,
// 响应式变量
variables() {
return {
type: this.type,
}
},
// 禁用这个查询
skip() {
return this.skipQuery
},
},
},
```
在这里,当 `skipQuery` 组件属性改变时,`skip` 将被自动调用。
你也可以直接访问查询并设置 `skip` 属性:
```js
this.$apollo.queries.tags.skip = true
```
## 响应式查询示例
这里是一个使用轮询的响应式查询示例:
```js
// Apollo 具体选项
apollo: {
// vue 实例上的 'tags' 数据属性
tags: {
query: gql`query tagList {
tags {
id,
label
}
}`,
pollInterval: 300, // 毫秒
},
},
```
这里是服务端的定义:
```js
export const schema = `
type Tag {
id: Int
label: String
}
type Query {
tags: [Tag]
}
schema {
query: Query
}
`
// 假数据生成器
import casual from 'casual'
// 生成一些标签
var id = 0
var tags = []
for (let i = 0; i < 42; i++) {
addTag(casual.word)
}
function addTag(label) {
let t = {
id: id++,
label,
}
tags.push(t)
return t
}
export const resolvers = {
Query: {
tags(root, args, context) {
return tags
},
},
}
```
## 手动添加智能查询
你可以使用 `$apollo.addSmartQuery(key, options)` 方法手动添加智能查询:
```js
created () {
this.$apollo.addSmartQuery('comments', {
// 选项同上文
})
}
```
::: tip
组件 `apollo` 选项中的每个查询入口都在内部调用此方法。
:::
## 高级选项
还有更多专用于 vue-apollo 的选项,请查看 [API 参考](../../api/smart-query.md)。
+310
View File
@@ -0,0 +1,310 @@
# 订阅
## 设置
*关于服务端实现,你可以看看 [这个简单的示例](https://github.com/Akryum/apollo-server-example)。*
要启用基于 websocket 的订阅,需要做一些额外的设置:
```
npm install --save apollo-link-ws apollo-utilities
```
```js
import Vue from 'vue'
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
// 新的引入文件
import { split } from 'apollo-link'
import { WebSocketLink } from 'apollo-link-ws'
import { getMainDefinition } from 'apollo-utilities'
import VueApollo from 'vue-apollo'
const httpLink = new HttpLink({
// 你需要在这里使用绝对路径
uri: 'http://localhost:3020/graphql',
})
// 创建订阅的 websocket 连接
const wsLink = new WebSocketLink({
uri: 'ws://localhost:3000/subscriptions',
options: {
reconnect: true,
},
})
// 使用分割连接的功能
// 你可以根据发送的操作类型将数据发送到不同的连接
const link = split(
// 根据操作类型分割
({ query }) => {
const { kind, operation } = getMainDefinition(query)
return kind === 'OperationDefinition' &&
operation === 'subscription'
},
wsLink,
httpLink
)
// 创建 apollo 客户端
const apolloClient = new ApolloClient({
link,
cache: new InMemoryCache(),
connectToDevTools: true,
})
// 像之前一样安装 vue 插件
Vue.use(VueApollo)
```
## 订阅更多
如果你需要更新一个来自订阅的查询结果,最好的方式是使用 `subscribeToMore` 查询方法。它将创建链接到查询的 [智能订阅](../../api/smart-subscription.md)。你只需要将 `subscribeToMore` 添加到查询中:
```js
apollo: {
tags: {
query: TAGS_QUERY,
subscribeToMore: {
document: gql`subscription name($param: String!) {
itemAdded(param: $param) {
id
label
}
}`,
// 传递给订阅的变量
// 由于我们使用了函数,因此它们是响应式的
variables () {
return {
param: this.param,
}
},
// 变更之前的结果
updateQuery: (previousResult, { subscriptionData }) => {
// 在这里用之前的结果和新数据组合成新的结果
},
}
}
}
```
::: tip
注意,你可以将一组订阅传递给 `subscribeToMore` 以将此查询关联到多个订阅。
:::
### Alternate usage
你可以使用 `this.$apollo.queries.<name>` 访问你在 `apollo` 选项中定义的查询,所以它看起来像这样:
```js
this.$apollo.queries.tags.subscribeToMore({
// GraphQL 文档
document: gql`subscription name($param: String!) {
itemAdded(param: $param) {
id
label
}
}`,
// 传递给订阅的变量
variables: {
param: '42',
},
// 变更之前的结果
updateQuery: (previousResult, { subscriptionData }) => {
// 在这里用之前的结果和新数据组合成新的结果
},
})
```
如果相关查询停止,订阅将自动销毁。
这里是一个示例:
```js
// 订阅的 GraphQL 文档
const TAG_ADDED = gql`subscription tags($type: String!) {
tagAdded(type: $type) {
id
label
type
}
}`
// SubscribeToMore 标签
// 我们有不同类型的标签
// 每种类型都有一个订阅 '频道'
this.$watch(() => this.type, (type, oldType) => {
if (type !== oldType || !this.tagsSub) {
// 我们需要在重新订阅之前取消订阅
if (this.tagsSub) {
this.tagsSub.unsubscribe()
}
// 在查询上订阅
this.tagsSub = this.$apollo.queries.tags.subscribeToMore({
document: TAG_ADDED,
variables: {
type,
},
// 变更之前的结果
updateQuery: (previousResult, { subscriptionData }) => {
// 如果我们在没有做操作的情况下已经添加了标签
// 这可能是由 addTag 变更上的 `updateQuery` 导致
if (previousResult.tags.find(tag => tag.id === subscriptionData.data.tagAdded.id)) {
return previousResult
}
return {
tags: [
...previousResult.tags,
// 添加新的标签
subscriptionData.data.tagAdded,
],
}
},
})
}
}, {
immediate: true,
})
```
## 简单订阅
::: danger
如果要使用订阅的结果更新查询,请使用 `subscribeToMore`
以下的方法适用于 'notify' 用例
:::
你可以在 `apollo` 选项中使用 `$subscribe` 关键字来声明 [智能订阅](../../api/smart-subscription.md)
```js
apollo: {
// 订阅
$subscribe: {
// 当添加一个标签时
tagAdded: {
query: gql`subscription tags($type: String!) {
tagAdded(type: $type) {
id
label
type
}
}`,
// 响应式变量
variables() {
// 像常规查询一样运作
// 在每次改变值时都会使用正确的变量重新订阅
return {
type: this.type,
}
},
// 结果钩子
result(data) {
console.log(data)
},
},
},
},
```
你可以使用 `this.$apollo.subscriptions.<name>` 访问这个订阅。
:::tip
和查询一样,你可以 [使用函数](./queries.md#option-function) 声明订阅,并且可以 [使用响应式函数](./queries.md#reactive-query-definition) 声明 `query` 选项。
:::
## 跳过订阅
如果订阅被跳过,它将被禁用且不再被更新。你可以使用 `skip` 选项:
```js
// Apollo 具体选项
apollo: {
// 订阅
$subscribe: {
// 当添加一个标签时
tags: {
query: gql`subscription tags($type: String!) {
tagAdded(type: $type) {
id
label
type
}
}`,
// 响应式变量
variables() {
return {
type: this.type,
}
},
// 结果钩子
result(data) {
// 更新本地数据
this.tags.push(data.tagAdded)
},
// 跳过这个订阅
skip() {
return this.skipSubscription
}
},
},
},
```
在这里,当 `skipSubscription` 组件属性改变时,`skip` 将被自动调用。
你也可以直接访问订阅并设置 `skip` 属性:
```js
this.$apollo.subscriptions.tags.skip = true
```
## 手动添加智能订阅
你可以使用 `$apollo.addSmartSubscription(key, options)` 方法手动添加智能订阅:
```js
created () {
this.$apollo.addSmartSubscription('tagAdded', {
// 选项同 '$subscribe'
})
}
```
:::tip
组件 `apollo` 选项中的每个 `$subscribe` 对象入口都在内部调用此方法。
:::
## 标准 Apollo 订阅
使用 `$apollo.subscribe()` 方法来创建一个 GraphQL 订阅,当组件被销毁时将自动终止。它**不会**创建智能订阅。
```js
mounted() {
const subQuery = gql`subscription tags($type: String!) {
tagAdded(type: $type) {
id
label
type
}
}`
const observer = this.$apollo.subscribe({
query: subQuery,
variables: {
type: 'City',
},
})
observer.subscribe({
next(data) {
console.log(data)
},
error(error) {
console.error(error)
},
})
},
```
+37
View File
@@ -0,0 +1,37 @@
# 什么是 Apollo 组件?
这些组件就像其他组件一样。它们在 prop 中使用 GraphQL 文档,并使用 [作用域插槽功能](https://vuejs.org/v2/guide/components-slots.html#Scoped-Slots) 来传递结果。
这样做的好处是你可以直接在模板中使用这些组件,而不是使用组件的 `apollo` 选项。在某些情况下,你甚至不需要在 `.vue` 中添加脚本部分!这种代码会更加声明式。
这是一个简单的例子:
```vue
<template>
<div class="users-list">
<!-- Apollo 查询 -->
<ApolloQuery :query="require('@/graphql/users.gql')">
<!-- 结果将自动更新 -->
<template slot-scope="{ result: { data, loading } }">
<!-- 一些内容 -->
<div v-if="loading">Loading...</div>
<ul v-else>
<li v-for="user of data.users" class="user">
{{ user.name }}
</li>
</ul>
</template>
</ApolloQuery>
</div>
</template>
<!-- 不需要脚本 -->
<style scoped>
.user {
list-style: none;
padding: 12px;
color: blue;
}
</style>
```
+23
View File
@@ -0,0 +1,23 @@
# ApolloMutation
你可以使用 `ApolloMutation`(或 `apollo-mutation`)组件直接在模板中调用 Apollo 变更。
这是一个简单的例子:
```vue
<ApolloMutation
:mutation="require('@/graphql/userLogin.gql')"
:variables="{
email,
password,
}"
@done="onDone"
>
<template slot-scope="{ mutate, loading, error }">
<button :disabled="loading" @click="mutate()">Click me</button>
<p v-if="error">An error occured: {{ error }}</p>
</template>
</ApolloMutation>
```
更多参见 [API 参考](../../api/apollo-mutation.md).
+28
View File
@@ -0,0 +1,28 @@
# ApolloQuery
你可以使用 `ApolloQuery`(或 `apollo-query`)组件直接在模板中侦听 Apollo 查询。
这是一个简单的例子:
```vue
<ApolloQuery
:query="require('../graphql/HelloWorld.gql')"
:variables="{ name }"
>
<template slot-scope="{ result: { loading, error, data } }">
<!-- Loading -->
<div v-if="loading" class="loading apollo">Loading...</div>
<!-- Error -->
<div v-else-if="error" class="error apollo">An error occured</div>
<!-- Result -->
<div v-else-if="data" class="result apollo">{{ data.hello }}</div>
<!-- No result -->
<div v-else class="no-result apollo">No result :(</div>
</template>
</ApolloQuery>
```
更多参见 [API 参考](../../api/apollo-query.md).
@@ -0,0 +1,88 @@
# ApolloSubscribeToMore
你可以使用 `ApolloSubscribeToMore`(或 `apollo-subscribe-to-more`)组件订阅更多数据。你可以在一个 `<ApolloQuery>` 组件中放置任意数量的订阅组件。
::: tip
如果更新关联到现有对象(例如更改某个字段的值),则不需要 `updateQuery`,因为 Apollo 客户端能够自动更新缓存。
:::
这是一个简单的例子:
```vue
<template>
<ApolloQuery :query="...">
<ApolloSubscribeToMore
:document="require('../gql/MessageAdded.gql')"
:variables="{ channel }"
:updateQuery="onMessageAdded"
/>
<!-- ... -->
</ApolloQuery>
</template>
<script>
export default {
data () {
return {
channel: 'general',
}
},
methods: {
onMessageAdded (previousResult, { subscriptionData }) {
// 之前的结果是不可变的
const newResult = {
messages: [...previousResult.messages],
}
// 添加问题到列表中
newResult.messages.push(subscriptionData.data.messageAdded)
return newResult
},
},
}
</script>
```
更多参见 [API 参考](../../api/apollo-subscribe-to-more.md).
## `updateQuery` 的示例
将新项添加到缓存中:
```js
methods: {
onMessageAdded (previousResult, { subscriptionData }) {
// 之前的结果是不可变的
const newResult = {
messages: [...previousResult.messages],
}
// 添加问题到列表中
newResult.messages.push(subscriptionData.data.messageAdded)
return newResult
}
}
```
从缓存中删除一项:
```js
methods: {
onMessageAdded (previousResult, { subscriptionData }) {
const removedMessage = subscriptionData.data.messageRemoved
const index = previousResult.messages.findIndex(
m => m.id === removedMessage.id
)
if (index === -1) return previousResult
// 之前的结果是不可变的
const newResult = {
messages: [...previousResult.messages],
}
// 从列表中移除问题
newResult.messages.splice(index, 1)
return newResult
}
}
```
+108
View File
@@ -0,0 +1,108 @@
# 安装
## Vue CLI Plugin
我为 [vue-cli](http://cli.vuejs.org) 制作了一个插件,因此仅用两分钟你就可以添加 Apollo(附带一个可选的 GraphQL 服务器)!✨🚀
在你的 vue-cli 3 项目中:
```bash
vue add apollo
```
然后你可以跳到下一部分:[基本用法](./apollo/)。
[更多信息](https://github.com/Akryum/vue-cli-plugin-apollo)
## Apollo Boost
Apollo Boost 是一种零配置开始使用 Apollo Client 的方式。它包含一些实用的默认值,例如我们推荐的 `InMemoryCache``HttpLink`,它非常适合用于快速启动开发:
安装:
```
npm install --save vue-apollo graphql apollo-boost
```
或:
```
yarn add vue-apollo graphql apollo-boost
```
### Apollo client
在你的应用中创建一个 `ApolloClient` 实例并安装 `VueApollo` 插件:
```js
import Vue from 'vue'
import ApolloClient from "apollo-boost"
import VueApollo from "vue-apollo"
const apolloProvider = new VueApollo({
defaultClient: new ApolloClient({
uri: "https://api.graphcms.com/simple/v1/awesomeTalksClone"
})
})
Vue.use(VueApollo)
```
## 手动操作
如果你想要更细的粒度控制,尝试在服务器端配置之前安装这些包,并且将 apollo 添加到 meteor.js 中。
```
npm install --save vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
```
或:
```
yarn add vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
```
### Apollo 客户端
在你的应用中创建一个 `ApolloClient` 实例并安装 `VueApollo` 插件:
```js
import Vue from 'vue'
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({
// 你需要在这里使用绝对路径
uri: 'http://localhost:3020/graphql',
})
// 创建 apollo 客户端
const apolloClient = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
connectToDevTools: true,
})
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
})
// 安装 vue 插件
Vue.use(VueApollo)
```
## Apollo provider
Provider 保存了可以在接下来被所有子组件使用的 Apollo 客户端实例。通过 `provide` 属性将它注入你的组件:
```js
new Vue({
el: '#app',
apolloProvider,
render: h => h(App),
})
```
+37
View File
@@ -0,0 +1,37 @@
# 本地状态
如果你需要管理本地数据,你可以使用 [apollo-link-state](https://github.com/apollographql/apollo-link-state) 和 `@client` 指令来实现:
```js
export default {
apollo: {
hello: gql`
query {
hello @client {
msg
}
}
`
},
mounted() {
// 变更 hello 消息
this.$apollo
.mutate({
mutation: gql`
mutation($msg: String!) {
updateHello(message: $msg) @client
}
`,
variables: {
msg: 'hello from link-state!'
}
})
}
}
```
[示例项目](https://codesandbox.io/s/zqqj82396p) (感谢 @chriswingler)
[Todo App](https://codesandbox.io/s/x2jr96r8pp) (感谢 @NikkitaFTW)
---
+32
View File
@@ -0,0 +1,32 @@
# 多客户端
如果你的应用需要连接到不同的 GraphQL 入口端点,你可以指定多个 apollo 客户端:
```js
const apolloProvider = new VueApollo({
clients: {
a: apolloClient,
b: otherApolloClient,
},
defaultClient: apolloClient,
})
```
在组件的 `apollo` 选项中,你可以使用 `$client` 为所有的查询、订阅和变更定义要使用的客户端(仅限在此组件内):
```js
export default {
apollo: {
$client: 'b',
},
}
```
你也可以在单个查询,订阅和变更的选项中使用 `client` 属性来指定客户端:
```js
tags: {
query: gql`...`,
client: 'b',
}
```
+362
View File
@@ -0,0 +1,362 @@
# 服务端渲染
## Vue CLI 插件
我为 [vue-cli](http://cli.vuejs.org) 制作了一个插件,因此仅用两分钟你就可以将你的 vue-apollo 应用转换为同构 SSR 应用!✨🚀
在你的 vue-cli 3 项目中:
```bash
vue add @akryum/ssr
```
[更多信息](https://github.com/Akryum/vue-cli-plugin-ssr)
## 预取组件
在要在服务端预取的查询上,添加 `prefetch` 选项。它可以是:
- 一个变量对象;
- 一个获取上下文对象(例如可以包含 URL)并返回一个变量对象的函数;
- `false` 禁用此查询的预取。
如果你在 `prefetch` 选项中返回一个变量对象,请确保它与 `variables` 选项的结果相匹配。如果它们不匹配,则在服务端渲染模板时,查询的数据属性将不会被填充。
::: danger
在服务端进行预取时,你无法访问组件实例。
:::
示例:
```js
export default {
apollo: {
allPosts: {
// 此查询将被预取
query: gql`query AllPosts {
allPosts {
id
imageUrl
description
}
}`,
prefetch: true,
}
}
}
```
示例 2
```js
export default {
apollo: {
post: {
query: gql`query Post($id: ID!) {
post (id: $id) {
id
imageUrl
description
}
}`,
prefetch: ({ route }) => {
return {
id: route.params.id,
}
},
variables () {
return {
id: this.id,
}
},
}
}
}
```
### 跳过预取
不预取查询的示例:
```js
export default {
apollo: {
allPosts: {
query: gql`query AllPosts {
allPosts {}
id
imageUrl
description
}
}`,
// 不要预取
prefetch: false,
}
}
}
```
如果要跳过特定组件的所有查询的预取,使用 `$prefetch` 选项:
```js
export default {
apollo: {
// 不要预取任何查询
$prefetch: false,
allPosts: {
query: gql`query AllPosts {
allPosts {
id
imageUrl
description
}
}`,
}
}
}
```
你也可以在任何组件上放置一个 `no-prefetch` 属性,以便在遍历树收集 Apollo 查询时忽略它:
```vue
<ApolloQuery no-prefetch>
```
## 在服务端
在服务端入口中,你需要在 Vue 中安装 `ApolloSSR` 插件:
```js
import Vue from 'vue'
import ApolloSSR from 'vue-apollo/ssr'
Vue.use(ApolloSSR)
```
使用 `ApolloSSR.prefetchAll` 方法来预取你已标记的所有 apollo 查询。第一个参数是 `apolloProvider`。第二个参数是要包含的组件定义数组(例如来自 `router.getMatchedComponents` 方法)。第三个参数是传递给 `prefetch` 钩子的上下文对象(参见上文),建议传入 vue-router 的 `currentRoute` 对象。当所有的 apollo 查询都被加载时,它返回已解决的(resolved) promise。
以下是一个使用了 vue-router 和 Vuex store 的示例:
```js
import Vue from 'vue'
import ApolloSSR from 'vue-apollo/ssr'
import App from './App.vue'
Vue.use(ApolloSSR)
export default () => new Promise((resolve, reject) => {
const { app, router, store, apolloProvider } = CreateApp({
ssr: true,
})
// 设置 router 的位置
router.push(context.url)
// 等待 router 解析完可能的异步钩子
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
// 匹配不到的路由
if (!matchedComponents.length) {
reject({ code: 404 })
}
let js = ''
// 调用匹配到路由的组件的预取钩子
// 每个 preFetch 钩子分配到一个 store action 并返回一个 Promise
// 当 action 操作完成且 store 状态已更新时解析这个 Promise
// Vuex Store 预取
Promise.all(matchedComponents.map(component => {
return component.asyncData && component.asyncData({
store,
route: router.currentRoute,
})
})
// Apollo 预取
// 这里将预取整个应用中的所有 Apollo 查询
.then(() => ApolloSSR.prefetchAll(apolloProvider, [App, ...matchedComponents], {
store,
route: router.currentRoute,
})
.then(() => {
// 将 Vuex 状态和 Apollo 缓存注入到页面
// 这将防止不必要的查询
// Vuex
js += `window.__INITIAL_STATE__=${JSON.stringify(store.state)};`
// Apollo
js += ApolloSSR.exportStates(apolloProvider)
resolve({
app,
js,
})
}).catch(reject)
})
})
```
使用 `ApolloSSR.exportStates(apolloProvider, options)` 方法来获取你需要注入到生成出来页面的 JavaScript 代码,这些代码用于将 apollo 缓存数据传递给客户端。
它需要一个 `options` 参数,默认为:
```js
{
// 全局变量名
globalName: '__APOLLO_STATE__',
// 变量设置到的全局对象
attachTo: 'window',
// 每个 apollo 客户端状态的 key 的前缀
exportNamespace: '',
}
```
你也可以使用 `ApolloSSR.getStates(apolloProvider, options)` 方法来获取 JS 对象而不是脚本字符串。
它需要一个 `options` 参数,默认为:
```js
{
// 每个 apollo 客户端状态的 key 的前缀
exportNamespace: '',
}
```
### 创建 Apollo Client
建议在一个带有 `ssr` 参数的函数内部创建 apollo 客户端,参数在服务端为 `true`,在客户端为 `false`
这里是一个示例:
```js
// src/api/apollo.js
import Vue from 'vue'
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'
// 安装 vue 插件
Vue.use(VueApollo)
// 创建 apollo 客户端
export function createApolloClient (ssr = false) {
const httpLink = new HttpLink({
// 你需要在这里使用绝对路径
uri: ENDPOINT + '/graphql',
})
const cache = new InMemoryCache()
// 如果在客户端则恢复注入状态
if (!ssr) {
if (typeof window !== 'undefined') {
const state = window.__APOLLO_STATE__
if (state) {
// 如果你有多个客户端,使用 `state.<client_id>`
cache.restore(state.defaultClient)
}
}
}
const apolloClient = new ApolloClient({
link: httpLink,
cache,
...(ssr ? {
// 在服务端设置此选项以优化 SSR 时的查询
ssrMode: true,
} : {
// 这将暂时禁用查询强制获取
ssrForceFetchDelay: 100,
}),
})
return apolloClient
}
```
常见的 `CreateApp` 方法示例:
```js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import { sync } from 'vuex-router-sync'
import VueApollo from 'vue-apollo'
import { createApolloClient } from './api/apollo'
import App from './ui/App.vue'
import routes from './routes'
import storeOptions from './store'
Vue.use(VueRouter)
Vue.use(Vuex)
function createApp (context) {
const router = new VueRouter({
mode: 'history',
routes,
})
const store = new Vuex.Store(storeOptions)
// 同步路由到 vuex store
// 将注册 `store.state.route`
sync(store, router)
// Apollo
const apolloClient = createApolloClient(context.ssr)
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
})
return {
app: new Vue({
el: '#app',
router,
store,
apolloProvider,
...App,
}),
router,
store,
apolloProvider,
}
}
export default createApp
```
在客户端:
```js
import CreateApp from './app'
CreateApp({
ssr: false,
})
```
在服务端:
```js
import CreateApp from './app'
export default () => new Promise((resolve, reject) => {
const { app, router, store, apolloProvider } = CreateApp({
ssr: true,
})
// 设置 router 的位置
router.push(context.url)
// 等待 router 解析完可能的异步钩子
router.onReady(() => {
// 预取,渲染 HTML(参见上文)
})
})
```
+152
View File
@@ -0,0 +1,152 @@
# 测试
要为 vue-apollo 查询和变更创建单元测试,你可以选择简单测试或使用模拟 GraqhQL schema 进行测试。所有的示例都使用了 [Jest](https://jestjs.io/) 和 [vue-test-utils](https://github.com/vuejs/vue-test-utils)。
## 简单测试
对于简单的查询测试,你只需要设置组件数据并检查组件如何使用 Jest 快照功能进行渲染。比如说,如果你有一个展示所有 Vue 英雄的查询,你可以添加一个包含单个英雄的模拟数组:
```js
test('displayed heroes correctly with query data', () => {
const wrapper = shallowMount(App, { localVue });
wrapper.setData({
allHeroes: [
{
id: 'some-id',
name: 'Evan You',
image: 'https://pbs.twimg.com/profile_images/888432310504370176/mhoGA4uj_400x400.jpg',
twitter: 'youyuxi',
github: 'yyx990803',
},
],
});
expect(wrapper.element).toMatchSnapshot();
});
```
对于简单的变更测试,你需要检查组件中是否调用了 `$apollo``mutate` 方法。接下来的示例在 `addHero` 方法中调用了变更:
```js
test('called Apollo mutation in addHero() method', () => {
const mutate = jest.fn();
const wrapper = mount(App, {
localVue,
mocks: {
$apollo: {
mutate,
},
},
});
wrapper.vm.addHero();
expect(mutate).toBeCalled();
});
```
## 使用模拟 GraqhQL schema 进行测试
你还可以使用 [模拟 GraphQL schema](https://www.apollographql.com/docs/graphql-tools/mocking.html) 进行更深入、更复杂的测试。这种方法并不包含 Apollo,但能够让你检查某些查询是否能够在给定的 schema 中正确执行。
为此,首先需要建立 schema
```js
const sourceSchema = `
type VueHero {
id: ID!
name: String!
image: String
github: String
twitter: String
}
input HeroInput {
name: String!
image: String
github: String
twitter: String
}
type Query {
allHeroes: [VueHero]
}
type Mutation {
addHero(hero: HeroInput!): VueHero!
deleteHero(name: String!): Boolean
}
`;
```
下一步是使用 `graphql-tools` 方法创建可执行的 schema
```js
import { makeExecutableSchema } from 'graphql-tools';
...
const schema = makeExecutableSchema({
typeDefs: sourceSchema,
});
```
之后你需要向 schema 添加模拟函数:
```js
import { addMockFunctionsToSchema } from 'graphql-tools';
...
addMockFunctionsToSchema({
schema,
});
```
指定 GraphQL 查询字符串:
```js
const query = `
query {
allHeroes {
id
name
twitter
github
image
}
}
`;
```
在测试用例中调用 GraphQL 查询,保存响应到组件数据中,然后检查渲染完成的组件是否与快照匹配:
```js
graphql(schema, query).then(result => {
wrapper.setData(result.data);
expect(wrapper.element).toMatchSnapshot();
});
```
在这个用例中,所有字符串字段将等于 `Hello World` 且所有数值都将为负数。如果你想要获得更贴近现实的响应,则应当为某些查询指定解析器:
```js
const resolvers = {
Query: {
allHeroes: () => [
{
id: '-pBE1JAyz',
name: 'Evan You',
image:
'https://pbs.twimg.com/profile_images/888432310504370176/mhoGA4uj_400x400.jpg',
twitter: 'youyuxi',
github: 'yyx990803',
},
],
},
};
```
然后你需要将解析器添加到可执行 schema,并在添加模拟函数时将 `preserveResolvers` 属性设置为 true
```js
const schema = makeExecutableSchema({
typeDefs: sourceSchema,
resolvers,
});
addMockFunctionsToSchema({
schema,
preserveResolvers: true,
});
```
你可以用同样的方法来测试变更。
---
+196
View File
@@ -0,0 +1,196 @@
# From vue-apollo 2 and Apollo 1
主要的变动与 apollo 客户端的设置有关。你的组件代码不应该受到影响。Apollo 现在使用更灵活的 [apollo-link](https://github.com/apollographql/apollo-link) 系统,允许将多个连接组合在一起以添加更多功能(如批处理,离线支持等)。
## 安装
### 包
之前:
```
npm install --save vue-apollo apollo-client
```
之后:
```
npm install --save vue-apollo@next graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
```
### 导入
之前:
```js
import Vue from 'vue'
import { ApolloClient, createBatchingNetworkInterface } from 'apollo-client'
import VueApollo from 'vue-apollo'
```
之后:
```js
import Vue from 'vue'
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'
```
### Apollo 设置
之前:
```js
// 创建网络接口
const networkInterface = createNetworkInterface({
uri: 'http://localhost:3000/graphql',
transportBatching: true,
})
// 创建订阅 websocket 客户端
const wsClient = new SubscriptionClient('ws://localhost:3000/subscriptions', {
reconnect: true,
})
// 使用订阅客户端扩展网络接口
const networkInterfaceWithSubscriptions = addGraphQLSubscriptions(
networkInterface,
wsClient,
)
// 用新的网络接口创建 apollo 客户端
const apolloClient = new ApolloClient({
networkInterface: networkInterfaceWithSubscriptions,
connectToDevTools: true,
})
```
之后:
```js
const httpLink = new HttpLink({
// 你需要在这里使用绝对路径
uri: 'http://localhost:3020/graphql',
})
// 创建订阅 websocket 连接
const wsLink = new WebSocketLink({
uri: 'ws://localhost:3000/subscriptions',
options: {
reconnect: true,
},
})
// 使用分割连接的功能
// 你可以根据发送的操作类型将数据发送到不同的连接
const link = split(
// 根据操作类型分割
({ query }) => {
const { kind, operation } = getMainDefinition(query)
return kind === 'OperationDefinition' &&
operation === 'subscription'
},
wsLink,
httpLink
)
// 创建 apollo 客户端
const apolloClient = new ApolloClient({
link,
cache: new InMemoryCache(),
connectToDevTools: true,
})
```
### 插件设置
之前:
```js
// 创建 apollo 客户端
const apolloClient = new ApolloClient({
networkInterface: createBatchingNetworkInterface({
uri: 'http://localhost:3020/graphql',
}),
connectToDevTools: true,
})
// 安装 vue 插件
Vue.use(VueApollo, {
apolloClient,
})
new Vue({
// ...
})
```
之后:
```js
const httpLink = new HttpLink({
// 你需要在这里使用绝对路径
uri: 'http://localhost:3020/graphql',
})
// 创建 apollo 客户端
const apolloClient = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
connectToDevTools: true,
})
// 安装 vue 插件
Vue.use(VueApollo)
// 创建一个 provider
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
})
// 使用 provider
new Vue({
provide: apolloProvider.provide(),
// ...
})
```
## 变更
查询 reducer 已经被移除。现在使用 `update` API 来更新缓存。
## 订阅
### 包
之前:
```
npm install --save subscriptions-transport-ws
```
之后:
```
npm install --save apollo-link-ws apollo-utilities
```
### 导入
之前:
```js
import { SubscriptionClient, addGraphQLSubscriptions } from 'subscriptions-transport-ws'
```
之后:
```js
import { split } from 'apollo-link'
import { WebSocketLink } from 'apollo-link-ws'
import { getMainDefinition } from 'apollo-utilities'
```
了解更多请查看 [apollo 官方文档](https://www.apollographql.com/docs/react/2.0-migration.html)。