登录页面的逻辑我们直接做到同一个页面中,通过一个 type 参数作为判断条件,判断当前状态是登录页面或是注册页面。
...
import cx from 'classnames'
...
const Login = () => {
...
const [type, setType] = useState('login'); // 登录注册类型
return <div className={s.auth}>
...
<div className={s.tab}>
<span className={cx({ [s.avtive]: type == 'login' })} onClick={() => setType('login')}>登录</span>
<span className={cx({ [s.avtive]: type == 'register' })} onClick={() => setType('register')}>注册</span>
</div>
</div>
<div className={s.form}>
...
{
type == 'register' ? <Cell icon={<CustomIcon type="mima" />}>
<Input
clearable
type="text"
placeholder="请输入验证码"
onChange={(value) => setVerify(value)}
/>
<Captcha ref={captchaRef} charNum={4} onChange={handleChange} />
</Cell> : null
}
</div>
<div className={s.operation}>
{
type == 'register' ? <div className={s.agree}>
<Checkbox />
<label className="text-light">阅读并同意<a>《掘掘手札条款》</a></label>
</div> : null
}
<Button onClick={onSubmit} block theme="primary">{type == 'login' ? '登录' : '注册'}</Button>
</div>
}
注意,如果引入了新的工具包,请自行安装,如上述代码就需要安装 classnames。可以通过 npm i classnames -S 指令
此时点击触发的 onSubmit 事件也很关键,同样需要通过 type 判断是登录还是注册,修改代码如下:
const onSubmit = async () => {
if (!username) {
Toast.show('请输入账号')
return
}
if (!password) {
Toast.show('请输入密码')
return
}
try {
// 判断是否是登录状态
if (type == 'login') {
// 执行登录接口,获取 token
const { data } = await post('/api/user/login', {
username,
password
});
// 将 token 写入 localStorage
localStorage.setItem('token', data.token);
} else {
if (!verify) {
Toast.show('请输入验证码')
return
};
if (verify != captcha) {
Toast.show('验证码错误')
return
};
const { data } = await post('/api/user/register', {
username,
password
});
Toast.show('注册成功');
// 注册成功,自动将 tab 切换到 login 状态
setType('login');
}
} catch (error) {
Toast.show('系统错误');
}
};
由于登录注册的账号和密码是同一参数,我们这边就直接复用了逻辑,并通过 type 判断调用哪一个接口。
重启项目,验证登录接口是否成功,如果成功则会返回 token 信息.
此时,我们本地的 localStorage 里,已经存下了 token,如下图所示:
到此,我们的登录注册页面算是完成了,我们拿到的 token 是有时效性的,后台设置的是 24 小时的时效,如果过期了,请求其他接口时,就会报错,从而通过逻辑判断重新回到登录页面。下一章节,我会详细分析这块内容。