基于vue-cli3搭建一个后台管理系统框架

15,373 阅读13分钟

一、安装

【1.1】安装Node

3.x需要node.js版本为8.9版或者更高的版本,点击这里可以安装node

安装过node后,输入下面命令行查询你的node版本:

node -v

如果当前版本不够,可以输入下面命令行来把node版本更新到最新的稳定版本

先清除npm缓存:npm cache clean -f

然后安装n模块:npm install -g n

升级node.js到最新稳定版:n stable

如果是mac 在命令前面加sudo:sudo n stable

【1.2】卸载旧版本

如果你之前已经全局安装过旧版本的vue-cli,需要先卸载它

npm uninstall vue-cli -g

【1.3】安装vue-cli3

// 安装vue-cli3
npm install -g @vue/cli 

// 安装后查看版本号
vue -V 或者 vue --version

二、创建项目

【2.1】创建项目命令

vue create project // project是项目名称

【2.2】选择模板

  • default (babel, eslint): 默认配置,只有Babel和eslint,其他的都要自己另外再配置
  • Manually select features: 手动配置

通过上下箭头可以切换选项,这里我们选择手动配置

【2.3】选择配置

根据你的项目需要来选择配置

  • 括号里有*代表选中
  • 上下箭头可切换选项
  • Space空格键是切换选中与取消
  • A键是切换全部选中和全部取消
  • I键是反向选择
  • Enter确认选择完成

这边选择了(Babel、Router、Vuex、CSS预处理器、Linter / Formatter格式检查)

再次询问是否保存配置:

1) 是否使用路由的 histroy 模式(Yes)

2)选择一个css预处理器(Sass/SCSS)

3)选择一个eslint配置(ESLint + Standard config)

4)选择什么时候进行eslint代码规则检查(Lint on save)

5)将babel、postcss、eslint这些配置文件放哪(In dedicated config files)

6)是否保存这份预设配置(Yes)

选择是的话,会让你填写一个预设文件的名字,下次创建一个vue项目,可以直接使用这个预设文件,而无需再进行配置。

【2.4】生成目录结构

  • node_modules: 这个文件夹里面是我们项目需要的一些依赖;
  • public: 静态文件夹,这个文件夹中的资源不会被webpack编译,构建生产包的时候,会被直接拷贝一份;
  • assets: 是页面和组件中用到的静态资源,比如公共样式文件,字体文件,图片等,该文件夹与public的区别是:该文件夹中的资源会被webpack编译;
  • components: 文件夹中存放我们的组件;
  • views: 文件夹中存放我们的页面;
  • App.vue: 这个文件是我们所有vue页面的顶层文件;
  • main.js: 是我们整个项目的入口文件;
  • router.js: 是路由的配置文件;
  • store.js: 是vuex的配置文件;
  • .browserslistrc: 文件用于给开发者设置浏览器版本的范围;
  • .eslintrc.js: eslint配置文件;
  • .gitignore: 需要git忽略的文件;
  • babel.config.js: babel的配置工具;
  • package-lock.json: 记录项目依赖中各个依赖之间的关系和版本,防止npm包中有不遵守“相同大版本号的同一个库包,其接口符合兼容要求”
  • 这一规范,导致项目运行报错;
  • package.json: 项目的描述文件,包括项目名、依赖的版本、作者、命令、入口文件等信息。
  • README.md: 项目的说明文档,项目介绍、License、一些命令(例如:启动命令、打包命令、单元测试命令等)

vue-cli3和vue-cli2的区别在于:

  1. 创建项目 vue create
  2. 启动项目 由npm run dev 改成 npm run serve
  3. 移除了配置文件目录 config 和 build 文件夹,如果需要自定义配置,需要自己新建vue.config.js文件
  4. 移除了 static 静态资源文件夹,新增 public 文件夹,静态资源转移到public目录中,通过/xx.xx可以直接访问,并且 index.html 移动到 public 中
  5. 在 src 文件夹中新增了 views 文件夹,用于分类 视图组件 和 公共组件
  6. 安装项目时会自动下载node-model文件夹

【2.5】启动项目

npm run serve


三、修改目录结构

由于现在的目录结构不利于后期的开发,现在我们增加部分文件,待后续可以进行功能扩展。在src文件下:新建api文件夹,router文件夹,utils文件夹,views文件夹,store文件夹。并在其文件下建子目录,详细请参考目录截图:


四、项目配置 Vue.config.js

vue-cli3.0构建项目目录中没有build和config目录,那么问题来了,我们如何去开发我们的项目呢?(比如设置代理、打包配置等问题)只需要在项目根目录中添加vue.config.js文件,注意是根目录非src下,它会被 @vue/cli-service 自动加载。参考Vue CLI

配置如下:

// vue.config.js
const path = require('path');

function resolve(dir) {
    return path.join(__dirname, dir);
}
module.exports = {
    // 部署应用包时的基本URL,默认为'/'
    // 假设你的应用将会部署在域名的根部,比如,https://www.vue-cli.com/,则设置为"/"
    // 如果你的应用是部署在一个子路径下,那么你需要在这里指定子路径,比如,如果你部署在 https://www.my-vue.com/my-app/; 那么将这个值改为 “/my-app/”
    publicPath: "/",

    //将构建好的文件输出到哪里 当运行 vue-cli-service build 时生成的生产环境构建文件的目录。注意目标目录在构建之前会被清除 (构建时传入 --no-clean 可关闭该行为)。
    outputDir: "dist",

    //放置生成的静态资源(js、css、img、fonts)的目录。
    assetsDir: "",

    // 指定生成的 index.html 的输出路径
    indexPath: "index.html",

    // 默认情况下,生成的静态资源在它们的文件名中包含了 hash 以便更好的控制缓存。然而,这也要求 index 的 HTML 是被 Vue CLI 自动生成的。如果你无法使用 Vue CLI 生成的 index HTML,你可以通过将这个选项设为 false 来关闭文件名哈希
    filenameHashing: true,

    // 构建多页面应用,页面的配置  
    pages: {
        index: {
            // page 的入口
            entry: 'src/main.js',
            // 模板来源
            template: 'public/index.html',
            // 在 dist/index.html 的输出
            filename: 'index.html',
            // 当使用 title 选项时,
            // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
            title: 'Index Page',
            // 在这个页面中包含的块,默认情况下会包含
            // 提取出来的通用 chunk 和 vendor chunk。
            chunks: ['chunk-vendors', 'chunk-common', 'index']
        },
        // 当使用只有入口的字符串格式时,
        // 模板会被推导为 `public/subpage.html`
        // 并且如果找不到的话,就回退到 `public/index.html`。
        // 输出文件名会被推导为 `subpage.html`。
        // subpage: 'src/subpage/main.js'
    },

    // 是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码。这个值会在 @vue/cli-plugin-eslint 被安装之后生效。
    // 设置为 true 时,eslint-loader 会将 lint 错误输出为编译警告。默认情况下,警告仅仅会被输出到命令行,且不会使得编译失败。
    // 如果你希望让 lint 错误在开发时直接显示在浏览器中,你可以使用 lintOnSave: 'error'。这会强制 eslint-loader 将 lint 错误输出为编译错误,同时也意味着 lint 错误将会导致编译失败。
    lintOnSave: false,

    //是否使用包含运行时编译器的 Vue 构建版本。设置为 true 后你就可以在 Vue 组件中使用 template 选项了,但是这会让你的应用额外增加 10kb 左右。
    runtimeCompiler: false,

    // 默认情况下 babel-loader 会忽略所有 node_modules 中的文件。如果你想要通过 Babel 显式转译一个依赖,可以在这个选项中列出来。
    transpileDependencies: [],

    //如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
    productionSourceMap: true,

    //是一个函数,会接收一个基于 webpack-chain 的 ChainableConfig 实例。允许对内部的 webpack 配置进行更细粒度的修改。
    chainWebpack: (config) => {
        //配置别名
        config.resolve.alias
            .set('@', resolve('src'))
            .set('assets', resolve('src/assets'))
            .set('components', resolve('src/components'))
            .set('router', resolve('src/router'))
            .set('utils', resolve('src/utils'))
            .set('store', resolve('src/store'))
            .set('views', resolve('src/views'))

    },

    //是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建。
    parallel: require("os").cpus().length > 1,

    // 向 PWA 插件传递选项。
    // https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
    pwa: {},

    // 所有 webpack-dev-server 的选项都支持。注意:有些值像 host、port 和 https 可能会被命令行参数覆写。
    //有些值像 publicPath 和 historyApiFallback 不应该被修改,因为它们需要和开发服务器的 publicPath 同步以保障正常的工作。
    // 代理配置
    devServer: {
        host: "0.0.0.0",
        port: 8080, // 端口号
        https: false, // https:{type:Boolean}
        open: true, // 配置自动启动浏览器  open: 'Google Chrome'-默认启动谷歌

        // 配置单个代理
        // proxy: 'http://localhost:9000' 

        // 配置多个代理
        proxy: {
            "/api": {
                // target: "https://127.0.0.0:8080", // 目标主机
                target: "https://mock.yonyoucloud.com/mock/5708",
                ws: true, //代理的WebSockets
                changeOrigin: true, // 允许websockets跨域
                pathRewrite: {
                    "^/api": ""
                }
            }
        }
    },

    // 第三方插件选项
    // 这是一个不进行任何 schema 验证的对象,因此它可以用来传递任何第三方插件选项。
    pluginOptions: {
        foo: {
            // 插件可以作为 `options.pluginOptions.foo` 访问这些选项。
        }
    },

    // 有的时候你想要向 webpack 的预处理器 loader 传递选项。你可以使用 vue.config.js 中的 css.loaderOptions 选项。比如你可以这样向所有 Sass/Less 样式传入共享的全局变量
    css: {
        loaderOptions: {
            // 给 sass-loader 传递选项
            sass: {
                prependData: `
                @import "@/assets/css/common.scss";
                @import "@/assets/css/mixin.scss";
                @import "@/assets/css/reset.scss";
                @import "@/assets/css/var.scss"; 
                `
            }
        }
    },
};

五、全局样式引用

在项目开发过程中,我们经常需要全局样式引用,例如主题色等,如果每次去写的化会变得很麻烦。因为我们应该了sass预语言编译,所以可以大胆的应用其特性。例如变量,函数,混入等。但是我们需要在项目中进行全局的配置才能有效果。不用在每一个页面都进行引入样式,就能直接引用。

【5.1】新建目录

在assets文件下增加css文件夹,在css文件夹下新建如下几个样式代码文件,具体的代码自行进行配置

common.scss 主要存放公共的样式

mixin.scss 主要存放混入样式

reset.scss 主要存放重置样式。

var.scss 主要存放变量

【5.2】全局引入

在vue.config.js配置文件中,加上以下代码

module.exports = {
    css: {
        loaderOptions: {
            // 给 sass-loader 传递选项
            sass: {
                prependData: `
                @import "@/assets/css/common.scss";
                @import "@/assets/css/mixin.scss";
                @import "@/assets/css/reset.scss";
                @import "@/assets/css/var.scss"; 
                `
            }
        }
    },
}

六、打包配置

在实际项目的开发中,我们一般会经历项目的开发阶段、测试阶段、预发布阶段和最终上线阶段,每一个阶段对于项目代码的要求可能都不尽相同,那么我们如何能够游刃有余的在不同阶段下使我们的项目呈现不同的效果,使用不同的功能呢?这里就需要引入环境的概念。作为一名开发人员,我们可能需要针对每一种环境编写一些不同的代码并且保证这些代码运行在正确的环境中,这就需要我们进行正确的环境配置和管理。

一般一个项目都会有以下 4 种环境:

  • 开发环境(开发阶段,本地开发版本,一般会使用一些调试工具或额外的辅助功能)
  • 测试环境(测试阶段,上线前版本,除了一些 bug 的修复,基本不会和上线版本有很大差别)
  • 预发布环境(即将上线阶段,上线前版本,预测线上出现问题的可能性,和上线版本无差别)
  • 生产环境(上线阶段,正式对外发布的版本,一般会进行优化,关掉错误报告)

有关环境变量的注意事项:

  • 环境文件放置根目录下
  • 环境名应该与环境文件统一
  • 除了 baseUrl 和 NODE_ENV 其他环境变量使用VUE_APP开头

在项目的根目录新建4个文件夹,分别对应开发环境(.env.dev),测试环境(.env.test),预发布环境(.env.pre),生产环境(env.prod)

.env.dev文件内容如下:

NODE_ENV = 'development'
VUE_APP_CURRENTMODE = 'dev'
VUE_APP_BASEURL = '本地开发api地址'

.env.test文件内容如下:

NODE_ENV = 'test'
VUE_APP_CURRENTMODE = 'test'
VUE_APP_BASEURL = '测试环境api地址'

.env.pre文件内容如下:

NODE_ENV = 'pre-release'
VUE_APP_CURRENTMODE = 'pre'
VUE_APP_BASEURL = '预发布环境api地址'

env.prod文件内容如下:

NODE_ENV = 'production'
VUE_APP_CURRENTMODE = 'prod'
VUE_APP_BASEURL = '正式环境api地址'

package.json配置:

    "scripts": {
        "dev": "vue-cli-service serve",
        "build:test": "vue-cli-service build --mode test",
        "build:per": "vue-cli-service build --mode pre-release",
        "build:prod": "vue-cli-service build --mode production",
        "build": "vue-cli-service build",
        "lint": "vue-cli-service lint"
    },

最后根据上面的配置进行打包:

  1. npm run dev //本地运行
  2. npm run build:test //测试环境打包
  3. npm run build:pre //预测试环境打包
  4. npm run build:prod //正式环境打包

注意:

在vue.config.js使用 proccess.env.NODE_ENV 进行访问就可以了

// vue.config.js
console.log(process.env.NODE_ENV); // development(在终端输出)

当你运行 npm run dev命令后会发现输出的是 development,因为 vue-cli-service serve 命令默认设置的环境是 development,你可以修改 package.json 中的 dev 脚本的命令为:

"scripts": {
"dev": "vue-cli-service serve --mode test",
}
// --mode test其实就是修改了 webpack 4 中的 mode 配置项为 test,同时其会读取对应 .env.[model]文件下的配置 
// 如果没找到对应配置文件,其会使用默认环境 development
// 同样 vue-cli-service build 会使用默认环境 production

七、安装使用iview

【7.1】安装iview

npm install iview -S

【7.2】main.js 引入iview

import iview from 'iview'
import 'iview/dist/styles/iview.css'
Vue.use(iview)

八、axios封装

在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中。他有很多优秀的特性,例如拦截请求和响应、取消请求、转换json、客户端防御XSRF等。所以我们的尤大大也是果断放弃了对其官方库vue-resource的维护,直接推荐我们使用axios库。如果还对axios不了解的,可以移步 axios中文说明

【8.1】安装

npm install axios --save-dev

【8.2】新建目录

在src目录下新建一个api文件夹,然后在里面新建一个axios.js和一个getData.js文件;axios.js文件用来封装我们的axios,getData.js用来统一管理我们的接口。

【8.3】axios.js封装axios

import axios from "axios";
import { Message } from "iview";
let router = import("@/router");

axios.defaults.baseURL = "/api";
axios.defaults.headers.post["Content-Type"] = "application/json;charset=UTF-8";
axios.defaults.headers["X-Requested-With"] = "XMLHttpRequest";
axios.defaults.headers["Cache-Control"] = "no-cache";
axios.defaults.headers["pragma"] = "no-cache";

let source = axios.CancelToken.source();

//请求添加token
axios.interceptors.request.use(request => {
  request.headers["Authorization"] = window.localStorage.getItem('token') ? window.localStorage.getItem('token') : "";
  return request;
});

//登录过期(token失效)跳转到登录页
axios.interceptors.response.use(response => {
  let data = response.data;
  if (
    data.state && [401].includes(data.state.code)
  ) {
    router.then(lib => {
      if (lib.default.currentRoute.name === "login") return;
      lib.default.push({
        name: "login"
      })
      Message.warning(data.state.msg);
    });
  }
  return response;
})

//返回值解构
axios.interceptors.response.use(response => {
  let data = response.data;
  let isJson = (response.headers["content-type"] || "").includes("json");
  if (isJson) {
    if (data.state && data.state.code === 200) {
      return Promise.resolve({
        data: data.data,
        msg: data.state.msg,
        code: data.state.code,
        page: data.page
      });
    }
    return Promise.reject(
      data.state &&
      data.state.msg ||
      "网络错误"
    );
  } else {
    return data;
  }
}, err => {
  let isCancel = axios.isCancel(err);
  if (isCancel) {
    return new Promise(() => {});
  }
  return Promise.reject(
    err.response.data &&
    err.response.data.state &&
    err.response.data.state.msg ||
    "网络错误"
  );
})

//切换页面取消请求
axios.interceptors.request.use(request => {
  request.cancelToken = source.token;
  return request;
});
router.then(lib => {
  lib.default.beforeEach((to, from, next) => {
    source.cancel()
    source = axios.CancelToken.source();
    next()
  })
})

export function post(url, data, otherConfig) {
  return axios.post(url, data, otherConfig);
}

export function get(url, data, otherConfig) {
  return axios.get(url, {
    params: data,
    ...otherConfig
  });
}

【8.4】getData.js 接口管理(例子)

import {get, post } from "./axios";

//获取程序配置
export function getConfig() {
    return get("static/config.json", null, { baseURL: "./" });
}

//获取用户信息(统一认证登录的用户)
export function getLoginInfo() {
    return get("/oauth/getLoginInfo");
}

//登录
export function login(params) {
    return post("/oauth/login", params);
}

//退出
export function logout(params) {
    return get("/oauth/logout", params);
}

【8.5】页面调用接口(例子)

import { login } from "@/api/getData.js";
export default {
  data() {
    return {
      userName: '',
      password: ''
    };
  },
  methods: {
    async login() {
      try {
        this.loading = true;
        let { msg } = await login({
          userName: this.userName,
          userPwd: this.password
        });
        this.$Message.success(msg);
        this.$router.push({ name: "loginPage" });
      } catch (e) {
        this.$Message.warning(e);
      } finally {
        this.loading = false;
      }
    },
  }
};

九、登录拦截(权限控制)

vue+router+axios 实现后台管理系统登录拦截(权限控制)

十、项目GitHub地址

vue-iview3-admin


文章每周持续更新,可以微信搜索「 前端大集锦 」第一时间阅读,回复【视频】【书籍】领取200G视频资料和30本PDF书籍资料