挑战30分钟写个用户登录注册系统(前端)- 我的全栈独立开发日记
前言
技术栈是 uni-app + uView2.0 + Vue.js
本教程的视频版本已发布在B站,欢迎交流~
准备工作
下载UI组件uView UI,作为uni-app插件引入,下载地址在这里
登录页面
先写好HTML骨架:
新建页面文件index.vue
,文件路径是pages/index/index.vue
<template>
<view class="login-page">
<u--image src="/static/login-bg.png" class="image-bg" mode="aspectFit" width="100%"></u--image>
<view class="form-content">
<u--form>
<u-form-item>
<u-icon name="account" size="24px"></u-icon>
<u--input placeholder="请输入用户名" border="bottom" v-model="username"></u--input>
</u-form-item>
<u-form-item>
<u-icon name="lock" size="24px"></u-icon>
<u--input placeholder="请输入密码" border="bottom" v-model="password" clearable :password="showPwd">
<template slot="suffix">
<view class="slot-list">
<u-icon :name="showPwd ? 'eye-off' : 'eye-fill'" @click="showPassword"
style="padding: 0 5px;"
></u-icon>
<u--text text="忘记密码" size="12"></u--text>
</view>
</template>
</u--input>
</u-form-item>
</u--form>
</view>
<view class="btn-list">
<u-button text="立即登录" type="primary" size="large" @click="onSubmit"></u-button>
<u-button text="注册" type="primary" size="large"
:plain="true" :hairline="true" @click="navRegister"
></u-button>
</view>
<view class="third-party-login">
<u-icon name="weixin-circle-fill" size="36px" color="#2cba00"></u-icon>
<u-icon name="zhifubao-circle-fill" size="36px" color="#019be1"></u-icon>
<u-icon name="weibo-circle-fill" size="36px" color="#df2125"></u-icon>
</view>
<u-radio-group v-model="agreeTerms" style="justify-content: center;align-items: center">
<u-radio shape="circle" name="1"></u-radio>
<span style="font-size: 12px">我已阅读并同意
<span style="color: #3c9cff">《用户协议》</span>和<span style="color: #3c9cff">《隐私协议》</span>
</span>
</u-radio-group>
<u-toast ref="uToast"></u-toast>
</view>
</template>
页面雏形就出来了
接下里我们用css修饰页面布局和颜色:
这里使用了flex布局
<style>
.login-page {
display: flex;
flex-direction: column;
padding: 2rem 2rem;
}
.image-bg {
align-items: center;
}
.form-content {
padding: 1rem 0rem;
}
.third-party-login {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 1rem 2rem;
gap: 0.5rem;
}
.slot-list {
display: flex;
flex-direction: row;
}
.btn-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
</style>
嗯,现在页面就很漂亮了
接下来补充业务逻辑代码:
使用javascript编写逻辑,它负责包括提交表单、请求API接口、与后端交互和控制动态弹窗等工作
还需要用到浏览器的本地存储能力localStorage
来存储后端返回的登录token,以便后续访问其他需要登录的接口
<script>
import {userAccountLogin} from '../../config/api.js'
export default {
data() {
return {
username: "",
password: "",
showPwd: true,
agreeTerms: 1,
}
},
methods: {
showPassword() {
this.showPwd = !this.showPwd
},
// 提交表单
onSubmit() {
if (this.agreeTerms != 1) {
this.$refs.uToast.show({
message: '请先勾选同意用户协议'
})
return
}
userAccountLogin({
username: this.username,
password: this.password
}).then(res => {
this.$refs.uToast.show({
message: '登录成功',
complete() {
// 保存登录态TOKEN
uni.setStorageSync('token', res.token)
uni.navigateTo({
url: '/pages/index/userinfo'
})
}
})
})
},
// 跳转注册页面
navRegister() {
uni.navigateTo({
url: '/pages/index/register'
})
}
}
}
</script>
登录成功会跳转到用户信息页面
用户信息页面
这里我们写一个简单的用户卡片来展示用户资料,然后还有一个修改昵称的功能,点击修改按钮,会跳出弹窗给用户修改自己的昵称。
一共涉及到两个和后端交互的接口,一是获取用户信息,而是修改用户昵称。
新建页面 userinfo.vue
<template>
<view>
<div class="usercard">
<div class="baseinfo">
<div class="avatar">
<u--image src="/static/logo.png" mode="aspectFit" width="60px"></u--image>
</div>
<div class="nameinfo">
<p>昵称:{{ userinfo.nickname == '' ? '用户' + userinfo.id : userinfo.nickname }}</p>
<p>UID:{{ userinfo.id }}</p>
</div>
</div>
<div class="userinfo">
<p>用户名:{{ userinfo.username }}</p>
<p>注册时间:{{ userinfo.created_at }}</p>
</div>
</div>
<div class="edit-info">
<u-popup :show="show" mode="center" @close="close" @open="open" round="10"
overlayOpacity="0.3" customStyle="width:70%;padding:10px;">
<view>
<u--form>
<u-form-item>
<u-icon name="account" size="24px"></u-icon>
<u--input placeholder="请输入新的昵称" v-model="nickname"></u--input>
</u-form-item>
</u--form>
<u-button @click="updateInfo" type="primary" icon="checkmark" size="small">
保存
</u-button>
</view>
</u-popup>
<u-button @click="show=true" type="primary" icon="edit-pen">修改昵称</u-button>
</div>
</view>
</template>
<script>
import {userAccountGetInfo, userAccountUpdateInfo} from '../../config/api.js'
export default {
data() {
return {
userinfo: {},
show: false,
nickname: "",
}
},
methods: {
open() {
},
close() {
this.show = false
},
getUserInfo() {
userAccountGetInfo().then(data => {
this.userinfo = data
this.nickname = data.nickname
})
},
updateInfo() {
userAccountUpdateInfo({
nickname: this.nickname
}).then(() => {
this.close()
})
// 刷新用户信息
this.getUserInfo()
}
},
onLoad() {
this.getUserInfo()
}
}
</script>
<style lang="scss">
.baseinfo {
display: flex;
flex-direction: row;
align-items: center;
width: 80%;
height: 80px;
padding: 1rem;
gap: 0.5rem;
.avatar {
display: flex;
}
.nameinfo {
display: flex;
flex-direction: column;
gap: 10px;
}
}
.userinfo {
padding: 0 1rem 1rem 1rem;
p {
margin-bottom: 10px;
}
}
.usercard {
padding: 0.5rem;
border-radius: 20px;
border: 1px solid $u-border-color;
margin: 5px;
background: linear-gradient(275deg, $u-primary-disabled, $u-primary-light);
box-shadow: 14px 8px 14px 3px rgba(43, 98, 169, 0.5);
}
</style>
细心的读者会注意到css样式的style标签有一个属性<style lang="scss">
和登录页面的有些不同,这里我们是用了scss语法来使得css可以支持嵌套语法,这样对于多层嵌套的样式代码来说便于阅读和维护。
接下来我们继续完成注册页面
注册页面
注册页面的骨架和登录页面大同小异,都要求用户填写用户名和密码,只不过多了一个确认密码的字段。稍微修改下javascript代码就可以了。
新建页面 register.vue
<template>
<view class="page-content">
<u--image src="/static/register-bg.png" mode="aspectFit"></u--image>
<view class="form-content">
<u--form>
<u-form-item>
<u-icon name="account" size="24px"></u-icon>
<u--input placeholder="请输入用户名" border="bottom" v-model="username"></u--input>
</u-form-item>
<u-form-item>
<u-icon name="lock" size="24px"></u-icon>
<u--input placeholder="请输入密码" border="bottom" v-model="password" clearable :password="showPwd">
<template slot="suffix">
<view class="slot-list">
<u-icon :name="showPwd ? 'eye-off' : 'eye-fill'" @click="showPassword"
style="padding: 0 5px;"
></u-icon>
</view>
</template>
</u--input>
</u-form-item>
<u-form-item>
<u-icon name="lock" size="24px"></u-icon>
<u--input placeholder="请再次输入密码" border="bottom" v-model="confirmPassword" clearable :password="showPwd">
<template slot="suffix">
<view class="slot-list">
<u-icon :name="showPwd ? 'eye-off' : 'eye-fill'" @click="showPassword"
style="padding: 0 5px;"
></u-icon>
</view>
</template>
</u--input>
</u-form-item>
</u--form>
</view>
<view class="btn-list">
<u-button text="立即注册" type="primary" size="large" @click="onSubmit"></u-button>
</view>
<u-radio-group v-model="agreeTerms" style="justify-content: center;align-items: center">
<u-radio shape="circle" name="1"></u-radio>
<span style="font-size: 12px">我已阅读并同意
<span style="color: #3c9cff">《用户协议》</span>和<span style="color: #3c9cff">《隐私协议》</span>
</span>
</u-radio-group>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import {userAccountRegister} from '../../config/api.js'
export default {
data() {
return {
username: "",
password: "",
confirmPassword: "",
agreeTerms: 0,
showPwd: true,
}
},
methods: {
showPassword() {
this.showPwd = !this.showPwd
},
onSubmit() {
if (this.agreeTerms != 1) {
this.$refs.uToast.show({
message: '请先勾选同意用户协议'
})
return
}
if (this.password !== this.confirmPassword) {
this.$refs.uToast.show({
message: '两次输入的密码不一致'
})
return
}
userAccountRegister({
username: this.username,
password: this.password
}).then(() => {
this.$refs.uToast.show({
message: '注册成功',
complete() {
// 跳转登录
uni.navigateTo({
url: '/pages/index/index'
})
}
})
})
},
}
}
</script>
<style lang="scss">
.page-content {
display: flex;
flex-direction: column;
padding: 2rem 2rem;
}
.image-bg {
align-items: center;
}
.form-content {
padding: 1rem 0rem;
}
.slot-list {
display: flex;
flex-direction: row;
}
.btn-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
padding-bottom: 1rem;
}
</style>
关于
我是一名独立开发者,只工作不上班,带你探索业界正流行的现代化全栈项目。
以下是近期会更新的一系列文章,欢迎关注~
- 用户-登录注册-后端
- 用户-登录注册-前端
- 用户-钱包充值-后端
- 用户-钱包充值-前端
- 营销-签到有礼-后端
- 营销-签到有礼-前端
- 营销-签到有礼-后端单元测试
- 营销-限时秒杀-后端
- 营销-限时秒杀-前端
- 营销-优惠券-后端
- 营销-优惠券-前端
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: