按部就班VUE+Element 前端应用开发(2)--- Vuex中的API、Store和View的使用

在咱们开发Vue应用的时候,不少时候须要记录一些变量的内容,这些能够用来作界面状态的承载,也能够做为页面间交换数据的处理,处理这些内容能够归为Vuex的状态控制。例如咱们每每前端须要访问后端数据,通常是经过封装的Web API调用获取数据,而使用Store模式来处理相关的数据或者状态的变化,而视图View主要就是界面的展现处理。本篇随笔主要介绍如何整合这三者之间的关系,实现数据的获取、处理、展现等逻辑操做。前端

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。关于Vuex的相关State、Getter、Mutation、Action、Module之间的差别和联系,详细能够参考下:https://vuex.vuejs.org/zh/vue

一、先后端的分离和Web API 优先路线设计

 Web API 是一种应用接口框架,它可以构建HTTP服务以支撑更普遍的客户端(包括浏览器,手机和平板电脑等移动设备)的框架,  ASP.NET Web API 是一种用于在 .NET Framework/ .net Core 上构建 RESTful 应用程序的理想平台。在目前发达的应用场景下,咱们每每须要接入Winform客户端、APP程序、网站程序、以及目前热火朝天的微信应用等,这些数据应该能够由同一个服务提供,这个就是咱们所须要构建的Web API平台。因为Web API层做为一个公共的接口层,咱们就很好保证了各个界面应用层的数据一致性。node

因为倾向于先后端的彻底分离,咱们后端就能够彻底由Web API统一构建支持,能够采用.net framework或者.net core构建的统一接口平台,能够简单由Asp.net 作的Web API接口平台,也能够基于ABP-aspnetboilerplate( ABP框架随笔介绍)框架基础上构建的Web API平台。webpack

 

这样咱们就能够基于这些API接口构建前端多项应用,如包括Web前端、Winform前端、以及对接各类APP等应用。ios

引入了先后端分离的VUE + Element 的开发方式,那么先后端的边界则很是清晰,前端能够在经过网络获取对应的JSON就能够构建前端的应用了。web

 在前端处理中,主要就是利用Vuex模式中的Store对象里实现对Action和Mutation的请求处理,获取数据后,实现对State状态中的数据进行更新。若是仅仅是当前页面的数据处理,甚至能够不须要存储State信息,直接获取到返回的数据,直接更新到界面视图上便可。vuex

在开发前期,咱们甚至能够不须要和后端发生任何关系,经过Mock数据代替从Web API上请求数据,只要Mock的数据结构和Web API接口返回的JSON一致,咱们就能够在后期实现快速的对接,而不影响现有的代码处理方式。vue-cli

  

二、Axios网络请求处理

在咱们进一步处理前,咱们须要知道Vuex里面的一些对象概念和他们之间的关系。axios

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。关于Vuex的相关State、Getter、Mutation、Action、Module之间的差别和联系,详细能够参考下:https://vuex.vuejs.org/zh/后端

在开始发起网络请求以前,咱们须要了解axios 这个东西,axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范。在这里咱们只须要知道它是很是强大的网络请求处理库,且获得普遍应用便可,列举几个代码案例进行了解。

POST请求

axios({
    method: 'post',
    url: '/user/12345',
    data: {
        firstName: 'Fred',
        lastName: 'Flintstone'
    }
})
.then(function (response) {
    console.log(response);
})
.catch(function (error) {
    console.log(error);
});

GET请求

axios
  .get('http://rap2api.taobao.org/app/mock/23080/resources/search',{
      params: {
         id: 5
      }
   })
  .then(res => {
    console.log('数据是:', res);
  })
  .catch((e) => {
    console.log('获取数据失败');
  });

若是咱们要跨域请求数据,在配置文件里设置代理,vue-cli3项目,须要在vue.config.js里面写配置。

能够分别设置请求拦截和响应拦截,在发出请求和响应到达then以前进行判断处理,通常的处理方式就是封装一个类如request类,而后进行对拦截器的统一处理,如在请求前增长一些用户身份信息等。 

// create an axios instance
const service = axios.create({
  timeout: 5000 // request timeout
})

// request 请求拦截
service.interceptors.request.use(
  config => {

    if (store.getters.token) {
      config.headers['X-Token'] = getToken()
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

 

三、Vuex中的API、Store和View的使用

咱们再次回到Vuex中的API、Store和View的使用介绍上。

 

 咱们来看看API的封装请求调用类的封装,以下所示,咱们建立了一些操做数据的API类文件,每一个API名称对应一个业务的集中处理,包括特定业务的列表请求、单个请求、增长、删除、修改等等均可以封装在一个API类里面。

 

 咱们来看看Product.js的类文件定义以下所示。

这里我用了Request和Axios的操做对比,二者很接近,由于request是对Axios的简单封装,主要就是拦截注入一些登陆信息和一些响应的错误处理而已。

import request from '@/utils/request'
import axios from 'axios'

这里的Url里面,经过代理配置的处理,会把对应的iqidi替换为对应外部域名的处理,从而实现对跨域处理请求数据的获取了,咱们这里只须要知道,url最终会转换为相似

http://www.iqidi.com/h5/GetProductList 这样实际的地址进行请求的便可,返回是一个JSON数据集合。

 因为Vue视图里面的JS处理部分,能够直接引入API进行请求数据,以下所示。

import { GetProductList } from '@/api/product'

而后咱们就能够在method方法里面定义一个获取API数据的方法了。

  methods: {
    getlist(type) {
       GetProductList({ type: type }).then(response => {
         const { data } = response
         this.productlist = data.list
         this.listLoading = false
       })
    }

这种调用是最直接的API调用,没有引入Store模块中封装的Action或者Mutation进行异步或者同步的处理。通常状况下直接使用这种方式比较简洁,由于大多数页面处理或者组件处理,不须要对数据进行全局状态的存储处理,也就是不须要进行全局Store对象的处理了。

若是咱们须要在全局存储对应的信息,那么就须要引入Store模块中对API调用的封装了,包括Action或者Mutation的处理。

咱们先来定义Store存储类,以下界面所示。

若是咱们须要对产品列表等数据进行全局状态的存储,那么咱们能够考虑建立一个对应Store目录下的模块,如product.js,来管理Action、Mutation和State等信息。

import { GetProductList, GetProductDetail } from '@/api/product'

const state = {
  productlist: [],
  productdetail: null
}
const mutations = {
  SET_PRODUCT_LIST: (state, list) => {
    state.productlist = list
  },
  SET_PRODUCT_DETAIL: (state, detail) => {
    state.productdetail = detail
  }
}

const actions = {
  // 产品列表
  getProductList({ commit }, { type }) {
    console.log(type);
    return new Promise((resolve, reject) => {
      GetProductList({ type: type }).then(response => {
        const { data } = response
        commit('SET_PRODUCT_LIST', data)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

  // 获取产品明细
  getProductDetail({ commit }, { id }) {
    return new Promise((resolve, reject) => {
      GetProductDetail({ id: id }).then(response => {
        const { data } = response
        commit('SET_PRODUCT_DETAIL', data)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

咱们下来看看,若是引入了Store模块的业务类,那么在界面视图中调用代码则修改成调用对应的Action或者Mutation了。

  methods: {
    getlist(type) {
      // GetProductList({ type: type }).then(response => {
      //   const { data } = response
      //   this.productlist = data.list
      //   this.listLoading = false
      // })

      this.$store.dispatch('product/getProductList', { type: type }).then(data => {
        this.productlist = data.list
        // this.loading = false
      }).catch((e) => {
        // this.loading = false
      })
    }

咱们这里强调一下,通常状况下在视图模块中使用API的类调用便可,不须要累赘的每一个业务模块,都建立一个Store的模块类进行相应的管理,只有在这些状态数据须要在多个页面或者组件中须要共享的时候,才考虑引入Store模块类进行细化管理。

咱们刚才说到,若是须要建立对应业务模块的Store状态管理模块,那么须要建立对应的模块类,如前面说到的product.js类文件。

其中Modules目录里面的按照业务区分边界的Vuex的Store管理类了,每一个对应业务建立一个单独的文件进行管理(若是须要用到的话)。

在index.js里面咱们经过模块动态加载的方式,把这些类按照不一样的命名空间进行加载进来,统一使用。

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'

Vue.use(Vuex)

// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)

// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // set './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  return modules
}, {})

const store = new Vuex.Store({
  modules,
  getters
})

export default store
相关文章
相关标签/搜索