在 Vue项目中如何使用GraphQL

梁丘洲
2023-12-01

什么是GraphQL

GraphQL 官方文档

Vue中项目中如何配置支持GraphQl

首先需要提前了解一下
Vue apollo
Graphql
为了webpack 能够解析Graphql 文件,需要在vue.config.js文件中配置

 chainWebpack: config => {
    config.module
      .use("vue-loader")
      .loader("vue-loader")
      .end()
  }

安装需要的依赖

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

在项目根目录下创建apollo文件夹,创建 apollo-options.js(apollo 相关配置) 和 vue-apollo.js(配置Vue apollo)文件

//apollo-options.js
import { ApolloLink } from "apollo-link";
import { createHttpLink } from "apollo-link-http";
import { onError } from "apollo-link-error";
import { InMemoryCache } from "apollo-cache-inmemory";
import ApolloClient from "apollo-client";
import { Message } from "element-ui";
import router from "@root/router";
import i18nInstance from "@root/i18n";

const httpLink = createHttpLink({
  uri:
    process.env.NODE_ENV === "development"
      ? '本地的开发路径'
      :  process.env.apiUrl, // 项目通过webpack配的api调用连接
    //  如果需要设置代理
    // '/graphql': {
    //         target: "需要代理的路径",
    //         changeOrigin: true,
    //         pathRewrite: {
    //            '^/graphql': '/graphql'
    //         }
    //     },
  fetch(uri, options) {
    const { operationName } = JSON.parse(options.body as string);
    // 由于 graphql 请求路径在浏览器中统一为‘/graphql’, 为了方便查看拼接上接口名称
    return fetch(`${uri}/?opname=${operationName}`, options);
  }
});

// 中间件为每个请求带上必要请求头参数
const middlewareLink = new ApolloLink((operation, forward) => {
  operation.setContext({
    headers: {
      "AUTH-TOKEN": localStorage.getItem("AuthToken"),
      Language: i18nInstance.locale
    }
  });

  return forward(operation).map(response => {
    // 过滤apollo 自带的__typename
    let filterData = JSON.stringify(response).replace(
      /\,"__typename\"[:]\"[0-9a-zA-Z_|!|(|)]{1,}\"/g,
      ""
    );
    return JSON.parse(filterData);
  })
});


const onRequestError = () => {
// 配置项目请求是否过期
  let hasBeenExpire = false;

  return (errorData) => {
    const { networkError, response } = errorData
    if (networkError) {
      Message.error("networkError");
      return
    }

    const error: any = response && response.errors && response.errors[0]
    let { code = "", message = 'Error' } = error || {}

    // 如果已经过期那就不再弹出错误信息 也不会多次触发路由跳转
    if (hasBeenExpire) {
      return
    }

    // 如果过期 页面跳转
    if (code === "0002"){
      hasBeenExpire = true
      router.push({ name: "Logout"})
    }

    Message.error(message);
  }
}

// 统一拦截请求错误
const errorLink = onError(error => onRequestError(error));

const options: any = {
  cache: new InMemoryCache(),
  link: errorLink.concat(middlewareLink.concat(httpLink)),
  defaultOptions: {
    watchQuery: {
      fetchPolicy: "no-cache"
    },
    query: {
      fetchPolicy: "no-cache"
    }
  }
};

export const gqlClient = new ApolloClient(options);

export default options;
// vue-apollo.js

import Vue from "vue";
import VueApollo from "vue-apollo";
import {
  createApolloClient,
  restartWebsockets
} from "vue-cli-plugin-apollo/graphql-client";

// Install the vue plugin
Vue.use(VueApollo);


export function createProvider() {
  // Create vue apollo provider
  const apolloProvider = new VueApollo({
    defaultClient: apolloClient,
    defaultOptions: {
      $query: {
        fetchPolicy: "no-cache"
      }
    },
  });

  return apolloProvider。provide();
}

由于是Vue结合Vuex,请求都会在 VueX的action中进行,所以将Graphql的请求注入到了rootState中,具体rootState 可到Vuex官网此处了解。

export default new Vuex.Store({
 // 可以Vuex的rootState中注入gqlClient
  state: {
    gql: gqlClient
  },
  modules: {},
  mutations: {},
  actions: {}
});

//main.js 
import {createProvider} from  @/apollo/vue-apollo.js;
//...

const apolloProvider = createProvider();

 new Vue({
	  router,
	  store,
	  i18n: i18n,
	  provide: apolloProvider,
}).$mount("#app");

至此配置完成,那么如何使用呢
在根目录下创建 graphql 文件,在此文件下创建各个模块的graphql文件,也就是前端写查询Schemal 的地方。如以下:

// graphql/user.gql

query getUser($input: updateUser){
  api:getUser(input:$input){
   edges{
      node{
        userCode
        userName
       }
   }
  }
}

mutation updateUser ($input: updateUser!) {
  api: updateUser(updateUser: $input){
    success
  }
}

mutation createUser($input: [createUser]!){
  api: createUser(createUser: $input){
    success
    list{
      updateUser
      createUser
    }
  }
}

mutation deleteUser($input: deleteUser!){
  api: deleteUser(deleteUser: $input){
    success
  }
}

由于此前已经将Graphql请求注入到Vuex 中,所以只需要在action中请求数据即可

import {
getUser,
updateUser,
createUser,
deleteUser
} from "@/graphql/user.gql";

export default {
  namespaced: true,
  state: {
    userList: [],
  },
  getters: {
  },
  actions: {
    // 订单列表
    async getUser({ commit, rootState }, data) {
      const res = await rootState.gql.query({
        query: getUser,
        variables: {
          input:data
        }
      });
     commit("setUserList",res.data.api.edges)
     return res;
    },
    // 订单列表
    async updateUser({ commit, rootState }, data) {
      const {
        data: { api }
      } = await rootState.gql.mutate({
        mutation: updateUser,
        variables: {
          updateUser: data
        }
      });

      return api;
    },
  },
  mutations: {
    setUserList(state, data) {
      state.userList = data;
    }
  }
};

在页面中直接使用Vuex 中action方法即可

<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import { State, Getter, Action, Mutation, namespace } from "vuex-class";

const user = namespace("user");
@Component({
  components: {},
})
export default class OMSIndex extends Vue {
  @user.State userList;
  @user.Action getUser;

  async mounted() {
    await this.getData();
  }

  async getData() {
    let sendParams = xxx;
    let res = await this.getUser(sendParams);
    console.log(res);//获取到数据了
  }
}
</script>

 类似资料: