《明日方舟》簽到效果實現

以前我寫了一篇 《明日方舟》前端界面復刻,其中有一個每日簽到頁面有一個聚光的效果,此次咱們來分析一下具體是如何實現的。

效果演示

實際效果如圖所示,移動到網格其中某個地方時,周圍會出現聚光效果:javascript

而在遊戲裏面,彷佛採用了靜態貼圖,這多是因爲手遊沒有這樣的交互動做,因此顯得有些差強人意。css

在一樣的 win10 裏面,也有相似的效果:前端

這一次,咱們試着在 web 裏面實現相似的效果。java

web 仿簽到日曆 copepen: READ MORE+react

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

arknights-react 演示地址: READ MORE+github

arknights-react 每日簽到源碼: READ MORE+web

實現思路

步驟分爲 4 步。dom

1. 分層

分開兩層圖層,數字層與網格層。佈局

讓數字層放在網格層之上,大概就是這種感受。

實際 dom 的排列順序保持一致便可,兩個層的內容重疊,大小也一致。

2. 繪製

在數字層繪製初內容,在網格層繪製出網格。

// 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 個屬性來控制遮罩。

另外加上點細節豐富一下,讓默認的文字是暗色,懸浮的是白色。

.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) 的位置。

// 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+

相關文章
相關標籤/搜索