当青训营遇上码上掘金
借助这次活动我想用React+TS+Scss 编写一个个人名片,磨练一下相关技术,于是选择主题一
基础设置
按照习惯将root、html、body等宽高设为100%,并将body的内边距设为0,清除a标签相关装饰,方便之后的布局
/* index.css */
:root,
body {
height: 100%;
margin: 0;
border: 0;
}
a {
text-decoration: none;
color: inherit;
}
p {
margin: 0;
border: 0;
}
由于App包裹在root中,为调整位置给root设置flex并将其居中
/* index.css */
#root {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
样式与动画相关CSS
flex与分区大小
想使用flex-grow把所剩高度分配给第二块,不过失效了——flex-grow只能用于主轴上,立即调整主轴方向
.App{
//...
flex-direction: column;
//...
.topBox {
flex-grow: 0; /* 让topBox不抢剩余空间 */
}
//...
.infoBox {
flex-grow: 1;
}
}
背景模糊处理
使用css设置背景图片,并让其适应div大小——使用 filter: blur(3px) 设置背景模糊
.backImg {
height: 100%;
filter: blur(3px); /* 背景模糊 */
background-blend-mode: darken; //定义了背景层的混合模式(图片与颜色)
}
小头像旋转动画
为使小头像居中,使用absolute定位,设置left:50%,并用 transform: translateX(-50%),不过在设置头像旋转动画时,动画的translate属性覆盖了平移,于是将动画移至子元素img中
/* 小图片 */
.ImgIcon {
//...
position: absolute; /* 相对位置 浮于最表面 */
bottom: 20px;
left: 50%; /* 距左侧50% */
transform: translateX(-50%); /* 左移自身50% */
/* 头像图片 */
> img {
//...将动画相关移到子类中,不影响父类的transform
animation: revolve 4s infinite linear;
animation-play-state: paused; /* 动画默认暂停 */
//...
}
}
给头像增加动画:当鼠标悬浮时旋转——动画设置0%和100%两个关键帧的角度,时间曲线选用等速linear,初始播放状态为暂停,当鼠标悬浮时运行动画
/* 小图片 */
.ImgIcon {
//...
> img {
//...
animation-play-state: paused; /* 动画默认暂停 */
&:hover {
animation-play-state: running; /* 动画继续播放 */
@keyframes revolve {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
}
}
}
}
点击——下拉与收起功能
使用点击下拉的方式展示信息
CSS部分
设置 position: absolute,完全透明,顶部距离为-20%并设置z-indx——让‘详情部分’被遮挡
/* 展示信息部分 scss */
.infoBox {
position: absolute; /* 相对定位 给动画做铺垫 */
opacity: 0;
top: -20%; /* 处于被遮住的位置 */
z-index: 1; /* 让其在底层不影响top的hover */
transition: 0.3s ease-out; /* 过度效果 */
}
通过 .clicked 来控制点击前后的样式——鼠标点击橙色区块会给“详情信息” 添加或移除 .clicked css类,并用 transition 生成过度动画
/* 点击激活——infoBox下拉 scss */
.clicked {
opacity: 1;
top: 40%;
}
React部分
使用 useState 记录鼠标点击状态,用 useRef 来操作 '详情部分'div元素,绑定一个onClick函数操作点击事件
useRef的模板部分写入元素的类型 HTMLInputElement,使得使用useRef时更加具体,ts可以提示相关信息
由于不确定函数被调用时,ref所指元素是否存在,所以在函数中使用时需要先做判断——可以加上 ? 解决编译报错: infoRef.current?
// React(TS)部分 下述代码省略了不相关结构
import React, { useState, useRef } from 'react@18';
function App(){
const [clicked, setClicked] = useState(false);
const infoRef = useRef<HTMLDivElement>(null);
const show: () => void = () => {
let elem = infoRef.current;
!clicked ? elem?.classList.add("clicked") : elem?.classList.remove("clicked");
setClicked(!clicked);
};
return (
<div>
<div>
<div>
<div className="showInfo" onClick={show}></div>
</div>
</div>
<div className="infoBox" ref={infoRef}></div>
</div>
)
}
点击事件根据定义的click的状态来添加或移除特定css类名——使用 classList.add() 和 classList.remove()
移动端适配
App设置为flex,并设置媒体查询适配PC和移动端不同的宽高——当屏幕宽度小于等于500px时视为移动端
/* App.scss */
@media screen and (max-width: 500px) {
.App {
width: 70%;
height: 70%;
}
}
收尾部分
最后,用css调整一下样式,比如鼠标指针、内填充、文字居中等等
由于码上掘金平台限制,无法以模块的形式引入图片资源,使用在线图床网站生成图片链接让 img、background可以访问图片资源
// 用到地址的相关标签
<div className="backImg" style={{ background: `url("https://i.328888.xyz/2023/02/09/3mrdv.jpeg") no-repeat `, backgroundSize: "contain" }}></div>
<div className="ImgIcon">
<img src="https://i.328888.xyz/2023/02/09/3mrdv.jpeg" alt="" />
</div>
//...
<span>我的github</span> <img src="https://i.328888.xyz/2023/02/09/3mcHy.jpeg" />
//...