挑战30分钟写个用户登录注册系统(前端)- 我的全栈独立开发日记

挑战30分钟写个用户登录注册系统(前端)- 我的全栈独立开发日记

前言

技术栈是 uni-app + uView2.0 + Vue.js

本教程的视频版本已发布在B站,欢迎交流~

戳我看视频:静夜Coding-无人声编程-机械键盘纯享版

准备工作

下载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>

页面雏形就出来了

Laravel

接下里我们用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>

嗯,现在页面就很漂亮了

Laravel

接下来补充业务逻辑代码:

使用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>

登录成功会跳转到用户信息页面

用户信息页面

这里我们写一个简单的用户卡片来展示用户资料,然后还有一个修改昵称的功能,点击修改按钮,会跳出弹窗给用户修改自己的昵称。

一共涉及到两个和后端交互的接口,一是获取用户信息,而是修改用户昵称。

Laravel

新建页面 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代码就可以了。

Laravel

新建页面 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 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 4

可以开个收费教程,放到腾讯课堂之类的网站。

1年前 评论
admin0000 (楼主) 1年前

不错不错,我这个后端仔学不会排版

1年前 评论

我在的公司都是用蓝湖,设计图传上去可以自动生成前端的代码。。

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!