이상적인 캐러셀 만들기, 1부
캐러셀은 스트리밍 및 전자상거래 웹사이트의 필수 요소입니다. Amazon과 Netflix는 모두 이를 중요한 탐색 도구로 사용합니다. 이 튜토리얼에서는 두 가지의 상호 작용 디자인을 평가하고 결과를 사용하여 완벽한 캐러셀을 구현합니다.
이 튜토리얼 시리즈에서는 JavaScript 모션 엔진 Popmotion의 일부 기능도 알아봅니다. 트위닝(페이지 매기기용), 포인터 추적(스크롤용), 스프링 물리학(즐거운 마무리 작업용)과 같은 애니메이션 도구를 제공합니다.
1부에서는 Amazon과 Netflix가 스크롤링을 구현하는 방법을 평가합니다. 그런 다음 터치로 스크롤할 수 있는 캐러셀을 구현하겠습니다.
이 시리즈가 끝날 때쯤에는 스프링 물리학을 사용하여 휠과 터치패드 스크롤, 페이징, 진행률 표시줄, 키보드 탐색 및 몇 가지 작은 터치를 구현하겠습니다. 또한 몇 가지 기본 기능 구성에 대해서도 살펴보겠습니다.
완벽한가요?
회전목마를 '완벽'하게 만드는 방법은 무엇인가요? 다음을 통해 액세스할 수 있어야 합니다.
- 마우스: 클릭하기 쉽고 내용을 가리지 않는 이전 및 다음 버튼을 제공해야 합니다.
- Touch: 손가락을 추적한 다음 손가락이 화면을 떠났을 때와 동일한 모멘텀으로 스크롤해야 합니다.
- 스크롤 휠: 자주 간과되는 Apple Magic Mouse와 많은 노트북 트랙패드는 부드러운 가로 스크롤을 제공합니다. 우리는 이러한 능력을 활용해야 합니다!
- 키보드: 많은 사용자가 마우스를 사용하여 탐색하는 것을 꺼리거나 사용할 수 없습니다. 이러한 사용자도 우리 제품을 사용할 수 있도록 캐러셀에 액세스할 수 있도록 하는 것이 중요합니다.
마지막으로 한 단계 더 나아가 슬라이더가 끝에 도달하면 캐러셀이 스프링 물리학을 통해 명확하고 본능적으로 반응하도록 하여 자신감 있고 즐거운 사용자 경험을 제공할 것입니다.
설정
먼저 이 CodePen을 포크하여 기본 캐러셀을 구축하는 데 필요한 HTML과 CSS를 얻습니다.
Pen은 Sass를 사용하여 CSS를 전처리하고 Babel을 사용하여 ES6 JavaScript를 트랜스파일합니다. window.popmotion
를 통해 액세스할 수 있는 Popmotion도 추가했습니다.
원하는 경우 코드를 로컬 프로젝트에 복사할 수 있지만 환경이 Sass 및 ES6를 지원하는지 확인해야 합니다. 또한 npm install popmotion
를 사용하여 Popmotion을 설치해야 합니다.
새 캐러셀 만들기
특정 페이지에는 캐러셀이 많이 있을 수 있습니다. 따라서 각각의 상태와 기능을 캡슐화하는 방법이 필요합니다.
저는 키워드 대신 factory functionclass
。工厂函数避免了使用经常令人困惑的 this
을 사용하고 이 튜토리얼의 코드를 단순화하겠습니다.
JavaScript 편집기에 다음 간단한 함수를 추가하세요.
으아아아이 carousel
함수에 캐러셀 전용 코드를 추가하겠습니다.
스크롤하는 방법과 이유
첫 번째 작업은 캐러셀 스크롤을 만드는 것입니다. 이 문제는 두 가지 방법으로 해결할 수 있습니다:
기본 브라우저 스크롤
확실한 해결책은 슬라이더에 overflow-x:scroll
를 설정하는 것입니다. 이렇게 하면 터치 및 수평 마우스 휠 장치를 포함한 모든 브라우저에서 기본 스크롤이 가능해집니다.
그러나 이 방법에는 단점도 있습니다:
- 컨테이너 외부의 콘텐츠는 보이지 않으므로 디자인이 제한될 수 있습니다.
- 또한 애니메이션을 사용하여 끝점에 도달했음을 나타내는 방법도 제한됩니다.
- 데스크톱 브라우저에는 보기 흉한(접근 가능하긴 하지만!) 가로 스크롤 막대가 있습니다.
또는:
애니메이션 translateX
캐러셀의 translateX
属性设置动画。这将是非常通用的,因为我们能够准确地实现我们喜欢的设计。 translateX
的性能也非常好,因为与 CSS left
속성에 애니메이션을 적용할 수도 있습니다. 우리가 원하는 디자인을 정확히 구현할 수 있기 때문에 이것은 매우 다재다능할 것입니다.
left
속성과 달리 기기의 GPU에서 처리할 수 있기 때문에 성능도 매우 좋습니다. 단점은 JavaScript를 사용하여 스크롤 기능을 다시 구현해야 한다는 것입니다. 이는 더 많은 작업과 더 많은 코드를 의미합니다.
Amazon과 Netflix는 스크롤링을 어떻게 구현하나요?
Amazon과 Netflix 캐러셀은 모두 이 문제를 해결하기 위해 서로 다른 절충안을 사용합니다.
Amazonleft
属性设置动画。对 left
"데스크톱" 모드에서 캐러셀의
left
而不是 translateX
대신 left
애니메이션을 만들기로 결정한 사람은 진짜 바보임에 틀림없어요 (스포일러:
当检测到触摸设备时,轮播会使用浏览器的本机滚动。仅在“移动”模式下启用此功能的问题是使用水平滚轮的桌面用户会错过。这也意味着轮播之外的任何内容都必须在视觉上被切断:
Netflix 正确动画轮播的 translateX
属性,并且在所有设备上均如此。这使他们能够拥有一种在轮播之外渗透的设计:
这反过来又允许他们做出奇特的设计,其中项目在轮播的 x 和 y 边缘之外放大,而周围的项目移开:
不幸的是,Netflix 对触摸设备滚动的重新实现并不令人满意:它使用基于手势的分页系统,感觉又慢又麻烦。也没有考虑水平滚轮。
我们可以做得更好。让我们编码吧!
像专业人士一样滚动
我们的第一步是获取 .slider
节点。当我们这样做时,让我们抓取它包含的项目,以便我们可以计算出滑块的尺寸。
function carousel(container) { const slider = container.querySelector('.slider'); const items = slider.querySelectorAll('.item'); }
测量轮播
我们可以通过测量滑块的宽度来计算出滑块的可见区域:
const sliderVisibleWidth = slider.offsetWidth;
我们还需要其中包含的所有项目的总宽度。为了使我们的 carousel
函数保持相对干净,让我们将此计算放在文件顶部的单独函数中。
通过使用 getBoundingClientRect
测量第一项的 left
偏移量和最后一项的 right
偏移量,我们可以使用差异在它们之间找到所有项目的总宽度。
function getTotalItemsWidth(items) { const { left } = items[0].getBoundingClientRect(); const { right } = items[items.length - 1].getBoundingClientRect(); return right - left; }
在我们的 sliderVisibleWidth
测量之后,写入:
const totalItemsWidth = getTotalItemsWidth(items);
我们现在可以算出我们的轮播应该允许滚动的最大距离。它是所有项目的总宽度,减去可见滑块的整个宽度。这提供了一个数字,允许最右边的项目与滑块的右侧对齐:
const maxXOffset = 0; const minXOffset = - (totalItemsWidth - sliderVisibleWidth);
完成这些测量后,我们就可以开始滚动轮播了。
设置 translateX
Popmotion 附带 CSS 渲染器,用于简单且高效地设置 CSS 属性。它还带有一个值函数,可用于跟踪数字,更重要的是(我们很快就会看到),可用于查询其速度。
在 JavaScript 文件的顶部,像这样导入它们:
const { css, value } = window.popmotion;
然后,在设置 minXOffset
后,为滑块创建一个 CSS 渲染器:
const sliderRenderer = css(slider);
并创建一个 value
来跟踪滑块的 x 偏移量,并在滑块的 translateX
属性发生变化时更新它:
const sliderX = value(0, (x) => sliderRenderer.set('x', x));
现在,水平移动滑块就像编写一样简单:
sliderX.set(-100);
试试吧!
触摸滚动
我们希望轮播在用户 水平拖动滑块时开始滚动,并在用户停止触摸屏幕时停止滚动。我们的事件处理程序将如下所示:
let action; function stopTouchScroll() { document.removeEventListener('touchend', stopTouchScroll); } function startTouchScroll(e) { document.addEventListener('touchend', stopTouchScroll); } slider.addEventListener('touchstart', startTouchScroll, { passive: false });
在我们的 startTouchScroll
函数中,我们想要:
- 停止任何其他为
sliderX
提供动力的操作。 - 找到原点接触点。
- 监听下一个
touchmove
事件,看看用户是垂直拖动还是水平拖动。
在document.addEventListener
后添加:
if (action) action.stop();
这将阻止任何其他操作(例如我们将在 stopTouchScroll
中实现的物理动力动量滚动)移动滑块。如果滑块滚动经过他们想要单击的项目或标题,这将允许用户立即“捕获”滑块。
接下来,我们需要存储原点触摸点。这将使我们能够看到用户接下来将手指移动到哪里。如果是垂直移动,我们将允许页面像往常一样滚动。如果是水平移动,我们将滚动滑块。
我们希望在事件处理程序之间共享此 touchOrigin
。所以在 let action;
之后添加:
let touchOrigin = {};
回到我们的 startTouchScroll
处理程序,添加:
const touch = e.touches[0]; touchOrigin = { x: touch.pageX, y: touch.pageY };
我们现在可以向 document
添加一个 touchmove
事件监听器,以根据此 touchOrigin
确定拖动方向:
document.addEventListener('touchmove', determineDragDirection);
我们的 defineDragDirection
函数将测量下一个触摸位置,检查它是否实际移动,如果是,则测量角度以确定它是垂直还是水平:
function determineDragDirection(e) { const touch = e.changedTouches[0]; const touchLocation = { x: touch.pageX, y: touch.pageY }; }
Popmotion 包含一些有用的计算器,用于测量两个 x/y 坐标之间的距离等内容。我们可以这样导入:
const { calc, css, value } = window.popmotion;
然后测量两点之间的距离是使用 distance
计算器:
const distance = calc.distance(touchOrigin, touchLocation);
现在,如果触摸已移动,我们可以取消设置此事件侦听器。
if (!distance) return; document.removeEventListener('touchmove', determineDragDirection);
使用 angle
计算器测量两点之间的角度:
const angle = calc.angle(touchOrigin, touchLocation);
我们可以通过将其传递给以下函数来确定该角度是水平角度还是垂直角度。将此函数添加到我们文件的最顶部:
function angleIsVertical(angle) { const isUp = ( angle <= -90 + 45 && angle >= -90 - 45 ); const isDown = ( angle <= 90 + 45 && angle >= 90 - 45 ); return (isUp || isDown); }
如果提供的角度在 -90 +/- 45 度(垂直向上)或 90 +/-45 度(垂直向下)范围内,此函数将返回 true
。因此我们可以添加另一个 return
子句,如果此函数返回 true
。
if (angleIsVertical(angle)) return;
指针跟踪
现在我们知道用户正在尝试滚动轮播,我们可以开始跟踪他们的手指。 Popmotion 提供了一个指针操作,可输出鼠标或触摸指针的 x/y 坐标。
首先导入指针
:
const { calc, css, pointer, value } = window.popmotion;
要跟踪触摸输入,请将原始事件提供给 pointer
:
action = pointer(e).start();
我们想要测量指针的初始 x
位置并将任何移动应用于滑块。为此,我们可以使用名为 applyOffset
的转换器。
转换器是纯函数,它接受一个值,并返回它——是的——转换后的值。例如:const double = (v) => v * 2
。
const { calc, css, pointer, transform, value } = window.popmotion; const { applyOffset } = transform;
applyOffset
是一个柯里化函数。这意味着当我们调用它时,它会创建一个新函数,然后可以向该函数传递一个值。我们首先使用要测量偏移量的数字(在本例中为 action.x
的当前值)以及要应用该偏移量的数字来调用它。在本例中,这就是我们的 sliderX
。
因此我们的 applyOffset
函数将如下所示:
const applyPointerMovement = applyOffset(action.x.get(), sliderX.get());
我们现在可以在指针的 output
回调中使用此函数,将指针移动应用到滑块。
action.output(({ x }) => slider.set(applyPointerMovement(x)));
停下来,有风格
轮播现在可以通过触摸拖动!您可以使用 Chrome 开发者工具中的设备模拟来测试这一点。
感觉有点笨拙,对吧?您以前可能遇到过这样的滚动感觉:抬起手指,滚动就停止了。或者滚动停止,然后一个小动画接管以假装滚动继续。
我们不会那样做。我们可以使用 Popmotion 中的物理动作来获取 sliderX
的真实速度,并在一段时间内对其施加摩擦力。
首先,将其添加到我们不断增长的导入列表中:
const { calc, css, physics, pointer, value } = window.popmotion;
然后,在 stopTouchScroll
函数的末尾添加:
if (action) action.stop(); action = physics({ from: sliderX.get(), velocity: sliderX.getVelocity(), friction: 0.2 }) .output((v) => sliderX.set(v)) .start();
这里,from
和 velocity
被设置为 sliderX
的当前值和速度。这确保了我们的物理模拟与用户的拖动运动具有相同的初始启动条件。
friction
被设置为 0.2
。摩擦力设置为从 0
到 1
的值,其中 0
根本没有摩擦力,而 1
是绝对摩擦力摩擦。尝试使用此值来查看当用户停止拖动时它对轮播的“感觉”产生的变化。
数字越小,感觉越轻,数字越大,动作越重。对于滚动动作,我觉得 0.2
在不稳定和迟缓之间取得了很好的平衡。
边界
但是有一个问题!如果您一直在使用新的触摸旋转木马,那么这是显而易见的。我们没有限制移动,因此可以真正扔掉你的旋转木马!
还有另一个变压器可以完成这项工作,clamp
。这也是一个柯里化函数,这意味着如果我们使用最小值和最大值调用它,例如 0
和 1
,它将返回一个新函数。在此示例中,新函数将限制给定的任何数字在 0
和 1
之间:
clamp(0, 1)(5); // returns 1
首先导入clamp
:
const { applyOffset, clamp } = transform;
我们希望在轮播中使用此夹紧功能,因此在定义 minXOffset
后添加此行:
const clampXOffset = clamp(minXOffset, maxXOffset);
我们将使用 pipe
转换器使用一些轻量函数组合来修改我们在操作上设置的两个 output
。
管道
当我们调用函数时,我们这样写:
foo(0);
如果我们想将该函数的输出提供给另一个函数,我们可以这样写:
bar(foo(0));
这变得有点难以阅读,而且随着我们添加越来越多的功能,情况只会变得更糟。
使用 pipe
,我们可以从 foo
和 bar
组成一个新函数,我们可以重用它:
const foobar = pipe(foo, bar); foobar(0);
它也是按照自然的开始 -> 结束顺序编写的,这使得它更容易理解。我们可以使用它将 applyOffset
和 clamp
组合成一个函数。导入 pipe
:
const { applyOffset, clamp, pipe } = transform;
将 output
回调替换为 pointer
:
pipe( ({ x }) => x, applyOffset(action.x.get(), sliderX.get()), clampXOffset, (v) => sliderX.set(v) )
并将 physicals
的 output
回调替换为:
pipe(clampXOffset, (v) => sliderX.set(v))
这种函数组合可以非常巧妙地从较小的、可重用的函数中创建描述性的、逐步的流程。
现在,当您拖动并抛出轮播时,它不会移动到其边界之外。
突然停止并不是很令人满意。但这是稍后部分的问题!
结论
这就是第 1 部分的全部内容。到目前为止,我们已经研究了现有的轮播,以了解不同滚动方法的优点和缺点。我们使用 Popmotion 的输入跟踪和物理原理,通过触摸滚动为轮播的 translateX
提供高性能动画。我们还了解了函数组合和柯里化函数。
您可以在此 CodePen 上获取“到目前为止的故事”的评论版本。
在接下来的几期中,我们将介绍:
- 用鼠标滚轮滚动
- 当窗口大小调整时重新测量轮播
- 分页,支持键盘和鼠标
- 借助弹簧物理原理实现令人愉悦的触感
期待在那里见到您!
위 내용은 이상적인 캐러셀 만들기, 1부의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











기사는 JavaScript 라이브러리 작성, 게시 및 유지 관리, 계획, 개발, 테스트, 문서 및 홍보 전략에 중점을 둡니다.

이 기사는 브라우저에서 JavaScript 성능을 최적화하기위한 전략에 대해 설명하고 실행 시간을 줄이고 페이지로드 속도에 미치는 영향을 최소화하는 데 중점을 둡니다.

프론트 엔드 개발시 프론트 엔드 열지대 티켓 인쇄를위한 자주 묻는 질문과 솔루션, 티켓 인쇄는 일반적인 요구 사항입니다. 그러나 많은 개발자들이 구현하고 있습니다 ...

이 기사는 브라우저 개발자 도구를 사용하여 효과적인 JavaScript 디버깅, 중단 점 설정, 콘솔 사용 및 성능 분석에 중점을 둡니다.

이 기사는 소스 맵을 사용하여 원래 코드에 다시 매핑하여 미니어링 된 JavaScript를 디버그하는 방법을 설명합니다. 소스 맵 활성화, 브레이크 포인트 설정 및 Chrome Devtools 및 Webpack과 같은 도구 사용에 대해 설명합니다.

이 튜토리얼은 Chart.js를 사용하여 파이, 링 및 버블 차트를 만드는 방법을 설명합니다. 이전에는 차트 유형의 차트 유형을 배웠습니다. JS : 라인 차트 및 막대 차트 (자습서 2)와 레이더 차트 및 극지 지역 차트 (자습서 3)를 배웠습니다. 파이 및 링 차트를 만듭니다 파이 차트와 링 차트는 다른 부분으로 나뉘어 진 전체의 비율을 보여주는 데 이상적입니다. 예를 들어, 파이 차트는 사파리에서 남성 사자, 여성 사자 및 젊은 사자의 비율 또는 선거에서 다른 후보자가받는 투표율을 보여주는 데 사용될 수 있습니다. 파이 차트는 단일 매개 변수 또는 데이터 세트를 비교하는 데만 적합합니다. 파이 차트의 팬 각도는 데이터 포인트의 숫자 크기에 의존하기 때문에 원형 차트는 값이 0 인 엔티티를 그릴 수 없습니다. 이것은 비율이 0 인 모든 엔티티를 의미합니다

기술 및 산업 요구에 따라 Python 및 JavaScript 개발자에 대한 절대 급여는 없습니다. 1. 파이썬은 데이터 과학 및 기계 학습에서 더 많은 비용을 지불 할 수 있습니다. 2. JavaScript는 프론트 엔드 및 풀 스택 개발에 큰 수요가 있으며 급여도 상당합니다. 3. 영향 요인에는 경험, 지리적 위치, 회사 규모 및 특정 기술이 포함됩니다.

엔트리 레벨 타입 스크립트 자습서를 마스터 한 후에는 TypeScript를 지원하고 JavaScript로 컴파일하는 IDE에서 자신의 코드를 작성할 수 있어야합니다. 이 튜토리얼은 TypeScript의 다양한 데이터 유형으로 뛰어납니다. JavaScript에는 NULL, UNDEFINED, BOOLEAN, 번호, 문자열, 기호 (ES6에 의해 소개 됨) 및 객체의 7 가지 데이터 유형이 있습니다. TypeScript는이 기반으로 더 많은 유형을 정의 하며이 튜토리얼은이 모든 튜토리얼을 자세히 다룹니다. 널 데이터 유형 JavaScript와 마찬가지로 Null in TypeScript
