创建登录页
在view下创建Login文件夹,新建index.tsx登录页
import { ChangeEvent, useEffect, useState } from "react";
import styles from "./login.module.scss"
import initLoginBg from "./init.ts";
import { Button,Input,Space } from 'antd';
import './login.less'
const view = ()=>{
//加载完这个组件之后
useEffect(()=>{
initLoginBg();
window.onresize = function(){initLoginBg};
}
)
//获取用户名输入信息
const [usernameVal,setUserNameVal] = useState(""); // 定义用户输入用户名信息这个变量
const [passwdVal,setPasswdVal] = useState(""); // 定义用户输入密码信息这个变量
const [captchaVal,setCaptchaVal] = useState(""); // 定义用户输入验证码信息这个变量
const usernameChange = (e:ChangeEvent<HTMLInputElement>) => {
//获取用户输入的用户名
//console.log(e.target.value);
//修改usernameVal变量为用户输入的用户名
setUserNameVal(e.target.value);
}
const passwdChange = (e:ChangeEvent<HTMLInputElement>) => {
//获取用户输入的密码
//console.log(e.target.value);
//修改usernameVal变量为用户输入的密码
setPasswdVal(e.target.value);
}
const captchaChange = (e:ChangeEvent<HTMLInputElement>) => {
//获取用户输入的验证码
//console.log(e.target.value);
//修改usernameVal变量为用户输入验证码
setCaptchaVal(e.target.value);
}
//点击登录按钮事件
const goToLogin = () => {
console.log("用户输入的用户名,密码,验证码分别是:",usernameVal,passwdVal,captchaVal);
}
return (
<div className={styles.loginPage}>
{/* 存放背景 */}
<canvas id="canvas" style={{display:"block"}}></canvas>
{/* 登录盒子 */}
<div className={styles.loginBox+ " loginbox"}>
{/* 标题部分 */}
<div className={styles.title}>
<h1>通用后台</h1>
<p>Better Everday</p>
</div>
{/* 表单部分 */}
<div className="form">
<Space direction="vertical" size="large" style={{display:'flex'}} >
<Input placeholder="用户名" onChange={usernameChange}/>
<Input.Password placeholder="密码" onChange={passwdChange}/>
<div className="captchaBox">
<Input placeholder="验证码" onChange={captchaChange}/>
<div className="captchaImg">
<img height="38" src="data:image/png;base64,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" alt="" />
</div>
</div>
<Button className="loginBtn" type="primary" block onClick={goToLogin}>登录</Button>
</Space>
</div>
</div>
</div>
)
}
export default view;
创建init.ts背景,星空效果背景页
export default function initLoginBg(){
var windowWidth = document.documentElement.clientWidth || document.body.clientWidth;
var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;
var canvas = document.getElementById('canvas') as HTMLCanvasElement,
ctx = canvas.getContext('2d') as CanvasRenderingContext2D,
w = canvas.width = windowWidth,
h = canvas.height = windowHeight,
hue = 217,
stars:IntStart[] = [],
count = 0,
maxStars = 500;//星星数量
var canvas2 = document.createElement('canvas') ,
ctx2 = canvas2.getContext('2d') as CanvasRenderingContext2D;
canvas2.width = 100;
canvas2.height = 100;
var half = canvas2.width / 2,
gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);
gradient2.addColorStop(0.025, '#CCC');
gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)');
gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)');
gradient2.addColorStop(1, 'transparent');
ctx2.fillStyle = gradient2;
ctx2.beginPath();
ctx2.arc(half, half, half, 0, Math.PI * 2);
ctx2.fill();
// End cache
function random(min:number, max=0) {
if (arguments.length < 2) {
max = min;
min = 0;
}
if (min > max) {
var hold = max;
max = min;
min = hold;
}
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function maxOrbit(x:number, y:number) {
var max = Math.max(x, y),
diameter = Math.round(Math.sqrt(max * max + max * max));
return diameter / 2;
//星星移动范围,值越大范围越小,
}
interface IntStart{
orbitRadius:number;
radius:number;
orbitX:number;
orbitY:number
timePassed:number;
speed:number;
alpha:number;
draw:()=>void;
}
var Star = function(this: IntStart) {
this.orbitRadius = random(maxOrbit(w, h));
this.radius = random(60, this.orbitRadius) / 18;
//星星大小
this.orbitX = w / 2;
this.orbitY = h / 2;
this.timePassed = random(0, maxStars);
this.speed = random(this.orbitRadius) / 500000;
//星星移动速度
this.alpha = random(2, 10) / 10;
count++;
stars[count] = this;
}
Star.prototype.draw = function() {
var x = Math.sin(this.timePassed) * this.orbitRadius + this.orbitX,
y = Math.cos(this.timePassed) * this.orbitRadius + this.orbitY,
twinkle = random(10);
if (twinkle === 1 && this.alpha > 0) {
this.alpha -= 0.05;
} else if (twinkle === 2 && this.alpha < 1) {
this.alpha += 0.05;
}
ctx.globalAlpha = this.alpha;
ctx.drawImage(canvas2, x - this.radius / 2, y - this.radius / 2, this.radius, this.radius);
this.timePassed += this.speed;
}
for (var i = 0; i < maxStars; i++) {
new Star.prototype.constructor();
}
function animation() {
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 0.5; //尾巴
ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 2)';
ctx.fillRect(0, 0, w, h)
ctx.globalCompositeOperation = 'lighter';
for (var i = 1, l = stars.length; i < l; i++) {
stars[i].draw();
};
window.requestAnimationFrame(animation);
}
animation();
}
新增login.module.scss样式文件
.loginPage{
position: relative;
.loginBox{
width: 450px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
color:#fff;
h1{
font-weight: bold;
font-size: 22px;
text-align: center;
color:#fff;
}
p{
text-align: center;
margin: 20px 0;
}
.title{
margin-bottom: 40px;
position: relative;
&:before,&:after{
content:"";
width: 100px;
height: 2px;
position: absolute;
background: linear-gradient(to right,rgba(255,255,255,0),#1976D2);
left: -20px;
top:18px;
}
&:after{
left: auto;
background: linear-gradient(to left,rgba(255,255,255,0),#1976D2);
right: -20px;
}
}
}
}
新增login.less自定义样式文件
.loginbox{
//控制表单元素
.ant-input, .ant-input-password {
background-color: rgba(255,255, 255, 0);
border-color:#1677ff;
color:#fff;
height:38px;
}
//控制输入框中提示文字
.ant-input::-webkit-input-placeholder{
//color:#1677ff;
color:rgba(22,119,255, 0.5)
}
//控制password组件中的输入框
.ant-input-password {
.ant-input{
height:28px;
}
}
// 控制眼睛图标
.ant-input-password-icon.anticon {
color:#1677ff;
}
//控制验证码盒子
.captchaBox{
display: flex;
.captchaImg{
margin-left: 20px;
cursor: pointer;
}
}
//控制登录按钮
.loginBtn{
height:38px;
}
}