电商前台项目——完成注册登录功能、路由守卫

电商前台项目——完成注册登录功能、路由守卫

一、完成注册部分

请添加图片描述

1、获取验证码

首先把登录注册的静态页面搞过来,然后实现验证码部分,输入手机号,发送请求获取一个验证码,然后直接展示在文本框里。

首先,写接口:

// 获取验证码
export const reqGetCode = (phone) => {
    
    
  return requests({
    
    
    url: `/user/passport/sendCode/${
      
      phone}`,
    method: "get",
  });
};

接着,是我们熟悉的vuex:

import {
    
     reqGetCode } from "@/api";

// 登录与注册模块
const state = {
    
    
  code: "",
};
const mutations = {
    
    
  GETCODE(state, code) {
    
    
    state.code = code;
  },
};
const actions = {
    
    
  // 获取验证码
  async getCode({
     
      commit }, phone) {
    
    
    let result = await reqGetCode(phone);
    // console.log("获取验证码" + result.data);
    if (result.code == 200) {
    
    
      commit("GETCODE", result.data);
      return "ok";
    } else {
    
    
      return Promise.reject(new Error(fail));
    }
  },
};
const getters = {
    
    };
export default {
    
    
  state,
  mutations,
  actions,
  getters,
};

最后,把请求回来的验证码展示在验证码框中:

请添加图片描述

请添加图片描述

2、完成用户注册

这部分也比较简单,主要是拿着手机号、验证码、密码去发送请求,添加到数据库。

熟悉的写接口环节:

// 注册
export const reqUserRegister = (phone, password, code) => {
    
    
  return requests({
    
    
    url: "/user/passport/register",
    data: {
    
    
      phone,
      password,
      code,
    },
    method: "post",
  });
};

再到我们滚瓜烂熟的vuex环节

const actions = {
    
    
  // 用户注册
  async userRegister({
     
      commit }, {
     
      phone, password, code }) {
    
    
    try {
    
    
      let result = await reqUserRegister(phone, password, code);
      //   console.log(result);
      if (result.code == 200) {
    
    
        return "注册成功";
      }
      if (result.code == 223) {
    
    
        return "该用户已注册!";
      }
    } catch (err) {
    
    
      alert("请求失败", err.message);
    }
  },
};
cons

最后,点击注册按钮派发请求:

请添加图片描述

export default {
    
    
  name: "Register",
  data() {
    
    
    return {
    
    
      // 收集表单数据
      // 手机号
      phone: "",
      // 验证码
      code: "",
      // 密码
      password: "",
      // 确认密码
      password1: "",
      // 是否同意协议
      agree: true,
    };
  },
  methods: {
    
    
    .......
    async userRegister() {
    
    
      try {
    
    
        //来个逻辑短路
        // 若phone、code、password都存在且password=password1,agree=true注册才会成功
        const {
    
     phone, password, password1, agree, code } = this;
        if (
          phone &&
          code &&
          password &&
          password1 &&
          password == password1 &&
          agree == true
        ) {
    
    
          let result = await this.$store.dispatch("userRegister", {
    
    
            phone,
            code,
            password,
          });
          alert(result);
          if (result == "注册成功") {
    
    
            this.$router.push("/login");
          }
        }
      } catch (err) {
    
    
        alert("注册失败!", err);
      }
    },
  },
};

二、登录

请添加图片描述

click.prevent阻止默认提交表单的操作,避免跳来跳去。

请添加图片描述

1、点击登录发送请求校验

写登录接口:

// 登录
export const reqLogin = (data) => {
    
    
  return requests({
    
    
    url: "/user/passport/login",
    data,
    method: "post",
  });
};

写vuex:

async userLogin({
     
      commit }, data) {
    
    
    let result = await reqLogin(data);
    console.log("登录信息" + result);
  },

派发请求,路由跳转:

// 用户登录
    async userLogin() {
    
    
      try {
    
    
        // 登录成功
        const {
    
     phone, password } = this;
        phone &&
          password &&
          (await this.$store.dispatch("userLogin", {
    
     phone, password }));
        // 跳转到路由首页
        this.$router.push("/home");
      } catch (error) {
    
    
        alert("登录失败" + error.message);
      }
    },

请求数据后,服务端会返回一个字段,名字叫token,用于唯一地标识用户。

2、保存下发的token

当我们点击登录,返回的数据是这样的,里面有一个字段叫token,它就是用户的唯一标识,将来我们请求用户相关的东西就要拿着这个token

由于vuex是非持久性存储数据,一刷新就没了,所以我们要把token放在本地存储中

// 登录与注册模块
const state = {
    
    
  ......
  token: localStorage.getItem("TOKEN"),
  ......
};
const mutations = {
    
    
  ......
  USERLOGIN(state, token) {
    
    
    state.token = token;
  },
};
const actions = {
    
    
  .......
  // 登录
  async userLogin({
     
      commit }, data) {
    
    
    let result = await reqLogin(data);
    // console.log("登录信息" + result);
    // 服务器下发的token是用户的唯一标识
    // 经常通过token找服务器要用户信息进行展示
    if (result.code == 200) {
    
    
      commit("USERLOGIN", result.data.token);
      // 持久化存储token
      localStorage.setItem("TOKEN", result.data.token);
      return "ok";
    } else {
    
    
      return Promise.reject(new Error("fail"));
    }
  },

后面的每个请求都要和token有关,所以我们要把token写到请求头中

请添加图片描述

3、拿着token请求用户数据并展示

未登录时左上角:

请添加图片描述

登录成功后:

请添加图片描述

这里有个问题,就是这个请求的派发应该写在哪里.

如果写在home页,在home页派发请求(实际是不对的,去别的页面刷新就没用户名了)

请添加图片描述

1、如果只在home页写,那么跳转到其他页面点击刷新vuex中的用户数据就没了;但是如果每个用到用户名的组件都要派发,那就太麻烦了。
2、如果在app写,那么派发请求是在登录前,还没有token呢就请求不到数据,只有登录之后刷新页面(已经有token)才能请求到(刷新页面app肯定第一个挂载)

解决方案就是用路由守卫做判断,没有用户数据就派发请求。(在下文会解决这个问题,现在先在home派发)

这里我们先把派发home里。先把请求用户数据的接口写好:

// 获取用户信息(需要带着用户的token向服务器要用户信息,写在请求头里)
export const reqGetUserMsg = () => {
    
    
  return requests({
    
    
    url: "/user/passport/auth/getUserInfo",
    method: "get",
  });
};

vuex保存数据到仓库:

// 获取用户信息
  async getUserMsg({
     
      commit }) {
    
    
    let result = await reqGetUserMsg();
    console.log("用户信息" + result.data);
    if (result.code == 200) {
    
    
      // 用户已经登录成功且获取到token
      commit("GETUSERMSG", result.data);
    }
  },

展示

请添加图片描述

computed: {
    
    
    userName() {
    
    
      return this.$store.state.user.userMsg.name;
    },
  },

4、退出登录

Header组件中,读取vuex的用户数据,拿到用户名

请添加图片描述

退出登录接口:

// 退出登录
export const reqLogout = () => {
    
    
  return requests({
    
    
    url: "/user/passport/logout",
    method: "get",
  });
};

vuex清除相关用户信息:

const mutations = {
    
    
  CLEAR(state) {
    
    
    // 把仓库中相关用户信息和本地存储清空
    state.token = "";
    state.userInfo = {
    
    };
    localStorage.removeItem("TOKEN");
  },
};
const actions = {
    
    
  // 退出登录
  async UserLogout({
     
      commit }) {
    
    
    let result = await reqLogout();
    if (result.code == 200) {
    
    
      commit("CLEAR");
      return "ok";
    } else {
    
    
      return Promise.reject(new Error("fail"));
    }
  },
};

退出后回到首页:

   // 退出登录
    async logout() {
    
    
      try {
    
    
        // 需要发请求通知服务器退出登录(清除一些数据)
        // 清除项目当中的数据(userInfo、token)
        // 退出成功
        await this.$store.dispatch("UserLogout");
        // 回到首页
        this.$router.push("/home");
      } catch (error) {
    
    
        alert("退出登录失败" + error.message);
      }
    },

5、路由守卫

上文还残留着一些问题没有解决。

  1. 登录后不应该还能回到登录页面,正常逻辑应该是未登录时或者退出登录后才能进入登录页面。
  2. 由于上文只在Home页面派发了获取用户信息的请求,所以当我们到别的页面时,用户信息就没了,可以到各个页面都派发请求,但这样太麻烦了。

上面这两个问题都可以使用路由守卫来解决。点击复习路由守卫

src/router/index.js
// 全局守卫——前置守卫
router.beforeEach(async (to, from, next) => {
    
    
  // 用户登录了才会有token
  let token = store.state.user.token;
  // 用户是否登录
  if (token) {
    
    
    // 登录了就不能再回到登录页,停留在首页
    if ((to.path = "/login")) {
    
    
      next("/home");
    }
    // 登录了去其他的页面
    else {
    
    
      // 如果有用户数据,放行
      if (store.state.user.userMsg.name) {
    
    
        next();
      }
      // 如果没有用户数据,先请求成功再放行
      else {
    
    
        try {
    
    
          // 这个请求在挂载之前,所以刷新也会先请求
          await store.dispatch("getUserMsg");
          next();
        } catch (err) {
    
    
          console.log("请求用户数据失败!", err);
          // 这里还有一种情况,token过期请求不到
          // 那么就要清空token,重新登录
          await store.dispatch("userLogout");
          // localStorage.removeItem("TOKEN");
          next("/login");
        }
      }
    }
  }
  // 如果没有登录
  else {
    
    
    //没登录不能去的路由地址
    let pages = ["/trade", "/pay", "/paysuccess", "/center/myorder"];
    if (pages.includes(to.path)) {
    
    
      // 如果没登陆往这几个页面跳,就回到登录页,并传想去的页面的地址
      // 这样能提升用户体验,登录完成后直接跳到刚才的页面
      next(`/login?redirect=${
      
      to.path}`);
    } else {
    
    
      next();
    }
  }
});

至此,登录与注册功能的笔记就整理得差不多啦,重新看之前写的代码发现还有很多改进的地方就浅改了一下,之前写的时候确实有很多细节没考虑到,还是得多思考多回头看看才行。

猜你喜欢

转载自blog.csdn.net/weixin_56498069/article/details/132986287