一啄巧、前端開(kāi)發(fā)環(huán)境
- 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
二、創(chuàng)建項(xiàng)目
vue init webpack icupo-web
npm install
三、安裝Element UI
npm install element-ui
按照官網(wǎng)的引入方式在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鉴逞,注意這個(gè)不要添加
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass']
}
五扰法、安裝axios與js-cookie
對(duì)axios的封裝有幾個(gè)好處:
- 統(tǒng)一Url配置
- 統(tǒng)一Api請(qǐng)求
- request攔截器,加入請(qǐng)求頭
- response攔截器决左,統(tǒng)一錯(cuò)誤處理,頁(yè)面重定向
- 結(jié)合vuex做全局的loading動(dòng)畫逗载,或錯(cuò)誤處理
- 將axios封裝成vue插件
5.1 安裝axios和js-cookie
npm install axios
npm install js-cookie
5.2 定義全局常量文件src/utils/global.js哆窿,并掛載到Vue,通過(guò)this.global調(diào)用常量的值厉斟。
// 后臺(tái)管理系統(tǒng)服務(wù)器地址
export const baseUrl = 'http://localhost:8001'
// 系統(tǒng)數(shù)據(jù)備份還原服務(wù)器地址
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,一些默認(rèn)的配置項(xiàng)
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的請(qǐng)求與響應(yīng)的處理擦秽,src/http/axios.js
- 導(dǎo)入配置文件的信息到axios對(duì)象
- 發(fā)送請(qǐng)求的時(shí)候攜帶token码荔,如果token不存在,則重定向到登錄頁(yè)面
- 統(tǒng)一處理響應(yīng)
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 請(qǐng)求攔截器
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 響應(yīng)攔截器
instance.interceptors.response.use(
response => {
return response.data
},
err => {
if (err && err.response) {
switch (err.response.status) {
case 400:
err.message = '請(qǐng)求錯(cuò)誤'
break
case 401:
err.message = '未授權(quán)感挥,請(qǐng)登錄'
break
case 403:
err.message = '拒絕訪問(wèn)'
break
case 404:
err.message = `請(qǐng)求地址出錯(cuò): ${err.response.config.url}`
break
case 408:
err.message = '請(qǐng)求超時(shí)'
break
case 500:
err.message = '服務(wù)器內(nèi)部錯(cuò)誤'
break
case 501:
err.message = '服務(wù)未實(shí)現(xiàn)'
break
case 502:
err.message = '網(wǎng)關(guān)錯(cuò)誤'
break
case 503:
err.message = '服務(wù)不可用'
break
case 504:
err.message = '網(wǎng)關(guān)超時(shí)'
break
case 505:
err.message = 'HTTP版本不受支持'
break
default:
}
}
console.error(err)
return Promise.reject(err)
}
)
// 請(qǐng)求處理
instance(options).then(res => {
resolve(res)
return false
}).catch(error => {
reject(error)
})
})
}
5.5 掛載api缩搅,可以通過(guò) "this.$api.模塊.方法" 的方式調(diào)用API。
- src/http/index.js
// 導(dǎo)入所有接口
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
/*
* 接口統(tǒng)一集成模塊
*/
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'
// 默認(rèn)全部導(dǎo)出
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'
/*
* 系統(tǒng)配置模塊
*/
// 保存
export const save = (data) => {
return axios({
url: '/config/save',
method: 'post',
data
})
}
// 刪除
export const batchDelete = (data) => {
return axios({
url: '/config/delete',
method: 'post',
data
})
}
// 分頁(yè)查詢
export const findPage = (data) => {
return axios({
url: '/config/findPage',
method: 'post',
data
})
}
import axios from '../axios'
/*
* 機(jī)構(gòu)管理模塊
*/
// 保存
export const save = (data) => {
return axios({
url: '/dept/save',
method: 'post',
data
})
}
// 刪除
export const batchDelete = (data) => {
return axios({
url: '/dept/delete',
method: 'post',
data
})
}
// 查詢機(jī)構(gòu)樹(shù)
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
})
}
// 分頁(yè)查詢
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
})
}
// 分頁(yè)查詢
export const findPage = (data) => {
return axios({
url: '/log/findPage',
method: 'post',
data
})
}
import axios from '../axios'
/*
* 系統(tǒng)登錄模塊
*/
// 登錄
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
})
}
// 分頁(yè)查詢
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
})
}
// 查找導(dǎo)航菜單樹(shù)
export const findNavTree = (params) => {
return axios({
url: '/menu/findNavTree',
method: 'get',
params
})
}
// 查找導(dǎo)航菜單樹(shù)
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
})
}
// 分頁(yè)查詢
export const findPage = (data) => {
return axios({
url: '/role/findPage',
method: 'post',
data
})
}
// 查詢?nèi)?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
})
}
// 分頁(yè)查詢
export const findPage = (data) => {
return axios({
url: '/user/findPage',
method: 'post',
data
})
}
// 導(dǎo)出Excel用戶信息
export const exportUserExcelFile = (data) => {
return axios({
url: '/user/exportUserExcelFile',
method: 'post',
data
})
}
// 查找用戶的菜單權(quán)限標(biāo)識(shí)集合
export const findPermissions = (params) => {
return axios({
url: '/user/findPermissions',
method: 'get',
params
})
}
// 根據(jù)用戶名查找
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) {
// 其它處理
})
}
四触幼、國(guó)際化
- 安裝依賴
npm install vue-i18n@8.26.5
- 配置src/i18n/index.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
// 注冊(cè)i18n實(shí)例并引入語(yǔ)言文件硼瓣,文件格式等下解析
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": "首頁(yè)",
"login": "登錄",
"logout": "退出登錄",
"doc": "文檔",
"blog": "博客",
"projectRepo": "項(xiàng)目",
"myMsg": "我的消息",
"config": "系統(tǒng)配置",
"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/>'
})
- 切換語(yǔ)言函數(shù):
changeLanguage(lang) {
lang === '' ? 'zh_cn' : lang
this.$i18n.locale = lang
}
- 使用方法:
# html中使用
{{$t('common.doc')}}
# js中使用
i18n.t('message.timeout')
五、全局狀態(tài)
- 安裝
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堂鲤。是屬于應(yīng)用內(nèi)的全局性的配置,比如主題色媒峡、導(dǎo)航欄收縮狀態(tài)等瘟栖,詳見(jiàn)注釋。
export default {
state: {
test: false, // 測(cè)試
menuRouteLoaded: false // 菜單和路由是否已經(jīng)加載
},
getters: {
test (state) {
return state.test
}
},
mutations: {
setTest (state, payload) {
state.test = payload.test
},
menuRouteLoaded (state, menuRouteLoaded) { // 改變菜單和路由的加載狀態(tài)
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/>'
})
- 通過(guò)computed計(jì)算屬性引入store屬性谅阿,
computed: {
...mapState({
***: state => state.app.***
})
}
- 通過(guò)語(yǔ)句this.$store.commit('mothodName', {})來(lái)修改值
六半哟、全站配置
- 樣式文件src/assets/css/site.css
# 內(nèi)容
* {
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調(diào)整tab為2個(gè)空格
# .eslintrc.js -> rules中添加
"indent": ["error", "tab"]
七签餐、自定義圖標(biāo)功能
打開(kāi)阿里icon寓涨,注冊(cè) >登錄>圖標(biāo)管理>我的項(xiàng)目。項(xiàng)目名稱:el-icon-third氯檐。