《明日方舟》签到效果实现

VOICE

以前我写了一篇 《明日方舟》前端界面复刻,其中有一个每日签到页面有一个聚光的效果,此次咱们来分析一下具体是如何实现的。前端

View

效果演示

实际效果如图所示,移动到网格其中某个地方时,周围会出现聚光效果:react

而在游戏里面,彷佛采用了静态贴图,这多是因为手游没有这样的交互动做,因此显得有些差强人意。git

在一样的 win10 里面,也有相似的效果:github

这一次,咱们试着在 web 里面实现相似的效果。web

web 仿签到日历 copepen: READ MORE+dom

《明日方舟》前端界面复刻文章地址: READ MORE+编辑器

arknights-react 演示地址: READ MORE+布局

arknights-react 每日签到源码: READ MORE+post

实现思路

步骤分为 4 步。ui

1. 分层

分开两层图层,数字层与网格层。

让数字层放在网格层之上,大概就是这种感受。

实际 dom 的排列顺序保持一致便可,两个层的内容重叠,大小也一致。

2. 绘制

在数字层绘制初内容,在网格层绘制出网格。

CODE EXAMPLE// react hook 
function Grid () {
  // 生成 60 个网格,其实多少无所谓,随便来。
 const [list, setList] = React.useState(
  Array.from({ length: 60 }, (_, i) => i + 1)
 )
 return ( <div className="grid"> <!-- 第一层:网格 --> <ul className="grid-list grid-border"> { list.map(item => <li className="grid-item" key={item}></li>) } </ul> <!-- 第二层:数字 --> <ul className="grid-list grid-num"> { list.map(item => <li className="grid-item" tabindex="0" key={item}>{item}</li>) } </ul> </div> ) }  ReactDOM.render( <Grid></Grid>, document.getElementById('root') ) 复制代码

效果以下

蓝色边框表示咱们的网格,而数字这是单独一层展现。

copepen 演示: READ MORE+

3. 显示遮罩

添加遮罩(mask)显示。

原理是用 mask 的其中 4 个属性来控制遮罩。

另外加上点细节丰富一下,让默认的文字是暗色,悬浮的是白色。

CODE EXAMPLE.grid-border {
  // mask 大小
  -webkit-mask-size: 240px 240px;
  // mask 不重复
  -webkit-mask-repeat: no-repeat;
  // mask 圆半径
  -webkit-mask-image: radial-gradient(circle, #fff, transparent 120px);
  // mask 位置
  -webkit-position: 0 0;
}
复制代码

效果以下:

copepen 演示: READ MORE+

4. 控制遮罩(mask)移动。

控制遮罩(mask)移动。

主要是控制 mask 的 position,所以咱们须要 (x, y) 两个坐标来决定 mask 的位置。

同时鼠标在网格上移动,以及离开的时候,来设置 (x, y) 的位置。

CODE EXAMPLE// react hook 实现
function Grid() {
    const [list, setList] = React.useState(
        Array.from({ length: 60 }, (_, i) => i + 1)
    )
 const $border = React.useRef(null) const [x, setX] = React.useState(-500) const [y, setY] = React.useState(-500)  // 将遮罩移动到鼠标位置 const handleMouseMove = (e) => { e.stopPropagation() const rect = $border.current ? $border.current.getBoundingClientRect() : null  setX(e.pageX - (rect ? rect.x : -500) - 150) setY(e.pageY - (rect ? rect.y : -500) - 150) }  //设置遮罩隐藏 const handleMouseLeave = () => { setX(-500) setY(-500) }  return ( <div className='grid' onMouseMove={handleMouseMove} onMouseLeave={handleMouseLeave} > <ul ref={$border} className='grid-list grid-border' style={{ WebkitMaskPosition: `${x}px ${y}px`, // 此处设置 mask 样式 maskPosition: `${x}px ${y}px`, }} > {list.map((item) => ( <li className='grid-item' key={item}></li> ))} </ul> <ul className='grid-list grid-num'> {list.map((item) => ( <li className='grid-item' tabindex='0' key={item}> {item} </li> ))} </ul> </div> ) }  // ...  复制代码

效果以下:

copepen 演示: READ MORE+

以上就是完整的效果啦!

总结

完成日历效果总共须要 4 个步骤:

  1. 分开两层图层,数字层与网格层。
  2. 在数字层绘制初内容,在网格层绘制出网格。
  3. 添加遮罩(mask)显示。
  4. 控制遮罩(mask)移动。

至于其它的页面布局细节,这里就很少作介绍了,若是有想了解的,能够看源码,也能够在下面评论。

源码地址

web 仿签到日历 copepen: READ MORE+

《明日方舟》前端界面复刻文章地址: READ MORE+

arknights-react 演示地址: READ MORE+

arknights-react 每日签到源码: READ MORE+

本文使用 mdnice 排版

相关文章
相关标签/搜索