安装 vue 脚手架:
cnpm install vue-cli -g / npm install vue-cli -g
搭建项目:
vue init webpack projectName
cd projectName
安装less预处理器
npm install less less-loader
找到webpack.base.conf.js文件module>rules中加入:
{
test: /\.less$/,
loader: "style-loader!css-loader!less-loader"
}
如需配置代理:
找到config>index.js文件
proxyTable: {
'/api':{
target: '代理域名',
changeOrigin: true,
secure: false,
pathRewrite:{
'^/api':'/api',
}
}
},
添加ui框架(element-ui)
npm install element-ui -save
main.js中加入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
路由配置:
import Vue from 'vue'
import VueRouter from 'vue-router'
import RouterMeta from '@/utils/router/router';
import Account from './account/account';
const Layout = r => require.ensure([], () => r(require('@/views/layout/layout.vue')), 'Layout');
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'layout',
component: Layout,
redirect:'/user',
children: [
...Account,
],
},
{
path: '/',
redirect: '/user',
},
{
path: '*',
name: '404',
redirect: '/user',
},
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
router.beforeEach((to, from, next) => RouterMeta(to, from, next));
export default router
routerMeta.js:
import wxApi from '@/models/wx/wx';
import wxLogin from '@/utils/wx/wxLogin';
import Local from '@/config/address/local';
const { redirect_url, openAddress } = Local;
let RouterMeta = async (to, from, next) => {
next();
// 以下逻辑为微信授权及业务场景,可删除
// if (!sessionStorage.getItem('url')) {
// sessionStorage.setItem('url', document.URL)
// }
//if(to.path === openAddress.remark || to.path === openAddress.evaluate){
//next();
//} else if(localStorage.getItem('unionId') && localStorage.getItem('openId')) {
//if(!localStorage.getItem('phone')) {
//if(to.path !== '/login') {
//return window.location.href = redirect_url;
//}else {
// next()
// }
// } else {
// next();
// }
// } else {
// if(window.location.href.split('?').length>1) {
// let query = await (window.location.href.split('?')[1]).split('&'), code;
// await query.forEach(item=>{
// if(item.split('=')[0]==='code') code = item.split('=')[1];
// });
// if(code) {
// let res = await wxApi.getWXInfo({ uri: code });
// await localStorage.setItem('openId', res.data.openId || '');
// await localStorage.setItem('phone', res.data.phone || '');
// await localStorage.setItem('unionId', res.data.unionId || '');
// await localStorage.setItem('userId', res.data.userId || '');
// await localStorage.setItem('token', res.data.token || '');
// if(res.data.phone) {
// next();
// } else {
// if(to.path !== '/login') {
// return window.location.href = redirect_url;
// }else {
// next();
// }
// }
// } else wxLogin();
// } else wxLogin();
// }
}
export default RouterMeta;
api封装:(如图)
fetch.js:
require('es6-promise').polyfill();
require('isomorphic-fetch');
import { api, formatUrl, parseJSON } from './plugins';
const Fetch = apiConfig => {
const serviceMap = {};
apiConfig.map(({ name, url, method }) => {
const U= url;
let Url= U;
return serviceMap[name]=async function(data= null){
serviceMap.credentials= 'include';
serviceMap.mode= 'cors';
serviceMap.method= method.toUpperCase();
delete serviceMap['body'];
switch (serviceMap.method) {
case 'GET' || 'DELETE':
if (data) Url= `${U}${formatUrl(data)}&t=${new Date().valueOf()}`;
else Url= `${U}${formatUrl({t:new Date().valueOf()})}`;
break;
case 'POST' || 'PUT':
Url = `${U}${formatUrl({t:new Date().valueOf()})}`;
serviceMap.headers = {'Content-Type':'application/json;charset=UTF-8','Accept':'application/json'};
serviceMap.body = data?JSON.stringify(data):'';
break;
default:
Url= U;
}
return new Promise((resolve, reject) => {
fetch(api + Url, serviceMap).then(response => { return response; })
.then(parseJSON)
.then(response => {
if(response.status==0){
resolve(response);
}else{
reject(response);
}
})
.catch(error => {
reject(error)
});
});
}
});
return serviceMap;
};
export default Fetch;
plugins.js:
const api = '/api';
export {
api,
};
export function formatUrl (obj){
let params = Object.values(obj).reduce((a, b, i) => `${a}${Object.keys(obj)[i]}=${b}&`, '?');
return params.substring(0, params.length - 1);
};
export function parseJSON(response) {
return response.json();
}
axios.js:
import $axios from 'axios';
import apiBase from './apiBase';
const { timeout, requestFun, responseFun, getOptions, validateStatus } = apiBase;
const service = $axios.create({
timeout,
validateStatus,
});
service.interceptors.request.use(requestFun);
service.interceptors.response.use(responseFun);
const ajax = ({ method, url, data, headers }) => {
let $options = getOptions({
method,
url,
data,
headers,
});
try {
return service($options);
}catch (ex) {
throw new Error(`network exception ! \n ex:${ex.message} \n method:${method} \n url:${url} \n params:${JSON.stringify(data)}`)
}
}
export default ajax;
/*
*
* 网络状态码
*
* */
const httpStatus = status => {
switch (status) {
case 400:
return '错误请求';
case 401:
return '未授权,请重新登录';
case 403:
return '拒绝访问';
case 404:
return '请求错误,未找到该资源';
case 405:
return '请求方法未允许';
case 408:
return '请求超时';
case 500:
return '服务器出错';
case 501:
return '网络未实现';
case 502:
return '网络错误';
case 503:
return '服务不可用';
case 504:
return '网络超时';
case 505:
return 'http版本不支持该请求';
default:
return `连接错误: ${status}`;
}
};
/*
*
* http 响应时间
*
* */
const timeout = 30000;
apiBase.js:
import Vue from 'vue';
import status from "@/config/http/status";
import Local from '@/config/address/local';
const _ = new Vue();
const { apiStatus, httpStatus, timeout } = status;
const { redirect_url, base_url } = Local;
class ApiBase {
constructor() {
this.timeout = timeout;
}
validateStatus (){
return true;
}
requestFun (config) {
_.$loading.show();
config.headers['token'] = localStorage.getItem('token') || '';
config.headers['source'] = process.env.VUE_APP_TYPE || 15;
if(config.method === 'post' || config.method === 'put') config.headers['Content-Type'] = 'application/json;charset=UTF-8';
return config;
}
responseFun (response) {
_.$loading.hide();
if(response.status === 200){
const res = response.data;
if (res.status === apiStatus.SUCCESS) {
return res;
} else if (
res.status === apiStatus.TOKEN_EXPIRED ||
res.status === apiStatus.USER_NON_LOGIN
){
window.location.href = redirect_url;
}else {
if(res) {
if(window.location.pathname === '/login') return _.$alert({msg: res.msg, type: "error", top: '40'});
else return _.$alert({msg: res.msg, type: "error"});
} else {
if(window.location.pathname === '/login') return _.$alert({msg: '服务器错误!!!', type: "error", top: '40'});
else return _.$alert({msg: '服务器错误!!!', type: "error"});
}
}
} else {
_.$alert({msg: httpStatus(response.status), type: "error"});
throw new Error(httpStatus(response.status));
}
}
getOptions ({ method, url, data, headers }) {
let $options = {}, uri = '', time = new Date().valueOf();
if(typeof url !== 'string') throw new Error('url must be string !');
if(!url) throw new Error('url must be required !');
if(typeof method !== 'string') throw new Error('method must be string !');
if(typeof data !== 'object') data = {};
$options['baseURL'] = base_url;
$options['url'] = `${url}?t=${time}`;
$options['headers'] = headers;
switch (method.toUpperCase()) {
case 'GET':
$options['method'] = 'GET';
$options['params'] = data;
break;
case 'GETQUERY':
$options['method'] = 'GET';
for (const params in data) {
uri += `/${data[params]}`;
}
$options['url'] = `${url}${uri}?t=${time}`
break;
case 'POST':
$options['method'] = 'POST'
$options['data'] = data;
break;
case 'DELETE':
$options['method'] = 'DELETE'
$options['params'] = data;
break;
case 'PUT':
$options['method'] = 'PUT'
$options['data'] = data;
break;
default:
$options['method'] = 'GET';
$options['params'] = data;
break;
}
return $options;
}
}
export default new ApiBase();
apiFactory.js:
import $axios from './axios';
const ApiFactory = module => {
let apiObject = {};
module.forEach( item => {
apiObject[item.name] = params => {
return $axios({
method: item.method,
url: item.url,
data: params,
headers: item.headers,
});
}
});
return apiObject;
}
export default ApiFactory;
api文件