☼ 注:笔者的文章是根据自己当前项目做的笔记,具体应用请参照自己实际项目情况
1、创建应用
npm install -g @vue/cli-service-global
vue create my-vue-project
cd my-vue-project
npm run serve
2、配置axios及proxy跨域代理
⑴ 安装http-proxy-middleware
npm install http-proxy-middleware --save
⑵ 在根目录新建一个vue.config.js文件
module.exports = {
devServer: {
proxy: {
'/c': {
target: 'https://10.8.20.25',
changeOrigin: true,
secure: false
},
'/v1': {
target: 'https://10.8.20.25',
changeOrigin: true,
secure: false
}
}
}
}
⑶ 安装axios
npm install axios --save
⑷ 在main.js中引用
import axios from 'axios'
Vue.prototype.axios = axios.create({
baseURL: window.location.origin
})
⑸ 在业务中使用
// 开发环境或预发布环境
const apiUrl = window.location.origin.includes('cms') ? 'v1/web/estatewebadmin' : 'clife-estate-api-web-admin'
this.url = `/${apiUrl}/estate/merchant/detail/${this.id}.do`
axios.post(this.url, { carNo: this.carNo }).then(res => console.log(res)).catch(err => console.log(err))
3、配置基本路径,解决打包首页空白问题
在vue.config.js文件中,添加以下配置
module.exports = {
publicPath: './', //基本路径,解决打包空白问题
}
4、配置rem方案
⑴ 在src目录下新建一个utils目录(用来放置工具函数),在utils目录下新建一个rem.js文件
/*设置REM方案*/
remFont()
window.addEventListener('resize', function () {
remFont();
// console.log(window.innerWidth)
});
function remFont() {
var html = document.getElementsByTagName('html')[0];
var width = window.innerWidth;
var font_Size = 0;
if(width >= 320 && width <= 1024){
font_Size = 100/375 * width;
}else if(width<320){
font_Size = 100/375 * 320;
}else{
font_Size = 100/375 * 1024;
}
html.style.fontSize = font_Size + 'px';
}
⑵ 在main.js文件中,引入rem.js
import './utils/rem'
⑶ 安装postcss-px2rem
npm i postcss-px2rem --save
⑷ 在vue.config.js中配置
const px2rem = require('postcss-px2rem')
const postcss = px2rem({
remUnit: 100 //基准大小 baseSize,需要和rem.js中相同
})
module.exports = {
css: {
loaderOptions: {
postcss: {
plugins: [
postcss
]
}
}
}
}
5、引入element-ui,配置按需加载
⑴ 安装element-ui
npm i element-ui --save
⑵ 在babel.config.js中配置
module.exports = {
presets: [
'@vue/app'
],
plugins: [["component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]]
}
⑶ 在main.js中引入
import { Button, Message } from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(Button)
Vue.component(Message.name, Message)
Vue.prototype.$message = Message
6、引入阿里iocn
⑴ 在src文件夹下新建一个assets文件夹,再新建一个iconfont文件夹,把阿里图库生成的文件放到文件夹下
⑵ 在main.js中引入
import '@/assets/iconfont/iconfont.css'
7、引入vue-echarts图表库
⑴ 安装vue-echarts
npm install echarts vue-echarts --save
⑵ 在vue.config.js中配置
module.exports = {
transpileDependencies: [
'vue-echarts',
'resize-detector'
]
}
⑶ 在main.js中引入
import ECharts from 'vue-echarts'
import chinaJson from 'echarts/map/json/china.json'
import 'echarts/lib/chart/map'
import 'echarts/lib/component/geo'
ECharts.registerMap('china', chinaJson)
Vue.prototype.$echarts = ECharts
Vue.component('v-chart', ECharts)
⑷ 使用
8、配置路由
⑴ 安装vue-router
npm install vue-router --save
⑵ 在src目录下新建一个router.js文件
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const baseUrl = './pages/'
const communityUrl = './pages/community/components/'
const routes = [
{ path: '/', redirect: '/dataCenter' },
{ path: '/dataCenter', component: () => import(`${baseUrl}dataCenter`) },
{ path: '/community', component: () => import(`${baseUrl}community`), children: [
{
path: '/',
component: () => import(`${communityUrl}guardView`)
}, {
path: 'parkGuard',
component: () => import(`${communityUrl}parkGuard`)
}
] }
]
export const router = new VueRouter({
routes
})
// 登录状态重定向
router.beforeEach((to, from, next) => {
if (!loginStatus && to.path !== '/login') {
next('/login')
} else {
next()
}
})
⑶ 在main.js中挂载
import { router } from './routes'
new Vue({
router,
render: h => h(App),
}).$mount('#app')
9、配置vuex
⑴ 安装vuex
npm i vuex --save
⑵ 在src目录下新建一个store文件夹,再新建一个index.js文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
isCollapse: false
},
mutations: {
toCollapse (state, bool) {
state.isCollapse = bool
}
}
})
⑶ 在业务代码中使用
10、结合axios拦截器和vuex模块化封装管理请求
⑴ 在src下新建一个api目录,用来统一管理接口地址
在api目录下新建一个config.js,配置baseURL
const HOST = window.location.origin
const apiUrl = HOST.includes('cms') ? '/v1/web/estatewebadmin' : '/clife-estate-api-web-admin'
export default HOST + apiUrl
再新建一个axios.js配置拦截器
import axios from 'axios'
import qs from 'qs'
import baseURL from './config'
import vm from '@/main'
const Axios = axios.create({
baseURL,
withCredentials: true, // 是否允许跨域请求携带cookie
responseType: 'json', // 服务器响应的数据类型, 默认json
headers: {
'Content-Type': 'application/json;charset=UTF-8' // 请求头content-type类型, 默认json
}
})
let loadingInstance = null
const loadingOn = loading => {
if (!loadingInstance && loading !== false) {
loadingInstance = vm.$loading({ target: '.el-main>div' })
}
}
const loadingOff = () => {
loadingInstance && setTimeout(() => {
loadingInstance.close()
loadingInstance = null
}, 500)
}
// 请求拦截器
Axios.interceptors.request.use(
config => {
// 检测网络
if (!navigator.onLine){
vm.$message.error('当前网络已断开,请联网重试!')
return
}
// 针对post请求和get请求处理
if (config.method === 'post') {
// 可以把自定义的信息和参数一起传过来,再做统一处理
const { headers, responseType, param, loading } = config.data || {}
// 开启loading
loadingOn(loading)
// 如果重写了headers, 则替换
if (headers) {
config.headers = headers
}
// 如果重写了responseType, 则替换
if (responseType) {
config.responseType = responseType
}
// 如果请求头Content-Type为表单形式,则通过qs插件把参数做相关处理
config.data = config.headers['Content-Type'] === 'application/x-www-form-urlencoded' ? qs.stringify(param) : param
} else {
// 开启loading
loadingOn(config.loading)
// 参数
config.params = config.param
}
// 取消请求
config.cancelToken = vm.$store.state.Root.source.token
return config
},
err => {
loadingOff()
return Promise.reject(err)
}
)
Axios.interceptors.response.use(
response => {
loadingOff()
const { data, config } = response || {}
// code为0,返回响应数据
if (+data.code === 0) {
return data
}
// 文件流格式
if (config.responseType === 'blob') {
// message提示后台返回json格式的错误信息
if (data.type === 'application/json') {
let reader = new FileReader()
reader.onload = e => JSON.parse(e.target.result).msg
reader.readAsText(data)
return
}
// 需要针对IE做兼容,所以直接返回blob对象,再针对不同浏览器做url转化处理
return new Blob([data], { type: data.type })
}
// 后台返回用户未登录或用户不存在
if (+data.code === 100010110 || +data.code === 100021401) {
return
}
// code非0
vm.$message(data.msg)
return Promise.reject(data)
},
err => {
loadingOff()
if (!err.response) {
// 如果是取消请求导致的错误,则不做msg提示
return Promise.reject(err)
}
vm.$message.warning('服务调用失败,请稍后重试!')
return Promise.reject(err)
}
)
export default Axios
然后按模块划分接口,比如 /api/setting/basic/project.js
import axios from '@/api/axios'
export default {
queryProject: data => axios.post('/estate/project/queryProject.do', data)
}
⑵ 在src目录下新建一个store目录, 把接口请求方法和数据处理统一放在vuex里完成
store目录下新建一个root.js,用来处理全局方法和数据,比如取消axios请求或收缩菜单等
export default {
namespaced: true,
state: {
isCollapse: false,
source: { token: null, cancel: null }
},
mutations: {
// 改变侧边菜单伸缩状态
toCollapse: (state, bool) => {
state.isCollapse = bool
},
// 取消axios请求
soureToken: (state, source) => {
state.source = source
}
}
}
再按模块划分不同的modules,和api下的模块保持一致,比如store/setting/basic/project.js
import Project from '@/api/setting/basic/project'
export default {
namespaced: true,
state: {
projectRecord: [],
totalRows: 0
},
actions: {
queryProject: async ({ state }, params) => {
const data = await Project.queryProject(params)
try {
state.projectRecord = data.data.record
state.totalRows = data.data.totalRows
} catch (err) {
return Promise.reject(err)
}
}
},
getters: {
projectList: state => {
return state.projectRecord.map(item => ({
id: item.projectId,
name: item.projectName
}))
}
}
}
然后在setting下新建一个index.js引入各个小模块的modules
import Project from './basic/project'
export default {
namespaced: true,
modules: {
Project
}
}
最后在store下新建一个index.js引入各个大模块的modules
import Vue from 'vue'
import Vuex from 'vuex'
import Root from './root'
import Setting from './setting'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
Root, Setting
}
})
⑶ 在页面调用请求,获取处理后的数据结果
import { mapState, mapGetters, mapMutations } from 'vuex'
export default {
computed: {
...mapState('Root', ['source']),
...mapState('Setting/Project', ['projectRecord']),
...mapGetters('Setting/Project', ['projectList']),
},
methods: {
...mapMutations('Root', ['soureToken']),
handleClick() {
this.source.cancel && this.source.cancel()
this.soureToken(this.$axios.CancelToken.source())
this.queryProject()
},
queryProject() {
this.$store.dispatch('Setting/Project/queryProject', {
param: {
data: {
project: {
projStatus: 1,
...this.formValue
},
pager: {
pageRows: 10,
pageIndex: 1,
paged: true
},
orderBy: {
orderColumn: 'createTime',
orderType: 'desc'
}
}
},
// loading: false
}).then(() => {
console.log(this.projectRecord)
})
}
},
created() {
this.queryProject()
}
}