如何使用Vanilla JavaScript创建一个可拖动的旋转木马

203 阅读5分钟

简介

一个网站的旋转木马或滑块是在单一空间内显示多个图像或内容的有效方式。它可以鼓励访问者集中注意力在重要的网站内容上,同时也可以通过节省屏幕空间来提高整体视觉效果。

在这篇文章中,我们将学习如何使用vanilla JavaScript从头开始创建一个可拖动的旋转木马。这将是非常详细和有解释的,以便每个人都能理解它。

**注意:**源代码可以在GitHub上找到。

开始吧

要在vanilla JavaScript中从头开始建立可拖动的旋转木马,我们需要使用一组独特的鼠标事件,例如。

  • mousedown:当指针在一个元素内时,鼠标按钮被按下,mousedown 事件被触发。
  • mouseenter:当鼠标第一次移入一个元素时,mouseenter 事件被触发。
  • mouseleave:: 当鼠标指针移出一个元素时,mouseleave 事件被触发(这与mouseenter 相反)。
  • mouseup:mouseup :当鼠标指针在元素内,并且鼠标上的一个按钮被释放时, 事件被触发。
  • mousemove:当光标在里面时移动鼠标,mousemove 事件被触发。

让我们开始创建我们的HTML文件;基本上,我们会有尽可能多的卡片,有我们想要的任何内容。为了避免粘贴超过80行的HTML代码,我会把内容从卡片中删除,而使用方框。

<div class="slider-container">
    <div class="inner-slider">
        <div class="card"></div>
        <div class="card"></div>
        <div class="card"></div>
        <div class="card"></div>
        <div class="card"></div>
        <div class="card"></div>
        <div class="card"></div>
    </div>
</div>

让我们也给slider-containerinner-slidercard 添加一些基本样式。

.card {
    height: 300px;
    width: 400px;
    border-radius: 5px;
}
.card:nth-child(odd) {
    background-color: blue;
}
.card:nth-child(even) {
    background-color: rgb(0, 183, 255);
}
.slider-container {
    width: 80%;
    height: 350px;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    overflow: hidden;
}
.inner-slider {
    width: 150%;
    display: flex;
    gap: 10px;
    pointer-events: none;
    position: absolute;
    top: 0;
    left: 0;
}

注意: overflow: hidden; 被添加到slider-container ,所以它隐藏了指定的width 以外的其他卡片。我们还将position: absolute;topleft 并列使用在inner-slider ,所以我们可以在以后用JavaScript来利用left 的位置。

在这一点上,你的页面应该是这样的。

让旋转木马变得可伸缩

第一步将是选择滑块元素、滑块本身和滑块容器。然后我们将设置三个变量,我们将在后面使用。

let sliderContainer = document.querySelector('.slider-container');
let innerSlider = document.querySelector('.inner-slider');

let pressed = false;
let startX;
let x;

如前所述,我们将使用大量的鼠标eventListeners 来处理各种操作。我们将主要把它们附加到父滑块元素上。

我们要注意的第一个事件是mousedown事件,它类似于但不完全等同于点击。在这里,我们将指定当用户点击滑块容器时我们想要发生什么。

**注意:**这与click 事件不同,click 事件是在一个完整的点击动作发生后触发的;也就是说,鼠标按钮被按下并释放,而指针仍在同一元素内。而mousedown ,是在第一次按下按钮的瞬间执行的。

sliderContainer.addEventListener('mousedown', () => {
    ...
})

为了证明我们之前初始化为falsepressed 变量被按下,我们将首先把true 赋给它。我们还将把startx 的值设置为x 方向的偏移值减去innerSlider 的偏移值后的值,即left ,目前是0 。我们可以通过尝试注销startx 的值来看看这意味着什么。

我们还将对cursor 进行样式设置,以便更好地进行交互。这将被设置为grabbing (为了检查这个作用,尝试在slidercontainer 内点击)。

sliderContainer.addEventListener("mousedown", (e) => {
    pressed = true;
    startX = e.offsetX - innerSlider.offsetLeft;
    sliderContainer.style.cursor = "grabbing";
});

我们寻找的下一个事件是mouseenter ;我们这样做是为了增加基本的交互性,通过样式化cursor ,以表明滑块或特定的滑块卡已经被抓取。

sliderContainer.addEventListener("mouseenter", () => {
    sliderContainer.style.cursor = "grab";
});

之后,我们将监听mouseup 事件,并将cursor 样式设置为grab ,这样当用户停止抓取或点击时,cursor 将变回grab 而不是grabbing 。我们还将把pressed 的值返回到false

sliderContainer.addEventListener("mouseup", () => {
    sliderContainer.style.cursor = "grab";
    pressed = false;
});

到此为止,我们已经能够添加一些互动性,但我们还没有实现主要功能,即可拖动的旋转木马。

处理核心逻辑

现在让我们来处理核心逻辑;我们仍将以sliderContainer 为目标,但这次我们将监听一个mousemove 事件。在回调函数中,我们将检查pressed 是否是false ,这样我们就可以返回函数,它将什么也不做。

sliderContainer.addEventListener("mousemove", (e) => {
    if (!pressed) return;
    ...
});

但是,如果pressedtrue ,我们就可以进行一些其他的逻辑。第一步将是防止默认行为,其次是将x 设置为offsetX (鼠标指针相对于容器滑块元素的X坐标)。

sliderContainer.addEventListener("mousemove", (e) => {
    if (!pressed) return;
    e.preventDefault();

    x = e.offsetX;
});

你会注意到,当我们对innerSlider CSS类进行样式设计时,我们添加了position: absolute 和一个left 的值0 。现在我们要在用户拖动旋转木马时将left 的值动态地改为x-startX 。(我们要从父 div 的偏移量中减去我们当前的位置)。

sliderContainer.addEventListener("mousemove", (e) => {
    if (!pressed) return;
    e.preventDefault();

    x = e.offsetX;

    innerSlider.style.left = `${x - startX}px`;
});

在这一点上,你会注意到一切都很好,因为我们的滑块现在可以正常拖动,但是滚动的位置没有限制,可以停止。

现在让我们通过定义一个新的函数来解决这个问题。首先,我们将获得滑块内部和外部容器的位置,然后我们可以创建两个条件语句,对两边都有效。

const checkBoundary = () => {
    let outer = sliderContainer.getBoundingClientRect();
    let inner = innerSlider.getBoundingClientRect();

    if (parseInt(innerSlider.style.left) > 0) {
        innerSlider.style.left = "0px";
    }

    if (inner.right < outer.right) {
        innerSlider.style.left = `-${inner.width - outer.width}px`;
    }
};

一旦完成这些,我们现在可以在mousemove 事件监听器内调用这个函数作为最后一件事。

sliderContainer.addEventListener("mousemove", (e) => {
    ...
    checkBoundary();
});

我们能够使用这种方法成功地用JavaScript从头开始创建一个可拖动的滑块。

总结

在这篇文章中,我们已经学会了如何使用vanilla JavaScript从头开始创建一个可拖动的旋转木马,我们还学会了所有使用的鼠标事件之间的区别。