实战指南:制作响应式登录页

本文是《React管理平台》第九节

通过本文我们将学会登录页的制作过程

布局

根据设计图制作登录页面,我们采用了Ant Design组件库进行布局,并加以CSS样式定制,使得布局对不同屏幕尺寸友好。

UI设计图

HTML布局核心代码

下面是Login.tsx文件的HTML部分代码,使用了Ant Design的Form, Input, 和Button组件:

html 复制代码
<div className={styles.loginBackground}>
  <div className={styles.login}>
    <div className={styles.title}>用户登录</div>
    <div className={styles.subTitle}>User Login</div>
    <Form name='basic' className={styles.loginForm} initialValues={{ remember: true }} onFinish={onFinish}>
      <Form.Item name='username' rules={[{ required: true, message: '请输入用户名!' }]}>
        <Input placeholder='用户名' size='large' />
      </Form.Item>

      <Form.Item name='password' rules={[{ required: true, message: '请输入密码!' }]}>
        <Input.Password placeholder='密码' autoComplete='new-password' size='large' />
      </Form.Item>

      <Form.Item>
        <Button
          className={styles.loginSubmit}
          size='large'
          type='primary'
          block
          htmlType='submit'
          loading={loading}
        >
          登录
        </Button>
      </Form.Item>
    </Form>
  </div>
</div>

这里需要注意,我们在Input.Password组件上使用了autoComplete='new-password'即可禁用浏览器的账号密码填充

如果只给密码加上autoComplete='new-password',编辑器会出现警告

所以<Input placeholder='用户名' autoComplete='new-password' size='large' />也需要加上autoComplete

CSS

CSS样式适配不同屏幕尺寸的响应式设计,代码如下:

css 复制代码
.loginBackground{
  height: 100vh;
  background: url("@/assets/images/login/loginBackground.png") center no-repeat;
  display: flex;
  justify-content: center;
  align-items: center;
}
.login{
  position: absolute;
  margin-left: 140px;
  left: 50%;
  top: 0;
  bottom:0;
  width: 450px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.title{
  font-size: 34px;
  color: #4e4e4e;
  letter-spacing: 4px;
}

.subTitle{
  font-size: 18px;
  color: #4e4e4e;
}
.loginForm{
  margin-top: 50px;
}
.loginSubmit{
  margin-top: 10px;
}

:global(.ant-input-outlined){
  background: #f6f9fe;
  border:1px solid #f6f9fe;
  height: 52px;
  border-radius: 26px;
  padding: 0 30px;
}
:global(.ant-input::placeholder){
  color:#1a76e1;

}
:global(.ant-btn-primary){
  background:#1a76e1;
  height: 52px;
  font-size: 24px;
  border-radius: 26px;
}

/* 媒体查询样式 */
@media (max-width: 1536px) and (max-height:900px) {
  .loginBackground {
    background-size: 1536px 900px;
  }

  .login {
    margin-left: 80px;
    width: 400px;
  }

}
@media (max-width: 1024px) {
  .loginBackground {
    background: #e7eeff;
  }

  .login {
    margin-left: 0;
    position: static;
    width: 80vw;
  }

  .title {
    font-size: 30px;
    text-align: center;
  }

  .subTitle {
    font-size: 16px;
    text-align: center;
  }

  :global(.ant-input-outlined) {
    background: #f8f9fe;
    height: 52px;
    border-radius: 26px;
    padding: 0 30px;
  }

  :global(.ant-input::placeholder) {
    color: #a7aaaf;
  }

  :global(.ant-btn-primary) {
    background: #4785e8;
    height: 52px;
    font-size: 20px;
    border-radius: 26px;
  }
}

在样式部分,我们使用了媒体查询 以适配不同尺寸的设备,使用:global覆盖Ant Design的样式

在浏览器中的效果:

最终的登录页面在浏览器中的效果能够随屏幕大小变化而自适应,保持美观和功能性。以下是一个示例动画,展现了页面的响应式设计:

逻辑

loading状态

在我们的Login.tsx文件中,通过useState来控制loading状态。它在开始时被设置为false

tsx 复制代码
const [loading, setLoading] = useState(false)

每当onFinish函数被调用时,我们将loading设置为true

javascript 复制代码
const onFinish = async () => {
  setLoading(true)
}

在浏览器中的效果:

登录接口

我们在src/types/api/system目录中新增login.ts文件,该文件是登录接口的类型声明文件,内容为:

ts 复制代码
export interface LoginParams {
  username: string
  password: string
}

export interface LoginResult {
  token: string
}

启动我们之前章节中创建的json-server服务来模拟mock数据

登录请求接口位于src/api/system目录中的login.ts文件中。

tsx 复制代码
// 登录参数与返回结果定义
export interface LoginParams { username: string; password: string; }
export interface LoginResult { token: string; }

// 登录请求与服务定义
export function postLogin(params: LoginParams) {
  return request.post<LoginResult>('/system/login', params, { isShowLoading: false, isShowError: true })
}

上述代码中,由于登录页增加了loading效果,所以全局的loading效果我们设置为false,即{ isShowLoading: false }

onFinish函数中,我们首先将loading状态设置为true,然后通过postLogin函数向后台发送请求。如果请求成功,我们将loading状态设置为false并显示成功的提示信息,最后我们将路由重定向到/welcome。一旦请求失败,我们只需要简单地把loading状态重置为false即可:

tsx 复制代码
const onFinish = async (values: LoginParams) => {
  try {
    setLoading(true)
    await postLogin(values)
    setLoading(false)

    message.success('登录成功')

    router.navigate('/welcome', { replace: true }).then(() => {})
  } catch (error) {
    setLoading(false)
  }
}

我们尝试输入错误的用户名和密码,看浏览器效果:

现在我们尝试输入正确的用户名和密码,看浏览器效果:

Token存储及更新

一旦用户成功登录,我们需要保存返回的token。我们将其存储在localStorage中并在zustand的token状态中进行更新。

先导入之前章节中封装的localStorage:import storage from '@/utils/localStorage.ts'

在接口请求下边新增存储token:

tsx 复制代码
const response = await postLogin(values)
storage.set('token', response.data.token) // <-这里

之后我们需要更新zustand的token

先导入

ts 复制代码
import { useUserStore } from '@/store'

调用useUserStore

tsx 复制代码
const updateToken = useUserStore(state => state.updateToken)

之后在接口请求下边调用:

tsx 复制代码
const response = await postLogin(values)
storage.set('token', response.data.token)
updateToken(response.data.token) // <-这里

让我在浏览器中测试:

完整代码

github.com/HandsomeWol...

相关推荐
万少8 小时前
HarmonyOS 开发必会 5 种 Builder 详解
前端·harmonyos
橙序员小站10 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
炫饭第一名13 小时前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员
王晓枫13 小时前
flutter接入三方库运行报错:Error running pod install
前端·flutter
符方昊13 小时前
React 19 对比 React 16 新特性解析
前端·react.js
ssshooter13 小时前
又被 Safari 差异坑了:textContent 拿到的值居然没换行?
前端
曲折13 小时前
Cesium-气象要素PNG色斑图叠加
前端·cesium
Forever7_14 小时前
Electron 淘汰!新的桌面端框架 更强大、更轻量化
前端·vue.js
不会敲代码114 小时前
前端组件化样式隔离实战:React CSS Modules、styled-components 与 Vue scoped 对比
css·vue.js·react.js
Angelial14 小时前
Vue3 嵌套路由 KeepAlive:动态缓存与反向配置方案
前端·vue.js