构建项目//pc端、移动端H5

文章目录

    • 移动端
    • pc端
    • 构建项目
    • 我的步骤
      • 示例一:vue init webpack 文件名
      • 示例二:vue create 文件名
      • vue.config.js 配置
      • ui框架包
      • 安装异步编程框架axios
      • 关于前端登录存储 token
      • js-cookie
      • 安装mock
      • 在vue项目中使用Nprogress.js进度条

vue-cli
安装 ui 库(eg:pc端用element ui、移动端用 vuex)

移动端

vux
github地址

pc端

elementUI
饿了么github地址
vue-admin-template
PanJiaChen/vue-element-admin

构建项目

vue前端开发项目框架搭建(node+webpack+vue)

Vue项目环境搭建总结

前端框架搭建-搭建vue环境(学习笔记)

其它:
vue-cli 3.x搭建项目以及其中vue.config.js文件的配置
Vue 创建项目后没有 webpack.config.js(vue.config.js) 文件
解决Vue-cli3没有vue.config.js文件夹及配置vue项目域名
Vue vue-config.js(字段属性详细介绍)

我的步骤

由于本机已有 nodejs、npm、vue-cli等,所以直接创建项目即可

示例一:vue init webpack 文件名

vue init webpack 文件名
构建项目//pc端、移动端H5_第1张图片

示例二:vue create 文件名

参考:超级详细的Vue-cli3使用教程

vue create 文件名

? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>( ) Babel                              //  代码编译
 ( ) TypeScript                         //  ts
 ( ) Progressive Web App (PWA) Support  //  支持渐进式网页应用程序
 ( ) Router                             //  vue路由
 ( ) Vuex                               //  状态管理模式
 ( ) CSS Pre-processors                 //  css预处理
 ( ) Linter / Formatter                 //  代码风格、格式校验
 ( ) Unit Testing                       //  单元测试
 ( ) E2E Testing                        //  端对端测试

一般项目开发只需要选择Babel、Router、Vuex就足够了。

vue.config.js 配置

module.exports = {
  devServer: {
    // 端口号
    port: 8080,
    // 配置不同的后台API地址
    proxy: {
      '/api': {
        target: 'http://www.dzm.com',
        ws: false,
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
}

ui框架包

element-ui官网:http://element-cn.eleme.io/#/zh-CN/component/installation

npm 安装

npm i element-ui -S

完整引入
在 main.js 中写入以下内容:

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';

Vue.use(ElementUI);

new Vue({
  el: '#app',
  render: h => h(App)
});

安装异步编程框架axios

axios中文文档|axios中文网:http://www.axios-js.com/zh-cn/docs/
vue项目中axios拦截器的使用和配置

  • 安装_使用 npm:
npm install axios
  • src/utils/request.js 中引入 axios
import axios from 'axios'

创建 axios 实例

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})

配置请求拦截器
service.interceptors.request.use({})

// request interceptor
service.interceptors.request.use(
  config => {
    // do something before request is sent

    if (store.getters.token) {
      // let each request carry token
      // ['X-Token'] is a custom headers key
      // please modify it according to the actual situation
      config.headers['X-Token'] = getToken()
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

配置响应拦截器
service.interceptors.response.use({})

// response interceptor
service.interceptors.response.use(
  response => {
    const res = response.data

    // if the custom code is not 20000, it is judged as an error.
    if (res.code !== 20000) {
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })

      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // to re-login
        MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
          confirmButtonText: 'Re-Login',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload()
          })
        })
      }
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return res
    }
  },
  error => {
    console.log('err' + error) // for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

输出 axios 实例

export default service

例子:

import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'

// create an axios instance
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})

// request interceptor
service.interceptors.request.use(
  config => {
    // do something before request is sent

    if (store.getters.token) {
      // let each request carry token
      // ['X-Token'] is a custom headers key
      // please modify it according to the actual situation
      config.headers['X-Token'] = getToken()
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  /**
   * If you want to get http information such as headers or status
   * Please return  response => response
  */

  /**
   * Determine the request status by custom code
   * Here is just an example
   * You can also judge the status by HTTP Status Code
   */
  response => {
    const res = response.data

    // if the custom code is not 20000, it is judged as an error.
    if (res.code !== 20000) {
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })

      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // to re-login
        MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
          confirmButtonText: 'Re-Login',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload()
          })
        })
      }
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return res
    }
  },
  error => {
    console.log('err' + error) // for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

src/utils/auth.js

import Cookies from 'js-cookie'

const TokenKey = 'vue_admin_template_token'

export function getToken() {
  return Cookies.get(TokenKey)
}

export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

export function removeToken() {
  return Cookies.remove(TokenKey)
}

例子:

import axios from "axios";
// import * as auth from "@/plugins/auth"
import {
  Notification as notification,
  MessageBox as Modal,
  Loading
} from "element-ui";
import store from "@/store";
import Vue from "vue";
import * as auth from "@/plugins/auth";

// Full config:  https://github.com/axios/axios#request-config
// axios.defaults.baseURL = '/rms'
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

let reqNum = 0;
let loadingInstance = null;

const err = error => {
  if (error.response) {
    let data = error.response.data;
    // const token = auth.getToken()
    // console.log("------异常响应------", token)
    // console.log("------异常响应------", error.response.status)
    switch (error.response.status) {
      case 403:
        notification.error({
          title: "系统提示",
          message: "拒绝访问",
          duration: 4000
        });
        break;
      case 511:
        Modal.alert("很抱歉,登录已过期,请重新登录", {
          title: "登录已过期",
          showClose: false,
          confirmButtonText: "重新登录",
          callback: () => {
            store.dispatch("Logout");
          }
        });
        throw new Error("Token失效,请重新登录");
      case 500:
        //notification.error({ message: '系统提示', description:'Token失效,请重新登录!',duration: 4})
        if (data.message == "Token失效,请重新登录") {
          // update-begin- --- author:scott ------ date:20190225 ---- for:Token失效采用弹框模式,不直接跳转----
          // store.dispatch('Logout').then(() => {
          //     window.location.reload()
          // })
          Modal.alert("很抱歉,登录已过期,请重新登录", {
            title: "登录已过期",
            showClose: false,
            confirmButtonText: "重新登录",
            callback: () => {
              store.dispatch("Logout");
            }
          });
          // update-end- --- author:scott ------ date:20190225 ---- for:Token失效采用弹框模式,不直接跳转----
        } else {
          notification.error({
            title: "系统提示",
            message: data,
            duration: 4000
          });
        }
        break;
      case 404:
        notification.error({
          title: "系统提示",
          message: "很抱歉,资源未找到!",
          duration: 4000
        });
        break;
      case 504:
        notification.error({
          title: "系统提示",
          message: "网络超时"
        });
        break;
      case 401:
        notification.error({
          title: "系统提示",
          message: "未授权,请重新登录",
          duration: 4000
        });
        break;

      case 302:
        window.location.href = `${process.env.VUE_APP_PublicPath}api/${window.location.host.includes("it.") && !window.location.href.includes(process.env.VUE_APP_PublicPath+"a")?'oauth/':''}login?backUrl=http://${window.location.host}${process.env.VUE_APP_PublicPath}%23/`;
        break;
      default:
        notification.error({
          title: "系统提示",
          message: data,
          duration: 4000
        });
        break;
    }
  }
  return Promise.reject(error);
};

let config = {
  baseURL: process.env.VUE_APP_PublicPath.replace(/\/$/, ""),
  timeout: 60 * 1000, // Timeout
  withCredentials: true // Check cross-site Access-Control
};

export const _axios = axios.create(config);

// 请求拦截器
_axios.interceptors.request.use(
  config => {
    let cancel;
    // 设置cancelToken对象
    config.cancelToken = new axios.CancelToken(c => {
      cancel = c;
    });

    //console.log(cancel);

    let urlList = ['task/getTaskTypeList', '/dict/getDictItems'];
    let isFilter = urlList.some(item => {
      let number = config.url.indexOf(item);
      return number > -1;
    })
    if (isFilter && !store.getters.isIntercept) {
      try {
        cancelRequest(config.url, cancel, "重复请求");
      } catch (e) {
        //
      }
    }
    config.headers["X-Requested-With"] = "XMLHttpRequest";

    if (
      config.url.indexOf("/rmsApi/") >= 0 ||
      config.url.indexOf("/api/") < 0
    ) {
      config.withCredentials = false;
    }

    if (auth.getAuthorization()) {
      config.headers["Authorization"] = auth.getAuthorization(); // 让每个请求携带自定义token 请根据实际情况自行修改
    }

    if (auth.getSystemUid()) {
      config.headers["SystemUid"] = auth.getSystemUid(); // 让每个请求携带自定义token 请根据实际情况自行修改
    } else {
      console.error("SystemUid not find");
    }

    if (config.responseType != "arraybuffer") {
      setTimeout(() => {
        if (!loadingInstance) {
          if (reqNum > 0) {
            loadingInstance = Loading.service({
              target: ".el-main",
              fullscreen: false,
              text: "数据请求中...",
              background: "rgba(0,0,0,0.1)"
            });
          }
        }
      }, 500);
      reqNum++;
    }
    // Do something before request is sent
    // const token = auth.getToken()
    // if (token) {
    //   config.headers['X-Access-Token'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
    // }
    if (config.method === "get") {
      let params = config.params;
      let Nparams = {};
      for (let item in params) {
        if (item.indexOf("like_") == 0) {
          Nparams[item.replace("like_", "")] = "*" + params[item] + "*";
        } else if (item.indexOf("left_like_") == 0) {
          Nparams[item.replace("left_like_", "")] = params[item] + "*";
        } else if (item.indexOf("right_like_") == 0) {
          Nparams[item.replace("right_like_", "")] = "*" + params[item];
        } else {
          Nparams[item] = params[item];
        }
      }
      config.params = Nparams;

      if (config.url.indexOf("/round/pagelist") >= 0) {
        config.params.column = config.params.column || "createTime"
        config.params.order = config.params.order || "DESC"
      }


      // 中央督察、自治区督察,分别给所有接口加 systemType
      // 整改管理两个督察类型分别在所有接口加 systemtype
      // routertag为'zydc'时添加 systemType=1
      var a = {
        systemType: 1
      }
      var b = {
        systemType: 2
      }
      if (store.getters.routerTag == 'zydc') {
        config.params = Object.assign(config.params, a)
      } else if (store.getters.routerTag == 'zzqdc') {
        config.params = Object.assign(config.params, b)
      } else if (store.getters.routerTag == 'zggl') {
        if (store.getters.zgglSystemType == '1') {
          config.params = Object.assign(config.params, a)
        } else if (store.getters.zgglSystemType == '2') {
          config.params = Object.assign(config.params, b)
        }
      }
    }

    return config;
  },
  error => {
    reqNum++;
    // Do something with request error
    return Promise.reject(error);
  }
);

// Add a response interceptor 响应拦截器
_axios.interceptors.response.use(
  function (response) {
    if (response.headers.sessionkey) {
      store.commit('Set_sessionkey', response.headers.sessionkey);
    }
    closeLoading();
    if (response.config.responseType == "arraybuffer") {
      const fileName = response.headers.filename;
      return Promise.resolve({
        fileName: decodeURI(fileName),
        data: response.data
      })
    }
    // Do something with response data
    if (!response.status >= 200 && !response.status < 300) {
      notification.warning({
        title: "系统提示",
        message: response.data,
        duration: 4000
      });
      return Promise.reject(response.data);
    }


    return response.data;
  },
  function (error) {
    closeLoading();
    // Do something with response error
    return err(error);
    //return Promise.reject(error);
  }
);
  • 在 src/api/下的 js 文件引入 axios 实例,然后写各种请求方法
import request from '@/utils/request'

export function login(data) {
  return request({
    url: '/vue-admin-template/user/login',
    method: 'post',
    data
  })
}

export function getInfo(token) {
  return request({
    url: '/vue-admin-template/user/info',
    method: 'get',
    params: { token }
  })
}

export function logout() {
  return request({
    url: '/vue-admin-template/user/logout',
    method: 'post'
  })
}

关于前端登录存储 token

localStorage存储方式:很详细的一篇文章!vue实现token用户登录
Vue刷新token,判断token是否过期、失效的最简便的方法

结合 vuex 存储 token
在store文件的state中初始化token,因为state中的数据不支持直接修改,所以我们需要定义方法setToken(设置token)getToken(获取token),然后我们就可以在登录接口处引入this.$store.commit('setToken',JSON.stringify(res.data.token))将后台传来的token存入Vuex和localStorage中,为什么还要存入localStorage,Vuex中的状态一旦页面刷新就不再存在,为了保持当前状态,需要通过localStorage中提取状态再传值给Vuex


import Vue from 'vue'
import Vuex from 'vuex'
 
Vue.use(Vuex)
 
export default new Vuex.Store({
  state: {
    token:''  //初始化token
  },
  mutations: {
    //存储token方法
    //设置token等于外部传递进来的值
    setToken(state, token) {
        state.token = token
        localStorage.token = token //同步存储token至localStorage
      },
  },
 getters : {
  //获取token方法
  //判断是否有token,如果没有重新赋值,返回给state的token
  getToken(state) {
    if (!state.token) {
      state.token = localStorage.getItem('token')
    }
    return state.token
    }
  },
  actions: {
 
  }
})

js-cookie

github地址:https://github.com/js-cookie/js-cookie
https://www.npmjs.com/package/js-cookie
js-cookie中文文档
vue项目中js-cookie的使用存储token

NPM 安装

npm install --save js-cookie

src/utils/auth.js 引入 Cookies

import Cookies from 'js-cookie'

例子:

import Cookies from 'js-cookie'

const TokenKey = 'vue_admin_template_token'

export function getToken() {
  return Cookies.get(TokenKey)
}

export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

export function removeToken() {
  return Cookies.remove(TokenKey)
}

安装mock

MockJS快速入门

前后端分离,前端通过mock开发,无需等待后端接口开发好了再开发
npm install mockjs

移除 mock
vue.config.js中移除webpack-dev-serverproxyafter这个Middleware就可以了。

proxy: {
  // change xxx-api/login => mock/login
  // detail: https://cli.vuejs.org/config/#devserver-proxy
  [process.env.VUE_APP_BASE_API]: {
    target: `http://localhost:${port}/mock`,
    changeOrigin: true,
    pathRewrite: {
      ['^' + process.env.VUE_APP_BASE_API]: ''
    }
  }
},
after: require('./mock/mock-server.js')

mock-server只会在开发环境中使用,线上生产环境目前使用MockJs进行模拟。如果不需要请移除。具体代码:main.js

import { mockXHR } from '../mock'
if (process.env.NODE_ENV === 'production') {
  mockXHR()
}
/**
 * If you don't want to use mock-server
 * you want to use MockJs for mock api
 * you can execute: mockXHR()
 *
 * Currently MockJs will be used in the production environment,
 * please remove it before going online ! ! !
 */
if (process.env.NODE_ENV === 'production') {
  const { mockXHR } = require('../mock')
  mockXHR()
}

修改
最常见的操作就是:你本地模拟了了一些数据,待后端完成接口后,逐步替换掉原先 mock 的接口。

我们以src/api/role.js中的getRoles接口为例。它原本是在mock/role/index.js中 mock 的数据。现在我们需要将它切换为真实后端数据,只要在mock/role/index.js找到对应的路由,之后将它删除即可。这时候你可以在network中,查看到真实的数据。

// api 中声明的路由
export function getRoles() {
  return request({
    url: '/roles',
    method: 'get'
  })
}

//找到对应的路由,并删除
{
    url: '/roles',
    type: 'get',
    response: _ => {
      return {
        code: 20000,
        data: roles
      }
    }
  },

在vue项目中使用Nprogress.js进度条

https://blog.csdn.net/qq_35844177/article/details/70171054

npm install --save nprogress

src/permission.js 中引入

import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

你可能感兴趣的:(项目相关)