IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Vue2 + ElementUI快速搭建后台 -> 正文阅读

[JavaScript知识库]Vue2 + ElementUI快速搭建后台

创建项目

此处不做详细描述,请参考:项目创建

添加环境变量

新建.env.development文件

VUE_APP_BASE_API = http
://localhost:3000

新建 .env.production 文件(根据项目需求,选择性创建)

VUE_APP_BASE_API = https
://api.xxx.xxx

安装基础依赖

yarn add element-ui axios moment

全局过滤器

新增 src/filters/index.js 文件

import moment from "moment";

/**
 * "Fri Dec 10 2021 01:01:49 GMT+0800 (China Standard Time)" => "2021年12月10日凌晨1点01分"
 * @param {number} num
 */
export function dateFormat(value) {
  if (!value) {
    return "";
  }

  moment.locale("zh-cn");
  return moment(value).format("LL");
}

/**
 * 10000 => "10,000"
 * @param {number} num
 */
export function thousandFormat(num) {
  const result = (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ","));
  return result + "元";
}

注册依赖

src/main.js

.
.
import
ElementUI
from
"element-ui";
import "element-ui/lib/theme-chalk/index.css";

Vue.config.productionTip = false;
Vue.use(ElementUI);

// 注册全局过滤器
import * as filters from "./filters";

Object.keys(filters).forEach((key) => {
  Vue.filter(key, filters[key]);
});
.
.

封装 axios

新增 src/utils/request.js 文件

import axios from "axios";
import { MessageBox, Message } from "element-ui";
import store from "@/store";
import { getToken } from "@/utils/auth";

// 创建axios实例
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // baseURL: "/api", // url = base url + request url
  // withCredentials: true, // 当跨域请求时,发送 cookies
  timeout: 5000, // 请求超时时间
});

// request拦截器
service.interceptors.request.use(
  (config) => {
    // do something 在发送请求前
    if (store.getters.token) {
      // 让每个请求携带token
      // ["X-Token"]为自定义key
      // 请根据实际情况自行修改
      config.headers["token"] = getToken();
    }
    return config;
  },
  (error) => {
    // do something 当请求错误
    console.log(error); // for debug
    return Promise.reject(error);
  }
);

// respone拦截器
service.interceptors.response.use(
  /**
   * 如果你想获取 http 信息,例如 headers 或 status
   * 请 return  response => response
   */

  /**
   * 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
   * 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
   */
  (response) => {
    const res = response.data;

    // 如果返回的自定义code不是20000, 认定为error。
    if (res.code !== 20000) {
      Message({
        message: res.message || "Error",
        type: "error",
        duration: 5 * 1000,
      });

      // 50008:非法的token; 50012:其他客户端登录了;  50014:Token 过期了;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // 重新登录
        MessageBox.confirm(
          "你已被登出,可以取消继续留在该页面,或者重新登录",
          "确定登出",
          {
            confirmButtonText: "重新登录",
            cancelButtonText: "取消",
            type: "warning",
          }
        ).then(() => {
          store.dispatch("user/resetToken").then(() => {
            // 为了重新实例化vue-router对象 避免bug
            location.reload();
          });
        });
      }
      return Promise.reject(new Error(res.message || "Error"));
    } else {
      return res;
    }
  },
  (error) => {
    console.log("err" + error); // for debug
    Message({
      message: error.message,
      type: "error",
      duration: 5 * 1000,
    });
    return Promise.reject(error);
  }
);

export default service;

由于上面 request 拦截器中读取 token 是从 cookie 中读的,所以接下来我们要配置 cookie

配置 cookie

1、装包

yarn add js-cookie

新增 src/utils/auth.js 文件

import Cookies from "js-cookie";

// cookie中key的命名
const TokenKey = "Admin-Token";

/**
 * 获取cookie中的token
 * @returns {*}
 */
export function getToken() {
  return Cookies.get(TokenKey);
}

/**
 * 设置token到cookie中
 * @param token
 * @param remember
 * @returns {*}
 */
export function setToken(token, remember = false) {
  // 记住我
  if (remember) {
    return Cookies.set(TokenKey, token, { expires: 7 })
  }

  return Cookies.set(TokenKey, token);
}

/**
 * 删除cookie中的token
 * @returns {*}
 */
export function removeToken() {
  return Cookies.remove(TokenKey);
}

CSS 文件

1、新建 src/styles/common.scss 文件

a {
    color: #1f99b0;
    text-decoration: none;
}

.clear:after {
    display: block;
    content: "clear";
    height: 0;
    clear: both;
    overflow: hidden;
    visibility: hidden;
}

2、新建 src/styles/element-ui.scss 文件

.el-menu-item.is-active {
    color: #1f99b0 !important;
}

.el-switch.is-checked .el-switch__core {
    border-color: #1f99b0 !important;
    background-color: #1f99b0 !important;
}

.el-button--primary {
    color: #fff !important;
    background-color: #1f99b0 !important;
    border-color: #1f99b0 !important;
}

.el-menu-item:focus, .el-menu-item:hover {
    background-color: #e1f0f0 !important;
}

.el-submenu__title:hover {
    background-color: #e1f0f0 !important;
}

.el-tag {
    background-color: #e1f0f0;
    border-color: #e1f0f0;
    color: #1f99b0;
}

.el-button.el-button--default:focus, .el-button.el-button--default:hover {
    color: #1f99b0;
    border-color: #dcdef6;
    background-color: #e1f0f0;
}

.el-radio__input.is-checked .el-radio__inner {
    border-color: #1f99b0;
    background: #1f99b0;
}

.el-radio__input.is-checked + .el-radio__label {
    color: #1f99b0;
}


.el-checkbox__input.is-checked .el-checkbox__inner, .el-checkbox__input.is-indeterminate .el-checkbox__inner {
    background-color: #1f99b0;
    border-color: #1f99b0;
}

.el-button--text{
    color: #1f99b0;
}

.el-button--text:focus, .el-button--text:hover {
    color: #1f99b0;
    text-decoration: underline;
}

.el-input.is-active .el-input__inner, .el-input__inner:focus {
    border-color: #1f99b0;
    outline: 0;
}

.el-cascader-node.in-active-path, .el-cascader-node.is-active, .el-cascader-node.is-selectable.in-checked-path {
    color: #1f99b0;
}

.el-radio__inner:hover {
    border-color: #1f99b0;
}

3、新建 src/styles/layouts.scss 文件

html, body {
    height: 100%;
    margin: 0;
}

#app {
    height: 100%;
}

.el-container, .el-aside, .el-aside .el-col, .el-menu {
    height: 100%;
}

.el-header, .el-footer {
    background-color: #e1f0f0;
    color: #333;
    height: 60px;
    line-height: 60px;
}

.el-header {
    position: fixed;
    top: 0;
    width: 100%;
    z-index: 2;
.logo {
    height: 40px;
    margin-top: 10px;
    float: left;
}

h1 {
    margin: 0 0 0 20px;
    font-size: 18px;
    font-weight: normal;
    float: left;
    line-height: 60px;;
}
}

.el-footer {
    position: fixed;
    bottom: 0;
    width: 100%;
    z-index: 2;
    text-align: center;
}

.el-aside {
    position: fixed;
    top: 60px;
    width: 100%;
    z-index: 2;
    background-color: #e1f0f0;
    color: #333;
    line-height: 200px;
}

.el-main {
    color: #333;
    overflow: visible;
    margin: 60px 0 0 200px;
    padding-bottom: 80px;
}

4、新建 src/styles/table.scss 文件

.sort-input input{
  width: 50px;
  text-align: center;
}

.el-table .cell .delete{
  margin-left: 10px;
}

5、新建 src/styles/index.scss 文件

@import './layouts.scss';
@import './common.scss';
@import './element-ui.scss';
@import './table.scss';

后台首页

修改 src/views/Home.vue 文件


<template>
  <div class="home">
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>仪表盘</el-breadcrumb-item>
    </el-breadcrumb>

    <el-divider></el-divider>

    <el-card class="box-card">
      <div slot="header" class="clearfix">
        长乐未央 <br />
        是什么意思?
      </div>
      <div class="info">
        汉时,有长乐宫又有未央宫。"长乐未央"四字,常见于汉宫瓦当。
        "长乐"的"乐",最早出自周公旦制礼作"乐"的乐。"乐者,天地之和也"《礼记·乐记》,"乐"的本质是"和"。"未央"意为未尽,没有穷尽。最早出自诗经(庭燎.小雅)夜如何其?夜未央,庭燎之光。
        "长乐未央"意为永远快乐,没有穷尽。
      </div>
    </el-card>
  </div>
</template>

<script>
  export default {
    name: "Home"
  };
</script>

<style scoped lang="scss">
  .info {
    font-size: 14px;
  }
</style>

布局模板

1、新建 src/views/layout/index.vue 组件

<template>
  <el-container>
    <el-header>
      <img
        src="https://images.clwy.cn/common/logo.png"
        alt="长乐未央Logo"
        class="logo"
      />
      <h1>长乐未央后台管理</h1>
    </el-header>
    <el-container>
      <Sidebar />
      <el-container>
        <el-main>
          <router-view />
        </el-main>
        <el-footer>
          Copyright 2013 - 2022 CLWY Inc. All Rights Reserved.
        </el-footer>
      </el-container>
    </el-container>
  </el-container>
</template>

<script>
  import Sidebar from "./components/Sidebar";

  export default {
    name: "Layout",
    components: {
      Sidebar
    }
  };
</script>

2、新建 src/views/layout/components/Sidebar/index.vue 组件

<template>
  <el-aside width="200px">
    <el-col>
      <el-menu
        :router="true"
        default-active="/"
        class="el-menu-vertical-demo"
      >
        <el-menu-item index="/">
          <i class="el-icon-pie-chart"></i>
          <span slot="title">仪表盘</span>
        </el-menu-item>

        <el-submenu index="article_manage">
          <template slot="title">
            <i class="el-icon-document"></i>
            <span>新闻管理</span>
          </template>
          <el-menu-item index="/articles">新闻</el-menu-item>
          <el-menu-item index="/articles/trash">回收站</el-menu-item>
        </el-submenu>

        <el-menu-item index="/users">
          <i class="el-icon-user"></i>
          <span slot="title">用户管理</span>
        </el-menu-item>

        <el-menu-item index="/settings">
          <i class="el-icon-setting"></i>
          <span slot="title">系统设置</span>
        </el-menu-item>
      </el-menu>
    </el-col>
  </el-aside>
</template>

2、修改 src/App.vue 文件

<template>
  <div id="app">
    <router-view />
  </div>
</template>

<script>
  export default {
    name: "App",
  };
</script>

3、新增 src/views/error-page/404.vuesrc/views/error-page/401.vue 页面,代码分别如下:

<template>
  <div>
    <div class="">
     404页面
    </div>
    <a href="" class="">返回上一页</a>
  </div>
</template>

<script>
export default {
  name: "Page404",
};
</script>
<template>
  <div class="errPage-container">
    <el-button icon="el-icon-arrow-left" class="pan-back-btn" @click="back">
      返回
    </el-button>
    <el-row>
      <el-col :span="12">
        <h1 class="text-jumbo text-ginormous">Oops!</h1>
        <h2>你没有权限去该页面</h2>
        <ul class="list-unstyled">
          <li>或者你可以去:</li>
          <li class="link-type">
            <router-link to="/"> 回首页 </router-link>
          </li>
        </ul>
      </el-col>
    </el-row>
  </div>
</template>

<script>
export default {
  name: "Page401",
  methods: {
    back() {
      if (this.$route.query.noGoBack) {
        this.$router.push({ path: "/" });
      } else {
        this.$router.go(-1);
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.errPage-container {
  width: 800px;
  max-width: 100%;
  margin: 100px auto;

  .pan-back-btn {
    background: #008489;
    color: #fff;
    border: none !important;
  }

  .pan-gif {
    margin: 0 auto;
    display: block;
  }

  .pan-img {
    display: block;
    margin: 0 auto;
    width: 100%;
  }

  .text-jumbo {
    font-size: 60px;
    font-weight: 700;
    color: #484848;
  }

  .list-unstyled {
    font-size: 14px;

    li {
      padding-bottom: 5px;
    }

    a {
      color: #008489;
      text-decoration: none;

      &:hover {
        text-decoration: underline;
      }
    }
  }
}
</style>

4、新增 src/views/auth/login.vue 登录页面

<template>
  <div class="sign-in">
    <el-row>
      <el-col :span="12" :offset="6">
        <h1>长乐未央后台</h1>
        <el-form
          :model="loginForm"
          :rules="loginRules"
          ref="ruleForm"
          label-width="100px"
          class="demo-ruleForm"
        >
          <el-form-item label="用户名" prop="username">
            <el-input v-model="loginForm.username"></el-input>
          </el-form-item>
          <el-form-item label="密码" prop="sort">
            <el-input v-model="loginForm.password" type="password"></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="handleLogin('ruleForm')">
              立即登录
            </el-button>
            <el-button @click="resetForm('ruleForm')">重置</el-button>
          </el-form-item>
        </el-form>
      </el-col>
    </el-row>
  </div>
</template>

<script>
export default {
  data() {
    return {
      loginForm: {
        username: "admin",
        password: "123123",
      },
      loginRules: {
        name: [{ required: true, message: "请输入用户名", trigger: "blur" }],
        password: [{ required: true, message: "请输入密码", trigger: "blur" }],
      },
    };
  },
  methods: {
    handleLogin(formName) {
      this.$refs[formName].validate(async (valid) => {
        if (valid) {
          await this.$store.dispatch("auth/login", this.loginForm);
          await this.$router.push({ path: "/" });
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    },
  },
};
</script>

<style scoped lang="scss">
.sign-in {
  padding-top: 100px;
}

h1 {
  text-align: center;
}
</style>

最后引入 css

1、修改 src/main.js 文件

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import "@/styles/index.scss";   // 引入所有 css

Vue.config.productionTip = false;
Vue.use(ElementUI);

// 注册全局过滤器
import * as filters from "./filters";

Object.keys(filters).forEach((key) => {
  Vue.filter(key, filters[key]);
});

new Vue({
  router,
  store,
  render: (h) => h(App)
}).$mount("#app");

2、修改 src/router/index.js ,将路由修改为懒加载模式

import Vue from "vue";
import VueRouter from "vue-router";
import Layout from "@/views/layout";

Vue.use(VueRouter);

const routes = [
  {
    path: "/login",
    component: () => import("@/views/auth/login")
  },
  {
    path: "/404",
    component: () => import("@/views/error-page/404")
  },
  {
    path: "/401",
    component: () => import("@/views/error-page/401")
  },
  {
    path: "/",
    component: Layout,
    children: [
      {
        path: "",
        name: "Home",
        component: () => import("@/views/home"),
        meta: { title: "首页" }
      }
    ]
  }
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes
});

export default router;

配置代理解决跨域

1、项目根目录下新建 vue.config.js 文件

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: process.env.VUE_APP_BASE_API,
        ws: true,
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      },
    }
  }
}

2、修改 src/utils/request.js 文件部分代码如下:

.
.
const service = axios.create({
  // baseURL: process.env.VUE_APP_BASE_API, 
  baseURL: "/api", // 打开此行代码
  // withCredentials: true, // 当跨域请求时,发送 cookies
  timeout: 5000, 
});
.
.

最终后台首页效果图如下:
在这里插入图片描述

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-28 15:20:07  更:2022-02-28 15:23:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:43:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码