Vue登录注册

  1. 注册

    1.1 注册页面的布局

    1.2 注册业务逻辑的实现

    1.3封装api

  2. 登录

    3.导航守卫

  3. 注册

    1.1 注册页面的布局

    需要用到Vant的Field组件

    1.views下新建一个注册页面 ,完成基本布局。引入Vue和Field并使用。

    3.给注册页面添加一个单独的路由,注册页面不需要底部。(注意,相关样式需要引入不同的组件,请细心查看官方文档,按需拿取内容)

  4. 利用计算属性给输入框做条件判断。本案例以手机号为例。

1.在views目录下创建三个文件

1.1、一个RetrievePass.vue文件写入注册的代码块

1.2、一个Register.vue文件写入手机验证码登录

1.3、一个Login.vue文件写入密码登录

RetrievePass.vue文件注册

<template>
<!-- 注册 -->
  <div>
    <div class="zhx_retrieve">
      <van-field v-model="sms" center clearable placeholder="请输入手机号">
        <template #button>
          <a size="small" type="primary">发送验证码</a>
        </template>
      </van-field>
      <van-cell-group>
        <van-field v-model="sss" placeholder="请输入验证码" />
      </van-cell-group>
      <van-cell-group>
        <van-field v-model="password" placeholder="请输入密码" />
      </van-cell-group>
    </div>
    <div class="zhx_login_button">
      <button>登录</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      sms: "",
      sss: "",
      password: "",
    };
  },
};
</script>

<style>
.zhx_retrieve {
  width: 100%;
  height: 25vh;
}
.zhx_login_button {
  width: 100%;
  height: 10vh;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 0.8rem;
}
.zhx_login_button button {
  width: 90%;
  height: 7vh;
  background: orange;
  border-radius: 18px;
  border: none;
}
</style>

  

1.2 注册业务逻辑的实现

注:在此之前,记住要先去路由页面添加一个注册页面的路由。

1.补充了密码以及验证码的计算属性判断

密码:如果为空返回空,如果不符合正则,返回格式错误,否则表示可以直接返回空

验证码:如果为空返回空,否则不为五位,返回验证码格式错误,否则成功返回空

2.验证码

绑定点击事件senCode

将提示信息{{buttonmsg}}放在按钮内容中。

定义函数:(定时器注意用箭头函数)每一秒钟定义一次,先提前声明时间,在计时器内让时间减减,当时间为零时,清除定时器,同时btn的内容改为发送验证码,最后return。未return时,让按钮内的内容为时间减减+后重新发送(注意:在开启定时器时,要让按钮禁止点击,在清除定时器后再让按钮可点。)

Register.vue文件手机验证码登录

<template>
  <!-- 手机验证登录 -->
  <div>
    <div class="zhx_login_img">
      <img src="../../assets/login/Login.png" alt="" />
    </div>
    <div class="zhx_register">
      <van-field v-model="sms" center clearable placeholder="请输入手机号">
        <template #button>
          <a
            
            v-show="isShow == false"
            size="small"
            type="primary"
            @click="onClickSend"
            >发送验证码</a
          >
          <a  v-show="isShow == true"
            >获取验证码({{ num }})</a
          >
        </template>
      </van-field>
      <van-cell-group>
        <van-field v-model="sss" placeholder="请输入验证码" />
      </van-cell-group>
    </div>
    <div class="zhx_register_pass">
      <span>*未注册的手机号将自动注册</span>
      <span @click="onLogin">使用密码登录</span>
    </div>
    <div class="zhx_login_button">
      <button @click="redister">登录</button>
    </div>
  </div>
</template>

<script>
import Vue from "vue";
import { Toast } from "vant";

Vue.use(Toast);
export default {
  data() {
    return {
      sms: "",
      sss: "",
      isShow: false,
      num: 60,
    };
  },
  methods: {
    onLogin() {
      this.$router.push("/login");
    },
    onClickSend() {
      this.$APP
        .smsCode({
          mobile: this.sms,
          sms_type: "login",
        })
        .then((res) => {
          console.log(res);
          if (res.data.code === 200) {
            this.countDown();
            Toast(res.data.msg);
          } else if (res.data.code == 201) {
            Toast(res.data.msg);
          }
        });
    },
    //倒计时
    countDown() {
      this.isShow = true;
      setInterval(() => {
        this.num--;
        if (this.num <= 0) {
          this.isShow = false;
          this.num = 60;
        }
      }, 1000);
    },

    redister() {
      this.$APP
        .login({
          mobile: this.sms,
          sms_code: this.sss,
          client: 1,
          type: 2,
        })
        .then((res) => {
          console.log(res);
          let token = res.data.data.remember_token;
          window.localStorage.setItem("token", token);
          this.$router.push("/home");
        });
    },
  },
};
</script>

<style scoped>
.zhx_register {
  width: 100%;
  height: 15vh;
}
.zhx_login_img {
  width: 100%;
  height: 30vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
.zhx_login_img img {
  width: 80%;
}

.zhx_login_button {
  width: 100%;
  height: 10vh;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 0.8rem;
}
.zhx_login_button button {
  width: 90%;
  height: 7vh;
  background: orange;
  border-radius: 18px;
  border: none;
}
.zhx_register_pass {
  width: 100%;
  height: 12vh;
  display: flex;
  justify-content: space-around;
  font-size: 0.6rem;
  color: gray;
}
</style>

  Login.vue文件密码登录

<template>
  <!-- 密码登录 -->
  <div class="zhx_login">
    <div class="zhx_login_img">
      <img src="../../assets/login/Login.png" alt="" />
    </div>
    <div>
      <van-form @submit="onSubmit">
        <van-field
          v-model="username"
          name="用户名"
          placeholder="用户名"
          :rules="[{ required: true, message: \'请填写用户名\' }]"
        />
        <van-field
          v-model="password"
          type="password"
          name="密码"
          placeholder="密码"
          :rules="[{ required: true, message: \'请填写密码\' }]"
        />
      </van-form>
    </div>
    <div class="zhx_login_register">
      <span @click="retrieve">找回密码</span>
      <div>
        <span @click="onRegister">注册/验证码登录</span>
      </div>
    </div>
    <div class="zhx_login_button">
      <button @click="onClickLogin">登录</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: "",
      password: "",
    };
  },
  methods: {
    onSubmit(values) {
      console.log("submit", values);
    },
    retrieve() {
      this.$router.push("/retrieve");
    },
    onRegister() {
      this.$router.push("/register");
    },
    //登录
    onClickLogin() {
      this.$APP
        .login({
          mobile: this.username,
          password: this.password,
          type: 1,
        })
        .then((res) => {
          console.log(res);
          let token = res.data.data.remember_token;
          window.localStorage.setItem("token", token);
          console.log(res.data.data.is_new);
          this.$router.push("/home");
        });
    },
  },
};
</script>

<style scoped>
.zhx_login {
  width: 100%;
}
.zhx_login_img {
  width: 100%;
  height: 30vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
.zhx_login_img img {
  width: 80%;
}
.zhx_login_register {
  width: 100%;
  height: 10vh;
  display: flex;
  align-items: center;
  justify-content: space-around;
  font-size: 0.6rem;
  color: gray;
}
.zhx_login_button {
  width: 100%;
  height: 10vh;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 0.8rem;
}
.zhx_login_button button {
  width: 90%;
  height: 7vh;
  background: orange;
  border-radius: 18px;
  border: none;
}
</style>

  

在src里创建一个api文件写入三个js文件进行封装

1.1、一个core.js文件封装axios请求拦截和响应拦截

1.2、一个index.js文件封装请求的方法

1.3、一个path.js文件封装接口

core.jsaxios请求拦截和响应拦截

import axios from "axios"
import apl from "./path"
import {
    Loading
} from \'element-ui\';

const instance = axios.create({ //axios创建的实例
    baseURL: \'http://120.53.31.103:84\', // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
    timeout: 5000, // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)  如果请求话费了超过 `timeout` 的时间,请求将被中断
    headers: {
        \'X-Custom-Header\': \'foobar\' // `headers` 是即将被发送的自定义请求头
    }
});

var loading = null


// 添加请求拦截器
instance.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    loading = Loading.service();
    return config;
}, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
});

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    setTimeout(function () {
        loading.close()
    }, 500)
    return response;
}, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
});

export function request(method, url, params) { //创建的request函数,把函数抛出
    switch (method) { //switch判断
        case apl.METHODS.GET: //当请求的方式为GET的时候,
            return get(url, params) //把get方式return出去
        case apl.METHODS.POST: //当请求的方式为POST的时候,
            return post(url, params) //把post方式return出去
    }
}

function get(url, params) { //封装的一个get函数
    return instance.get(url, params)
}

function post(url, params) { //封装的一个post函数
    return instance.post(url, params)
}

  index.js文件请求的方法

import {
    request
} from "../apl/core"
import apl from "../apl/path"

const APP = {
    login(params) {
        return request(apl.METHODS.POST, apl.URL.Login, params);
    },
    smsCode(params) {
        return request(apl.METHODS.POST, apl.URL.SmsCode, params);
    },
    change(params) {
        return request(apl.METHODS.POST, apl.URL.Change, params);
    },
}

export default APP

  path.js文件接口

const apl = {
    METHODS: {
        GET: "get", //get请求
        POST: "post" //post请求
    },
    //接口路径
    URL: {
        //登录
        Login: "/api/app/login",
        //验证码登录
        SmsCode: "/api/app/smsCode",
        //修改密码
        Change: "/api/app/password"
    }
}
export default apl

  在router文件里配置需要的文件

import Vue from \'vue\'
import VueRouter from \'vue-router\'

Vue.use(VueRouter)

const routes = [
  {
    path: \'/\',
    name: \'Home\',
    component: () => import(\'../views/Home.vue\')
  },
  {
    path: \'/login\',
    name: \'Login\',
    component: () => import(\'../views/login/Login.vue\')
  },
  {
    path: \'/register\',
    name: \'Register\',
    component: () => import(\'../views/login/Register.vue\')
  },
  {
    path: \'/retrievePass\',
    name: \'RetrievePass\',
    component: () => import(\'../views/login/RetrievePass.vue\')
  },
  {
    path: \'/home\',
    name: \'Home\',
    component: () => import(\'../views/Home.vue\')
  }
]

const router = new VueRouter({
  // mode: \'history\',
  base: process.env.BASE_URL,
  routes
})

export default router

  在min.js里配置自己需要的组件

import Vue from \'vue\'
import App from \'./App.vue\'
import router from \'./router\'
import store from \'./store\'
import Vant from "vant"
import "vant/lib/index.css"
import axios from "axios"
import ElementUI from \'element-ui\';
import \'element-ui/lib/theme-chalk/index.css\';
Vue.use(ElementUI);
Vue.use(Vant)
Vue.prototype.$axios = axios
Vue.config.productionTip = false

import APP from \'./apl/index\'
Vue.prototype.$APP = APP;


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