「青训营 X 码上掘金」| 我的名片

85 阅读3分钟

当青训营遇上码上掘金

​借助这次活动我想用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;
}

image-20230204235003667.png

样式与动画相关CSS

flex与分区大小

​ 想使用flex-grow把所剩高度分配给第二块,不过失效了——flex-grow只能用于主轴上,立即调整主轴方向

.App{
    //...
	flex-direction: column;
    //...
    .topBox {
    	flex-grow: 0; /* 让topBox不抢剩余空间 */
    }
    //...
    .infoBox {
    	flex-grow: 1;
    }
}  

image-20230204235047166.png

背景模糊处理

​ 使用css设置背景图片,并让其适应div大小——使用 filter: blur(3px) 设置背景模糊

.backImg {
        height: 100%;
        filter: blur(3px); /* 背景模糊 */
        background-blend-mode: darken; //定义了背景层的混合模式(图片与颜色)
      }

小头像旋转动画

spinning.gif

​ 为使小头像居中,使用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);
              }
            }
          }
        }
      }
    }

点击——下拉与收起功能

​ 使用点击下拉的方式展示信息

click.gif

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%;
  }
}

动画.gif

收尾部分

​ 最后,用css调整一下样式,比如鼠标指针、内填充、文字居中等等

​ 由于码上掘金平台限制,无法以模块的形式引入图片资源,使用在线图床网站生成图片链接让 imgbackground可以访问图片资源

image-20230209011349889.png

// 用到地址的相关标签
<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" />
//...