当一个摆子前端太闲的时候会做什么

国破山河在,城春草木深。 ——杜甫·春望

今日周一,在下与诸位同道中人一起来讨论一个话题: 当一个前端空闲的时候会做些什么

🤯是独自深耕论坛,钻研学术?

👯还是三两闲聊打趣,坐而论道?

💆‍♂️亦或是闭目养神,神游天地?

作为一名优秀的(摆子、摸鱼、切图…)前端开发者,在下在空闲时间最喜欢做的还是钻研(混)前端技术(工作量)。

新的一周,新的开始,上篇文章中有同学批评在下说不够”玩”,那么 这周就”简单”画一个鼠标精灵再交予各位”玩一玩”吧。

说明一下:在下说的玩,是写一遍嗷 温馨提示:文章较长,图片较多,不耐看的同学可以先去文末玩一玩在下的”大眼”,不满足了再去创造属于各位自己的鼠标精灵

以下是这周”玩具”的简单介绍:

  • 名称:大眼
  • 生辰:发文时间的昨天(2022-08-15)
  • 性别:随意
  • 情绪:发怒/常态
  • 状态:休眠/工作中
  • 简介:没啥特别的,大眼就干一件事,就是盯着你的鼠标,以防你找不到鼠标了。不过大眼有起床气,而且非常懒散,容易犯困。

大眼生活照:

当一个摆子前端太闲的时候会做什么

接下来请各位跟随在下的节奏,一步一步把自己的”大眼”创造出来。

👀 画”大眼”先画圆

老话说”画人先画骨”,同样画大眼也得先画它的骨,嗯……也就是个圆,没错,就是个普通的圆

在下的笔法还是老套路,先给他一个容器。


复制代码

给大眼容器添加一些必要的样式

body {
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    background-color: #111;
}
.eyeSocket {
    position: absolute; // 浮动居中
    left: calc(50% - 75px);
    top: calc(50% - 75px);
    width: 150px; // 固定宽度
    aspect-ratio: 1; // 长宽比 1:1 如果浏览器不支持该属性,换成 height: 150px 也一样
    border-radius: 50%;
    border: 4px solid rgb(41, 104, 217);
    z-index: 1;
}
复制代码

效果:

当一个摆子前端太闲的时候会做什么

然后就是另外两个圆和一些阴影效果,由于另外两个圆没有特殊的动效,所以在下使用两个 伪元素来实现

.eyeSocket::before,
.eyeSocket::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%); // 居中
    border-radius: 50%;
    box-sizing: border-box; // css3盒子模型
}
.eyeSocket::before {
    width: calc(100% + 20px);
    height: calc(100% + 20px);
    border: 6px solid #02ffff;
}
.eyeSocket::after {
    width: 100%;
    height: 100%;
    border: 4px solid rgb(35, 22, 140);
    box-shadow: inset 0px 0px 30px rgb(35, 22, 140);
}
复制代码

效果:

当一个摆子前端太闲的时候会做什么

👀 画龙需点睛

大眼的眼球画好了,之后就需要给它点上眼睛,喜欢什么样的眼睛因人而异,在下就选择这种 分割线来作为大眼的眼仁。

为了方便做一些过渡效果,在下使用 echarts来完成这个眼仁。

首先在下需要各位通过任何方式引入 echarts库,然后给眼仁一个容器,并初始化 echarts画布。


复制代码
#eyeball {
    width: 100%;
    height: 100%;
}
复制代码
// 画眼球
let eyeball = document.getElementById('eyeball'); // 获取eyeball元素
let eyeballChart = echarts.init(eyeball); // 初始化画布
function getEyeballChart() {
    eyeballChart.setOption({
        series: [
            {
                type: 'gauge', // 使用仪表盘类型
                radius: '-20%', // 采用负数是为了让分割线从内向外延伸
                clockwise: false,
                startAngle: '0', // 起始角度
                endAngle: '270', // 结束角度
                splitNumber: 3, // 分割数量,会将270度分割为3份,所以有四根线
                detail: false,
                axisLine: {
                    show: false,
                },
                axisTick: false,
                splitLine: {
                    show: true,
                    length: 12, // 分割线长度
                    lineStyle: {
                        shadowBlur: 20, // 阴影渐变
                        shadowColor: 'rgb(0, 238, 255)', // 阴影颜色
                        shadowOffsetY: '0',
                        color: 'rgb(0, 238, 255)', // 分割线颜色
                        width: 4, // 分割线宽度
                    }
                },
                axisLabel: false
            },
            {
                type: 'gauge',
                radius: '-20%',
                clockwise: false,
                startAngle: '45', // 倾斜45度
                endAngle: '315',
                splitNumber: 3,
                detail: false,
                axisLine: {
                    show: false,
                },
                axisTick: false,
                splitLine: {
                    show: true,
                    length: 12,
                    lineStyle: {
                        shadowBlur: 20,
                        shadowColor: 'rgb(0, 238, 255)',
                        shadowOffsetY: '0',
                        color: 'rgb(0, 238, 255)',
                        width: 4,
                    }
                },
                axisLabel: false
            }
        ]
    })
}
getEyeballChart();
复制代码

效果:

当一个摆子前端太闲的时候会做什么

眼仁就这么轻轻松松的画好了,对于常用echarts的同学可以说是轻而易举,对吧。

同时一个静态的大眼也创建完毕,接下来就要给大眼赋予生命了。

再次提醒:长文,而且代码量多,建议抽思路看即可。

✨ 生命仪式:休眠状态

赋予生命是神圣的,她需要一个过程,所以在下从最简单的开始—— 休眠状态

在下给大眼设计的休眠状态,就是闭着眼睛睡觉,其实不露出眼仁同时有节奏的呼吸(缩放)罢了,相比于整个生命仪式来说,还是比较简单的,只需要修改大眼外框的大小即可。

呼吸

这里在下采用的是 css转换+动画的方式


复制代码
/* ...其他样式 */
.eyeSocketSleeping {
    animation: sleeping 6s infinite;
}

@keyframes sleeping {
    0% {
        transform: scale(1);
    }

    50% {
        transform: scale(1.2);
    }

    100% {
        transform: scale(1);
    }
}
复制代码

闭眼

搞定了 呼吸,但是睁着眼睛怎么睡得着?

所以接下来在下要帮助大眼把眼睛闭上,这时候咱们前面给眼睛设置负数 radius的好处就来了( 其实是在下设计好的),因为 分割线是从内向外延伸的,所以此时只需要慢慢减小分割线的高度,即可实现眼睛慢慢缩小的效果,即在下给大眼设计的闭眼效果。

实现的效果是:大眼慢慢闭上眼睛(分割线缩小至0),然后开始 呼吸

直接上代码

<div class="eyeSocket" id="bigEye"> // &#x53BB;&#x6389; eyeSocketSleeping &#x6837;&#x5F0F;&#xFF0C;&#x6DFB;&#x52A0;id

</div>
&#x590D;&#x5236;&#x4EE3;&#x7801;
let bigEye = document.getElementById('bigEye'); // &#x83B7;&#x53D6;&#x5143;&#x7D20;
// ...&#x5176;&#x4ED6;&#x4EE3;&#x7801;
let leftRotSize = 0; // &#x65CB;&#x8F6C;&#x89D2;&#x5EA6;
let ballSize = 12; // &#x773C;&#x775B;&#x5C3A;&#x5BF8;
let rotTimer; // &#x5B9A;&#x65F6;&#x5668;

function getEyeballChart() {
    eyeballChart.setOption({
        series: [
            {
                startAngle: ${0 + leftRotSize * 5}, // &#x52A0;&#x4E3A;&#x9006;&#x65F6;&#x9488;&#x65CB;&#x8F6C;&#xFF0C;&#x4E58;5&#x8868;&#x793A;&#x901F;&#x5EA6;&#x4E3A;leftRotSize&#x7684;&#x500D;
            endAngle: ${270 + leftRotSize * 5}, // &#x5373;&#x53D8;&#x4E3A;&#x6BCF;10&#x5FAE;&#x79D2;&#x79FB;&#x52A8;0.5&#x5EA6;&#xFF0C;1234678&#x540C;&#x7406;
                // ...&#x5176;&#x4ED6;
                splitLine: {
                    length: ballSize, // &#x5206;&#x5272;&#x7EBF;&#x9AD8;&#x5EA6;&#x8BBE;&#x7F6E;&#x4E3A;&#x773C;&#x7403;&#x5C3A;&#x5BF8;&#x53D8;&#x91CF;
                },
            },
            {
                startAngle: ${45 + leftRotSize * 5},
                endAngle: ${315 + leftRotSize * 5},
                // ...&#x5176;&#x4ED6;
                splitLine: {
                    length: ballSize, // &#x540C;&#x4E0A;
                }
            },
            }
        ]
    })
}
// &#x4F11;&#x7720;
function toSleep() {
    clearInterval(rotTimer); // &#x6E05;&#x9664;&#x5B9A;&#x65F6;&#x5668;
    rotTimer = setInterval(() => {
        getEyeballChart()
        if (ballSize > 0) {
            ballSize -= 0.1; // &#x5F53;&#x773C;&#x7403;&#x5B58;&#x5728;&#x65F6;&#x6162;&#x6162;&#x51CF;&#x5C0F;
        } else {
            bigEye.className = 'eyeSocket eyeSocketSleeping'; // &#x773C;&#x7403;&#x6D88;&#x5931;&#x540E;&#x6DFB;&#x52A0;&#x547C;&#x5438;
        }
        leftRotSize === 360 ? (leftRotSize = 0) : (leftRotSize += 0.1); // &#x65CB;&#x8F6C;&#xFF0C;
    }, 10);
}
getEyeballChart();
toSleep()
&#x590D;&#x5236;&#x4EE3;&#x7801;

旋转实现原理:(看过在下第一篇动效的同学对旋转的实现原理应该不陌生)
修改每个圈的起始角度(startAngle)和结束角度(endAngle),并不断刷新视图,
增加度数为逆时针旋转,减去度数为顺时针旋转

如此一来就实现了眼睛缩小消失,然后开始呼吸的过程,同时咱们的大眼也进入了生命仪式之 休眠状态(乱入的鼠标有点烦);

✨ 生命仪式:起床气状态

在下相信,在座(站?蹲?)的各位同僚身边或者自身都存在一些小毛病,譬如咱们的大眼,它不但懒,喜欢睡觉,甚至叫醒它还会生气,通俗讲就是有 起床气

心理学上说有种说法是: 情绪会让你接近生命的本真

生命不就是情绪的结合嘛,没有情绪怎么能称之为生命的呢?

在设计之前我们还有点准备工作,就是让大眼先处于 休眠状态

<div class="eyeSocket eyeSocketSleeping" id="bigEye"> // &#x6DFB;&#x52A0;&#x4F11;&#x7720;

</div>
&#x590D;&#x5236;&#x4EE3;&#x7801;
// ...&#x5176;&#x4ED6;&#x4EE3;&#x7801;
let ballSize = 0; // &#x521D;&#x59CB;&#x773C;&#x7403;&#x5C3A;&#x5BF8;&#x4E3A;0
// ...&#x5176;&#x4ED6;&#x4EE3;&#x7801;
// getEyeballChart(); // &#x628A;&#x8FD9;&#x4E24;&#x884C;&#x5220;&#x6389;
// toSleep() // &#x628A;&#x8FD9;&#x4E24;&#x884C;&#x5220;&#x6389;
&#x590D;&#x5236;&#x4EE3;&#x7801;

唤醒

然后我们需要唤醒大眼,所以首先我们需要添加 唤醒动作——点击事件;

let bigEye = document.getElementById('bigEye'); // &#x83B7;&#x53D6;&#x5143;&#x7D20;
// ...&#x5176;&#x4ED6;&#x4EE3;&#x7801;
let leftRotSize = 0;
let ballSize = 0;
let rotTimer;
let isSleep = true; // &#x662F;&#x5426;&#x5904;&#x4E8E;&#x4F11;&#x7720;&#x72B6;&#x6001;
// &#x6DFB;&#x52A0;&#x70B9;&#x51FB;&#x4E8B;&#x4EF6;&#xFF0C;&#x5F53;&#x5904;&#x4E8E;&#x4F11;&#x7720;&#x72B6;&#x6001;&#x65F6;&#x6267;&#x884C;&#x5524;&#x9192;&#x65B9;&#x6CD5;
bigEye.addEventListener('click', () => {
    if (!isSleep) return;
    clickToWeakup();
})
// &#x5524;&#x9192;
function clickToWeakup() {
    isSleep = false; // &#x4FEE;&#x6539;&#x72B6;&#x6001;
    bigEye.className = 'eyeSocket'; // &#x6E05;&#x9664;&#x4F11;&#x7720;&#x72B6;&#x6001;
    clearInterval(rotTimer); // &#x6E05;&#x9664;&#x5B9A;&#x65F6;&#x5668;
    rotTimer = setInterval(() => {
        getEyeballChart()
        ballSize <= 12 360 && (ballsize +="0.1);" leftrotsize="==" ? (leftrotsize="0)" : }, 10); } 复制代码< code></=>

这样点一下大眼它就 苏醒了过来:

当一个摆子前端太闲的时候会做什么

生气

但是!

这是一个没有情绪的大眼,而在下需要的是一个有 起床气的大眼,所以这样的大眼咱们不要!

退格←…退格←…退格←…退格←…退格←…退格←……

……

慢点慢点,也不是全都不要了,咱们只需要修改一下他唤醒以后的操作,给他添加上 起床气不就行了?

接着来吧:

首先我们把代表了大眼常态的 蓝色系抽离出来,使用 css&#x53D8;&#x91CF;&#x4EE3;&#x66FF;,然后再苏醒后给他添加成代表生气的 红色系

body {
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    background-color: #111;
    perspective: 1000px;
    --c-eyeSocket: rgb(41, 104, 217);
    --c-eyeSocket-outer: #02ffff;
    --c-eyeSocket-outer-shadow: transparent;
    --c-eyeSocket-inner: rgb(35, 22, 140);
}
.eyeSocket {
    /* &#x5176;&#x4ED6;&#x5C5E;&#x6027; */
    border: 4px solid var(--c-eyeSocket);
    box-shadow: 0px 0px 50px var(--c-eyeSocket-outer-shadow); /* &#x5F53;&#x751F;&#x6C14;&#x65F6;&#x6DFB;&#x52A0;&#x7EA2;&#x8272;&#x5916;&#x53D1;&#x5149;&#xFF0C;&#x5E38;&#x6001;&#x5219;&#x4FDD;&#x6301;&#x900F;&#x660E; */
    transition: border 0.5s ease-in-out, box-shadow 0.5s ease-in-out; /* &#x6DFB;&#x52A0;&#x8FC7;&#x6E21;&#x6548;&#x679C; */
}
.eyeSocket::before,
.eyeSocket::after {
    /* &#x5176;&#x4ED6;&#x5C5E;&#x6027; */
    transition: all 0.5s ease-in-out; /* &#x6DFB;&#x52A0;&#x8FC7;&#x6E21;&#x6548;&#x679C; */
}
.eyeSocket::before {
    /* &#x5176;&#x4ED6;&#x5C5E;&#x6027; */
    border: 6px solid var(--c-eyeSocket-outer);
}
.eyeSocket::after {
    /* &#x5176;&#x4ED6;&#x5C5E;&#x6027; */
    border: 4px solid var(--c-eyeSocket-inner);
    box-shadow: inset 0px 0px 30px var(--c-eyeSocket-inner);
}
&#x590D;&#x5236;&#x4EE3;&#x7801;
// ...&#x5176;&#x4ED6;&#x4EE3;&#x7801;
let ballColor = 'transparent'; // &#x9ED8;&#x8BA4;&#x900F;&#x660E;&#xFF0C;&#x5176;&#x5B9E;&#x9ED8;&#x8BA4;&#x662F;&#x5565;&#x90FD;&#x65E0;&#x6240;&#x8C13;&#xFF0C;&#x53CD;&#x6B63;&#x770B;&#x4E0D;&#x89C1;

function getEyeballChart() {
    eyeballChart.setOption({
        series: [
            {
                // ...&#x5176;&#x4ED6;
                splitLine: {
                    // ...&#x5176;&#x4ED6;
                    lineStyle: {
                        // ...&#x5176;&#x4ED6;
                        shadowColor: ballColor, // &#x628A;&#x773C;&#x775B;&#x7684;&#x773C;&#x5F71;&#x989C;&#x8272;&#x8BBE;&#x4E3A;&#x53D8;&#x91CF;&#x63A7;&#x5236;
                        color: ballColor,
                    }
                },
            },
            {
                // ...&#x5176;&#x4ED6;
                splitLine: {
                    // ...&#x5176;&#x4ED6;
                    lineStyle: {
                        // ...&#x5176;&#x4ED6;
                        shadowColor: ballColor,
                        color: ballColor,
                    }
                }
            },
            }
        ]
    })
}
// &#x751F;&#x6C14;&#x6A21;&#x5F0F;
function setAngry() {
    // &#x901A;&#x8FC7;js&#x4FEE;&#x6539;body&#x7684;css&#x53D8;&#x91CF;
    document.body.style.setProperty('--c-eyeSocket', 'rgb(255,187,255)');
    document.body.style.setProperty('--c-eyeSocket-outer', 'rgb(238,85,135)');
    document.body.style.setProperty('--c-eyeSocket-outer-shadow', 'rgb(255, 60, 86)');
    document.body.style.setProperty('--c-eyeSocket-inner', 'rgb(208,14,74)');
    ballColor = 'rgb(208,14,74)';
}
// &#x5E38;&#x6001;&#x6A21;&#x5F0F;
function setNormal() {
    document.body.style.setProperty('--c-eyeSocket', 'rgb(41, 104, 217)');
    document.body.style.setProperty('--c-eyeSocket-outer', '#02ffff');
    document.body.style.setProperty('--c-eyeSocket-outer-shadow', 'transparent');
    document.body.style.setProperty('--c-eyeSocket-inner', 'rgb(35, 22, 140)');
    ballColor = 'rgb(0,238,255)';
}
// &#x5524;&#x9192;
function clickToWeakup() {
    isSleep = false;
    bigEye.className = 'eyeSocket';
    setAngry(); // &#x8BBE;&#x7F6E;&#x4E3A;&#x751F;&#x6C14;&#x6A21;&#x5F0F;
    clearInterval(rotTimer);
    rotTimer = setInterval(() => {
        getEyeballChart()
        ballSize <= 50 360 && (ballsize +="1);" leftrotsize="==" ? (leftrotsize="0)" : }, 10); } 点击 bigeye.addeventlistener('click', ()> {
    if (!isSleep) return;
    clickToWeakup();
})
&#x590D;&#x5236;&#x4EE3;&#x7801;</=>

大眼生气长这样:

当一个摆子前端太闲的时候会做什么

更生气

不知道在座(站?蹲擦?)各位是如何看待,但是在下看来,大眼这样好像还不够生气。

没错还不够生气,如何让大眼起来更生气呢,生气到 发火如何?

嗦干酒干!

在下这里采用的是 svg&#x6EE4;&#x955C;的方法, svg&#x6EE4;&#x955C;的属性和使用方法非常繁多,在下使用得也不是很娴熟,本文中在下就不赘述了,网上冲浪有许多技术大牛讲的非常好,希望各位勉励自己。emmmm…… 然后来教会在下,记得给在下留言文章地址

在下使用的是 feTurbulence来形成噪声,然后用 feDisplacementMap替换来给大眼添加粒子效果,因为 feDisplacementMap会混合掉元素,所以在下需要给大眼新增一个大眼替身来代替大眼被融合。

创建大眼替身

<div class="filter"> // &#x6DFB;&#x52A0;&#x6EE4;&#x955C;&#x7684;&#x5143;&#x7D20;
    <div class="eyeSocket" id="eyeFilter"> // &#x5927;&#x773C;&#x66FF;&#x8EAB;
    </div>
</div>
&#x590D;&#x5236;&#x4EE3;&#x7801;
.filter {
    width: 100%;
    height: 100%;
}
.eyeSocket,
.filter .eyeSocket { /* &#x7ED9;&#x66FF;&#x8EAB;&#x52A0;&#x4E0A;&#x76F8;&#x540C;&#x7684;&#x6837;&#x5F0F; */
    /* ...&#x539F;&#x5C5E;&#x6027; */
}
&#x590D;&#x5236;&#x4EE3;&#x7801;

当一个摆子前端太闲的时候会做什么

融合


<!-- Svg滤镜 -->
<svg width="0">
    <filter id="filter">
        <feturbulence basefrequency="1">
            <animate id="animate1" attributename="baseFrequency" dur="1s" from="0.5" to="0.55" begin="0s;animate1.end">
            </animate>
            <animate id="animate2" attributename="baseFrequency" dur="1s" from="0.55" to="0.5" begin="animate2.end">
            </animate>
        </feturbulence>
        <fedisplacementmap in="SourceGraphic" scale="50" xchannelselector="R" ychannelselector="B"/>
    </filter>
</svg>
&#x590D;&#x5236;&#x4EE3;&#x7801;
.filter {
    width: 100%;
    height: 100%;
    filter: url('#filter'); /* &#x5F00;&#x542F;&#x6EE4;&#x955C; */
}
&#x590D;&#x5236;&#x4EE3;&#x7801;

芜湖~果然献祭了一只”大眼”出来的效果看起来确实还不错哈?确实看起来酷炫多了,不愧是“献祭”啊!

真眼出现

既然粒子效果已经产生,咱们的真实大眼也就不需要躲躲藏藏了,该站出来获取这粒子”光环”了!

大眼:哈!

额……

其实……

也挺好看的嘛,不是吗?毕竟不是献祭的真正的大眼,毕竟是个替身,效果没有本体好也是很正常的对吧。

本质上是因为 feDisplacementMap设置了 scale属性的原因。 feDisplacementMap其实就是一个位置替换滤镜,通过就是改变元素和图形的像素位置的进行重新映射,然后替换一个新的位置,形成一个新的图形。
scale就是替换公式计算后偏移值相乘的比例,影响着图形的偏移量和呈现的效果。

但是话虽如此,咱这个光环不能真的就这么戴着呀,咱们还需要对光环的位置进行一些微调。

.filter .eyeSocket {
    left: calc(50% - 92px);
    top: calc(50% - 92px);
}
&#x590D;&#x5236;&#x4EE3;&#x7801;

当一个摆子前端太闲的时候会做什么

看看,看看!这不就顺眼多了吗,献祭了替身,所以尺寸都是非常契合的,而且共用了样式,所以当大眼 生气的时候,光环也会跟着生气。

这下光环也有了,看起来的确比之前更生气了。

但是我们还需要对大眼做一些细微的调整,因为大眼在常规状态下并不需要这个光环,睡着的时候光环在旁边”滋啦滋啦”不吵的慌么,所以我们还需要把常态下的大眼光环给消除掉。

在下采用的是不透明度 opacity来控制,当大眼处于生气状态时,光环为不透明;处于常规状态时光环透明不可见。

.filter .eyeSocket {
    opacity: 0; // &#x9ED8;&#x8BA4;&#x72B6;&#x6001;&#x4E0B;&#x4E0D;&#x900F;&#x660E;&#x5EA6;&#x4E3A;0
    left: calc(50% - 92px);
    top: calc(50% - 92px);
    transition: all 0.5s ease-in-out; // &#x6DFB;&#x52A0;&#x8FC7;&#x6E21;&#x6548;&#x679C;&#xFF0C;&#x503C;&#x5F97;&#x6CE8;&#x610F;&#x7684;&#x662F;&#x4E0D;&#x80FD;&#x4E22;&#x4E86;&#x539F;&#x672C;&#x7684;&#x8FC7;&#x6E21;&#x6548;&#x679C;&#xFF0C;&#x6240;&#x4EE5;&#x8FD9;&#x91CC;&#x4F7F;&#x7528;all
}
&#x590D;&#x5236;&#x4EE3;&#x7801;
// ...&#x5176;&#x4ED6;&#x4EE3;&#x7801;
let eyeFilter = document.getElementById('eyeFilter'); // &#x83B7;&#x53D6;&#x5143;&#x7D20;
// &#x5524;&#x9192;
function clickToWeakup() {
    eyeFilter.style.opacity = '1'; // &#x4E0D;&#x900F;&#x660E;&#x5EA6;&#x8BBE;&#x4E3A;1
    // ...&#x5176;&#x4ED6;
}
deathEye.addEventListener('click', () => {
    if (!isSleep) return;
    clickToWeakup();
})
&#x590D;&#x5236;&#x4EE3;&#x7801;

这样设置完,一个更生气的大眼就这样出现了:

更更生气

不知看到这样 发火的大眼,各位是不是已经满足于此。

但是在下认为不,在下觉得一个真正足够生气的大眼,不只局限于自己生气,还需要找人发泄!!

所以在下还给大眼添加了一些大眼找人的动效(当然是找不到的,它这么笨)。

其实就是让大眼左右旋转,通过 css&#x8F6C;&#x6362;来实现。


<!-- Svg滤镜 -->
<svg width="0">
    ...

</svg>
&#x590D;&#x5236;&#x4EE3;&#x7801;
/* ...&#x5176;&#x4ED6;&#x6837;&#x5F0F; */
body {
    /* ...&#x5176;&#x4ED6;&#x5C5E;&#x6027; */
    perspective: 1000px;
}
.eyeSocketLooking {
    animation: lookAround 2.5s; // &#x6DFB;&#x52A0;&#x52A8;&#x753B;&#xFF0C;&#x53EA;&#x64AD;&#x653E;&#x4E00;&#x6B21;
}
/* &#x73AF;&#x89C6;&#x52A8;&#x753B; */
@keyframes lookAround {
    0% {
        transform: translateX(0) rotateY(0);
    }

    10% {
        transform: translateX(0) rotateY(0);
    }

    40% {
        transform: translateX(-70px) rotateY(-30deg);
    }

    80% {
        transform: translateX(70px) rotateY(30deg);
    }

    100% {
        transform: translateX(0) rotateY(0);
    }
}
&#x590D;&#x5236;&#x4EE3;&#x7801;
// ...&#x5176;&#x4ED6;&#x4EE3;&#x7801;
let bigEye = document.getElementById('bigEye'); // &#x83B7;&#x53D6;&#x5143;&#x7D20;
let eyeFilter = document.getElementById('eyeFilter');

// &#x5524;&#x9192;
function clickToWeakup() {
    // ...&#x5176;&#x4ED6;&#x4EE3;&#x7801;
    eyeFilter.className = bigEye.className = 'eyeSocket eyeSocketLooking'; // &#x540C;&#x65F6;&#x7ED9;&#x5927;&#x773C;&#x548C;&#x5149;&#x73AF;&#x6DFB;&#x52A0;&#x73AF;&#x89C6;&#x52A8;&#x753B;
}

bigEye.addEventListener('click', () => {
    if (!isSleep) return;
    clickToWeakup();
})
&#x590D;&#x5236;&#x4EE3;&#x7801;

看看大眼在找什么?

向左看时,Y轴偏移量为-70px,同时按Y轴旋转-30°
向右看时,Y轴偏移量为70px,同时Y轴旋转30°

✨ 生命仪式:自我调整状态

这个状态非常好理解,大眼虽然有 起床气,但是也仅限于起床对吧,总不能一直让它生气,气坏了咋办,带着情绪工作,效果也不好不是吗。

所以我们还需要给它一点时间,让它自我调整一下,恢复成正常状态。

这个 自我调整状态就是一个从生气状态变回常态的过程,在这个过程中,大眼需要将生气状态的红色系切换为常态的蓝色系,同时 红眼也会慢慢褪去恢复正常。

其实这个 自我调整状态还是属于唤醒状态中,只是需要放在 起床气状态之后。

这里在下采纳了上文中有位同学给的建议,监听动画结束事件 webkitAnimationEnd,然后将 自我调整放在动画结束以后。

同时这里也有两个步骤:

  1. 退出 起床气状态
  2. 变回常态

为了保证两个步骤的先后顺序,可以使用 Promise来实现。不懂 Promise的同学可以先去学习一下,在下也讲不清楚哈哈哈哈。

// ...&#x5176;&#x4ED6;&#x4EE3;&#x7801;
bigEye.addEventListener('webkitAnimationEnd', () => { // &#x76D1;&#x542C;&#x52A8;&#x753B;&#x7ED3;&#x675F;&#x4E8B;&#x4EF6;
    new Promise(res => {
        clearInterval(rotTimer); // &#x6E05;&#x9664;&#x5B9A;&#x65F6;&#x5668;
        rotTimer = setInterval(() => {
            getEyeballChart(); // &#x66F4;&#x65B0;&#x89C6;&#x56FE;
            ballSize > 0 && (ballSize -= 0.5); // &#x773C;&#x7403;&#x5C3A;&#x5BF8;&#x51CF;&#x5C0F;
            leftRotSize === 360 ? (leftRotSize = 0) : (leftRotSize += 0.1);
            if (ballSize === 0) { // &#x5F53;&#x773C;&#x7403;&#x5C3A;&#x5BF8;&#x4E3A;0&#x65F6;&#xFF0C;&#x5C06;Promise&#x6807;&#x8BB0;&#x4E3A;resolved&#xFF0C;&#x7136;&#x540E;&#x6267;&#x884C;&#x540E;&#x9762;&#x7684;&#x4EE3;&#x7801;
                clearInterval(rotTimer);
                res();
            }
        }, 10);
    }).then(() => {
        eyeFilter.style.opacity = '0'; // &#x6E05;&#x9664;&#x5149;&#x73AF;
        eyeFilter.className = bigEye.className = 'eyeSocket'; // &#x6E05;&#x9664;&#x73AF;&#x89C6;&#x52A8;&#x753B;
        setNormal(); // &#x8BBE;&#x7F6E;&#x5E38;&#x6001;&#x6837;&#x5F0F;
        rotTimer = setInterval(() => {
            getEyeballChart();
            ballSize <= 12 360 && (ballsize +="0.1);" 眼球尺寸缓慢增加 leftrotsize="==" ? (leftrotsize="0)" : }, 10); }) 复制代码< code></=>

添加了这样一个监听事件后,咱们的大眼就已经具备了自我调整的能力了:

当一个摆子前端太闲的时候会做什么

✨ 生命仪式:工作状态

接下来就到了大眼重中之重的环节,也就是大眼的 工作状态

在下给大眼的工作非常简单,就是单纯的盯住在下的鼠标,如果各位想给各自的大眼一些其他的功能,可以自己发挥。

盯住鼠标,不只是说说而已,那么怎么样才能让大眼表现出他已经盯住了呢?

在下的思路是:

  1. 以大眼的位置为原点建立一个直角坐标系
  2. 然后通过监听鼠标移动事件,获取鼠标所在位置,计算出鼠标处于大眼坐标系的坐标。
  3. 将整个视口背景以X轴和Y轴进行等分成无数个旋转角度,通过鼠标坐标的数值和正负来 调整大眼眼框和眼睛的Y轴和Z轴旋转,从而达到盯住鼠标的目的。

好的,咱们理清思路,接下来就是付诸于行动。

// ...&#x5176;&#x4ED6;&#x4EE3;&#x7801;
// &#x5DE5;&#x4F5C;
function focusOnMouse(e) {
    {
        // &#x89C6;&#x53E3;&#x5C3A;&#x5BF8;&#xFF0C;&#x83B7;&#x53D6;&#x5230;&#x6574;&#x4E2A;&#x89C6;&#x53E3;&#x7684;&#x5927;&#x5C0F;
        let clientWidth = document.body.clientWidth;
        let clientHeight = document.body.clientHeight;
        // &#x539F;&#x70B9;&#xFF0C;&#x5373;bigEye&#x4E2D;&#x5FC3;&#x4F4D;&#x7F6E;&#xFF0C;&#x9875;&#x9762;&#x4E2D;&#x5FC3;
        let origin = [clientWidth / 2, clientHeight / 2];
        // &#x9F20;&#x6807;&#x5750;&#x6807;
        let mouseCoords = [e.clientX - origin[0], origin[1] - e.clientY];
        // &#x65CB;&#x8F6C;&#x89D2;&#x5EA6;
        let eyeXDeg = mouseCoords[1] / clientHeight * 80; // &#x8FD9;&#x91CC;&#x7684;80&#x4EE3;&#x8868;&#x7684;&#x662F;&#x6700;&#x4E0A;&#x4E0B;&#x8FB9;&#x7F18;&#x5927;&#x773C;X&#x8F74;&#x65CB;&#x8F6C;&#x89D2;&#x5EA6;
        let eyeYDeg = mouseCoords[0] / clientWidth * 60;
        bigEye.style.transform = rotateY(${eyeYDeg}deg) rotateX(${eyeXDeg}deg);
        eyeball.style.transform = translate(${eyeYDeg / 1.5}px, ${-eyeXDeg / 1.5}px);
    }
}
&#x590D;&#x5236;&#x4EE3;&#x7801;

注意: 如果觉得旋转角度不够大,可以调整代码中的 8060,最大可以到180,也就是完全朝向,但是由于大眼终归是一个平面生物,如果旋转度数过大,就很容易穿帮,如果旋转角度为180,大眼就会在某个方向完全消失看不见(因为大眼没有厚度,这个也许是可以优化的点),所以个人喜好调整吧。

咱们来看看大眼工作时的飒爽英姿:

当一个摆子前端太闲的时候会做什么

✨ 生命仪式:懒惰状态

顾名思义, 懒惰状态就是……懒惰状态。

在下给大眼设计的懒惰状态就是当在下的鼠标超过 30&#x79D2;没有移动时,大眼就会进入 休眠状态

所以 生命仪式的最后收尾其实非常的轻松,没有大量的代码,只需要添加一个定时器,然后修改 休眠状态的代码,将大眼的所有参数初始化即可。

// ...&#x5176;&#x4ED6;&#x4EE3;&#x7801;
let sleepTimer; // &#x4F11;&#x7720;&#x5B9A;&#x65F6;&#x5668;

// &#x4F11;&#x7720;
function toSleep() {
    // ...&#x5176;&#x4ED6;&#x64CD;&#x4F5C;
    document.body.removeEventListener('mousemove', focusOnMouse); // &#x79FB;&#x9664;&#x9F20;&#x6807;&#x79FB;&#x52A8;&#x4E8B;&#x4EF6;
    bigEye.style.transform = rotateY(0deg) rotateX(0deg); // &#x5927;&#x773C;&#x5F52;&#x4F4D;
    eyeball.style.transform = translate(0px, 0px); // &#x773C;&#x775B;&#x5F52;&#x4F4D;
}
// &#x5DE5;&#x4F5C;
function focusOnMouse(e) {
    // ...&#x5176;&#x4ED6;&#x64CD;&#x4F5C;
    // &#x8BBE;&#x7F6E;&#x4F11;&#x7720;
    if (sleepTimer) clearTimeout(sleepTimer); // &#x5982;&#x679C;&#x4F11;&#x7720;&#x5B9A;&#x65F6;&#x5668;&#x5DF2;&#x7ECF;&#x88AB;&#x8BBE;&#x7F6E;&#xFF0C;&#x5219;&#x6E05;&#x9664;&#x4F11;&#x7720;&#x5B9A;&#x65F6;&#x5668;
    sleepTimer = setTimeout(() => { // &#x91CD;&#x65B0;&#x8BA1;&#x65F6;
        toSleep();
    }, 30000);
}
&#x590D;&#x5236;&#x4EE3;&#x7801;

感谢上次掘金官方的提醒,在下把线上代码贴在这,在下文笔较差,看不下去的同学可以直接过来玩一玩,感兴趣再去创建自己的大眼。(没有点运行的不要来问我为什么出不来!!!)

如果自己在码上掘金动手的同学记得不要忘记添加echarts资源

当一个摆子前端太闲的时候会做什么

💐 结语

好家伙,原来再写一遍大眼会这么累,这次是真真正正的”玩”了一天,有功夫的各位同僚也可以去玩一玩,于在下的基础上进行完善,创造出属于各位自己的大眼。当然如果有一些比较好玩的动效也可以留言告知在下,当下次混工作量时在下可以有东西写。

就这样!

Original: https://blog.csdn.net/m0_68036862/article/details/127820001
Author: SYBH.
Title: 当一个摆子前端太闲的时候会做什么

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/657100/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球