如果想看该实战系列的其他内容,请移步至 Vue.js 实战系列之实现视频类WebApp的项目开发。
项目仓库地址,欢迎 Star
实现效果
功能实现
-
引入 Vuex
什么是 Vuex?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
通俗点说:此时有一个根组件和两个子组件,如果根组件与子组件之间通信,可以通过 props 传值的方式来实现;但是如果想要让两个子组件进行通信,此时实现起来就比较复杂,在未引入 Vuex 之前,可以将子组件A的内容传给父组件,然后父组件接收到再传递给子组件B,相当于父组件作为一个中介进行传递,但是引入 Vuex 之后实现起来就比较简单啦。-
安装 Vuex
yarn add vuex
-
Vuex 核心
state
: 存放状态mutations
:state
成员的操作actions
: 异步操作 (action
与mutation
的区别在于action
技能执行异步操作又能执行同步操作,而mutations
只能执行同步操作)getters
: 加工state
成员给外界modules
: 模块化状态管理
-
Vuex 流程图
-
-
使用
modules
模块化管理数据在
src/store
文件夹下,新建modules
文件夹,创建sign.js
模块const sign = { // 命名空间 namespaced: true, state: { // 默认的验证码 verifyCode: '000000', }, mutations: { }, actions: { }, getters: { }, }; export default sign;
更新
src/store/index.js
将刚才创建的sign
模块导入import Vue from 'vue'; import Vuex from 'vuex'; import sign from './modules/sign'; Vue.use(Vuex); export default new Vuex.Store({ state: { }, mutations: { }, actions: { }, modules: { sign, }, });
-
验证码登录流程实现
正常流程下,验证码是由后端为我们返回的,此时我们没有真实的后端接口,所以现在我们将后端返回的验证码值写死在 state 中,后期将通过 nodejs 来实现一个后端接口,欢迎关注。
-
创建验证码页面
Code.vue
<template> <div class="sign"> <div class="sign-header"> <span class="iconfont icon-guanbi" style="font-size: 30px"></span> <span style="color: #686868"> 帮助</span> </div> <div class="sign-content"> <div class="des"> <h2>请输入验证码</h2> <p>验证码已通过短信发送至+8615998362261</p> </div> </div> <div class="sign-box"> <div class="inp"> <input v-model="code" @input="changeCode" type="number" class="inp-controll" placeholder="请输入验证码" /> </div> <div class="time"> {{ time }} </div> </div> <div class="not-dx"> <p>收不到短信?<a>获取语言验证码</a></p> </div> <div class="code-btn"> <button :disabled="disabled" :class="btnBg ? 'active' : ''" @click="getCode" > 登录 </button> </div> </div> </template> <script> export default { data() { return { // 短信发送倒计时 time: 60, }; }, }; </script> <style lang="less" scoped> .sign { padding: 30px; background: #fff; .sign-header { display: flex; justify-content: space-between; align-items: center; font-size: 18px; } .sign-content { padding: 20px 10px; h2 { margin: 0; font-size: 22px; font-weight: bold; } p { font-size: 14px; line-height: 20px; color: #adadad; } } .sign-box { display: flex; height: 50px; margin: 0; align-items: center; background-color: #f9f9f9; .inp { height: 36px; width: 90%; margin-left: 10px; .inp-controll { caret-color: #fe2c55; height: 36px; background-color: #f9f9f9; width: 90%; font-size: 16px; border: none; outline: none; } } .time { text-align: right; width: 80px; font-size: 16px; line-height: 80px; margin-right: 10px; } } .not-dx { margin-top: 10px; p { color: #b9b9b9; font-size: 14px; a { color: #3d79b4; } } } .code-btn { button { margin: 10px 0; width: 100%; padding: 15px 0; border: none; letter-spacing: 1px; font-size: 17px; color: #fff; font-weight: 600; background: #dbdbdb; border-radius: 2px; } .active { color: #ffffff; background-color: #fe2c55; } } } </style>
-
更新
src/store/modules/sign.js
import router from '../../router'; const sign = { // 命名空间 namespaced: true, state: { // 默认的验证码 verifyCode: '000000', }, mutations: { }, actions: { // 登录操作 sign({ state, commit, rootState }, params) { // 登录成功之后 session 中缓存登录标识 sessionStorage.setItem('isLogin', JSON.stringify(true)); // 登录成功之后 跳转到 webApp 主页 router.replace({ path: '/' }); }, }, getters: { }, }; export default sign;
-
更新
Code.vue
完成登录引入
mapActions
,调用sign.js
中的sign
方法实现登录
使用this.$store.state.
获取state
中的值
使用van-loading
实现加载中动画<template> <div class="sign"> <div class="sign-header"> <span class="iconfont icon-fanhui" style="font-size: 30px" @click="goBack" ></span> <span style="color: #686868"> 帮助</span> </div> <div class="sign-content"> <div class="des"> <h2>请输入验证码</h2> <p>验证码已通过短信发送至+86{{ tel }}</p> </div> </div> <div class="sign-box"> <div class="inp"> <input v-model="code" @input="changeCode" type="number" class="inp-controll" placeholder="请输入验证码" /> </div> <div class="time"> {{ time }} </div> </div> <div class="not-dx"> <p>收不到短信?<a>获取语言验证码</a></p> </div> <div class="code-btn"> <button :disabled="disabled" :class="btnBg ? 'active' : ''" @click="Login" > <div v-if="!loading"> {{ msg }} </div> <div v-else class="loading"> <van-loading color="#1989fa" size="16px" /> {{ msg }} </div> </button> </div> </div> </template> <script> import { mapActions } from 'vuex'; export default { data() { return { tel: '', // 电话号码 code: '', // 验证码 verifyCode: '', // state中提供的默认验证码 time: 60, // 短信发送倒计时 disabled: true, btnBg: false, loading: false, msg: '登录', }; }, created() { this.getCode(); this.tel = this.$route.query.tel; }, methods: { ...mapActions('sign', ['sign']), // 监听输入验证码 changeCode(e) { this.code = e.target.value; if (this.code === this.verifyCode) { this.disabled = false; this.btnBg = true; } else { console.log('验证码输入错误'); } }, // 获取验证码 getCode() { this.verifyCode = this.$store.state.sign.verifyCode; this.countDown(); }, // 倒计时 countDown() { if (this.time > 0) { this.time -= 1; setTimeout(this.countDown, 1000); } else { this.time = '重新发送'; } }, // 登录按钮点击事件 Login() { this.loading = true; this.msg = '登录中'; setTimeout(() => { this.loading = false; this.msg = '登录成功'; }, 1500); setTimeout(() => { this.sign({ code: this.code }); // 登录跳转操作 }, 2000); }, // 返回上个页面 goBack() { this.$router.go(-1); }, }, }; </script> <style lang="less" scoped> .sign { ... .code-btn { button { .loading { display: flex; justify-content: center; align-items: center; } } } } </style>
-
总结
本章节需要注意的几个点:
Vuex
的使用- 使用
modules
模块化管理数据 SessionStorage
前端数据存储- 登录流程实现
上一章节: 11. 手机号登录、密码登录、其它方式登录的实现
下一章节: 13. 自定义全局弹出框组件的实现
项目整体介绍:Vue.js 项目实战之实现视频播放类WebApp的项目开发(仿抖音app)
项目仓库地址,欢迎 Star。
有任何问题欢迎评论区留言讨论。