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之间关系

范例网页请点此


<<:  [01] 笔记走向

>>:  Day01-系列文介绍、规划

[Day 6]中秋时在做什麽,有没有空,可以帮想标题吗(前端篇)

今天要先来看Native Camp的流程,首先是点击注册後的页面, 有信箱和密码,还有SSO的选项,...

(Day7) 隐含转型 - 偷偷转换的 Strings 与 Numbers 类型

前言 昨天介绍了 JS 中强制转型,显性转型的部分,今天就要介绍最坑人的隐含转型 这边同样将隐含转型...

Day 25 constructors、this、static

constructors : Java 中建立物件需要建构子,如果类别没有定义建构子,编译器就会提供...

第30天 - 文件审核系统(8)_审核端END

延续昨天要讲的 DS.php https://ithelp.ithome.com.tw/articl...

数位 AI 新时代

人的科技文明发展始终来自於人性 在数位的新时代浪潮席卷之下,世界各国不论是个人的发展,还是组织企业团...