需要源码请私我,因为该资源已存在,无法上传到我的资源中
尚硅谷课程“尚品汇”注册登录页实现
注册页
配置路由
- 在src目录下新建pages-组件/router-路由/
- 注册和登录、首页组件路由配置
-
新建router文件夹存放路由配置信息以及暴露路由
-
在routes文件中引入路由组件,配置路由信息并对外暴露
-
在index.js中注册路由
-
在main.js中注册路由
-
在App.vue中设置路由出口
-
最终效果:在地址栏输入对应的路由信息即可跳转
完成静态页面
- 注册页面静态实现
- 在register.vue中
- 框架
<template>
<div class="register-container">
<!-- 注册内容 -->
<div class="register">
<h3>注册新用户
<span class="go">我有账号,去 <a href="login.html" target="_blank">登陆</a>
</span>
</h3>
<div class="content">
<label>手机号:</label>
<input type="text" placeholder="请输入你的手机号">
<span class="error-msg">错误提示信息</span>
</div>
<div class="content">
<label>验证码:</label>
<input type="text" placeholder="请输入验证码">
<button>获取验证码</button>
<span class="error-msg">错误提示信息</span>
</div>
<div class="content">
<label>登录密码:</label>
<input type="text" placeholder="请输入你的登录密码">
<span class="error-msg">错误提示信息</span>
</div>
<div class="content">
<label>确认密码:</label>
<input type="text" placeholder="请输入确认密码">
<span class="error-msg">错误提示信息</span>
</div>
<div class="controls">
<input name="m1" type="checkbox">
<span>同意协议并注册《尚品汇用户协议》</span>
<span class="error-msg">错误提示信息</span>
</div>
<div class="btn">
<button>完成注册</button>
</div>
</div>
<!-- 底部 -->
<div class="copyright">
<ul>
<li>关于我们</li>
<li>联系我们</li>
<li>联系客服</li>
<li>商家入驻</li>
<li>营销中心</li>
<li>手机尚品汇</li>
<li>销售联盟</li>
<li>尚品汇社区</li>
</ul>
<div class="address">地址:北京市昌平区宏福科技园综合楼6层</div>
<div class="beian">京ICP备19006430号
</div>
</div>
</div>
</template>
- 样式(使用less预编译)
<style lang="less" scoped>
.register-container {
.register {
width: 1200px;
height: 445px;
border: 1px solid rgb(223, 223, 223);
margin: 0 auto;
h3 {
background: #ececec;
margin: 0;
padding: 6px 15px;
color: #333;
border-bottom: 1px solid #dfdfdf;
font-size: 20.04px;
line-height: 30.06px;
span {
font-size: 14px;
float: right;
a {
color: #e1251b;
}
}
}
div:nth-of-type(1) {
margin-top: 40px;
}
.content {
padding-left: 390px;
margin-bottom: 18px;
position: relative;
label {
font-size: 14px;
width: 96px;
text-align: right;
display: inline-block;
}
input {
width: 270px;
height: 38px;
padding-left: 8px;
box-sizing: border-box;
margin-left: 5px;
outline: none;
border: 1px solid #999;
}
img {
vertical-align: sub;
}
.error-msg {
position: absolute;
top: 100%;
left: 495px;
color: red;
}
}
.controls {
text-align: center;
position: relative;
input {
vertical-align: middle;
}
.error-msg {
position: absolute;
top: 100%;
left: 495px;
color: red;
}
}
.btn {
text-align: center;
line-height: 36px;
margin: 17px 0 0 55px;
button {
outline: none;
width: 270px;
height: 36px;
background: #e1251b;
color: #fff !important;
display: inline-block;
font-size: 16px;
}
}
}
.copyright {
width: 1200px;
margin: 0 auto;
text-align: center;
line-height: 24px;
ul {
li {
display: inline-block;
border-right: 1px solid #e4e4e4;
padding: 0 20px;
margin: 15px 0;
}
}
}
}
</style>
注意:出现以下报错
由于使用了less语法,缺失了less-loader;安装less/less-loader依赖即可解决报错
效果:
请求接口
- 接口封装
- 在src目录下新建api文件夹
- 在api目录下新建requests.js(axios二次封装)
- 安装axios依赖
- 封装axios
import axios from "axios";
// 对axios二次封装
const requests = axios({
baseURL: '/api',
timeout: 5000
})
// 设置请求拦截器
requests.interceptors.request.use((config) => {
return config
})
// 设置响应拦截器
requests.interceptors.response.use((res) => {
return res.data
}, (error) => {
console.log(error);
return Promise.reject(new Error('faile'))
})
// 对外暴露
export default requests
-
在api目录下新建index.js(请求定制)
-
在vue.config.js中设置代理跨域。
- 注意:每次写完配置文件后要重新启动服务
// 代理跨域
devServer: {
proxy: {
'/api': {
// target是目标请求URL
target: 'http://gmall-h5-api.atguigu.cn',
}
}
}
- 在api/index.js中定制注册页相关请求
- 获取验证码:
export const reqGetCode = (phone) => requests({
url: `/user/passport/sendCode/${phone}`,
method: 'GET'
})
- 注册请求
// 注册请求
export const reqRegisterUser = (data) => requests({
url: '/user/passport/register',
method: 'POST',
data
})
-
获取注册页的表单内容
- 在data内声明表单元素
data() { return { // 表单数据 // 手机号 phone: '', // 验证码 code: '', // 密码 password: '', // 确认密码 repassword: '' }; },
- 使用v-model响应式绑定数据框,获取用户输入数据
<input v-model="phone" type="text" placeholder="请输入你的手机号"> <input v-model="code" type="text" placeholder="请输入验证码"> 密码与上面一致
- 效果:
组件身上data属性有了响应的响应式数据。
-
在src目录下新建store文件夹,用于存放组件的仓库
- 新建user.js文件,用于存放于用户相关的信息
// 导入获取验证码的请求 import { reqGetCode } from '@/api/index' // 存放数据 const state = {} // 修改state的 const mutations = {} // 提交mutations,异步操作 const actions = { // 获取验证码 // commit:占位,用于派发mutations;phone:请求的参数 getCode({ commit }, phone) { let result = reqGetCode(phone) console.log(result); } } // 对state内数据的计算 const getters = {} // 对外暴露 export default { state, mutations, actions, getters }
- 在store目录下新建index.js文件,用作大仓库
import Vue from 'vue' import Vuex from 'vuex' // 使用插件 Vue.use(Vuex) // 导入小仓库 import user from './User/user' // 对外暴露store的一个类的实例 export default new Vuex.Store({ modules: { // 小仓库 user } })
- 在main.js中注册大仓库
// 引入仓库 import store from './store' new Vue({ render: h => h(App), // 注册路由信息 router, // 注册仓库 store }).$mount('#app')
效果:
-
获取验证码
- 在register.vue组件中给’获取验证码’按钮添加点击事件。在method中派发actions
<button @click="getCode">获取验证码</button> methods: { // 获取验证码 getCode() { const { phone } = this // 派发actions this.$store.dispatch('getCode', phone) } },
效果:
- 将返回的验证码存到user仓库
- 将仓库中的code直接显示在‘获取验证码’的input框中。在register组件中的methods方法内修改getCode方法
// 获取验证码
async getCode() {
// try等待派发的actions返回成功的Promise后,直接修改code值
try {
const { phone } = this
// 派发actions
await this.$store.dispatch('getCode', phone)
this.code = this.$store.state.user.code
} catch (error) {
console.log('获取失败');
}
}
效果:
-
注册请求
- 在user仓库中调用注册请求
async registerUserInfo({ commit }, data) { let result = await reqRegisterUser(data) // 当结果200代表成功 if (result.code == 200) { return 'ok' } else { return Promise.reject(new Error('faile')) } }
- 给‘完成注册’按钮添加点击事件
<button @click="register">完成注册</button>
- 在methods中写该方法
// 注册请求 async register() { try { const { phone, code, password } = this // 派发注册请求的actions await this.$store.dispatch('registerUserInfo', { phone, code, password }) // 注册结果返回成功后跳转到登录页面 this.$router.push('/login') } catch (error) { console.log(error); } }
效果:
登录页
- 完成静态页面,在login.vue组件中
- 搭建框架
<template>
<div class="login-container">
<!-- 登录 -->
<div class="login-wrap">
<div class="login">
<div class="loginform">
<ul class="tab clearFix">
<li>
<a href="##" style="border-right: 0;">扫描登录</a>
</li>
<li>
<a href="##" class="current">账户登录</a>
</li>
</ul>
<div class="content">
<form action="##">
<div class="input-text clearFix">
<span></span>
<input type="text" placeholder="邮箱/用户名/手机号">
</div>
<div class="input-text clearFix">
<span class="pwd"></span>
<input type="text" placeholder="请输入密码">
</div>
<div class="setting clearFix">
<label class="checkbox inline">
<input name="m1" type="checkbox" value="2" checked="">
自动登录
</label>
<span class="forget">忘记密码?</span>
</div>
<button class="btn">登 录</button>
</form>
<div class="call clearFix">
<ul>
<li><img src="./images/qq.png" alt=""></li>
<li><img src="./images/sina.png" alt=""></li>
<li><img src="./images/ali.png" alt=""></li>
<li><img src="./images/weixin.png" alt=""></li>
</ul>
<router-link class="register" to="/register">立即注册</router-link>
</div>
</div>
</div>
</div>
</div>
<!-- 底部 -->
<div class="copyright">
<ul>
<li>关于我们</li>
<li>联系我们</li>
<li>联系客服</li>
<li>商家入驻</li>
<li>营销中心</li>
<li>手机尚品汇</li>
<li>销售联盟</li>
<li>尚品汇社区</li>
</ul>
<div class="address">地址:北京市昌平区宏福科技园综合楼6层</div>
<div class="beian">京ICP备19006430号
</div>
</div>
</div>
</template>
注意:报错图片资源加载错误
先导入图片资源,在修改图片的src路径即可
- 引入样式
<style lang="less" scoped>
.login-container {
.login-wrap {
height: 487px;
background-color: #e93854;
.login {
width: 1200px;
height: 487px;
margin: 0 auto;
background: url(./images/loginbg.png) no-repeat;
}
.loginform {
width: 420px;
height: 406px;
box-sizing: border-box;
background: #fff;
float: right;
top: 45px;
position: relative;
padding: 20px;
.tab {
li {
width: 50%;
float: left;
text-align: center;
a {
width: 100%;
display: block;
height: 50px;
line-height: 50px;
font-size: 20px;
font-weight: 700;
color: #333;
border: 1px solid #ddd;
box-sizing: border-box;
text-decoration: none;
}
.current {
border-bottom: none;
border-top-color: #28a3ef;
color: #e1251b;
}
}
}
.content {
width: 380px;
height: 316px;
box-sizing: border-box;
border: 1px solid #ddd;
border-top: none;
padding: 18px;
form {
margin: 15px 0 18px 0;
font-size: 12px;
line-height: 18px;
.input-text {
margin-bottom: 16px;
span {
float: left;
width: 37px;
height: 32px;
border: 1px solid #ccc;
background: url(../../assets/icons.png) no-repeat -10px -201px;
box-sizing: border-box;
border-radius: 2px 0 0 2px;
}
.pwd {
background-position: -72px -201px;
}
input {
width: 302px;
height: 32px;
box-sizing: border-box;
border: 1px solid #ccc;
border-left: none;
float: left;
padding-top: 6px;
padding-bottom: 6px;
font-size: 14px;
line-height: 22px;
padding-right: 8px;
padding-left: 8px;
border-radius: 0 2px 2px 0;
outline: none;
}
}
.setting {
label {
float: left;
}
.forget {
float: right;
}
}
.btn {
background-color: #e1251b;
padding: 6px;
border-radius: 0;
font-size: 16px;
font-family: 微软雅黑;
word-spacing: 4px;
border: 1px solid #e1251b;
color: #fff;
width: 100%;
height: 36px;
margin-top: 25px;
outline: none;
}
}
.call {
margin-top: 30px;
ul {
float: left;
li {
float: left;
margin-right: 5px;
}
}
.register {
float: right;
font-size: 15px;
line-height: 38px;
}
.register:hover {
color: #4cb9fc;
text-decoration: underline;
}
}
}
}
}
.copyright {
width: 1200px;
margin: 0 auto;
text-align: center;
line-height: 24px;
ul {
li {
display: inline-block;
border-right: 1px solid #e4e4e4;
padding: 0 20px;
margin: 15px 0;
}
}
}
}
</style>
效果:
-
登录请求:这里因为不用接收过多的请求返回结果。所以采用不使用仓库派发actions,直接在组件中派发的方法
- 在main.js中导入api,注册为全局事件
-
使用v-model获取用户输入,在login.vue组件methods中写登录方法,
// 登录 async login() { // 将data解构 const { phone, password } = this let result = await this.$API.reqLoginUser({ phone, password }) // 登录成功 if (result.code == 200) { // 将token和name存到本地 localStorage.setItem('TOKEN', result.data.token) localStorage.setItem('Name', result.data.name) // 跳转到首页 this.$router.push('/') } else { console.log('登录失败'); } }
注意:登录成功后会返回一个token,存到本地
-
未存储本地前:
-
登录成功后存本地结果:
返回值效果:
-
总结
- 重点:
- 路由跳转传参:使用的是query和params参数
- 代理跨域、请求定制
- 不使用仓库,直接在组件实例中发请求
- 出自尚硅谷“尚品汇”项目