小白实战玩转demo——KissKiss(暖她一整天)

2,385 阅读6分钟

前言

分享一个有趣的demo。

QQ录屏20231109133502_-original-original.gif

1. HTML结构

首先,我们需要一个HTML文件来定义动画的结构。创建一个index.html文件,并添加以下代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="./kiss.css">
  <title>kiss</title>
</head>
<body>
  <div class="container">
    <div class="ball" id="l-ball">
      <div class="face face-l">
        <div class="eye eye-l"></div>
        <div class="eye eye-r"></div>
        <div class="mouth"></div>
      </div>
    </div>
    <div class="ball" id="r-ball">
      <div class="face face-r">
        <div class="eye eye-l eye-r-p"></div>
        <div class="eye eye-r eye-r-p"></div>
        <div class="mouth mouth-r"></div>
        <div class="kiss-m">
          <div class="kiss"></div>
          <div class="kiss"></div>
        </div>
      </div>
    </div>
  </div>
<script src="kiss.js"></script>
</body>
</html>

body>标签内,有一个包含两个球形元素的容器(<div class="container">)。左球(<div class="ball" id="l-ball">),右球(<div class="ball" id="r-ball">)每个球形元素内部包含了眼睛(<div class="eye">)、嘴巴(<div class="mouth">)等表情元素,以及定义了特殊动画效果的吻(<div class="kiss">)元素。这些元素的外观和动画效果是通过CSS样式(<link rel="stylesheet" href="./kiss.css">)和JavaScript脚本(<script src="kiss.js"></script>)来定义和控制的。

2. CSS样式

接下来,我们使用CSS来设计外观。在同一目录下创建一个kiss.css文件,并添加以下代码:

body{
    background-color: #f8909c;
    margin: 0;
    /* position: relative; */
  }
  .container{
    width: 232px;
    position: absolute; /* 绝对定位 */
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    font-size: 0px;
  }
  .ball{
    width: 100px;
    height: 100px;
    border-radius: 50%;
    border: 8px solid #000;
    background-color: #fff;
    position: relative;
    display: inline-block;
  }
  .face{
    width: 70px;
    height: 30px;
    position: absolute;
    right: 0;
    top: 30px;
  }
  .face::before{
    content: "";
    width: 18px;
    height: 8px;
    border-radius: 50%;
    background-color: #badc58;
    position: absolute;
    right: -8px;
    top: 20px;
  }
  .face::after{
    content: "";
    width: 18px;
    height: 8px;
    border-radius: 50%;
    background-color: #badc58;
    position: absolute;
    left: -5px;
    top: 20px;
  }
  .eye{
    width: 15px;
    height: 14px;
    border-radius: 50%;
    border-bottom: 5px solid #000;
    position: absolute;
  }
  .eye-l{
    left: 10px;
  }
  .eye-r{
    right: 5px;
  }
  .mouth{
    width: 30px;
    height: 14px;
    border-radius: 50%;
    border-bottom: 5px solid #000;
    position: absolute;
    left: 0;
    right: 0;
    bottom: -5px;
    margin: 0 auto;
    transform: translate(3px);
  }
  
  #l-ball{
    animation: close 4s ease infinite;
    z-index: 2;
  }
  @keyframes close {
    0% { transform: translate(0); }
    20% { transform: translate(20px); }
    35% { transform: translate(20px); }
    55% { transform: translate(0); }
    100% { transform: translate(0); }
  }
  .face-l{
    animation: face 4s ease infinite;
  }
  @keyframes face{
    0% { transform: translate(0) rotate(0);}
    10% { transform: translate(0) rotate(0);}
    20% { transform: translate(5px) rotate(-2deg);}
    28% { transform: translate(0) rotate(0);}
    35% { transform: translate(5px) rotate(-2deg);}
    50% { transform: translate(0) rotate(0);}
    100% { transform: translate(0) rotate(0);}
  }
  
  .face-r{
    left: 0;
    top: 37px;
  }
  .face-r::before{
    width: 10px;
    height: 10px;
    right: -4px;
  }
  .face-r::after{
    width: 10px;
    height: 10px;
    left: 5px;
  }
  .eye-r-p{
    border-top: 5px solid #000;
    border-bottom: none;
  }
  .kiss-m{
    position: absolute;
    left: 20px;
    top: 22px;
    opacity: 0;
    animation: kiss-m 4s ease infinite;
  }
  .kiss{
    width: 13px;
    height: 10px;
    border-radius: 50%;
    border-left: 5px solid #000;
  }
  
  #r-ball{
    animation: kiss 4s ease infinite;
  }
  @keyframes kiss{
    40% { transform: translate(0); }
    50% { transform: translate(30px) rotateZ(20deg); }
    60% { transform: translate(-33px); }
    67% { transform: translate(-33px); }
    77% { transform: translate(0); }
  }
  .mouth-r{
    animation: mouth-m 4s ease infinite;
  }
  @keyframes mouth-m {
    0% { opacity: 1; }
    54.9% { opacity: 1; }
    55% { opacity: 0; }
    66% { opacity: 0; }
    66.1% { opacity: 1; }
  }
  @keyframes kiss-m{
    0% { opacity: 0; }
    55% { opacity: 0; }
    55.1% { opacity: 1; }
    66% { opacity: 1; }
    66.1% { opacity: 0; }
  }

这段CSS代码包含了对页面元素的样式和动画效果的定义,解释如下:

  • body{ ... }: 设置整个页面的背景颜色为 #f8909c,并将页面边距(margin)设为0。
  • .container{ ... }: 定义一个包含两个球形元素的容器的样式。设置容器的宽度为232px,绝对定位在页面居中,并将字体大小设置为0px,使内部的文本不可见。
  • .ball{ ... }: 定义球形元素的样式,包括宽度、高度、边框、背景颜色等。将球形元素设置为相对定位(position: relative)和内联块元素(display: inline-block)。
  • .face{ ... }: 定义面部元素的样式,包括宽度、高度、位置等。面部元素相对于父元素绝对定位。
  • .face::before{ ... } 和 .face::after{ ... }: 定义面部元素前后的小元素样式,用于创建面部的特殊效果。
  • .eye{ ... }: 定义眼睛元素的样式,包括宽度、高度、边框、位置等。
  • .eye-l{ ... } 和 .eye-r{ ... }: 分别定义左眼和右眼的位置。
  • .mouth{ ... }: 定义嘴巴元素的样式,包括宽度、高度、边框、位置等。通过transform属性实现嘴巴的定位。
  • #l-ball{ ... }: 定义左球形元素的动画效果,通过@keyframes规定了球形元素的运动轨迹。
  • .face-l{ ... }: 定义左侧面部元素的动画效果,通过@keyframes规定了面部元素的旋转动画。
  • .face-r{ ... }: 定义右侧面部元素的位置。
  • .face-r::before{ ... } 和 .face-r::after{ ... }: 定义右侧面部元素前后的小元素样式,用于创建面部的特殊效果。
  • .eye-r-p{ ... }: 定义右眼的特殊效果,实现眨眼动画。
  • .kiss-m{ ... }: 定义吻元素的样式和动画效果,设置了吻的位置和不透明度,并通过@keyframes规定了吻的运动和透明度变化。
  • .kiss{ ... }: 定义吻的样式,包括宽度、高度、边框等。
  • #r-ball{ ... }: 定义右球形元素的动画效果,通过@keyframes规定了球形元素的运动轨迹。
  • .mouth-r{ ... }: 定义嘴巴元素的动画效果,通过@keyframes规定了嘴巴的透明度变化。
  • 这些样式和动画效果共同实现了页面中球形元素和面部元素的动态效果。

3. JavaScript逻辑

最后,我们使用JavaScript来实现动态kiss效果。在同一目录下创建一个kiss.js文件,并添加以下代码

if ('WebSocket' in window) {
	(function() {
		function refreshCSS() {
			var sheets = [].slice.call(document.getElementsByTagName("link"));
			var head = document.getElementsByTagName("head")[0];
			for (var i = 0; i < sheets.length; ++i) {
				var elem = sheets[i];
				head.removeChild(elem);
				var rel = elem.rel;
				if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
					var url = elem.href.replace(/(&|?)_cacheOverride=\d+/, '');
					elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
				}
				head.appendChild(elem);
			}
		}
		var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
		var address = protocol + window.location.host + window.location.pathname + '/ws';
		var socket = new WebSocket(address);
		socket.onmessage = function(msg) {
			if (msg.data == 'reload') window.location.reload();
			else if (msg.data == 'refreshcss') refreshCSS();
		};
		console.log('Live reload enabled.');
	})();
}

这段JavaScript代码实现了一个实时页面刷新(live reload)的功能,基于WebSocket技术。以下是代码的功能解释:

  • if ('WebSocket' in window) { ... }: 检查浏览器是否支持WebSocket。
  • (function() { ... })();: 创建一个立即执行函数,用于封装代码,防止污染全局作用域。
  • function refreshCSS() { ... }: 定义了一个函数refreshCSS,用于刷新页面中的CSS样式。
  • var sheets = [].slice.call(document.getElementsByTagName("link"));: 获取页面中所有的<link>元素(通常用于引入外部样式表)。
  • var head = document.getElementsByTagName("head")[0];: 获取页面中的<head>元素。
  • for (var i = 0; i < sheets.length; ++i) { ... }: 遍历所有的<link>元素。
  • var elem = sheets[i];: 获取当前遍历到的<link>元素。
  • head.removeChild(elem);: 从文档中移除当前的<link>元素。
  • var rel = elem.rel;: 获取当前<link>元素的rel属性值。
  • if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") { ... }: 检查当前<link>元素是否是样式表,并且是否有有效的href属性。
  • var url = elem.href.replace(/(&|?)_cacheOverride=\d+/, '');: 从href属性中移除之前可能添加的缓存参数。
  • elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());: 将href属性加上新的缓存参数,以强制浏览器重新加载样式表。
  • head.appendChild(elem);: 将更新后的<link>元素重新添加到文档中。
  • var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';: 根据当前页面的协议(HTTP或HTTPS)确定WebSocket的协议。
  • var address = protocol + window.location.host + window.location.pathname + '/ws';: 构建WebSocket的地址,包括主机、路径和/ws端点。
  • var socket = new WebSocket(address);: 创建WebSocket连接。
  • socket.onmessage = function(msg) { ... }: 定义WebSocket的消息处理函数,根据接收到的消息内容执行相应的操作。
  • if (msg.data == 'reload') window.location.reload();: 如果接收到的消息内容为'reload',则刷新页面。
  • else if (msg.data == 'refreshcss') refreshCSS();: 如果接收到的消息内容为'refreshcss',则调用refreshCSS()函数刷新页面中的CSS样式。
  • console.log('Live reload enabled.');: 在控制台输出消息,表示实时页面刷新功能已启用。

效果展示

QQ录屏20231109133502_-original-original.gif

最后

恭喜你已经学会这个demo啦,快去试试吧!看看你的效果跟我一样吗?我将全部代码贴在文章最后啦!

我的Gitee:     CodeSpace (gitee.com)

技术小白记录学习过程,有错误或不解的地方还请评论区留言,如果这篇文章对你有所帮助请 “点赞 收藏+关注” ,感谢支持!!