從0到1搭建Element的后臺(tái)框架的方法步驟
由于最近公司要開(kāi)發(fā)一個(gè)后臺(tái)管理系統(tǒng),查閱了很多vue框架,本人覺(jué)得element簡(jiǎn)潔,方便,于是選擇它作為我們的首選框架,并分享給大家,如果您覺(jué)得有需要改進(jìn)的地方可以提出來(lái)一起探討,Github地址。本文篇幅比較長(zhǎng),希望同學(xué)們可以耐心的讀下去,如有不懂可以下方留言
一、初始化項(xiàng)目
首先全局安裝的vue框架,這里是用的npm包管理工具來(lái)安裝的,如果你的網(wǎng)不是很好的話可以先安裝淘寶鏡像 npm install -g cnpm -registry=https://registry.npm.taobao.org,然后通過(guò)cnpm來(lái)安裝
cnpm install -g @vue/cli or npm install -g @vue/cli
其次開(kāi)始安裝vue腳手架,當(dāng)前是第三版本vue-cli 3.x
cnpm install -g @vue/cli
安裝完成后,你還可以用這個(gè)命令來(lái)檢查其版本是否正確 (3.x):
vue --version
安裝腳手架后開(kāi)始創(chuàng)建我們的項(xiàng)目
vue create vue-admin-project
隨后會(huì)出現(xiàn)兩個(gè)選項(xiàng)

選擇第二項(xiàng)并繼續(xù),并選擇自己需要配置的功能,完成后并繼續(xù),然后開(kāi)始生成項(xiàng)目
項(xiàng)目初始化成功

接下來(lái)按照上面的提示運(yùn)行 cd app以及啟動(dòng)本地服務(wù)器 npm run serve,當(dāng)運(yùn)行完成之后會(huì)提示你打來(lái)本地端口 http://localhost:8080,會(huì)出現(xiàn)歡迎頁(yè)面,此時(shí)代表你的vue項(xiàng)目初始化完成。

二、文件目錄介紹與整理
整理前的初始目錄
|-- vue-admin-project |-- .gitignore //git項(xiàng)目忽視文件 |-- babel.config.js //babel 配置文件 |-- package-lock.json //記錄安裝包的具體版本號(hào) |-- package.json //包的類型 |-- README.md |-- public //項(xiàng)目打包后的目錄 | |-- favicon.ico | |-- index.html |-- src //項(xiàng)目開(kāi)發(fā)目錄 |-- App.vue //主入口文件 |-- main.js //主入口文件 |-- router.js //vue-router文件 |-- store.js //vuex |-- assets //靜態(tài)文件 |-- logo.png |-- components //組件存放目錄 |-- HelloWorld.vue |-- views //視圖目錄 |-- About.vue |-- Home.vue
整理后的目錄,主要更改 /src文件夾下的目錄
|-- vue-admin-project |-- .gitignore |-- babel.config.js |-- package-lock.json |-- package.json |-- README.md |-- public |-- favicon.ico |-- index.html |-- src |-- App.vue |-- main.js |-- assets |-- logo.png |-- components |-- HelloWorld.vue |-- router //路由配置文件夾 |-- router.js |-- store //狀態(tài)管理文件夾 |-- store.js |-- views |-- About.vue |-- Home.vue
三、開(kāi)發(fā)環(huán)境與線上環(huán)境配置
vue-cli 3.0x與vue-cli 2.0x最主要的區(qū)別是項(xiàng)目結(jié)構(gòu)目錄精簡(jiǎn)化,這也帶來(lái)了許多問(wèn)題,很多配置需要自己配置,由于2.0x版本中直接在 cofig/文件夾下面配置開(kāi)發(fā)環(huán)境與線上環(huán)境,3.0x則需要自己配置。
首先配置開(kāi)發(fā)環(huán)境,在項(xiàng)目根目錄下新建一個(gè)文件 .env文件。
NODE_ENV="development" //開(kāi)發(fā)環(huán)境 BASE_URL="http://localhost:3000/" //開(kāi)發(fā)環(huán)境接口地址
接下來(lái)我們配置線上環(huán)境,同樣在項(xiàng)目根目錄新建一個(gè)文件 .env.prod這就表明是生產(chǎn)環(huán)境。
NODE_ENV="production" //生產(chǎn)環(huán)境 BASE_URL="url" //生產(chǎn)環(huán)境的地址
現(xiàn)在我們?nèi)绾卧陧?xiàng)目中判斷當(dāng)前環(huán)境呢?
我們可以根據(jù) process.env.BASE_URL來(lái)獲取它是線上環(huán)境還是開(kāi)發(fā)環(huán)境,后面會(huì)有運(yùn)用
if(process.env.NODE_ENV='development'){
console.log( process.env.BASE_URL) //http://localhost:3000/
}else{
console.log( process.env.BASE_URL) //url
}
至此,我們成功的配置好了開(kāi)發(fā)環(huán)境與線上環(huán)境。
四、vue.config.js配置
講到 vue.config.js項(xiàng)目配置文件,又不得不說(shuō)下3.x和2.x的區(qū)別,2.x里面webpack相關(guān)的配置項(xiàng)直接在項(xiàng)目的 build/webpack.base.conf.js里面配置,而3.x完全在 vue.config.js中配置,這使得整個(gè)項(xiàng)目看起來(lái)更加簡(jiǎn)潔明了,項(xiàng)目運(yùn)行速度更快。
由于項(xiàng)目初始化的時(shí)候沒(méi)有 vue.config.js配置文件,因此我們需要在項(xiàng)目根目錄下新建一個(gè) vue.config.js配置項(xiàng)。
在這個(gè)配置項(xiàng)里面,本項(xiàng)目主要是配置三個(gè)東西,第一個(gè)就是目錄別名 alias,另一個(gè)是項(xiàng)目啟動(dòng)時(shí)自動(dòng)打開(kāi)瀏覽器,最后一個(gè)就是處理引入的全局scss文件。當(dāng)然有 vue.config.js的配置遠(yuǎn)遠(yuǎn)不止這幾項(xiàng),有興趣的同學(xué)可以去看看vue.config.js具體配置,具體代碼如下。
let path=require('path');
function resolve(dir){
return path.join(__dirname,dir)
}
module.exports = {
chainWebpack: config => {
//設(shè)置別名
config.resolve.alias
.set('@',resolve('src'))
},
devServer: {
open:true //打開(kāi)瀏覽器窗口
},
//定義scss全局變量
css: {
loaderOptions: {
sass: {
data: `@import "@/assets/scss/global.scss";`
}
}
}
}
五、ElementUI引入
開(kāi)始安裝ElementUI
vue add element
接下來(lái)兩個(gè)選項(xiàng),第一個(gè)是全部引入,第二個(gè)是按需引入,我選擇第一個(gè) Fully import,大家可以按照自己的項(xiàng)目而定。接下來(lái)會(huì)詢問(wèn)是否引入scss,這里選擇是,語(yǔ)言選擇zh-cn。
接下來(lái)會(huì)提示安裝成功,并在項(xiàng)目首頁(yè)有一個(gè)element樣式的按鈕。
六、vue-router路由介紹入
路由管理也是本項(xiàng)目核心部分。
1.引入文件
import Vue from 'vue' import Router from 'vue-router' import store from '../store/store' //引入狀態(tài)管理 import NProgress from 'nprogress' //引入進(jìn)度條組件 cnpm install nprogress --save import 'nprogress/nprogress.css' Vue.use(Router)
2.路由懶加載
/**
*@parma {String} name 文件夾名稱
*@parma {String} component 視圖組件名稱
*/
const getComponent = (name,component) => () => import(`@/views/${name}/${component}.vue`);
3.路由配置
const myRouter=new Router({
routes: [
{
path: '/',
redirect: '/home',
component: getComponent('login','index')
},
{
path: '/login',
name: 'login',
component: getComponent('login','index')
},
{
path: '/',
component:getComponent('layout','Layout'),
children:[{
path:'/home',
name:'home',
component: getComponent('home','index'),
meta:{title:'首頁(yè)'}
},
{
path:'/icon',
component: getComponent('icons','index'),
name:'icon',
meta:{title:'自定義圖標(biāo)'}
},
{
path:'/editor',
component: getComponent('component','editor'),
name:'editor',
meta:{title:'富文本編譯器'}
},
{
path:'/countTo',
component: getComponent('component','countTo'),
name:'countTo',
meta:{title:'數(shù)字滾動(dòng)'}
},
{
path:'/tree',
component: getComponent('component','tree'),
name:'tree',
meta:{title:'自定義樹(shù)'}
},
{
path:'/treeTable',
component: getComponent('component','treeTable'),
name:'treeTable',
meta:{title:'表格樹(shù)'}
},
{
path:'/treeSelect',
component: getComponent('component','treeSelect'),
name:'treeSelect',
meta:{title:'下拉樹(shù)'}
},
{
path:'/draglist',
component: getComponent('draggable','draglist'),
name:'draglist',
meta:{title:'拖拽列表'}
},
{
path:'/dragtable',
component: getComponent('draggable','dragtable'),
name:'dragtable',
meta:{title:'拖拽表格'}
},
{
path:'/cricle',
component: getComponent('charts','cricle'),
name:'cricle',
meta:{title:'餅圖'}
},
]
}
]
})
4.本項(xiàng)目存在一個(gè)token,來(lái)驗(yàn)證權(quán)限問(wèn)題,因此進(jìn)入頁(yè)面的時(shí)候需要判斷是否存在token,如果不存在則跳轉(zhuǎn)到登陸頁(yè)面
//判斷是否存在token
myRouter.beforeEach((to,from,next)=>{
NProgress.start()
if (to.path !== '/login' && !store.state.token) {
next('/login') //跳轉(zhuǎn)登錄
NProgress.done() // 結(jié)束Progress
}
next()
})
myRouter.afterEach(() => {
NProgress.done() // 結(jié)束Progress
})
5.導(dǎo)出路由
export default myRouter
七、axios引入并封裝
1.接口處理我選擇的是axios,由于它遵循promise規(guī)范,能很好的避免回調(diào)地獄?,F(xiàn)在我們開(kāi)始安裝
cnpm install axios -S
2.在 src目錄下新建文件夾命名為 api,里面新建兩個(gè)文件,一個(gè)是 api.js,用于接口的整合,另一個(gè)是 request.js,根據(jù)相關(guān)業(yè)務(wù)封裝axios請(qǐng)求。
request.js
1.引入依賴
import axios from "axios";
import router from "../router/router";
import {
Loading
} from "element-ui";
import {messages} from '../assets/js/common.js' //封裝的提示文件
import store from '../store/store' //引入vuex
2.編寫(xiě)axios基本設(shè)置
axios.defaults.timeout = 60000; //設(shè)置接口超時(shí)時(shí)間 axios.defaults.baseURL = process.env.BASE_URL; //根據(jù)環(huán)境設(shè)置基礎(chǔ)路徑 axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8"; //設(shè)置編碼 let loading = null; //初始化loading
3.編寫(xiě)請(qǐng)求攔截,也就是說(shuō)在請(qǐng)求接口前要做的事情
/*
*請(qǐng)求前攔截
*用于處理需要請(qǐng)求前的操作
*/
axios.interceptors.request.use(
config => {
loading = Loading.service({
text: "正在加載中......",
fullscreen: true
});
if (store.state.token) {
config.headers["Authorization"] = "Bearer " + store.state.token;
}
return config;
},
error => {
return Promise.reject(error);
}
);
4.編寫(xiě)請(qǐng)求響應(yīng)攔截,用于處理數(shù)據(jù)返回操作
/*
*請(qǐng)求響應(yīng)攔截
*用于處理數(shù)據(jù)返回后的操作
*/
axios.interceptors.response.use(
response => {
return new Promise((resolve, reject) => {
//請(qǐng)求成功后關(guān)閉加載框
if (loading) {
loading.close();
}
const res = response.data;
if (res.err_code === 0) {
resolve(res)
} else{
reject(res)
}
})
},
error => {
console.log(error)
//請(qǐng)求成功后關(guān)閉加載框
if (loading) {
loading.close();
}
//斷網(wǎng)處理或者請(qǐng)求超時(shí)
if (!error.response) {
//請(qǐng)求超時(shí)
if (error.message.includes("timeout")) {
console.log("超時(shí)了");
messages("error", "請(qǐng)求超時(shí),請(qǐng)檢查互聯(lián)網(wǎng)連接");
} else {
//斷網(wǎng),可以展示斷網(wǎng)組件
console.log("斷網(wǎng)了");
messages("error", "請(qǐng)檢查網(wǎng)絡(luò)是否已連接");
}
return;
}
const status = error.response.status;
switch (status) {
case 500:
messages("error", "服務(wù)器內(nèi)部錯(cuò)誤");
break;
case 404:
messages(
"error",
"未找到遠(yuǎn)程服務(wù)器"
);
break;
case 401:
messages("warning", "用戶登陸過(guò)期,請(qǐng)重新登陸");
localStorage.removeItem("token");
setTimeout(() => {
router.replace({
path: "/login",
query: {
redirect: router.currentRoute.fullPath
}
});
}, 1000);
break;
case 400:
messages("error", "數(shù)據(jù)異常");
break;
default:
messages("error", error.response.data.message);
}
return Promise.reject(error);
}
);
5.請(qǐng)求相關(guān)的事情已經(jīng)完成,現(xiàn)在開(kāi)始封裝get,post請(qǐng)求
/*
*get方法,對(duì)應(yīng)get請(qǐng)求
*@param {String} url [請(qǐng)求的url地址]
*@param {Object} params [請(qǐng)求時(shí)候攜帶的參數(shù)]
*/
export function get(url, params) {
return new Promise((resolve, reject) => {
axios
.get(url, {
params
})
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
/*
*post方法,對(duì)應(yīng)post請(qǐng)求
*@param {String} url [請(qǐng)求的url地址]
*@param {Object} params [請(qǐng)求時(shí)候攜帶的參數(shù)]
*/
export function post(url, params) {
return new Promise((resolve, reject) => {
axios
.post(url, params)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
api.js
封裝好axios的業(yè)務(wù)邏輯之后自然要開(kāi)始,運(yùn)用,首先引入 get以及 post方法
import {get,post} from './request';
接下來(lái)開(kāi)始封裝接口,并導(dǎo)出
//登陸
export const login=(login)=>post('/api/post/user/login',login)
//上傳
export const upload=(upload)=>get('/api/get/upload',upload)
那我們?nèi)绾握{(diào)用接口呢?以登陸頁(yè)面為例。
import { login } from "@/api/api.js"; //引入login
/**
* @oarma {Object} login 接口傳遞的參數(shù)
*/
login(login)
.then(res => {
//成功之后要做的事情
})
.catch(err => {
//出錯(cuò)時(shí)要做的事情
});
接口相關(guān)的邏輯已經(jīng)處理完。
八、vuex引入
由于vue項(xiàng)目中組件之間傳遞數(shù)據(jù)比較復(fù)雜,因此官方引入了一個(gè)全局狀態(tài)管理的東東,也就是現(xiàn)在要說(shuō)的vuex,vuex能更好的管理數(shù)據(jù),方便組件之間的通信。
現(xiàn)在在store文件夾下面新建四個(gè)文件 state.js, mutations.js, getter.js, action.js。
state.js
state就是Vuex中的公共的狀態(tài), 我是將state看作是所有組件的data, 用于保存所有組件的公共數(shù)據(jù).
const state = {
token: '',//權(quán)限驗(yàn)證
tagsList: [], //打開(kāi)的標(biāo)簽頁(yè)個(gè)數(shù),
isCollapse: false, //側(cè)邊導(dǎo)航是否折疊
}
export default state //導(dǎo)出
mutations.js
我將mutaions理解為store中的methods, mutations對(duì)象中保存著更改數(shù)據(jù)的回調(diào)函數(shù),該函數(shù)名官方規(guī)定叫type, 第一個(gè)參數(shù)是state, 第二參數(shù)是payload, 也就是自定義的參數(shù).改變state的值必須經(jīng)過(guò)mutations
const mutations = {
//保存token
COMMIT_TOKEN(state, object) {
state.token = object.token;
},
//保存標(biāo)簽
TAGES_LIST(state, arr) {
state.tagsList = arr;
},
IS_COLLAPSE(state, bool) {
state.isCollapse = bool;
}
}
export default mutations
getter.js
我將getters屬性理解為所有組件的computed屬性,也就是計(jì)算屬性。vuex的官方文檔也是說(shuō)到可以將getter理解為store的計(jì)算屬性, getters的返回值會(huì)根據(jù)它的依賴被緩存起來(lái),且只有當(dāng)它的依賴值發(fā)生了改變才會(huì)被重新計(jì)算。
const getters={
//你要計(jì)算的屬性
}
export default getters
action.js
actions 類似于 mutations,不同在于:
1.actions提交的是mutations而不是直接變更狀態(tài)
2.actions中可以包含異步操作, mutations中絕對(duì)不允許出現(xiàn)異步
3.actions中的回調(diào)函數(shù)的第一個(gè)參數(shù)是context, 是一個(gè)與store實(shí)例具有相同屬性和方法的對(duì)象
const actions={
}
export default actions
store.js
store.js是vuex模塊整合文件,由于刷新頁(yè)面會(huì)造成vuex數(shù)據(jù)丟失,所以這里引入了一個(gè)vuex數(shù)據(jù)持久話插件,將state里面的數(shù)據(jù)保存到localstorage。
安裝 vuex-persistedstate
npm install vuex-persistedstate --save
import Vue from 'vue'
import Vuex from 'vuex'
import state from "./state";
import mutations from "./mutations";
import actions from "./actions";
import getters from "./getters";
//引入vuex 數(shù)據(jù)持久化插件
import createPersistedState from "vuex-persistedstate"
Vue.use(Vuex)
export default new Vuex.Store({
state,
mutations,
actions,
getters,
plugins: [createPersistedState()]
})
至此vuex引入完畢,如同學(xué)們還有不明白的可以去翻閱vuex文檔。
九、首頁(yè)布局介紹
現(xiàn)在我們開(kāi)始進(jìn)行頁(yè)面的布局。首先我們來(lái)分析下首頁(yè)的情況

- 側(cè)邊欄
- 頂部欄
- 內(nèi)容部分
首先我們?cè)?view文件夾下面新建一個(gè) layout文件夾,里面再添加一個(gè) layout.vue,以及 compentents文件夾。
側(cè)邊欄
在compentents文件夾下面新建一個(gè) Aside.vue文件,實(shí)現(xiàn)路由跳轉(zhuǎn)相關(guān)的邏輯,運(yùn)用了element導(dǎo)航菜單的路由模式,如有不明白的可以去ElementUI導(dǎo)航菜單去看看。
<template>
<div class="aside">
<el-menu
:default-active="onRoutes"
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose"
:collapse="isCollapse"
active-text-color="#bdb7ff"
router
>
<template v-for="item in items">
<template v-if="item.subs">
<el-submenu :index="item.index" :key="item.index">
<template slot="title">
<i :class="item.icon"></i>
<span slot="title">{{ item.title }}</span>
</template>
<template v-for="subItem in item.subs">
<el-submenu v-if="subItem.subs" :index="subItem.index" :key="subItem.index">
<template slot="title">{{ subItem.title }}</template>
<el-menu-item
v-for="(threeItem,i) in subItem.subs"
:key="i"
:index="threeItem.index"
>{{ threeItem.title }}</el-menu-item>
</el-submenu>
<el-menu-item v-else :index="subItem.index" :key="subItem.index">{{ subItem.title }}</el-menu-item>
</template>
</el-submenu>
</template>
<template v-else>
<el-menu-item :index="item.index" :key="item.index">
<i :class="item.icon"></i>
<span slot="title">{{ item.title }}</span>
</el-menu-item>
</template>
</template>
</el-menu>
</div>
</template>
import { mapState } from "vuex";
export default {
data() {
return {
//配置目錄
items: [
{
icon: "el-icon-edit-outline",
index: "home",
title: "系統(tǒng)首頁(yè)"
},
{
icon: "el-icon-edit-outline",
index: "icon",
title: "自定義圖標(biāo)"
},
{
icon: "el-icon-edit-outline",
index: "component",
title: "組件",
subs: [
{
index: "editor",
title: "富文本編譯器"
},
{
index: "countTo",
title: "數(shù)字滾動(dòng)"
},
{
index: "trees",
title: "樹(shù)形控件",
subs: [
{
index: "tree",
title: "自定義樹(shù)"
},
{
index: "treeSelect",
title: "下拉樹(shù)"
}
// ,{
// index:'treeTable',
// title:'表格樹(shù)',
// }
]
},
]
},
{
icon: "el-icon-edit-outline",
index: "draggable",
title: "拖拽",
subs: [
{
index: "draglist",
title: "拖拽列表"
},
{
index: "dragtable",
title: "拖拽表格"
}
]
},
{
icon: "el-icon-edit-outline",
index: "charts",
title: "圖表",
subs: [
{
index: "cricle",
title: "餅圖"
},
]
},
{
icon: "el-icon-edit-outline",
index: "7",
title: "錯(cuò)誤處理",
subs: [
{
index: "permission",
title: "權(quán)限測(cè)試"
},
{
index: "404",
title: "404頁(yè)面"
}
]
},
]
};
},
computed: {
onRoutes() {
return this.$route.path.replace("/", "");
},
...mapState(["isCollapse"]) //從vuex里面獲取菜單是否折疊
},
methods: {
//下拉展開(kāi)
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
//下來(lái)關(guān)閉
handleClose(key, keyPath) {
console.log(key, keyPath);
}
}
};
頂部欄
在 view/compentents文件夾下面新建一個(gè) Header.vue
<template>
<div class="head-container clearfix">
<div class="header-left">
<showAside :toggle-click="toggleClick"/>
</div>
<div class="header-right">
<div class="header-user-con">
<!-- 全屏顯示 -->
<div class="btn-fullscreen" @click="handleFullScreen">
<el-tooltip effect="dark" :content="fullscreen?`取消全屏`:`全屏`" placement="bottom">
<i class="el-icon-rank"></i>
</el-tooltip>
</div>
<!-- 消息中心 -->
<div class="btn-bell">
<el-tooltip effect="dark" :content="message?`有${message}條未讀消息`:`消息中心`" placement="bottom">
<router-link to="/tabs">
<i class="el-icon-bell"></i>
</router-link>
</el-tooltip>
<span class="btn-bell-badge" v-if="message"></span>
</div>
<!-- 用戶名下拉菜單 -->
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<img
src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3266090804,66355162&fm=26&gp=0.jpg"
class="user-avatar"
>
{{username }}<i class="el-icon-caret-bottom"/>
</div>
<el-dropdown-menu slot="dropdown" class="user-dropdown">
<router-link class="inlineBlock" to="/">
<el-dropdown-item>首頁(yè)</el-dropdown-item>
</router-link>
<el-dropdown-item>個(gè)人設(shè)置</el-dropdown-item>
<el-dropdown-item divided>
<span style="display:block;" @click="logout">退出登陸</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
</template>
import showAside from "@/components/showAside.vue";//引入了一個(gè)側(cè)邊欄是否折疊的組件
export default {
// name:'header',
components: {
showAside
},
data() {
return {
fullscreen: false,
name: "linxin",
message: 2,
username: "zyh"
};
},
computed: {
isCollapse: {
get: function() {
return this.$store.state.isCollapse;
},
set: function(newValue) {
console.log(newValue);
this.$store.commit("IS_COLLAPSE", newValue);//提交到vuex
}
}
},
methods: {
toggleClick() {
this.isCollapse = !this.isCollapse;
},
// 用戶名下拉菜單選擇事件
logout(command) {
this.$router.push("/login");
},
// 全屏事件
handleFullScreen() {
let element = document.documentElement;
if (this.fullscreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
} else {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.msRequestFullscreen) {
// IE11
element.msRequestFullscreen();
}
}
this.fullscreen = !this.fullscreen;
}
}
};
現(xiàn)在在 src/components文件夾下面新建一個(gè) showAside.vue組件
<template> <div class="clearfix"> <div class="showAside pull-left" @click="toggleClick"> <i class="el-icon-menu"></i> </div> </div> </template>
export default {
name: "showAside",
props: {
toggleClick: {
type: Function,
default: null
}
}
};
頂部導(dǎo)航欄標(biāo)簽組件
在 view/compentents文件夾下面新建一個(gè) Tags.vue
<template>
<!-- 打開(kāi)標(biāo)簽的容器 -->
<div class="tags">
<ul>
<li
class="tags-li"
v-for="(item,index) in tagsList"
:key="index"
:class="{'active': isActive(item.path)}"
>
<router-link :to="item.path" class="tags-li-title">{{item.title}}</router-link>
<span class="tags-li-icon" @click="closeTags(index)">
<i class="el-icon-close"></i>
</span>
</li>
</ul>
<div class="tags-close-box">
<el-dropdown @command="handleCommand">
<el-button size="mini" type="primary">
標(biāo)簽選項(xiàng)
<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu size="small" slot="dropdown">
<el-dropdown-item command="closeOther">關(guān)閉其他</el-dropdown-item>
<!-- <el-dropdown-item command="all">關(guān)閉所有</el-dropdown-item> -->
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
import { messages } from "@/assets/js/common.js";
export default {
created() {
//判斷標(biāo)簽里面是否有值 有的話直接加載
if (this.tagsList.length == 0) {
this.setTags(this.$route);
}
},
computed: {
//computed 方法里面沒(méi)有set方法因此不能使用mapState,需要重新定義set方法
tagsList: {
get: function() {
return this.$store.state.tagsList;
},
set: function(newValue) {
this.$store.commit("TAGES_LIST", newValue);
// this.$store.state.tagsList = newValue;
}
}
},
watch: {
//監(jiān)聽(tīng)路由變化
$route(newValue, oldValue) {
this.setTags(newValue);
}
},
methods: {
//選中的高亮
isActive(path) {
return path === this.$route.fullPath;
},
handleCommand(command) {
if (command == "closeOther") {
// 關(guān)閉其他標(biāo)簽
const curItem = this.tagsList.filter(item => {
return item.path === this.$route.fullPath;
});
this.tagsList = curItem;
}
},
//添加標(biāo)簽
setTags(route) {
let isIn = this.tagsList.some(item => {
//判斷標(biāo)簽是否存在
return item.path === route.fullPath;
});
//不存在
if (!isIn) {
// 判斷當(dāng)前的標(biāo)簽個(gè)數(shù)
if (this.tagsList.length >= 10) {
messages("warning", "當(dāng)標(biāo)簽大于10個(gè),請(qǐng)關(guān)閉后再打開(kāi)");
} else {
this.tagsList.push({
title: route.meta.title,
path: route.fullPath,
name: route.name
});
//存到vuex
this.$store.commit("TAGES_LIST", this.tagsList);
}
}
},
closeTags(index) {
console.log(this.tagsList.length);
if (this.tagsList.length == 1) {
messages("warning", "不可全都關(guān)閉");
} else {
//刪除當(dāng)前
let tags = this.tagsList.splice(index, 1);
this.$store.commit("TAGES_LIST", this.tagsList);
}
}
}
};
接下來(lái)在 view/compentents文件夾下面新建一個(gè) Main.vue,主要是將頂部導(dǎo)航標(biāo)簽欄以及內(nèi)容部分結(jié)合起來(lái)。
<template>
<div class="container">
<tags />
<div class="contents">
<transition name="fade-transform" mode="out-in">
<router-view></router-view>
</transition>
</div>
</div>
</template>
import Tags from './Tags.vue'
export default {
components:{
Tags
}
}
相關(guān)組件寫(xiě)好,在layout組件中匯總
<template> <div class="wrapper"> <Aside class="aside-container"/> <div class="main-container" :class="isCollapse==true?'container_collapse':''"> <Header/> <Main/> </div> </div> </template>
import Aside from "./components/Aside.vue";
import Header from "./components/Header.vue";
import Main from "./components/Main.vue";
import { mapState } from "vuex";
export default {
name: "Layout",
components: {
Aside,
Header,
Main
},
computed: {
...mapState(["isCollapse"])
}
};
至此首頁(yè)布局已經(jīng)規(guī)劃完成,如有不太清楚的可以查看項(xiàng)目地址
十、結(jié)語(yǔ)
管理系統(tǒng)是多種多樣的,每家公司都有不同的業(yè)務(wù)邏輯,本篇文章也只是拋磚引玉,還有許多需要修正改進(jìn)的地方,如果同學(xué)們有更好的想法可以提出來(lái)希望大家一起完善本項(xiàng)目。
|-- vue-admin-project |-- .env |-- .env.prod |-- .env.test |-- .gitignore |-- babel.config.js |-- package-lock.json |-- package.json |-- README.md |-- vue.config.js |-- public | |-- favicon.ico | |-- index.html |-- src |-- App.vue |-- element-variables.scss |-- main.js |-- api | |-- api.js | |-- request.js |-- assets | |-- logo.png | |-- css | | |-- normalize.css | | |-- public.css | |-- icon | | |-- demo.css | | |-- demo_index.html | | |-- iconfont.css | | |-- iconfont.eot | | |-- iconfont.js | | |-- iconfont.svg | | |-- iconfont.ttf | | |-- iconfont.woff | | |-- iconfont.woff2 | |-- img | | |-- tou.jpg | |-- js | | |-- common.js | |-- scss | |-- global.scss |-- components | |-- showAside.vue |-- plugins | |-- element.js |-- router | |-- router.js |-- store | |-- actions.js | |-- getters.js | |-- mutations.js | |-- state.js | |-- store.js |-- views |-- layout | |-- Layout.vue | |-- components | |-- Aside.vue | |-- Header.vue | |-- Main.vue | |-- Tags.vue
最后項(xiàng)目目錄文件結(jié)構(gòu)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue3?vite異步組件及路由懶加載實(shí)戰(zhàn)示例
這篇文章主要為大家介紹了vue3?vite異步組件及路由懶加載實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
mockjs+vue頁(yè)面直接展示數(shù)據(jù)的方法
這篇文章主要介紹了mockjs+vue頁(yè)面直接展示數(shù)據(jù)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
vue 使用 echarts 繪制中國(guó)地圖的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue 使用 echarts 繪制中國(guó)地圖,內(nèi)容包括插入echarts所需模塊及完整的代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01
vue3+element-plus動(dòng)態(tài)路由菜單示例代碼
這篇文章主要介紹了vue3+element-plus動(dòng)態(tài)路由菜單示例代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-11-11
解決vue-cli項(xiàng)目webpack打包后iconfont文件路徑的問(wèn)題
今天小編就為大家分享一篇解決vue-cli項(xiàng)目webpack打包后iconfont文件路徑的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
簡(jiǎn)單了解Vue + ElementUI后臺(tái)管理模板
這篇文章主要介紹了簡(jiǎn)單了解Vue + ElementUI后臺(tái)管理模板,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
詳解vue 配合vue-resource調(diào)用接口獲取數(shù)據(jù)
本篇文章主要介紹了vue 配合vue-resource調(diào)用接口獲取數(shù)據(jù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
vue draggable resizable gorkys與v-chart使用與總結(jié)
這篇文章主要介紹了vue draggable resizable gorkys與v-chart使用與總結(jié),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09

