一、前端开发环境
- Visual Studio Code
- Node JS
- Webpack:npm install webpack -g
- vue-cli:npm install vue-cli -g
- 淘宝镜像:npm install -g cnpm --registry=https://registry.npm.taobao.org
- Yarn:npm i yarn -g -verbose
二、创建项目
vue init webpack icupo-web
npm install
三、安装Element UI
npm install element-ui
按照官网的引入方式在main.js中引入:
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
...
Vue.use(ElementUI)
四、安装scss
# 注意安装的版本
npm install node-sass@4.14.1
npm install sass-loader@7.3.1
配置build/webpack.base.conf.js,注意这个不要添加
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass']
}
五、安装axios与js-cookie
对axios的封装有几个好处:
- 统一Url配置
- 统一Api请求
- request拦截器,加入请求头
- response拦截器,统一错误处理,页面重定向
- 结合vuex做全局的loading动画,或错误处理
- 将axios封装成vue插件
5.1 安装axios和js-cookie
npm install axios
npm install js-cookie
5.2 定义全局常量文件src/utils/global.js,并挂载到Vue,通过this.global调用常量的值。
// 后台管理系统服务器地址
export const baseUrl = 'http://localhost:8001'
// 系统数据备份还原服务器地址
export const backupBaseUrl = 'http://localhost:8002'
export default {
baseUrl,
backupBaseUrl
}
在main.js中挂载
import global from '@/utils/global'
...
Vue.prototype.global = global
5.3 配置axios,src/http/config.js,一些默认的配置项
import { baseUrl } from '@/utils/global'
export default {
method: 'get',
baseUrl: baseUrl,
Headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
data: {},
timeout: 300000,
withCredentials: true,
responseType: 'json'
}
5.4 axios的请求与响应的处理,src/http/axios.js
- 导入配置文件的信息到axios对象
- 发送请求的时候携带token,如果token不存在,则重定向到登录页面
- 统一处理响应
import axios from 'axios'
import config from './config'
import Cookies from 'js-cookie'
import router from '../router'
export default function $axios(options) {
return new Promise((resolve, reject) => {
const instance = axios.create({
baseURL: config.baseUrl,
headers: config.headers,
timeout: config.timeout,
withCredentials: config.withCredentials
})
// request 请求拦截器
instance.interceptors.request.use(
config => {
let token = Cookies.get('token')
if (token) {
config.headers.Authorization = 'Bearer ' + token
} else {
router.push('/login')
}
return config
},
error => {
return Promise.reject(error)
}
)
// response 响应拦截器
instance.interceptors.response.use(
response => {
return response.data
},
err => {
if (err && err.response) {
switch (err.response.status) {
case 400:
err.message = '请求错误'
break
case 401:
err.message = '未授权,请登录'
break
case 403:
err.message = '拒绝访问'
break
case 404:
err.message = `请求地址出错: ${err.response.config.url}`
break
case 408:
err.message = '请求超时'
break
case 500:
err.message = '服务器内部错误'
break
case 501:
err.message = '服务未实现'
break
case 502:
err.message = '网关错误'
break
case 503:
err.message = '服务不可用'
break
case 504:
err.message = '网关超时'
break
case 505:
err.message = 'HTTP版本不受支持'
break
default:
}
}
console.error(err)
return Promise.reject(err)
}
)
// 请求处理
instance(options).then(res => {
resolve(res)
return false
}).catch(error => {
reject(error)
})
})
}
5.5 挂载api,可以通过 "this.$api.模块.方法" 的方式调用API。
- src/http/index.js
// 导入所有接口
import api from './api'
const install = Vue => {
if (install.installed) {
return
}
install.installed = true
Object.defineProperties(Vue.prototype, {
$api: {
get () {
return api
}
}
})
}
export default install
- src/http/api.js
/*
* 接口统一集成模块
*/
import * as login from './modules/login'
import * as user from './modules/user'
import * as dept from './modules/dept'
import * as role from './modules/role'
import * as menu from './modules/menu'
import * as dict from './modules/dict'
import * as config from './modules/config'
import * as log from './modules/log'
import * as loginlog from './modules/loginlog'
// 默认全部导出
export default {
login,
user,
dept,
role,
menu,
dict,
config,
log,
loginlog
}
- main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import global from './utils/global'
import api from './http'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.config.productionTip = false
Vue.use(api)
Vue.use(ElementUI)
Vue.prototype.global = global
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
5.6 一些api的案例
import axios from '../axios'
/*
* 系统配置模块
*/
// 保存
export const save = (data) => {
return axios({
url: '/config/save',
method: 'post',
data
})
}
// 删除
export const batchDelete = (data) => {
return axios({
url: '/config/delete',
method: 'post',
data
})
}
// 分页查询
export const findPage = (data) => {
return axios({
url: '/config/findPage',
method: 'post',
data
})
}
import axios from '../axios'
/*
* 机构管理模块
*/
// 保存
export const save = (data) => {
return axios({
url: '/dept/save',
method: 'post',
data
})
}
// 删除
export const batchDelete = (data) => {
return axios({
url: '/dept/delete',
method: 'post',
data
})
}
// 查询机构树
export const findDeptTree = () => {
return axios({
url: '/dept/findTree',
method: 'get'
})
}
import axios from '../axios'
/*
* 字典管理模块
*/
// 保存
export const save = (data) => {
return axios({
url: '/dict/save',
method: 'post',
data
})
}
// 删除
export const batchDelete = (data) => {
return axios({
url: '/dict/delete',
method: 'post',
data
})
}
// 分页查询
export const findPage = (data) => {
return axios({
url: '/dict/findPage',
method: 'post',
data
})
}
import axios from '../axios'
/*
* 操作日志模块
*/
// 删除
export const batchDelete = (data) => {
return axios({
url: '/log/delete',
method: 'post',
data
})
}
// 分页查询
export const findPage = (data) => {
return axios({
url: '/log/findPage',
method: 'post',
data
})
}
import axios from '../axios'
/*
* 系统登录模块
*/
// 登录
export const login = data => {
return axios({
url: 'login',
method: 'post',
data
})
}
// 登出
export const logout = () => {
return axios({
url: 'logout',
method: 'get'
})
}
import axios from '../axios'
/*
* 操作日志模块
*/
// 删除
export const batchDelete = (data) => {
return axios({
url: '/loginlog/delete',
method: 'post',
data
})
}
// 分页查询
export const findPage = (data) => {
return axios({
url: '/loginlog/findPage',
method: 'post',
data
})
}
import axios from '../axios'
/*
* 菜单管理模块
*/
// 保存
export const save = (data) => {
return axios({
url: '/menu/save',
method: 'post',
data
})
}
// 删除
export const batchDelete = (data) => {
return axios({
url: '/menu/delete',
method: 'post',
data
})
}
// 查找导航菜单树
export const findNavTree = (params) => {
return axios({
url: '/menu/findNavTree',
method: 'get',
params
})
}
// 查找导航菜单树
export const findMenuTree = () => {
return axios({
url: '/menu/findMenuTree',
method: 'get'
})
}
import axios from '../axios'
/*
* 角色管理模块
*/
// 保存
export const save = (data) => {
return axios({
url: '/role/save',
method: 'post',
data
})
}
// 删除
export const batchDelete = (data) => {
return axios({
url: '/role/delete',
method: 'post',
data
})
}
// 分页查询
export const findPage = (data) => {
return axios({
url: '/role/findPage',
method: 'post',
data
})
}
// 查询全部
export const findAll = () => {
return axios({
url: '/role/findAll',
method: 'get'
})
}
// 查询角色菜单集合
export const findRoleMenus = (params) => {
return axios({
url: '/role/findRoleMenus',
method: 'get',
params
})
}
// 保存角色菜单集合
export const saveRoleMenus = (data) => {
return axios({
url: '/role/saveRoleMenus',
method: 'post',
data
})
}
import axios from '../axios'
/*
* 用户管理模块
*/
// 保存
export const save = (data) => {
return axios({
url: '/user/save',
method: 'post',
data
})
}
// 删除
export const batchDelete = (data) => {
return axios({
url: '/user/delete',
method: 'post',
data
})
}
// 分页查询
export const findPage = (data) => {
return axios({
url: '/user/findPage',
method: 'post',
data
})
}
// 导出Excel用户信息
export const exportUserExcelFile = (data) => {
return axios({
url: '/user/exportUserExcelFile',
method: 'post',
data
})
}
// 查找用户的菜单权限标识集合
export const findPermissions = (params) => {
return axios({
url: '/user/findPermissions',
method: 'get',
params
})
}
// 根据用户名查找
export const findByName = (params) => {
return axios({
url: '/user/findByName',
method: 'get',
params
})
}
// 更新用户密码
export const updatePassword = (params) => {
return axios({
url: '/user/updatePassword',
method: 'get',
params
})
}
3.4 登录逻辑
login() {
this.$api.login.login().then(function(res) {
Cookies.set('token', res.token)
router.push('/')
}).catch(function(res) {
// 其它处理
})
}
四、国际化
- 安装依赖
npm install vue-i18n@8.26.5
- 配置src/i18n/index.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
// 注册i18n实例并引入语言文件,文件格式等下解析
const i18n = new VueI18n({
locale: 'zh_cn',
messages: {
'zh_cn': require('@/assets/languages/zh_cn.json'),
'en_us': require('@/assets/languages/en_us.json')
}
})
export default i18n
{
"common": {
"home": "首页",
"login": "登录",
"logout": "退出登录",
"doc": "文档",
"blog": "博客",
"projectRepo": "项目",
"myMsg": "我的消息",
"config": "系统配置",
"backup": "备份",
"restore": "还原",
"backupRestore": "备份还原",
"versionName": "版本名称",
"exit": "退出"
},
"action": {
"operation": "操作",
"add": "新增",
"edit": "编辑",
"delete": "删除",
"batchDelete": "批量删除",
"search": "查询",
"loading": "拼命加载中",
"submit": "提交",
"comfirm": "确定",
"cancel": "取消",
"reset": "重置"
}
}
{
"common": {
"home": "Home",
"login": "Login",
"logout": "Logout",
"doc": "Document",
"blog": "Blog",
"projectRepo": "Project",
"myMsg": "My Message",
"config": "Config",
"backup": "Backup",
"restore": "Restore",
"backupRestore": "Backup Restore",
"versionName": "Version",
"exit": "Exit"
},
"action": {
"operation": "Operation",
"add": "Add",
"edit": "Edit",
"delete": "Delete",
"batchDelete": "Batch Delete",
"search": "Search",
"loading": "loading",
"submit": "Submit",
"comfirm": "Comfirm",
"cancel": "Cancel",
"reset": "Reset"
}
}
import Vue from 'vue'
import App from './App'
import router from './router'
import i18n from './i18n'
import global from './utils/global'
import api from './http'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.config.productionTip = false
Vue.use(api)
Vue.use(ElementUI)
Vue.prototype.global = global
/* eslint-disable no-new */
new Vue({
el: '#app',
i18n,
router,
components: { App },
template: '<App/>'
})
- 切换语言函数:
changeLanguage(lang) {
lang === '' ? 'zh_cn' : lang
this.$i18n.locale = lang
}
- 使用方法:
# html中使用
{{$t('common.doc')}}
# js中使用
i18n.t('message.timeout')
五、全局状态
- 安装
npm install vuex@3.6.2
- 编写配置文件,src/store/index.js
import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex);
// 引入子模块
import app from './modules/app'
import tab from './modules/tab'
import user from './modules/user'
import menu from './modules/menu'
const store = new vuex.Store({
modules: {
app: app,
tab: tab,
user: user,
menu: menu
}
})
export default store
- app.js。是属于应用内的全局性的配置,比如主题色、导航栏收缩状态等,详见注释。
export default {
state: {
test: false, // 测试
menuRouteLoaded: false // 菜单和路由是否已经加载
},
getters: {
test (state) {
return state.test
}
},
mutations: {
setTest (state, payload) {
state.test = payload.test
},
menuRouteLoaded (state, menuRouteLoaded) { // 改变菜单和路由的加载状态
state.menuRouteLoaded = menuRouteLoaded
}
},
actions: {
}
}
import Vue from 'vue'
import App from './App'
import router from './router'
import i18n from './i18n'
import store from './store'
import global from './utils/global'
import api from './http'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.config.productionTip = false
Vue.use(api)
Vue.use(ElementUI)
Vue.prototype.global = global
/* eslint-disable no-new */
new Vue({
el: '#app',
i18n,
router,
store,
components: { App },
template: '<App/>'
})
- 通过computed计算属性引入store属性,
computed: {
...mapState({
***: state => state.app.***
})
}
- 通过语句this.$store.commit('mothodName', {})来修改值
六、全站配置
- 样式文件src/assets/css/site.css
# 内容
* {
margin: 0;
padding: 0;
user-select: none;
}
# main.js中引入
import './assets/css/site.css'
- 全局图片文件src/assets/img/site。
- App.vue
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
</style>
- vscode调整tab为2个空格
# .eslintrc.js -> rules中添加
"indent": ["error", "tab"]
七、自定义图标功能
打开阿里icon,注册 >登录>图标管理>我的项目。项目名称:el-icon-third。