因爲最近公司要開發一個後臺管理系統,查閱了不少vue框架,本人以爲element簡潔,方便,因而選擇它做爲咱們的首選框架,並分享給你們,若是您以爲有須要改進的地方能夠提出來一塊兒探討,Github地址。本文篇幅比較長,但願同窗們能夠耐心的讀下去,若有不懂能夠下方留言javascript
目錄 |
---|
1.目錄 |
2.初始化項目 |
3.文件目錄介紹與整理 |
4.開發環境與線上環境配置 |
5.vue.config.js配置 |
6.ElementUI引入 |
7.vue-router路由介紹 |
8.axios引入並封裝 |
9.vuex引入 |
10.首頁佈局介紹 |
11.結語 |
首先全局安裝vue腳手架,當前是第三版本vue-cli3.x,這裏是用的npm包管理工具來安裝的,若是你的網不是很好的話能夠先安裝淘寶鏡像 npm install -g cnpm -registry=https://registry.npm.taobao.org
,而後經過cnpm來安裝css
cnpm install -g @vue/cli or npm install -g @vue/cli
複製代碼
安裝完成後,你還能夠用這個命令來檢查其版本是否正確 (3.x):html
vue --version
複製代碼
安裝腳手架後開始建立咱們的項目vue
vue create vue-admin-project
複製代碼
隨後會出現兩個選項java
選擇第二項並繼續,並選擇本身須要配置的功能,完成後並繼續,而後開始生成項目 項目初始化成功 接下來按照上面的提示運行cd app
以及啓動本地服務器
npm run serve
,當運行完成以後會提示你打來本地端口
http://localhost:8080
,會出現歡迎頁面,此時表明你的vue項目初始化完成。
整理前的初始目錄webpack
|-- vue-admin-project
|-- .gitignore //git項目忽視文件
|-- babel.config.js //babel 配置文件
|-- package-lock.json //記錄安裝包的具體版本號
|-- package.json //包的類型
|-- README.md
|-- public //項目打包後的目錄
| |-- favicon.ico
| |-- index.html
|-- src //項目開發目錄
|-- App.vue //主入口文件
|-- main.js //主入口文件
|-- router.js //vue-router文件
|-- store.js //vuex
|-- assets //靜態文件
|-- logo.png
|-- components //組件存放目錄
|-- HelloWorld.vue
|-- views //視圖目錄
|-- About.vue
|-- Home.vue
複製代碼
整理後的目錄,主要更改/src
文件夾下的目錄ios
|-- 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 //狀態管理文件夾
|-- store.js
|-- views
|-- About.vue
|-- Home.vue
複製代碼
vue-cli 3.0x與vue-cli 2.0x最主要的區別是項目結構目錄精簡化,這也帶來了許多問題,不少配置須要本身配置,因爲2.0x版本中直接在cofig/
文件夾下面配置開發環境與線上環境,3.0x則須要本身配置。
首先配置開發環境,在項目根目錄下新建一個文件.env
文件。c++
NODE_ENV="development" //開發環境
BASE_URL="http://localhost:3000/" //開發環境接口地址
複製代碼
接下來咱們配置線上環境,一樣在項目根目錄新建一個文件.env.prod
這就代表是生產環境。git
NODE_ENV="production" //生產環境
BASE_URL="url" //生產環境的地址
複製代碼
如今咱們如何在項目中判斷當前環境呢?
咱們能夠根據process.env.BASE_URL
來獲取它是線上環境仍是開發環境,後面會有運用es6
if(process.env.NODE_ENV='development'){
console.log( process.env.BASE_URL) //http://localhost:3000/
}else{
console.log( process.env.BASE_URL) //url
}
複製代碼
至此,咱們成功的配置好了開發環境與線上環境。
講到vue.config.js
項目配置文件,又不得不說下3.x和2.x的區別,2.x裏面webpack相關的配置項直接在項目的build/webpack.base.conf.js
裏面配置,而3.x徹底在vue.config.js
中配置,這使得整個項目看起來更加簡潔明瞭,項目運行速度更快。
因爲項目初始化的時候沒有vue.config.js
配置文件,所以咱們須要在項目根目錄下新建一個vue.config.js
配置項。
在這個配置項裏面,本項目主要是配置三個東西,第一個就是目錄別名alias
,另外一個是項目啓動時自動打開瀏覽器,最後一個就是處理引入的全局scss文件。固然有vue.config.js
的配置遠遠不止這幾項,有興趣的同窗能夠去看看vue.config.js具體配置,具體代碼以下。
let path=require('path');
function resolve(dir){
return path.join(__dirname,dir)
}
module.exports = {
chainWebpack: config => {
//設置別名
config.resolve.alias
.set('@',resolve('src'))
},
devServer: {
open:true //打開瀏覽器窗口
},
//定義scss全局變量
css: {
loaderOptions: {
sass: {
data: `@import "@/assets/scss/global.scss";`
}
}
}
}
複製代碼
開始安裝ElementUI
vue add element
複製代碼
接下來兩個選項,第一個是所有引入,第二個是按需引入,我選擇第一個Fully import
,你們能夠按照本身的項目而定。接下來會詢問是否引入scss,這裏選擇是,語言選擇zh-cn。
接下來會提示安裝成功,並在項目首頁有一個element樣式的按鈕。
路由管理也是本項目核心部分。
1.引入文件
import Vue from 'vue'
import Router from 'vue-router'
import store from '../store/store' //引入狀態管理
import NProgress from 'nprogress' //引入進度條組件 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:'首頁'}
},
{
path:'/icon',
component: getComponent('icons','index'),
name:'icon',
meta:{title:'自定義圖標'}
},
{
path:'/editor',
component: getComponent('component','editor'),
name:'editor',
meta:{title:'富文本編譯器'}
},
{
path:'/countTo',
component: getComponent('component','countTo'),
name:'countTo',
meta:{title:'數字滾動'}
},
{
path:'/tree',
component: getComponent('component','tree'),
name:'tree',
meta:{title:'自定義樹'}
},
{
path:'/treeTable',
component: getComponent('component','treeTable'),
name:'treeTable',
meta:{title:'表格樹'}
},
{
path:'/treeSelect',
component: getComponent('component','treeSelect'),
name:'treeSelect',
meta:{title:'下拉樹'}
},
{
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.本項目存在一個token,來驗證權限問題,所以進入頁面的時候須要判斷是否存在token,若是不存在則跳轉到登錄頁面
//判斷是否存在token
myRouter.beforeEach((to,from,next)=>{
NProgress.start()
if (to.path !== '/login' && !store.state.token) {
next('/login') //跳轉登陸
NProgress.done() // 結束Progress
}
next()
})
myRouter.afterEach(() => {
NProgress.done() // 結束Progress
})
複製代碼
5.導出路由
export default myRouter
複製代碼
1.接口處理我選擇的是axios,因爲它遵循promise規範,能很好的避免回調地獄。如今咱們開始安裝
cnpm install axios -S
複製代碼
2.在src
目錄下新建文件夾命名爲api
,裏面新建兩個文件,一個是api.js
,用於接口的整合,另外一個是request.js
,根據相關業務封裝axios請求。
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.編寫axios基本設置
axios.defaults.timeout = 60000; //設置接口超時時間
axios.defaults.baseURL = process.env.BASE_URL; //根據環境設置基礎路徑
axios.defaults.headers.post["Content-Type"] =
"application/x-www-form-urlencoded;charset=UTF-8"; //設置編碼
let loading = null; //初始化loading
複製代碼
3.編寫請求攔截,也就是說在請求接口前要作的事情
/* *請求前攔截 *用於處理須要請求前的操做 */
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.編寫請求響應攔截,用於處理數據返回操做
/* *請求響應攔截 *用於處理數據返回後的操做 */
axios.interceptors.response.use(
response => {
return new Promise((resolve, reject) => {
//請求成功後關閉加載框
if (loading) {
loading.close();
}
const res = response.data;
if (res.err_code === 0) {
resolve(res)
} else{
reject(res)
}
})
},
error => {
console.log(error)
//請求成功後關閉加載框
if (loading) {
loading.close();
}
//斷網處理或者請求超時
if (!error.response) {
//請求超時
if (error.message.includes("timeout")) {
console.log("超時了");
messages("error", "請求超時,請檢查互聯網鏈接");
} else {
//斷網,能夠展現斷網組件
console.log("斷網了");
messages("error", "請檢查網絡是否已鏈接");
}
return;
}
const status = error.response.status;
switch (status) {
case 500:
messages("error", "服務器內部錯誤");
break;
case 404:
messages(
"error",
"未找到遠程服務器"
);
break;
case 401:
messages("warning", "用戶登錄過時,請從新登錄");
localStorage.removeItem("token");
setTimeout(() => {
router.replace({
path: "/login",
query: {
redirect: router.currentRoute.fullPath
}
});
}, 1000);
break;
case 400:
messages("error", "數據異常");
break;
default:
messages("error", error.response.data.message);
}
return Promise.reject(error);
}
);
複製代碼
5.請求相關的事情已經完成,如今開始封裝get,post請求
/* *get方法,對應get請求 *@param {String} url [請求的url地址] *@param {Object} params [請求時候攜帶的參數] */
export function get(url, params) {
return new Promise((resolve, reject) => {
axios
.get(url, {
params
})
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
/* *post方法,對應post請求 *@param {String} url [請求的url地址] *@param {Object} params [請求時候攜帶的參數] */
export function post(url, params) {
return new Promise((resolve, reject) => {
axios
.post(url, params)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
複製代碼
get
以及post
方法import {get,post} from './request';
複製代碼
接下來開始封裝接口,並導出
//登錄
export const login=(login)=>post('/api/post/user/login',login)
//上傳
export const upload=(upload)=>get('/api/get/upload',upload)
複製代碼
那咱們如何調用接口呢?以登錄頁面爲例。
import { login } from "@/api/api.js"; //引入login
複製代碼
/** * @oarma {Object} login 接口傳遞的參數 */
login(login)
.then(res => {
//成功以後要作的事情
})
.catch(err => {
//出錯時要作的事情
});
複製代碼
接口相關的邏輯已經處理完。
因爲vue項目中組件之間傳遞數據比較複雜,所以官方引入了一個全局狀態管理的東東,也就是如今要說的vuex,vuex能更好的管理數據,方便組件之間的通訊。
如今在store文件夾下面新建四個文件state.js
,mutations.js
,getter.js
,action.js
。
const state = {
token: '',//權限驗證
tagsList: [], //打開的標籤頁個數,
isCollapse: false, //側邊導航是否摺疊
}
export default state //導出
複製代碼
const mutations = {
//保存token
COMMIT_TOKEN(state, object) {
state.token = object.token;
},
//保存標籤
TAGES_LIST(state, arr) {
state.tagsList = arr;
},
IS_COLLAPSE(state, bool) {
state.isCollapse = bool;
}
}
export default mutations
複製代碼
const getters={
//你要計算的屬性
}
export default getters
複製代碼
const actions={
}
export default actions
複製代碼
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 數據持久化插件
import createPersistedState from "vuex-persistedstate"
Vue.use(Vuex)
export default new Vuex.Store({
state,
mutations,
actions,
getters,
plugins: [createPersistedState()]
})
複製代碼
至此vuex引入完畢,如同窗們還有不明白的能夠去翻閱vuex文檔。
如今咱們開始進行頁面的佈局。首先咱們來分析下首頁的狀況
view
文件夾下面新建一個layout
文件夾,裏面再添加一個layout.vue
,以及compentents
文件夾。Aside.vue
文件,實現路由跳轉相關的邏輯,運用了element導航菜單的路由模式,若有不明白的能夠去ElementUI導航菜單去看看。<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: "系統首頁"
},
{
icon: "el-icon-edit-outline",
index: "icon",
title: "自定義圖標"
},
{
icon: "el-icon-edit-outline",
index: "component",
title: "組件",
subs: [
{
index: "editor",
title: "富文本編譯器"
},
{
index: "countTo",
title: "數字滾動"
},
{
index: "trees",
title: "樹形控件",
subs: [
{
index: "tree",
title: "自定義樹"
},
{
index: "treeSelect",
title: "下拉樹"
}
// ,{
// index:'treeTable',
// title:'表格樹',
// }
]
},
]
},
{
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: "錯誤處理",
subs: [
{
index: "permission",
title: "權限測試"
},
{
index: "404",
title: "404頁面"
}
]
},
]
};
},
computed: {
onRoutes() {
return this.$route.path.replace("/", "");
},
...mapState(["isCollapse"]) //從vuex裏面獲取菜單是否摺疊
},
methods: {
//下拉展開
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
//下來關閉
handleClose(key, keyPath) {
console.log(key, keyPath);
}
}
};
複製代碼
view/compentents
文件夾下面新建一個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>首頁</el-dropdown-item>
</router-link>
<el-dropdown-item>我的設置</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";//引入了一個側邊欄是否摺疊的組件
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;
}
}
};
複製代碼
如今在src/components
文件夾下面新建一個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
}
}
};
複製代碼
view/compentents
文件夾下面新建一個Tags.vue
<template>
<!-- 打開標籤的容器 -->
<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">
標籤選項
<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu size="small" slot="dropdown">
<el-dropdown-item command="closeOther">關閉其餘</el-dropdown-item>
<!-- <el-dropdown-item command="all">關閉全部</el-dropdown-item> -->
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
複製代碼
import { messages } from "@/assets/js/common.js";
export default {
created() {
//判斷標籤裏面是否有值 有的話直接加載
if (this.tagsList.length == 0) {
this.setTags(this.$route);
}
},
computed: {
//computed 方法裏面沒有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: {
//監聽路由變化
$route(newValue, oldValue) {
this.setTags(newValue);
}
},
methods: {
//選中的高亮
isActive(path) {
return path === this.$route.fullPath;
},
handleCommand(command) {
if (command == "closeOther") {
// 關閉其餘標籤
const curItem = this.tagsList.filter(item => {
return item.path === this.$route.fullPath;
});
this.tagsList = curItem;
}
},
//添加標籤
setTags(route) {
let isIn = this.tagsList.some(item => {
//判斷標籤是否存在
return item.path === route.fullPath;
});
//不存在
if (!isIn) {
// 判斷當前的標籤個數
if (this.tagsList.length >= 10) {
messages("warning", "當標籤大於10個,請關閉後再打開");
} 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", "不可全都關閉");
} else {
//刪除當前
let tags = this.tagsList.splice(index, 1);
this.$store.commit("TAGES_LIST", this.tagsList);
}
}
}
};
複製代碼
接下來在view/compentents
文件夾下面新建一個Main.vue
,主要是將頂部導航標籤欄以及內容部分結合起來。
<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
}
}
複製代碼
相關組件寫好,在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"])
}
};
複製代碼
至此首頁佈局已經規劃完成,若有不太清楚的能夠查看項目地址
管理系統是多種多樣的,每家公司都有不一樣的業務邏輯,本篇文章也只是拋磚引玉,還有許多須要修正改進的地方,若是同窗們有更好的想法能夠提出來但願你們一塊兒完善本項目。
|-- 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
複製代碼
最後項目目錄文件結構