超赞Win10日历悬停效果,爱了爱了(使用HTMLCSS和vanilla JS)
Posted 海拥✘
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了超赞Win10日历悬停效果,爱了爱了(使用HTMLCSS和vanilla JS)相关的知识,希望对你有一定的参考价值。
在本文中,我将向您解释我是如何创建自己的Windows 10悬停效果日历的
本文可能有点复杂,但这是针对初学者的,如果您已经精通JS,并且知道Grid悬停逻辑,则可以快速遍历代码以了解发生了什么。如果基础较差也没关系,建议点赞收藏日后慢慢研究
观察结果
1.毫无疑问, 这里使用了“网格悬停”效果,但是在光标周围的每个方向上突出显示了一个以上元素的边框,即,元素后面的元素也被突出显示了
2.日期没有按钮悬停效果
3.网格悬停效果不适用于活动日期(今天的date)元素。
4.默认情况下,活动日期在边框和背景之间有一个空格。如果选择其他日期,则消除间隔。
5.点击日期(非有效日期)只有一个彩色边框
6.活动元素的边框被照亮
入门
您可能已经猜到了,我将从网格效果代码开始。
网格的前7个元素是星期名称和休息日期。由于日历一次显示42个日期,因此我在中添加了42个win-btn
元素win-grid
。一些日期处于非活动状态,其中之一处于活动状态,因此我相应地添加了类。
html
<html>
<head>
<title>Windows 10 calendar hover effect</title>
</head>
<body>
<h1>Windows 10 Calendar hover effect</h1>
<div class="win-grid">
<p class="week" id="1">Mo</p>
<p class="week" id="2">Tu</p>
<p class="week" id="3">We</p>
<p class="week" id="4">Th</p>
<p class="week" id="5">Fr</p>
<p class="week" id="6">Sa</p>
<p class="week" id="7">Su</p>
<div class="win-btn win-btn-inactive" id="40">29</div>
<div class="win-btn win-btn-inactive" id="41">30</div>
<div class="win-btn win-btn-inactive" id="42">31</div>
<div class="win-btn" id="1">1</div>
<div class="win-btn" id="2">2</div>
<div class="win-btn" id="3">3</div>
<div class="win-btn" id="4">4</div>
<div class="win-btn" id="5">5</div>
<div class="win-btn" id="6">6</div>
<div class="win-btn" id="7">7</div>
<div class="win-btn" id="8">8</div>
<div class="win-btn" id="9">9</div>
<div class="win-btn" id="10">10</div>
<div class="win-btn" id="11">11</div>
<div class="win-btn" id="12">12</div>
<div class="win-btn" id="13">13</div>
<div class="win-btn" id="14">14</div>
<div class="win-btn" id="15">15</div>
<div class="win-btn" id="16">16</div>
<div class="win-btn win-btn-active" id="17">17</div>
<div class="win-btn" id="18">18</div>
<div class="win-btn" id="19">19</div>
<div class="win-btn" id="20">20</div>
<div class="win-btn" id="21">21</div>
<div class="win-btn" id="22">22</div>
<div class="win-btn" id="23">23</div>
<div class="win-btn" id="24">24</div>
<div class="win-btn" id="25">25</div>
<div class="win-btn" id="26">26</div>
<div class="win-btn" id="27">27</div>
<div class="win-btn" id="28">28</div>
<div class="win-btn" id="29">29</div>
<div class="win-btn" id="30">30</div>
<div class="win-btn win-btn-inactive" id="31">1</div>
<div class="win-btn win-btn-inactive" id="32">2</div>
<div class="win-btn win-btn-inactive" id="33">3</div>
<div class="win-btn win-btn-inactive" id="34">4</div>
<div class="win-btn win-btn-inactive" id="35">5</div>
<div class="win-btn win-btn-inactive" id="36">6</div>
<div class="win-btn win-btn-inactive" id="37">7</div>
<div class="win-btn win-btn-inactive" id="38">8</div>
<div class="win-btn win-btn-inactive" id="39">9</div>
</div>
</body>
</html>
里面的CSS,我们改变的列数在网格中7,并添加以下类:win-btn-inactive
,win-btn-active
,win-btn-selected
。
CSS
@import url("https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100&display=swap");
* {
box-sizing: border-box !important;
color: white;
text-transform: capitalize !important;
font-family: "Noto Sans JP", sans-serif;
letter-spacing: 2px;
}
body {
background-color: black;
display: flex;
flex-flow: column wrap;
justify-content: center;
align-items: center;
}
.win-grid {
border: 1px solid white;
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-gap: 0.2rem;
align-items: stretch;
text-align: center;
padding: 2rem;
cursor: default;
}
.win-btn {
padding: 1rem;
text-align: center;
border-radius: 0px;
border: 3px solid transparent;
}
/* Today's Date */
.win-btn-active {
background: red;
}
/* Other Month's Date */
.win-btn-inactive {
color: #ffffff5f;
}
/* Clicked Date */
.win-btn-selected {
border: 3px solid red;
}
button:focus {
outline: none;
}
除win-btn
事件侦听器外,JS代码几乎相同。我们不再需要那些了。另外,由于我们向元素添加了更多类,因此我们不能仅直接比较className网格悬停事件中的。我们需要检查该类是否存在于元素的中classList。
JS
const offset = 69;
const angles = []; //in deg
for (let i = 0; i <= 360; i += 45) {
angles.push((i * Math.PI) / 180);
}
let nearBy = [];
function clearNearBy() {
nearBy.splice(0, nearBy.length).forEach((e) => (e.style.borderImage = null));
}
const body = document.querySelector(".win-grid");
body.addEventListener("mousemove", (e) => {
const x = e.x; //x position within the element.
const y = e.y; //y position within the element.
clearNearBy();
nearBy = angles.reduce((acc, rad, i, arr) => {
const cx = Math.floor(x + Math.cos(rad) * offset);
const cy = Math.floor(y + Math.sin(rad) * offset);
const element = document.elementFromPoint(cx, cy);
if (element !== null) {
console.log("cursor at ", x, y, "element at ", cx, cy, element.id);
if (
element.classList.contains("win-btn") &&
acc.findIndex((ae) => ae.id === element.id) < 0
) {
const brect = element.getBoundingClientRect();
const bx = x - brect.left; //x position within the element.
const by = y - brect.top; //y position within the element.
if (!element.style.borderImage)
element.style.borderImage = `radial-gradient(${offset * 2}px ${offset * 2}px at ${bx}px ${by}px ,rgba(255,255,255,0.7),rgba(255,255,255,0.1),transparent ) 9 / 1px / 0px stretch `;
return [...acc, element];
}
}
return acc;
}, []);
});
body.onmouseleave = (e) => {
clearNearBy();
};
这就是我们的初始日历的样子
微调网格效果
如您所见,网格效果有效,但是我们需要修复一些错误并进行一些状态管理。让我们研究每个错误并讨论其解决方案。
问题1——非常接近光标的元素未突出显示
很奇怪吧!当光标非常靠近某个元素时,其目标win-grid
仅是该元素,因此理想情况下必须突出显示所有附近的元素。但是这里发生了什么,您能猜出原因吗?
对于那些仍然没有get到它的人,该offset值大于附近的元素,因此,以蓝色显示的元素不会被突出显示!为了解决这个问题,我们需要将偏移量值减小到一个更接近的值。但是,如果偏移量小于元素的尺寸,它将如何到达附近的8个元素?
解决方案1
我们可以做的是,我们可以在每条偏移线上指定2个点,而不仅仅是定位端点。第一个点可能非常靠近中心,第二个点仅是端点。
在撰写本文时,我才意识到还有一些优化的余地!在网格效果中,我们正在计算8个值,根据我的新方法,我们将不得不计算16个值!如您所见,我们可以跳过一些“第一点”计算,即靠近中心且主要目的是检测极近的元素的点。
因此,我们将只计算4个NearBy点,因此每次鼠标移动总共要计算12个点,而不是8个。
问题2——有效日期的边框和背景之间的差距
这听起来似乎不是一个大问题,但请考虑一下。你会怎么做?我们想到的最明显的想法是,将每个win-btn
元素包装在a内div,并对外部容器元素应用边框效果。
但是这样做会增加DOM中元素的数量,此外,我们还必须更改代码中正在检测的元素。
因此,每次移动光标时,我们都会得到一个附近的win-btn
元素,然后必须更改其父元素的样式。当鼠标移到容器元素上方时,我们还需要添加场景,并且对添加到我们的DOM中的新元素进行此类次要事件处理。
这样,我们只是添加了越来越多可以避免的事件侦听器。
解决方案2
有一个CSS属性,可以帮助我们准确地完成所需的操作。它被称为background-origin
。
background-origin
CSS属性设置背景的原点:从边框开始,在边框内或在填充内。默认值为border-box
,这表示背景从边框结束的地方开始。
我们将使用content-box
值,因为这将使我们能够使用盒子模型的填充区域作为边框和背景之间的间隙!
剩余逻辑
现在剩下的唯一事情是所选日期的次要状态处理。我们需要记住先前选择的元素,以便在选择新日期时,首先清除上一个元素的边框,然后添加边框,然后将边框添加到新元素中。
我们将要做的是创建一个具有边框样式的CSS类,并根据需要从元素中添加或删除该类。
/* Clicked Date */
.win-btn-selected {
border: 3px solid red;
}
如果选择了有效日期以外的其他任何日期,则有效日期的背景会一直扩展到边框(如其通常的行为)。因此我们也将为此开设一门课; win-btn-active-unselected
这将更改background-origin
回border-box
。
最终代码
CSS
@import url("https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100&display=swap");
* {
box-sizing: border-box !important;
color: white;
text-transform: capitalize !important;
font-family: "Noto Sans JP", sans-serif;
letter-spacing: 2px;
}
body {
background-color: black;
display: flex;
flex-flow: column wrap;
justify-content超赞圆形动画进度条,爱了爱了(使用HTMLCSS和bootstrap框架)
超赞圆形动画进度条,爱了爱了(使用HTMLCSS和bootstrap框架)