iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
自我挑戰組

JS30 學習日記系列 第 16

Day 16 - CSS Text Shadow Mouse Move Effect

前言

JS 30 是由加拿大的全端工程師 Wes Bos 免費提供的 JavaScript 簡單應用課程,課程主打 No FrameworksNo CompilersNo LibrariesNo Boilerplate 在30天的30部教學影片裡,建立30個JavaScript的有趣小東西。

另外,Wes Bos 也很無私地在 Github 上公開了所有 JS 30 課程的程式碼,有興趣的話可以去 fork 或下載。


本日目標

製作讓文字陰影跟著滑鼠一起移動的效果。


解析程式碼

HTML 部分

.hero內放入我們預計要用來產生文字陰影(Text Shadow)效果的文字(h1)。

h1上有一個特殊的屬性:contenteditable,表示<h1></h1>之間的內容是可以被修改的。

<div class="hero">
    <h1 contenteditable>?WOAH!</h1>
</div>

<h1></h1>之間的內容可被修改如下:

  • 修改前

  • 修改後

JS 部分

在實作文字陰影效果之前,我們要先取得.hero和內部的h1

const hero = document.querySelector('.hero');
const text = hero.querySelector('h1');

由於我們的目的是產生文字陰影隨著滑鼠移動的效果,所以在.hero上註冊mousemove 事件的監聽器並以shadow()進行事件處理。

hero.addEventListener('mousemove',shadow);

shadow() :

const { offsetWidth: width, offsetHeight: height} = hero; : 最初,我們必須先取得.herowidthheight,用來計算後續文字陰影的移動量。

let { offsetX: x, offsetY: y} = e; : 我們也必須知道現在滑鼠所在的座標。

注意,這裡我們使用的是 ES6 Destructuring Assignment(解構賦值)的語法所以不使用像是const width = hero.offsetWidth;const height = hero.offsetHeight;這種較繁瑣的寫法。

function shadow(e){
    //const width = hero.offsetWidth;
    //const height = hero.offsetHeight;
    const { offsetWidth: width, offsetHeight: height} = hero;
      
    //where the person's cursor was
    //let x = e.offsetX;
    //let y = e.offsetY;
    let { offsetX: x, offsetY: y} = e;
}

因為event.offsetXevent.offsetY取得的是滑鼠相對於事件源元素(srcElement)的X,Y坐標,所以當我們把滑鼠移動到h1得到的座標就會是以h1的左上角為(0,0)開始的位置。

這樣的位置是有問題的,我們原本要取得的應該是滑鼠在視窗裡面的位置(或說是滑鼠相對.hero的位置),所以必須要做一點修正。

我們在觸發mousemove event的 DOM 物件不是.hero的情況下(this !== e.target)進行座標修正,只要滑鼠處於h1內部,就分別把(x,y)加上h1相對.hero左方和上方的距離。

function shadow(e){
    /*上略...*/
    //if hovering h1 instead of hero, then modify the x and the y values
    if (this !== e.target){
        x = x + e.target.offsetLeft;
        y = y + e.target.offsetTop;
    }
}

接下來,我們要決定文字陰影實際上可以移動的距離和範圍。

宣告常數walk作為在(x,y)方向所能移動的最遠距離,這裡我們設為500,也就是向左或向右各250、向上或向下各250

const xWalk = Math.round((x / width * walk) - (walk / 2));,把.hero的中心點x 座標指定為0x的範圍從-250~250(視窗最左邊到最右邊)。

const yWalk = Math.round((y / height * walk) - (walk / 2));,把.hero的中心點y 座標指定為0y的範圍從-250~250(視窗最上面到最下面)。

結合兩者,畫面上的座標 : 左上角(-250,-250)、正中央(0,0)、右下角(250,250)

const walk = 500;

function shadow(e){
      /*上略...*/
      //how far the text shadow should actually go
      const xWalk = Math.round((x / width * walk) - (walk / 2));
      const yWalk = Math.round((y / height * walk) - (walk / 2));
}
  • TextShadow能移動的範圍 (以walk = 500為例)

決定TextShadow可以移動的範圍後,接下來只要設定TextShadow的移動方向和顏色就完成囉!

function shadow(e){
    /*上略...*/
    text.style.textShadow = `
        ${xWalk}px ${yWalk}px 0 rgba(255,0,255,0.7),
        ${xWalk * -1}px ${yWalk}px 0 rgba(0,255,255,0.7),
        ${yWalk}px ${xWalk * -1}px 0 rgba(0,255,0,0.7),
        ${yWalk * -1}px ${xWalk}px 0 rgba(0,0,255,0.7)
     `;
}

範例畫面:

補充資料:

contenteditable
[筆記] ES6: Destructuring Assignment 解構賦值的使用
JS一秒區分clientX,offsetX,screenX,pageX之間關係

範例網頁請點此


上一篇
Day 15 - LocalStorage and Event Delegation
下一篇
Day 17 - Sorting Band Names without articles
系列文
JS30 學習日記30

尚未有邦友留言

立即登入留言