从0到1搭建Element的后台框架的方法步骤

由于最近公司要开发一个后台管理系统,查阅了很多vue框架,本人觉得element简洁,方便,于是选择它作为我们的首选框架,并分享给大家,如果您觉得有需要改进的地方可以提出来一起探讨,Github地址。本文篇幅比较长,希望同学们可以耐心的读下去,如有不懂可以下方留言

一、初始化项目

首先全局安装的vue框架,这里是用的npm包管理工具来安装的,如果你的网不是很好的话可以先安装淘宝镜像 npm install -g cnpm -registry=https://registry.npm.taobao.org,然后通过cnpm来安装

cnpm install -g @vue/cli or npm install -g @vue/cli

其次开始安装vue脚手架,当前是第三版本vue-cli 3.x

cnpm install -g @vue/cli

安装完成后,你还可以用这个命令来检查其版本是否正确 (3.x):

vue --version

安装脚手架后开始创建我们的项目

vue create vue-admin-project

随后会出现两个选项

选择第二项并继续,并选择自己需要配置的功能,完成后并继续,然后开始生成项目

项目初始化成功

接下来按照上面的提示运行 cd app以及启动本地服务器 npm run serve,当运行完成之后会提示你打来本地端口 http://localhost:8080,会出现欢迎页面,此时代表你的vue项目初始化完成。

二、文件目录介绍与整理

整理前的初始目录

|-- 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文件夹下的目录

|-- 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文件。

 NODE_ENV="development"    //开发环境
 BASE_URL="http://localhost:3000/" //开发环境接口地址

接下来我们配置线上环境,同样在项目根目录新建一个文件 .env.prod这就表明是生产环境。

 NODE_ENV="production"    //生产环境
 BASE_URL="url" //生产环境的地址

现在我们如何在项目中判断当前环境呢?

我们可以根据 process.env.BASE_URL来获取它是线上环境还是开发环境,后面会有运用

 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配置

讲到 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引入

开始安装ElementUI

vue add element

接下来两个选项,第一个是全部引入,第二个是按需引入,我选择第一个 Fully import,大家可以按照自己的项目而定。接下来会询问是否引入scss,这里选择是,语言选择zh-cn。

接下来会提示安装成功,并在项目首页有一个element样式的按钮。

六、vue-router路由介绍入

路由管理也是本项目核心部分。

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

七、axios引入并封装

1.接口处理我选择的是axios,由于它遵循promise规范,能很好的避免回调地狱。现在我们开始安装

 cnpm install axios -S

2.在 src目录下新建文件夹命名为 api,里面新建两个文件,一个是 api.js,用于接口的整合,另一个是 request.js,根据相关业务封装axios请求。

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.编写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);
    });
  });
 }

api.js

封装好axios的业务逻辑之后自然要开始,运用,首先引入 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 => {
  //出错时要做的事情
 });

接口相关的逻辑已经处理完。

八、vuex引入

由于vue项目中组件之间传递数据比较复杂,因此官方引入了一个全局状态管理的东东,也就是现在要说的vuex,vuex能更好的管理数据,方便组件之间的通信。

现在在store文件夹下面新建四个文件 state.js, mutations.js, getter.js, action.js

state.js

state就是Vuex中的公共的状态, 我是将state看作是所有组件的data, 用于保存所有组件的公共数据.

 const state = {
  token: '',//权限验证
  tagsList: [], //打开的标签页个数,
  isCollapse: false, //侧边导航是否折叠
 }
 export default state //导出

mutations.js

我将mutaions理解为store中的methods, mutations对象中保存着更改数据的回调函数,该函数名官方规定叫type, 第一个参数是state, 第二参数是payload, 也就是自定义的参数.改变state的值必须经过mutations

 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

getter.js

我将getters属性理解为所有组件的computed属性,也就是计算属性。vuex的官方文档也是说到可以将getter理解为store的计算属性, getters的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

 const getters={
  //你要计算的属性
 }
 export default getters

action.js

actions 类似于 mutations,不同在于:

1.actions提交的是mutations而不是直接变更状态

2.actions中可以包含异步操作, mutations中绝对不允许出现异步

3.actions中的回调函数的第一个参数是context, 是一个与store实例具有相同属性和方法的对象

 const actions={

 }
 export default actions

store.js

store.js是vuex模块整合文件,由于刷新页面会造成vuex数据丢失,所以这里引入了一个vuex数据持久话插件,将state里面的数据保存到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 数据持久化插件
 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文件夹。

侧边栏

在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

最后项目目录文件结构

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 如何使用VuePress搭建一个类型element ui文档

    网站成果样式 项目书写步骤 github地址:https://github.com/xuhuihui/dataCom 官网:http://caibaojian.com/vuepress/guide/getting-started.html 参考文章:https://www.jb51.net/article/156259.htm 前言:我先git clone官方github,运行查看完整效果. 再根据官网介绍和参考文章,结合完整的代码,自己一步步配置内容.最后,参考element的设计样式,修改并

  • 搭建element-ui的Vue前端工程操作实例

    一.安装npm镜像 (1)下载node.js, 配置node.js的环境变量 检测PATH环境变量是否配置了Node.js,点击开始=>运行=>输入"cmd" => 输入命令"path" 检查Node.js版本 在命令窗口输入:npm install -g cnpm –registry=https://registry.npm.taobao.org 二.安装全局vue-cli (1)npm install -g vue-cli 回车,验证是否安装成

  • VUE+Element环境搭建与安装的方法步骤

    1,安装node,确保安装4.0版本以上,具体的安装可以百度. 2,在命令行创建文件夹 3,安装Vue-cli 输入:cnpm install -g vue-cli , 回车, 等待安装.... 输入:vue ,查看vue相关信息 4,初始化项目 vue init webpack last_demo 然后等一下就会出现相关的信息,再自己去选择安装的一些设置 安装完的时候,你的文件夹就变成了这样了: 如果你的文件夹中没有node_modules的文件,那么你就要在命令行中打开你的项目并输入: np

  • laravel5.4+vue+element简单搭建的示例代码

    如今laravel来到5.4版本,更方便引入vue了,具体步骤如下: 1.下载laravel5.4,这边是下载地址(里面的配置文件都写得差不多了)! 2.打开package.json 内容如下 { "private": true, "scripts": { "dev": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webp

  • 从0到1搭建Element的后台框架的方法步骤

    由于最近公司要开发一个后台管理系统,查阅了很多vue框架,本人觉得element简洁,方便,于是选择它作为我们的首选框架,并分享给大家,如果您觉得有需要改进的地方可以提出来一起探讨,Github地址.本文篇幅比较长,希望同学们可以耐心的读下去,如有不懂可以下方留言 一.初始化项目 首先全局安装的vue框架,这里是用的npm包管理工具来安装的,如果你的网不是很好的话可以先安装淘宝镜像 npm install -g cnpm -registry=https://registry.npm.taobao

  • Linux搭建C++开发调试环境的方法步骤

    安装g++ Linux编译C++程序必须安装g++编译器.这里使用yum方式安装.首先切换到root账号,su - root 然后输入密码. 执行yum install gcc-c++(注意不是yum install g++),报错. 报错是因为yum需要配置正确的服务器地址,服务器是提供yum安装包的,也被称作yum源.配置yum源的配置文件在/etc/yum.repos.d/目录下,可以看到系统自带了两个文件. cat 文件名称,会打印文件全部内容.可以看到两个文件要么没配置,要么地址是无法

  • 手把手搭建Java共享网盘的方法步骤

    项目介绍 在线共享网盘采用jsp+servlet搭建项目结构实现共享网盘,项目分为管理员,普通用户和付费用户三种角色,根据不同角色控制不同权限,实现不同用户对个人文件文件,所有文件,共享文件的增删改查操作. 项目适用人群 正在做毕设的学生,或者需要项目实战练习的Java学习者 开发环境: jdk 8 intellij idea tomcat 8.5.40 mysql 5.7 所用技术: jsp+servlet js+ajax layUi jdbc直连 项目访问地址 http://localhos

  • 从0开始简单部署腾讯云服务器的方法步骤

    由于是第一次发帖,如有写得不好,不对的地方希望大家在评论里指出,以后改进.谢谢!!!. 下面开始: 一:购买腾讯云: 首先进入腾讯云的官网:https://cloud.tencent.com/?fromSource=gwzcw.150044.150044.150044  注册后进行认证. 认证完了后选择 产品 - 云服务器 .如下图: 大家可按照自己的需要进行选择.我这里的话选择的是Windows 2008 便于操作. 如果大家只是想着弄来玩两天的话,腾讯有一个新用户15天的服务器体验活动,只需

  • Spring+Mybatis+Mysql搭建分布式数据库访问框架的方法

    一.前言 用Java开发企业应用软件, 经常会采用Spring+MyBatis+Mysql搭建数据库框架.如果数据量很大,一个MYSQL库存储数据访问效率很低,往往会采用分库存储管理的方式.本文讲述如何通过Spring+Mybatis构建多数据库访问的架构,并采用多线程提升数据库的访问效率. 需要说明一下,这种方式只适合数据库数量.名称固定,且不是特别多的情况.针对数据库数量不固定的情况,后面再写一篇处理方案. 二.整体方案 三.开发环境准备 3.1 下载Spring.Mybatis.Mysql

  • 从0到1搭建element后台框架优化篇(打包优化)

    前言 hello,咱又见了~~嘻嘻.本次主要来说说这个打包优化的问题.一个vue项目从开发到上线必须得经历打包过程,一个项目的打包优化与否都决定了你这个项目的运行速度以及用户体验.本次主要是针对vue.config,js的配置进行优化.项目地址 开发环境与生产环境 开发环境与生产环境的配置也是开发中的必不可少的一环.本项目是由vue-cli3开发,vue-cli3深度集成了webpack,如果不熟悉vue-cli3可以先去官网看看相关配置. 开发环境 在项目根目录下新建.env.developm

  • 仿vue-cli搭建属于自己的脚手架的方法步骤

    脚手架是啥 从前我总觉得脚手架是个很高大上的东西,好像得牛叉:ox:一点的人才写的出来,可望而不可即.其实并不是因为困难使我们放弃,而是因为放弃才显得困难(这是个好词好句:see_no_evil:).只要你肯花个一天半天的时间:fist:,也能写出属于你自己的脚手架. 早前脚手架这个词是从 vue-cli 这里认识的,我们通过 npm install -g vue-cli 命令全局安装脚手架后, 再执行 vue init webpack project-name 就能初始化好一个自己的项目,真是

  • 基于springboot搭建的web系统架构的方法步骤

    从接触springboot开始,便深深的被它的简洁性深深的折服了,精简的配置,方便的集成,使我再也不想用传统的ssm框架来搭建项目,一大堆的配置文件,维护起来很不方便,集成的时候也要费力不少.从第一次使用springboot开始,一个简单的main方法,甚至一个配置文件也不需要(当然我是指的没有任何数据交互,没有任何组件集成的情况),就可以把一个web项目启动起来,下面总结一下自从使用springboot依赖,慢慢完善的自己的一个web系统的架构,肯定不是最好的,但平时自己用着很舒服. 1. 配

  • 基于webpack4搭建的react项目框架的方法

    介绍 框架介绍,使用webpac构建的react单页面应用,集成antd.使用webpack-dev-server启动本地服务,加入热更新便于开发调试.使用bundle-loader进行代码切割懒加载 手动搭建,不使用cli,大量注释适合初学者对webpack的理解学习,对react项目的深入了解 启动 git clone https://gitee.com/wjj0720/react-demo.git cd react-demo yarn yarn start 打包 yarn build 目录

  • Docker实现从零开始搭建SOLO个人博客的方法步骤

    目录 一.环境准备 二.安装Docker 三.安装mysql主从数据库 3.1.mysql环境准备 3.2.启动mysql主库从库 3.3.登陆mysql主库 3.4.登陆mysql从库 3.5.主从参数说明 四.搭建solo博客 五.Nginx实现反向代理solo博客 六.成果展示 一.环境准备 要想在公网访问你的博客,首先你需要一台云服务器,也就是租用各大云厂商的服务器,像我就是花68块买了一年青云的1核2G的服务器,你现在看到的博客就是在这台服务器上,最好也购买一个专属的域名.一年十几就够

随机推荐