Heim > Web-Frontend > js-Tutorial > Hauptteil

Das ideale Karussell bauen, Teil 1

王林
Freigeben: 2023-09-04 18:25:09
Original
766 Leute haben es durchsucht

Karussells sind ein fester Bestandteil von Streaming- und E-Commerce-Websites. Sowohl Amazon als auch Netflix nutzen sie als wichtige Navigationstools. In diesem Tutorial bewerten wir das Interaktionsdesign beider und nutzen unsere Erkenntnisse, um das perfekte Karussell zu implementieren.

In dieser Tutorialreihe lernen wir auch einige Funktionen der JavaScript-Motion-Engine Popmotion kennen. Es bietet Animationstools wie Tweening (zum Paginieren), Zeigerverfolgung (zum Scrollen) und Federphysik (für unseren wunderbaren letzten Schliff).

Teil 1 wird bewerten, wie Amazon und Netflix Scrollen implementieren. Wir werden dann ein Karussell implementieren, das per Touch gescrollt werden kann.

Am Ende dieser Serie werden wir die Federphysik nutzen, um Rad- und Touchpad-Scrolling, Paging, Fortschrittsbalken, Tastaturnavigation und ein paar kleine Berührungen zu implementieren. Wir werden auch auf einige grundlegende Funktionszusammensetzungen eingehen.

Ist es perfekt?

Wie macht man das Karussell „perfekt“? Es muss erreichbar sein über:

  • Maus: Es sollte über Schaltflächen zum Zurück- und Weitergehen verfügen, die leicht anzuklicken sind und den Inhalt nicht verdecken.
  • Touch: Es sollte dem Finger folgen und dann mit der gleichen Geschwindigkeit scrollen, als wenn der Finger den Bildschirm verlassen hätte.
  • Scrollrad: Die oft übersehene Apple Magic Mouse und viele Laptop-Trackpads bieten reibungsloses horizontales Scrollen. Diese Fähigkeiten sollten wir uns zunutze machen!
  • Tastatur: Viele Benutzer sind nicht bereit oder nicht in der Lage, mit der Maus zu navigieren. Es ist wichtig, unsere Karussells zugänglich zu machen, damit auch diese Benutzer unser Produkt nutzen können.

Abschließend gehen wir noch einen Schritt weiter und sorgen dafür, dass das Karussell über die Federphysik klar und instinktiv reagiert, wenn der Schieber sein Ende erreicht, was für ein sicheres und angenehmes Benutzererlebnis sorgt.

Einstellungen

Besorgen wir uns zunächst den HTML- und CSS-Code, der zum Erstellen eines einfachen Karussells erforderlich ist, indem wir diesen CodePen forken.

Pen verwendet Sass zur Vorverarbeitung von CSS und Babel zum Transpilieren von ES6-JavaScript. Ich habe auch Popmotion hinzugefügt, auf das über window.popmotion zugegriffen werden kann.

Sie können den Code bei Bedarf in ein lokales Projekt kopieren, müssen jedoch sicherstellen, dass Ihre Umgebung Sass und ES6 unterstützt. Sie müssen Popmotion außerdem mit npm install popmotion installieren.

Erstellen Sie ein neues Karussell

Auf jeder Seite können wir viele Karussells haben. Wir brauchen also eine Möglichkeit, den Zustand und die Funktionalität jedes einzelnen zusammenzufassen.

Ich werde Factory-Funktion anstelle des class。工厂函数避免了使用经常令人困惑的 this-Schlüsselworts verwenden und den Code für dieses Tutorial vereinfachen.

Fügen Sie in Ihrem JavaScript-Editor diese einfache Funktion hinzu:

function carousel(container) {
}

carousel(document.querySelector('.container'));
Nach dem Login kopieren

Wir werden in dieser carousel Funktion karussellspezifischen Code hinzufügen.

Wie und warum man scrollt

Unsere erste Aufgabe besteht darin, die Karussellrolle herzustellen. Wir können dieses Problem auf zwei Arten lösen:

Natives Browser-Scrollen

Die offensichtliche Lösung besteht darin, overflow-x:scroll auf dem Schieberegler einzustellen. Dies ermöglicht natives Scrollen in allen Browsern, einschließlich Touch-Geräten und Geräten mit horizontalem Mausrad.

Allerdings hat diese Methode auch Nachteile:

  • Inhalte außerhalb des Containers sind nicht sichtbar, was unser Design einschränken kann.
  • Es schränkt auch die Art und Weise ein, wie wir Animationen verwenden können, um anzuzeigen, dass der Endpunkt erreicht wurde.
  • Desktop-Browser verfügen über eine hässliche (wenn auch zugängliche!) horizontale Bildlaufleiste.

oder:

Animation translateX

Wir können auch die translateX 属性设置动画。这将是非常通用的,因为我们能够准确地实现我们喜欢的设计。 translateX 的性能也非常好,因为与 CSS left-Eigenschaft des Karussells animieren. Dies wird sehr vielseitig sein, da wir genau das Design umsetzen können, das uns gefällt.

Die Leistung ist auch sehr gut, da sie im Gegensatz zur CSS-Eigenschaft left von der GPU des Geräts verarbeitet werden kann.

Der Nachteil besteht darin, dass wir die Scroll-Funktion mithilfe von JavaScript neu implementieren müssen. Das bedeutet mehr Arbeit, mehr Code.

Wie implementieren Amazon und Netflix Scrollen?

Amazon- und Netflix-Karussells gehen beide unterschiedliche Kompromisse ein, um dieses Problem zu lösen.

Amazonleft 属性设置动画。对 left Das Animieren eines Karussells

im „Desktop“-Modus ist eine sehr schlechte Wahl, da eine Änderung eine Neuberechnung des Layouts auslöst. Dies ist CPU-intensiv und ältere Maschinen werden Schwierigkeiten haben, 60 fps zu erreichen.

left 而不是 translateXWer sich entschieden hat, links statt zu animieren, muss ein echter Idiot sein (Spoiler:

Das war ich, damals im Jahr 2012. So erleuchtet hatten wir nicht)🎜

当检测到触摸设备时,轮播会使用浏览器的本机滚动。仅在“移动”模式下启用此功能的问题是使用水平滚轮的桌面用户会错过。这也意味着轮播之外的任何内容都必须在视觉上被切断:

制作理想的旋转木马,第 1 部分

Netflix 正确动画轮播的 translateX 属性,并且在所有设备上均如此。这使他们能够拥有一种在轮播之外渗透的设计:

制作理想的旋转木马,第 1 部分

这反过来又允许他们做出奇特的设计,其中项目在轮播的 x 和 y 边缘之外放大,而周围的项目移开:

制作理想的旋转木马,第 1 部分

不幸的是,Netflix 对触摸设备滚动的重新实现并不令人满意:它使用基于手势的分页系统,感觉又慢又麻烦。也没有考虑水平滚轮。

我们可以做得更好。让我们编码吧!

像专业人士一样滚动

我们的第一步是获取 .slider 节点。当我们这样做时,让我们抓取它包含的项目,以便我们可以计算出滑块的尺寸。

function carousel(container) {
  const slider = container.querySelector('.slider');
  const items = slider.querySelectorAll('.item');
}
Nach dem Login kopieren

测量轮播

我们可以通过测量滑块的宽度来计算出滑块的可见区域:

const sliderVisibleWidth = slider.offsetWidth;
Nach dem Login kopieren

我们还需要其中包含的所有项目的总宽度。为了使我们的 carousel 函数保持相对干净,让我们将此计算放在文件顶部的单独函数中。

通过使用 getBoundingClientRect 测量第一项的 left 偏移量和最后一项的 right 偏移量,我们可以使用差异在它们之间找到所有项目的总宽度。

function getTotalItemsWidth(items) {
  const { left } = items[0].getBoundingClientRect();
  const { right } = items[items.length - 1].getBoundingClientRect();
  return right - left;
}
Nach dem Login kopieren

在我们的 sliderVisibleWidth 测量之后,写入:

const totalItemsWidth = getTotalItemsWidth(items);
Nach dem Login kopieren

我们现在可以算出我们的轮播应该允许滚动的最大距离。它是所有项目的总宽度,减去可见滑块的整个宽度。这提供了一个数字,允许最右边的项目与滑块的右侧对齐:

const maxXOffset = 0;
const minXOffset = - (totalItemsWidth - sliderVisibleWidth);
Nach dem Login kopieren

完成这些测量后,我们就可以开始滚动轮播了。

设置 translateX

Popmotion 附带 CSS 渲染器,用于简单且高效地设置 CSS 属性。它还带有一个值函数,可用于跟踪数字,更重要的是(我们很快就会看到),可用于查询其速度。

在 JavaScript 文件的顶部,像这样导入它们:

const { css, value } = window.popmotion;
Nach dem Login kopieren

然后,在设置 minXOffset 后,为滑块创建一个 CSS 渲染器:

const sliderRenderer = css(slider);
Nach dem Login kopieren

并创建一个 value 来跟踪滑块的 x 偏移量,并在滑块的 translateX 属性发生变化时更新它:

const sliderX = value(0, (x) => sliderRenderer.set('x', x));
Nach dem Login kopieren

现在,水平移动滑块就像编写一样简单:

sliderX.set(-100);
Nach dem Login kopieren

试试吧!

触摸滚动

我们希望轮播在用户 水平拖动滑块时开始滚动,并在用户停止触摸屏幕时停止滚动。我们的事件处理程序将如下所示:

let action;

function stopTouchScroll() {
  document.removeEventListener('touchend', stopTouchScroll);
}

function startTouchScroll(e) {
  document.addEventListener('touchend', stopTouchScroll);
}

slider.addEventListener('touchstart', startTouchScroll, { passive: false });
Nach dem Login kopieren

在我们的 startTouchScroll 函数中,我们想要:

  • 停止任何其他为 sliderX 提供动力的操作。
  • 找到原点接触点。
  • 监听下一个 touchmove 事件,看看用户是垂直拖动还是水平拖动。

document.addEventListener后添加:

if (action) action.stop();
Nach dem Login kopieren

这将阻止任何其他操作(例如我们将在 stopTouchScroll 中实现的物理动力动量滚动)移动滑块。如果滑块滚动经过他们想要单击的项目或标题,这将允许用户立即“捕获”滑块。

接下来,我们需要存储原点触摸点。这将使我们能够看到用户接下来将手指移动到哪里。如果是垂直移动,我们将允许页面像往常一样滚动。如果是水平移动,我们将滚动滑块。

我们希望在事件处理程序之间共享此 touchOrigin。所以在 let action; 之后添加:

let touchOrigin = {};
Nach dem Login kopieren

回到我们的 startTouchScroll 处理程序,添加:

const touch = e.touches[0];
touchOrigin = {
  x: touch.pageX,
  y: touch.pageY
};
Nach dem Login kopieren

我们现在可以向 document 添加一个 touchmove 事件监听器,以根据此 touchOrigin 确定拖动方向:

document.addEventListener('touchmove', determineDragDirection);
Nach dem Login kopieren

我们的 defineDragDirection 函数将测量下一个触摸位置,检查它是否实际移动,如果是,则测量角度以确定它是垂直还是水平:

function determineDragDirection(e) {
  const touch = e.changedTouches[0];
  const touchLocation = {
    x: touch.pageX,
    y: touch.pageY
  };
}
Nach dem Login kopieren

Popmotion 包含一些有用的计算器,用于测量两个 x/y 坐标之间的距离等内容。我们可以这样导入:

const { calc, css, value } = window.popmotion;
Nach dem Login kopieren

然后测量两点之间的距离是使用 distance 计算器:

const distance = calc.distance(touchOrigin, touchLocation);
Nach dem Login kopieren

现在,如果触摸已移动,我们可以取消设置此事件侦听器。

if (!distance) return;
document.removeEventListener('touchmove', determineDragDirection);
Nach dem Login kopieren

使用 angle 计算器测量两点之间的角度:

const angle = calc.angle(touchOrigin, touchLocation);
Nach dem Login kopieren

我们可以通过将其传递给以下函数来确定该角度是水平角度还是垂直角度。将此函数添加到我们文件的最顶部:

function angleIsVertical(angle) {
  const isUp = (
    angle <= -90 + 45 &&
    angle >= -90 - 45
  );
  const isDown = (
    angle <= 90 + 45 &&
    angle >= 90 - 45
  );

  return (isUp || isDown);
}
Nach dem Login kopieren

如果提供的角度在 -90 +/- 45 度(垂直向上)或 90 +/-45 度(垂直向下)范围内,此函数将返回 true。因此我们可以添加另一个 return 子句,如果此函数返回 true

if (angleIsVertical(angle)) return;
Nach dem Login kopieren

指针跟踪

现在我们知道用户正在尝试滚动轮播,我们可以开始跟踪他们的手指。 Popmotion 提供了一个指针操作,可输出鼠标或触摸指针的 x/y 坐标。

首先导入指针

const { calc, css, pointer, value } = window.popmotion;
Nach dem Login kopieren

要跟踪触摸输入,请将原始事件提供给 pointer

action = pointer(e).start();
Nach dem Login kopieren

我们想要测量指针的初始 x 位置并将任何移动应用于滑块。为此,我们可以使用名为 applyOffset 的转换器。

转换器是纯函数,它接受一个值,并返回它——是的——转换后的值。例如:const double = (v) => v * 2

const { calc, css, pointer, transform, value } = window.popmotion;
const { applyOffset } = transform;
Nach dem Login kopieren

applyOffset 是一个柯里化函数。这意味着当我们调用它时,它会创建一个新函数,然后可以向该函数传递一个值。我们首先使用要测量偏移量的数字(在本例中为 action.x 的当前值)以及要应用该偏移量的数字来调用它。在本例中,这就是我们的 sliderX

因此我们的 applyOffset 函数将如下所示:

const applyPointerMovement = applyOffset(action.x.get(), sliderX.get());
Nach dem Login kopieren

我们现在可以在指针的 output 回调中使用此函数,将指针移动应用到滑块。

action.output(({ x }) => slider.set(applyPointerMovement(x)));
Nach dem Login kopieren

停下来,有风格

轮播现在可以通过触摸拖动!您可以使用 Chrome 开发者工具中的设备模拟来测试这一点。

感觉有点笨拙,对吧?您以前可能遇到过这样的滚动感觉:抬起手指,滚动就停止了。或者滚动停止,然后一个小动画接管以假装滚动继续。

我们不会那样做。我们可以使用 Popmotion 中的物理动作来获取 sliderX 的真实速度,并在一段时间内对其施加摩擦力。

首先,将其添加到我们不断增长的导入列表中:

const { calc, css, physics, pointer, value } = window.popmotion;
Nach dem Login kopieren

然后,在 stopTouchScroll 函数的末尾添加:

if (action) action.stop();

action = physics({
  from: sliderX.get(),
  velocity: sliderX.getVelocity(),
  friction: 0.2
})
  .output((v) => sliderX.set(v))
  .start();
Nach dem Login kopieren

这里,fromvelocity 被设置为 sliderX 的当前值和速度。这确保了我们的物理模拟与用户的拖动运动具有相同的初始启动条件。​​

friction 被设置为 0.2。摩擦力设置为从 01 的值,其中 0 根本没有摩擦力,而 1 是绝对摩擦力摩擦。尝试使用此值来查看当用户停止拖动时它对轮播的“感觉”产生的变化。

数字越小,感觉越轻,数字越大,动作越重。对于滚动动作,我觉得 0.2 在不稳定和迟缓之间取得了很好的平衡。

边界

但是有一个问题!如果您一直在使用新的触摸旋转木马,那么这是显而易见的。我们没有限制移动,因此可以真正扔掉你的旋转木马!

还有另一个变压器可以完成这项工作,clamp。这也是一个柯里化函数,这意味着如果我们使用最小值和最大值调用它,例如 01,它将返回一个新函数。在此示例中,新函数将限制给定的任何数字在 01 之间:

clamp(0, 1)(5); // returns 1
Nach dem Login kopieren

首先导入clamp:

const { applyOffset, clamp } = transform;
Nach dem Login kopieren

我们希望在轮播中使用此夹紧功能,因此在定义 minXOffset 后添加此行:

const clampXOffset = clamp(minXOffset, maxXOffset);
Nach dem Login kopieren

我们将使用 pipe 转换器使用一些轻量函数组合来修改我们在操作上设置的两个 output

管道

当我们调用函数时,我们这样写:

foo(0);
Nach dem Login kopieren

如果我们想将该函数的输出提供给另一个函数,我们可以这样写:

bar(foo(0));
Nach dem Login kopieren

这变得有点难以阅读,而且随着我们添加越来越多的功能,情况只会变得更糟。

使用 pipe,我们可以从 foobar 组成一个新函数,我们可以重用它:

const foobar = pipe(foo, bar);
foobar(0);
Nach dem Login kopieren

它也是按照自然的开始 -> 结束顺序编写的,这使得它更容易理解。我们可以使用它将 applyOffsetclamp 组合成一个函数。导入 pipe

const { applyOffset, clamp, pipe } = transform;
Nach dem Login kopieren

output 回调替换为 pointer

pipe(
  ({ x }) => x,
  applyOffset(action.x.get(), sliderX.get()),
  clampXOffset,
  (v) => sliderX.set(v)
)
Nach dem Login kopieren

并将 physicalsoutput 回调替换为:

pipe(clampXOffset, (v) => sliderX.set(v))
Nach dem Login kopieren

这种函数组合可以非常巧妙地从较小的、可重用的函数中创建描述性的、逐步的流程。

现在,当您拖动并抛出轮播时,它不会移动到其边界之外。

突然停止并不是很令人满意。但这是稍后部分的问题!

结论

这就是第 1 部分的全部内容。到目前为止,我们已经研究了现有的轮播,以了解不同滚动方法的优点和缺点。我们使用 Popmotion 的输入跟踪和物理原理,通过触摸滚动为轮播的 translateX 提供高性能动画。我们还了解了函数组合和柯里化函数。

您可以在此 CodePen 上获取“到目前为止的故事”的评论版本。

在接下来的几期中,我们将介绍:

  • 用鼠标滚轮滚动
  • 当窗口大小调整时重新测量轮播
  • 分页,支持键盘和鼠标
  • 借助弹簧物理原理实现令人愉悦的触感

期待在那里见到您!

Das obige ist der detaillierte Inhalt vonDas ideale Karussell bauen, Teil 1. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!