专栏首页solate 杂货铺vue3+element-plus+router+vuex+axios从零开始搭建(3)

vue3+element-plus+router+vuex+axios从零开始搭建(3)

618销售冠军是如何炼成的?揭秘电商“盘活”上亿销售数据的奇招!>>>

vuex+router+axios+mockjs

这一章主要是基础组件安装, 各个组件之间会有使用的关系,需要注意一下。

vuex

使用vuex管理全局状态, Vuex 是什么

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

state.js

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

const state = {
  token: "", //权限验证
};
export default state; //导出

mutations.js

mutations对象中保存着更改数据的回调函数, 改变state的值必须经过mutations

const mutations = {
  //保存token
  setToken(state, object) {
    state.token = object.data.token;
  },
};
export default mutations;

getters.js

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

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

actions.js

actions 类似于 mutations,不同在于:

  1. actions提交的是mutations而不是直接变更状态
  2. actions中可以包含异步操作, mutations中绝对不允许出现异步
  3. actions中的回调函数的第一个参数是context, 是一个与store实例具有相同属性和方法的对象
const actions = {};
export default actions;

index.js (store.js)

初始化任务时如果选择了vuex, 那么就会有index.js,

store.js是vuex模块整合文件,由于刷新页面会造成vuex数据丢失,

这里引入了一个vuex数据持久话插件,将state里面的数据保存到localstorage。 安装vuex-persistedstate, (这个我没装暂时不需要,有需要的可以装)

npm install vuex-persistedstate --save
import { createStore } from "vuex";
import state from "./state";
import mutations from "./mutations";
import actions from "./actions";
import getters from "./getters";

export default createStore({
  state,
  mutations,
  actions,
  getters,
  modules: {},
});

这个是下面博客使用这个组件的配置。

    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()]
    })

vue-router

在安装时选择了Router组件后在main.js里会有自动有router, 详细main.js查看上一篇

然后进入router/index.js文件中

  1. 引入文件

这里添加状态管理和进度条组件

import { createRouter, createWebHistory } from "vue-router";
import store from "@/store/index"; //引入状态管理
import NProgress from "nprogress"; //引入进度条组件 cnpm install nprogress --save
import "nprogress/nprogress.css";

2.路由懒加载

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

路由懒加载

/**
 *@parma {String} name 文件夹名称
 *@parma {String} component 视图组件名称
 */
const getComponent = (name, component) => () =>
  import(`@/views/${name}/${component}.vue`);

3.路由配置

const 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: "首页" },
      },
    ],
  },
];

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
});

4.本项目存在一个token,来验证权限问题,因此进入页面的时候需要判断是否存在token,如果不存在则跳转到登陆页面

//判断是否存在token
router.beforeEach((to, from, next) => {
  NProgress.start();
  if (to.path !== "/login" && !store.state.token) {
    next("/login"); //跳转登录
    NProgress.done(); // 结束Progress
  }
  next();
});
router.afterEach(() => {
  NProgress.done(); // 结束Progress
});

5.导出路由

export default router;

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/index";
import store from "@/store/index"; //引入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"; //设置编码

3.编写请求拦截,也就是说在请求接口前要做的事情

/*
 *请求前拦截
 *用于处理需要请求前的操作
 */
axios.interceptors.request.use(
  (config) => {
    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) => {
      const res = response.data;
      if (res.errCode === 0) {
        resolve(res);
      } else {
        reject(res);
      }
    });
  },
  (error) => {
    console.log(error);
    //断网处理或者请求超时
    if (!error.response) {
      //请求超时
      if (error.message.includes("timeout")) {
        console.log("超时了");
        this.$message.error("请求超时,请检查互联网连接");
      } else {
        //断网,可以展示断网组件
        console.log("断网了");
        this.$message.error("请检查网络是否已连接");
      }
      return;
    }
    const status = error.response.status;
    switch (status) {
      case 500:
        this.$message.error("服务器内部错误");
        break;
      case 404:
        this.$message.error("未找到远程服务器");
        break;
      case 401:
        this.$message.warn("用户登陆过期,请重新登陆");
        localStorage.removeItem("token");
        setTimeout(() => {
          router.replace({
            path: "/login",
            query: {
              redirect: router.currentRoute.fullPath,
            },
          });
        }, 1000);
        break;
      case 400:
        this.$message.error("数据异常");
        break;
      default:
        this.$message.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 = (params) => post("/api/login", params);

//上传
export const upload = (upload) => get("/api/upload", upload);

那我们如何调用接口呢?以登陆页面为例。

import { login } from "@/api/api"; //引入login
    /**
    * @oarma {Object} login 接口传递的参数
    */
    login(this.postData)
        .then((res) => {
           //成功之后要做的事情
        })
        .catch((err) => {
            //出错时要做的事情
        });

mockjs

有了接口以后需要模拟后台返回数据,这个时候就可以使用mock组件

  1. 安装

mockjs文档

# 安装
npm install mockjs
  1. 在src目录下创建mock文件夹

无侵入整合MockJS与Vue3.0实例

utils

  1. formatOptions.js
import qs from "qs";

export default function formatOptions(options) {
  let { url, type, body } = options;
  let params = null;
  if (type === "GET" || type === "DELETE") {
    let index = url.indexOf("?");
    let paramsString = index > -1 ? url.slice(index + 1) : "";
    if (paramsString !== "") {
      params = qs.parse(paramsString);
    }
  } else {
    params = {};
    if (body instanceof FormData) {
      for (let [key, value] of body.entries()) {
        params[decodeURIComponent(key)] = decodeURIComponent(value);
      }
    } else {
      try {
        params = JSON.parse(body);
      } catch (e) {
        params = qs.parse(body);
      }
    }
  }
  if (params !== null && Object.keys(params).length === 0) {
    params = null;
  }
  return { url, type, params };
}
  1. mock.js
import Mock from "mockjs";
import formatOptions from "./formatOptions";

Mock._mock = Mock.mock;
Mock.mock = function (url, method, resFunc) {
  if (arguments.length === 1) {
    return this._mock(url);
  }
  if (arguments.length === 2) {
    console.error(
      "Function Mock.mock require three params: url, method, resFunc!!!"
    );
    return;
  }
  if (arguments.length === 3) {
    let methods = ["get", "post", "put", "delete"];
    if (!methods.includes(method.toLowerCase())) {
      console.error(
        "Function Mock.mock's second param should be get, post, put, delete!!!"
      );
      return;
    }
    if (typeof resFunc !== "function") {
      console.error("Function Mock.mock's third param should be a function!!!");
      return;
    }
  }
  // 将注册的 url 转成能匹配查询字符串的正则
  if (typeof url === "string") {
    url = url.replace(/\//g, "\\/");
    url += "(|\\?.*)$";
    url = new RegExp(url);
  } else if (!(url instanceof RegExp)) {
    console.error(
      "Function Mock.mock's first param should be a string or regexp!!!"
    );
    return;
  }
  this._mock(url, method, function (options) {
    // 格式化 options 对象
    options = formatOptions(options);
    let res = null;
    try {
      res = resFunc(options);
    } catch (err) {
      res = err;
    }
    // 将返回的测试数据打印到控制台
    console.groupCollapsed(
      `%c${options.type.toLowerCase()} | ${options.url}`,
      "color: green;"
    );
    console.log("%cparams: ", "color: #38f");
    console.log(options.params);
    console.log("%cresponseData: ", "color: #38f");
    console.log(res);
    console.groupEnd();
    console.log("---------------");
    return res;
  });
};

export default Mock;

api

这里就可以和axios里的api对应起来

import Mock from "../utils/mock";

//注册

//登录
Mock.mock("/api/login", "post", (options) => {
  console.log(options);
  return {
    errCode: 0,
    data: {
      token: "token",
    },
    message: "token已发送: token",
  };
});

index.js

这里引入api

//引入Mock接口规则文件
import "./api/login.js";

这里就吧该引入的组件就都引入完成了

views 实现

现在整体结构还没有设计,现在只是用来演示组件整体是正确的

1.main.js

import { createApp } from "vue";
import ElementPlus from "element-plus";
import "element-plus/lib/theme-chalk/index.css";
import App from "./App.vue";
import router from "./router";
import store from "./store";

//条件引入模拟服务器 MockJS优先级高于域名代理 会导致远程API无法访问
//小心,Boolean('false')等于true 'false'不等于false
eval(process.env.NODE_ENV == "development") && require("@/mock");

const app = createApp(App);
app.use(ElementPlus);
app.use(store);
app.use(router);
app.mount("#app");

2.App.vue

<template>
  <router-view />
</template>

<style lang="stylus">
#app
  font-family Avenir, Helvetica, Arial, sans-serif
  -webkit-font-smoothing antialiased
  -moz-osx-font-smoothing grayscale
  text-align center
  color #2c3e50
  margin-top 60px
</style>

3.home/index.vue

<template>
  <div>主页</div>
</template>

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

<style scoped></style>

4.layout/layout.vue

<template>
  <div>
    样式模块
    <router-view></router-view>
  </div>
</template>

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

<style scoped></style>

5.login/index.vue

这里使用了axios, vuex的内容注意一下

<template>
  <div>
    <h3>登录页</h3>
    <el-form :model="postData" :rules="theRules" ref="loginForm">
      <el-form-item label="用户名" prop="username">
        <el-input v-model="postData.username"></el-input>
      </el-form-item>
      <el-form-item label="用户名" prop="username">
        <el-input
          type="password"
          v-model="postData.password"
          autocomplete="off"
          show-password
        ></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm('loginForm')">
          提交
        </el-button>
        <el-button @click="resetForm('loginForm')"> 重置 </el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
import { login } from "@/api/api"; //引入login
export default {
  name: "index",
  data: function () {
    return {
      postData: {
        password: "admin",
        username: "admin",
      },
      theRules: {},
    };
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          login(this.postData)
            .then((res) => {
              //提交数据到vuex
              this.$store.commit("setToken", res);
              this.$message.success("登录成功");
              this.$router.push({
                path: "/home",
              });
            })
            .catch((err) => {
              this.$message("error", err.message);
            });
        } else {
          return false;
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    },
  },
};
</script>

<style scoped></style>

参考

从0到1搭建Element的后台框架

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • vue3+element-plus+router+vuex+axios从零开始搭建(1)vue3+element-plus

    1.下载node, 不要使用最新的版本element-plus组件没支持到最新的版本。

    solate
  • vue3+element-plus+router+vuex+axios从零开始搭建(2)

    vue-cli 3.0x与vue-cli 2.0x最主要的区别是项目结构目录精简化,这也带来了许多问题,很多配置需要自己配置,

    solate
  • Vite开发快速入门

    Vite (法语意为 "快速的",发音 /vit/) 是一种面向现代浏览器的一个更轻、更快的前端构建工具,能够显著提升前端的开发体验。除了Vite外,前端著名的...

    xiangzhihong
  • 10分钟简单的了解下 Vite 相关内容

    Vite已经出来很久了,新版本也比较稳定,有没有打算入手一下,推荐下面这篇文章。

    前端达人
  • 从 0 开始手把手带你搭建一套规范的 Vue3.x 工程化项目

    Vue3 跟 Vite 正式版发布有很长一段时间了,生态圈也渐渐丰富起来,作者已在多个项目中使用,总结一下:就是快!也不用担心稳定性问题,开发体验真不是一般好!...

    XPoet
  • Vue3 全家桶 + Element Plus + Vite + TypeScript + Eslint 项目配置最佳实践

    而且 Element Plus + Vite 也出了一段时间了,是时候该上手体验分享一波了。

    Sneaker-前端公虾米
  • 从 Vite 与 Vue 开始的 D3 数据可视化之旅

    这是一个极其简单的并尽可能面向未来的新手教程,它将指导你简单地使用 Vite 启动 Vue 的脚手架,并开始 D3 数据可视化的相关开发。而你无需 Vue 相关...

    云游君
  • 这几款基于vue3和vite的开箱即用的中后台管理模版,让你yyds!

    我们都知道 vue3 已经发布一年多了,相关的生态也在慢慢建立,很多公司也在尝试用 vue3 来开发自己的应用系统。但是由于生态的不完善以及缺乏成熟方案的落地,...

    徐小夕
  • Vue3发布半年我不学,摸鱼爽歪歪,哎~就是玩儿

    是从 Vue 2 开始学基础还是直接学 Vue 3 ?尤雨溪给出的答案是:“直接学 Vue 3 就行了,基础概念是一模一样的。”

    程序员十三
  • 使用Vite2+TypeScript4+Vue3技术栈,如何入手开发项目

    已经两周没有发文了,自己临时有点事耽误了,在这里向大家表示深深地歉意。今天,我们使用vite2.0+vue3+ts来开发一个demo项目。

    用户3806669
  • 做个开源博客学习Vite2 + Vue3 (一)搭建项目

    不会 webpack,遇到报错就一头雾水,完全不知道怎么办,而且体积还大速度还慢。 所以尤雨溪做了 vite 后就很向往,只是知道自己水平有限还是等大佬先趟趟...

    用户1174620
  • Electron13+Vue3+ElementPlus模仿macOS桌面版后台系统框架

    electron-vue3-macOS 一款整合vite2.x+electron13跨平台构建模仿mac桌面UI后台管理系统。

    andy2018
  • 一步步使用SpringBoot结合Vue实现登录和用户管理功能

    前后端分离开发是当今开发的主流。本篇文章从零开始,一步步使用SpringBoot结合Vue来实现日常开发中最常见的登录功能,以及登录之后对用户的管理功能。通过这...

    三分恶
  • 使用Vue完成前后端分离开发Spring,Django,Flask(一)

    本篇题为 使用Vue,Spring Boot,Flask,Django 完成Vue前后端分离开发 将通过一个项目整合(一前端项目对应三个后端项目),完成一个简单...

    双鬼带单
  • 每天学一点 Vue3(一) CND方式的安装以及简单使用 js脚本的引用方式数据绑定和UI库的使用Vuex状态管理的简单使用路由的简单使用

    感觉vue3的新特性很舒服,这样才是写软件的感觉嘛。打算用Vue实现自己的一些想法。

    用户1174620
  • 关于 vue3 + typescript 项目中常用的知识点汇总

    在实际项目开发中,常常会遇到这么一个场景,某一个路由是不需要渲染到侧边栏导航上的,此时我们可以给该路由添加一个hidden属性来实现。

    前端达人
  • 全栈的自我修养: 001环境搭建 (使用Vue,Spring Boot,Flask 完成Vue前后端分离开发)

    本系列文章将从一个完整的项目是如何开发的过程进行编写,期间会涉及前端、后端和一些运维的知识。

    双鬼带单
  • 解锁 Vue3 全家桶 + TS 的正确姿势

    https://juejin.cn/post/6980267119933931551

    @超人
  • 使用 Vue3 重构 Vue2 项目(长文)

    2020年9月18日,vue3正式版发布了,前几天把文档整体读了一遍,感触很深,可以解决我项目中的一些痛点,于是就决定重构之前那个vue2的开源项目。

    coder_koala

扫码关注云+社区

领取腾讯云代金券