Ant Design Vue集成GraphQL Apollo

安裝Apollo客戶端插件

npm install vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag --save

安裝加載器加載graphql后綴文件

打開根目錄的vue.config.js,在vueConfig(不是Ant Design Pro框架的,是在webpack.base.config.js實(shí)現(xiàn))下的chainWebpack函數(shù)中加入以下內(nèi)容:

// 支持.gql || .graphql文件
  config.module
      .rule("graphql")
      .test(/\.(graphql|gql)$/)
      .use("graphql-tag/loader")
      .loader("graphql-tag/loader")
      .end();

這樣運(yùn)行的時(shí)候能將文件后綴為.gql或.graphql的文件一起加入webpack打包

因?yàn)槲沂菍raphql內(nèi)容寫成不同的文件來(lái)使用,類似使用axios有個(gè)單獨(dú)的api文件夾一樣,這樣我們可以針對(duì)單獨(dú)的業(yè)務(wù)存放一個(gè)單獨(dú)的graphql文件,易讀、也方便維護(hù)。

使用Vue集成graphql

main.js中添加以下內(nèi)容:

/********************Graphql Apollo客戶端******************/
import storage from 'store'
import {ApolloClient} from 'apollo-client'
import {HttpLink} from 'apollo-link-http'
import {InMemoryCache} from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'
import {ApolloLink} from 'apollo-link'
const apiLink = new HttpLink({
  uri: process.env.VUE_APP_API_GRAPHQL_URL    //請(qǐng)求路徑
})
const middlewareLink = new ApolloLink((operation, forward) => {
  const token = storage.get('Access-Token')
  operation.setContext({
    headers: {
      'api-token': token || null, // 如果不需要添加header頭,這步可以忽略
    }
  })
  return forward(operation)
})
const apiClient = new ApolloClient({
  link: middlewareLink.concat(apiLink),  // 如果不添加請(qǐng)求頭直接放路徑
  cache: new InMemoryCache()
})
const apolloProvider = new VueApollo({
  defaultClient: apiClient  // 默認(rèn)請(qǐng)求路徑,如果只有一個(gè)請(qǐng)求就使用這個(gè)就行
})
Vue.use(VueApollo)
/********************Graphql客戶端End******************/

這樣就完成集成了。

如何使用

  1. src文件夾下創(chuàng)建文件夾graphql,專門存放graphql文件。
  2. graphql文件夾中創(chuàng)建一個(gè)user.gql(如果你使用VSCode編輯器,會(huì)提示你安裝gql插件,安裝上,開發(fā)方便很多),隨便寫一個(gè)查詢語(yǔ)句試試水:
# 查詢列表,q_shops是自定義的函數(shù)名,第3步引用時(shí)需要用到
query q_shops($page: Int!, $search: ShopSearch!) {
  shops(first: 10, page: $page, search: $search) {
    data {
      id
      user_id
      name
      phone
      status
      notice
      address
      location
      created_at
    }
    paginatorInfo {
      total
      lastPage
      currentPage
    }
  }
}
  1. 在Vue頁(yè)面中使用
    引入gql文件:
import { q_shops } from '@/graphql/shop.gql'

使用Apollo客戶端執(zhí)行g(shù)ql語(yǔ)句

// 此處我是做一個(gè)列表查詢,variables里的參數(shù)以及then里的業(yè)務(wù)實(shí)現(xiàn)根據(jù)自己需求編寫
        this.$apollo.query({
          query: q_shops,
          variables: {
            "page": parameter.pageNo
          },
        })
        .then((response) => {
          console.log('graphql response', response)
          var result = response.data.shops
          result['current_page'] = result.paginatorInfo.currentPage
          result['total'] = result.paginatorInfo.total
          return result
        })
        .catch((error) => {})

這樣就完成Apollo集成及使用了。

擴(kuò)展

獲取數(shù)據(jù)有緩存如何處理?

Apollo客戶端默認(rèn)有做數(shù)據(jù)緩存功能,當(dāng)你第一次查詢時(shí)會(huì)緩存當(dāng)前查詢語(yǔ)句的數(shù)據(jù),第二次用相同的語(yǔ)句及參數(shù)查詢不會(huì)進(jìn)行網(wǎng)絡(luò)請(qǐng)求,直接返回第一次查詢的數(shù)據(jù)。從性能的角度來(lái)考慮,出發(fā)點(diǎn)挺好的,不過(guò)對(duì)于我們需要經(jīng)常做增刪改查的功能時(shí),就不實(shí)用了。解決方式很簡(jiǎn)單,在query時(shí)加入fetchPolicy: 'no-cache'即可。以上述的查詢語(yǔ)句為例,實(shí)現(xiàn)代碼如下:

        this.$apollo.query({
          query: q_shops,
          variables: {
            "page": parameter.pageNo
          },
          fetchPolicy: 'no-cache'  // 加上這句即可
        })
        .then((response) => {
          console.log('graphql response', response)
          var result = response.data.shops
          result['current_page'] = result.paginatorInfo.currentPage
          result['total'] = result.paginatorInfo.total
          return result
        })
        .catch((error) => {})

做簡(jiǎn)易的封裝

每次執(zhí)行g(shù)raphql語(yǔ)句要寫一大堆結(jié)構(gòu)代碼,太麻煩了。把相同結(jié)構(gòu)代碼封裝起來(lái)(個(gè)人方式封裝,不一定適用大家,能用的拿去就好),具體實(shí)現(xiàn):

  1. /src/utils/文件夾中創(chuàng)建apollo.js(不喜歡這個(gè)名字隨便換)。
  2. 封裝代碼如下:
/**
 * 自封裝的graphql Apollo工具類
 */

/**
 * 查詢單條信息
 * @param {*} _this 傳this
 * @param {*} graphqlStr 對(duì)應(yīng)的graphql查詢語(yǔ)句
 * @param {*} params 參數(shù)
 * @param {*} schema 返回?cái)?shù)據(jù)有一層schema,需要拿到這一層的數(shù)據(jù)
 * @param {*} callback 回調(diào)函數(shù)
 */
export function querySingle(_this, graphqlStr, params, schema, callback = null) {
  return _this.$apollo.query({
      query: graphqlStr,
      variables: params,
      fetchPolicy: 'no-cache'
    })
    .then((response) => {
      console.log('graphql response', response)
      var result = schema ? response.data[schema] : response.data
      callback && callback(result, true)
      return result
    })
    .catch((error) => {
      _this.$notification['error']({
        message: '查詢失敗',
        description: '錯(cuò)誤信息:' + error.message,
      })
    })
}

/**
 * 查詢列表
 * @param {*} _this 傳this
 * @param {*} graphqlStr 對(duì)應(yīng)的graphql查詢語(yǔ)句
 * @param {*} pageParams 分頁(yè)參數(shù)
 * @param {*} schema 返回?cái)?shù)據(jù)有一層schema,需要拿到這一層的數(shù)據(jù),再組裝分頁(yè)數(shù)據(jù)給STable
 * @param {*} callback 回調(diào)函數(shù)
 */
export function queryList(_this, graphqlStr, pageParams, schema, callback = null) {
  var params = {}
  if (pageParams.pageNo) {
    params = {
      "page": pageParams.pageNo
    }
  } else {
    params = pageParams
  }
  console.log(pageParams, graphqlStr)

  return _this.$apollo.query({
      query: graphqlStr,
      variables: params,
      fetchPolicy: 'no-cache'
    })
    .then((response) => {
      console.log('graphql response', response)
      var result = response.data[schema]
      result['current_page'] = result.paginatorInfo.currentPage
      result['total'] = result.paginatorInfo.total
      if (callback) {
        return callback(result, true)
      }
      return result
    })
    .catch((error) => {
      _this.$notification['error']({
        message: '查詢失敗',
        description: '錯(cuò)誤信息:' + error.message,
      })
    })
}

/**
 * 多個(gè)查詢集合
 * @param {*} _this 傳this
 * @param {*} graphqlStr 對(duì)應(yīng)的graphql查詢語(yǔ)句
 * @param {*} params 參數(shù)
 * @param {*} callback 回調(diào)函數(shù)
 */
export function queryMulti(_this, graphqlStr, params, callback = null) {
  console.log(params, graphqlStr)

  return _this.$apollo.query({
      query: graphqlStr,
      variables: params,
      fetchPolicy: 'no-cache'
    })
    .then((response) => {
      console.log('graphql response', response)
      var result = response.data
      if (callback) {
        callback(result, true)
      }
      return result
    })
    .catch((error) => {
      _this.$notification['error']({
        message: '查詢失敗',
        description: '錯(cuò)誤信息:' + error.message,
      })
    })
}

/**
 * 創(chuàng)建數(shù)據(jù)
 * @param {*} _this 傳this
 * @param {*} graphqlStr 對(duì)應(yīng)的graphql查詢語(yǔ)句
 * @param {*} params 參數(shù)
 * @param {*} callback 回調(diào)函數(shù)
 */
export function createData(_this, graphqlStr, params, callback = null) {
  return _this.$apollo.mutate({
      mutation: graphqlStr,
      variables: params
    })
    .then((response) => {
      console.log('graphql response', response)
      callback && callback(response, true)
      return response
    })
    .catch((error) => {
      if (error.graphQLErrors[0].extensions.validation) {
        var validation = error.graphQLErrors[0].extensions.validation
        var msg = (validation[Object.keys(validation)[0]])[0]
        _this.$notification['error']({
          message: '新建失敗',
          description: '錯(cuò)誤信息:' + msg,
        })
      } else {
        _this.$notification['error']({
          message: '新建失敗',
          description: '錯(cuò)誤信息:' + error.graphQLErrors[0].message,
        })
      }
    })
}

/**
 * 修改數(shù)據(jù)
 * @param {*} _this 傳this
 * @param {*} graphqlStr 對(duì)應(yīng)的graphql查詢語(yǔ)句
 * @param {*} params 參數(shù)
 * @param {*} callback 回調(diào)函數(shù)
 */
export function updateData(_this, graphqlStr, params, callback = null) {
  return _this.$apollo.mutate({
      mutation: graphqlStr,
      variables: params,
    })
    .then((response) => {
      console.log('graphql response', response)
      callback && callback(response, true)
      return response
    })
    .catch((error) => {
      if (error.graphQLErrors[0].extensions.validation) {
        var validation = error.graphQLErrors[0].extensions.validation
        var msg = (validation[Object.keys(validation)[0]])[0]
        _this.$notification['error']({
          message: '修改失敗',
          description: '錯(cuò)誤信息:' + msg,
        })
      } else {
        _this.$notification['error']({
          message: '修改失敗',
          description: '錯(cuò)誤信息:' + error.graphQLErrors[0].message,
        })
      }
    })
}

/**
 * 刪除數(shù)據(jù)
 * @param {*} _this 傳this
 * @param {*} graphqlStr 對(duì)應(yīng)的graphql查詢語(yǔ)句
 * @param {*} params 參數(shù)
 * @param {*} callback 回調(diào)函數(shù)
 */
export function deleteData(_this, graphqlStr, params, callback = null) {
  return _this.$apollo.mutate({
      mutation: graphqlStr,
      variables: params,
    })
    .then((response) => {
      console.log('graphql response', response)
      callback && callback(response, true)
      return response
    })
    .catch((error) => {
      if (error.graphQLErrors[0].extensions.validation) {
        var validation = error.graphQLErrors[0].extensions.validation
        var msg = (validation[Object.keys(validation)[0]])[0]
        _this.$notification['error']({
          message: '刪除失敗',
          description: '錯(cuò)誤信息:' + msg,
        })
      } else {
        _this.$notification['error']({
          message: '刪除失敗',
          description: '錯(cuò)誤信息:' + error.graphQLErrors[0].message,
        })
      }
    })
}

以上對(duì)增刪改查都做了簡(jiǎn)單的封裝,以及多個(gè)graphql語(yǔ)句執(zhí)行的函數(shù)封裝,錯(cuò)誤提示等處理。

  1. 封裝后的使用:
// 引入封裝的文件
import { querySingle, queryList, createData, updateData } from '@/utils/apollo'

...

// 使用封裝后的查詢,傳參調(diào)用就完事了
var vars = {}
vars['search'] = {}
vars['page'] = parameter.pageNo
return queryList(this, q_shops, vars, 'shops')

參考并感謝

https://segmentfault.com/a/1190000016320117
https://segmentfault.com/q/1010000016610922
https://blog.csdn.net/winnie__wei/article/details/80598309
https://blog.csdn.net/Missbelover/article/details/102651403
https://www.cnblogs.com/lhxsoft/p/11904388.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容