Advertisement
  1. Web Design
  2. Animation

إنشاء دائره في أحسن الاحوال ، الجزء الثاني

Scroll to top
Read Time: 10 min
This post is part of a series called Create the Perfect Carousel.
Create the Perfect Carousel, Part 1
Create the Perfect Carousel, Part 3

() translation by (you can also view the original English article)

مرحبًا بك مرة أخرى في سلسلة إنشاء برنامج تعليمي رائع حول " دائره في أحسن حال". نحن نعمل على إنشاء دائري يسهل الوصول إليه وممتعه باستخدام فيزياء جافا سكريبت وPopmotion ، وتوين وإمكانات تتبع الإدخال.

في الجزء الأول من برنامجنا التعليمي ، ألقينا نظرة على كيفية إنشاء Amazon و Netflix انشاء الدائره وتقييم إيجابيات وسلبيات أساليبهما. من خلال تعلمنا ، قررنا وضع إستراتيجية لعنصر دائرينا وتنفيذ التمرير باللمس باستخدام الفيزياء.

في الجزء الثاني ، سنقوم بتنفيذ تمرير الماوس الأفقي. سننظر أيضًا في بعض تقنيات ترقيم الصفحات الشائعة وتنفيذ واحد. أخيرًا ، سنقوم بربط شريط تقدم يوضح مدى المسافة التي يمر بها المستخدم.

يمكنك استعادة نقطة الحفظ الخاصة بك عن طريق فتح CodePen هذا ، والذي يلتقط من حيث توقفت.

تمرير الماوس الأفقي

من النادر أن تحترم مكتبة جافا سكريبت JavaScript التمرير الأفقي للماوس. هذا عار: على أجهزة الكمبيوتر المحمولة والماوس التي تقوم بتنفيذ التمرير الأفقي المتركز على قوة الدفع، يعد هذا أسرع طريقة للتنقل في الدائره. إنه أمر سيء مثل إجبار مستخدمي اللمس على التنقل عبر الأزرار بدلاً من التمرير السريع.

لحسن الحظ ، يمكن تنفيذه في بضعة أسطر من الكود. في نهاية الدائره الوظفيه، أضف مستمع أحداث جديدًا:

1
container.addEventListener('wheel', onWheel);

أسفل الحدث startTouchScroll ، إضافة وظيفة الاصطدام تسمىonWheel :

1
function onWheel(e) {
2
  console.log(e.deltaX)
3
}

الآن ، إذا قمت بتشغيل عجلة التمرير فوق الدائره والتحقق من لوحة التحكم الخاصة بك ، سترى مسافة العجلة على إخراج المحور السيني.

كما هو الحال مع اللمس ، إذا كانت حركة العجلة في الغالب عموديًا ، فيجب تمرير الصفحة كالمعتاد. إذا كان الوضع أفقيًا ، فنحن نريد التقاط حركة العجلة وتطبيقها على الرف الدائري.وهكذا، في onWheel ، استبدل console.log مع:

1
const angle = calc.angle({
2
  x: e.deltaX,
3
  y: e.deltaY
4
});
5
6
if (angleIsVertical(angle)) return;
7
8
e.stopPropagation();
9
e.preventDefault();

ستوقف كتلة التعليمات البرمجية هذه تمرير الصفحة إذا كان التمرير أفقيًا. إن تحديث تعديل إزاحة slider الخاص بنا أصبح الآن مجرد مسألة أخذ خاصية deltaX للحدث وإضافة ذلك إلى قيمة sliderX الحالية الخاصة بنا :

1
const newX = clampXOffset(
2
  sliderX.get() + - e.deltaX
3
);
4
sliderX.set(newX);

إننا نعيد استخدام وظيفة clampXOffset السابقة الخاصة بنا لملء هذه العملية الحسابية والتأكد من عدم تمرير الرف الدائري إلى ما بعد حدوده المقيسة.

وبصرف النظر عن Throttling التمرير الأحداث

سوف يشرح أي برنامج تعليمي جيد يتناول أحداث الإدخال مدى أهمية اختراق هذه الأحداث.وذلك لأن أحداث التمرير والفأرة واللمس يمكن إطلاقها بشكل أسرع من معدل الإطارات الخاص بالجهاز.

لا ترغب في تنفيذ أعمال لا داعي لها لاستخدام موارد كثيرة مثل عرض الرف الدائري مرتين في إطار واحد ، حيث أنه مضيعة للموارد وطريقة سريعة لإنشاء واجهة تتسم ببطء الشركات.

لم يلمس هذا البرنامج التعليمي ذلك لأن العارضين الذين يوفرهم Popmotion يقومون بتطبيق Framesync ، وهو جدولة عمل صغيرة متزامنة مع الإطار. هذا يعني أنه بإمكانك الاتصال بـ (v) => sliderRenderer.set ('x'، v) عدة مرات متتالية ، ولن يحدث العرض المكلف إلا مرة واحدة ، في الإطار التالي.

ترقيم الصفحات

هذا التمرير الانتهاء. الآن نحن بحاجة إلى إدخال بعض الحياة في أزرار التنقل غير المحببة حتى الآن.

الآن ، هذا البرنامج التعليمي حول التفاعل ، لذا لا تتردد في تصميم هذه الأزرار كما يحلو لك.شخصيا ، أجد أسهم الاتجاه أكثر بديهية (وتدويلها بشكل كامل افتراضيا!).

كيف يجب أن ترقيم الصفحات؟

هناك استراتيجيتان واضحتان يمكن أن نتخذهما عند ترقيم المكتبة الدوّارة: عنصرًا تلو الآخر أو أول عنصر محجوب . هناك استراتيجية صحيحة واحدة فقط ، ولكن لأنني رأيت النموذج الآخر الذي تم تنفيذه في كثير من الأحيان ، أعتقد أنه من الجدير شرح سبب عدم صحته .

1. البند حسب الموضوع

Item By Item Example

ما عليك سوى قياس إزاحة العنصر التالي في القائمة وتحريك الرف بمقدار هذا المقدار. إنها خوارزمية بسيطة للغاية أفترض أنها مختصرة لبساطتها بدلاً من سهولة استخدامها.

تكمن المشكلة في أن معظم الشاشات ستتمكن من عرض الكثير من العناصر في كل مرة ، وسيقوم الأشخاص بمسحها ضوئيًا قبل محاولة التنقل.

إنه شعور بطيء ، إن لم يكن محبطًا تمامًا. الوضع الوحيد الذي سيكون فيه هذا الخيار جيدًا إذا كنت تعرف أن العناصر الموجودة في دائرتك هي بنفس العرض أو أصغر قليلاً من المساحة القابلة للعرض.

ومع ذلك ، إذا نظرنا إلى عناصر متعددة ، فمن الأفضل استخدام طريقة العنصر الأول غير الظاهر:

2. أول عنصر محجوب

The First Obscured ItemThe First Obscured ItemThe First Obscured Item

تبحث هذه الطريقة ببساطة عن أول عنصر محجوب في الاتجاه الذي نرغب في تحريكه دائريًا ، ويأخذ مقدار الإزاحة x منه ، ثم ينتقل إلى ذلك.

عند القيام بذلك ، نقوم بسحب الحد الأقصى لعدد العناصر الجديدة التي تعمل على افتراض أن المستخدم قد شاهد كل تلك الموجودة حاليًا.

نظرًا لأننا نقوم بسحب المزيد من العناصر ، تتطلب المكتبة الدوارة نقرات أقل للتنقل. سيزيد التنقل الأسرع من التفاعل وسيضمن للمستخدمين رؤية المزيد من منتجاتك.

المستمعون للحدث

أولاً ، دعنا ننشئ مستمعي الحدث لدينا حتى نتمكن من بدء اللعب مع ترقيم الصفحات.

نحتاج أولاً إلى اختيار أزرارنا السابقة والتالية. في الجزء العلوي من وظيفة الرف الدائري، أضف:

1
const nextButton = container.querySelector('.next');
2
const prevButton = container.querySelector('.prev');

ثم ، في الجزء السفلي من وظيفة الرف الدائري ، أضف المستمعين للحدث:

1
nextButton.addEventListener('click', gotoNext);
2
prevButton.addEventListener('click', gotoPrev);

وأخيرًا ، وفوق كتلة المستمعين للحدث ، أضف الوظائف الفعلية:

1
function goto(delta) {
2
}
3
4
const gotoNext = () => goto(1);
5
const gotoPrev = () => goto(-1);

goto هي الوظيفة التي ستعالج كل منطق ترقيم الصفحات. يستغرق الأمر مجرد رقم يمثل اتجاه السفر الذي نرغب في ترقيم صفحاته. gotoNext و gotoPrev ببساطة استدعاء هذه الوظيفة مع 1 أو -1 ، على التوالي.

حساب "صفحة"

يمكن للمستخدم التمرير بحرية هذه دائري، وهناك N البنود في غضون ذلك، ويمكن تغيير حجمها دائري. وبالتالي ، لا ينطبق مفهوم الصفحة التقليدية هنا مباشرةً. لن نحسب عدد الصفحات.

بدلاً من ذلك ، عندما يتم استدعاء وظيفة goto ، سننظر في اتجاه دلتا ونبحث عن العنصر الأول الغير مرئي جزئيًا. سيصبح هذا العنصر الأول في "الصفحة" التالية.

تتمثل الخطوة الأولى في الحصول على الإزاحة الحالية من شريط التمرير الخاص بنا ، واستخدام ذلك مع العرض المرئي الكامل للشريط التمريري لحساب إزاحة "مثالية" نرغب في التمرير إليها. التعويض المثالي هو ما من شأنه أن انتقل إلى إذا كنا سذجا لمحتويات شريط التمرير. يوفر لك مكانًا رائعًا لبدء البحث عن العنصر الأول.

1
const currentX = sliderX.get();
2
let targetX = currentX + (- sliderVisibleWidth * delta);

يمكننا استخدام التحسين الأمثل هنا. من خلال تقديم targetX الخاص بنا إلى وظيفةclampXOffset التي قمنا بعملها في البرنامج التعليمي السابق ، يمكننا معرفة ما إذا كان ناتجها مختلفًا عن targetX . إذا كان الأمر كذلك ، فهذا يعني أن targetX يقع خارج حدود التمرير الخاصة بنا ، لذلك لا نحتاج إلى معرفة العنصر الأقرب. نحن فقط انتقل إلى النهاية.

1
const clampedX = clampXOffset(targetX);
2
3
targetX = (targetX === clampedX)
4
  ? findClosestItemOffset(targetX, delta)
5
  : clampedX;

العثور على أقرب عنصر

من المهم ملاحظة أن التعليمة البرمجية التالية تعمل على افتراض أن كافة العناصر الموجودة في المكتبة لديك بنفس الحجم . بموجب هذا الافتراض ، يمكننا إجراء تحسينات مثل عدم الاضطرار إلى قياس حجم كل عنصر. إذا البنود الخاصة بك و أحجام مختلفة، وهذا سوف لا تزال تجعل نقطة انطلاق جيدة.

فوق الدالة goto ، أضف الدالة findClosestItemOffset المشار إليها في القصاصه الأخيره:

1
function findClosestItem(targetX, delta) {
2
}

أولاً ، نحتاج إلى معرفة مدى اتساع عناصرنا والتباعد بينها. وElement.getBoundingClientRect () الطريقة يمكن أن توفير كافة المعلومات التي تحتاج إليها. ل عرض ، ونحن ببساطةنقيس العنصر الفريق الأول. لحساب التباعد بين العناصر ، يمكننا قياس الإزاحة الصحيحة للعنصر الأول والإزاحة اليسرى من الثانية ، ومن ثم طرح الأول من الأخير:

1
const { right, width } = items[0].getBoundingClientRect();
2
const spacing = items[1].getBoundingClientRect().left - right;

الآن ، مع المتغيرات targetX و delta التي مررنا بها إلى الوظيفة ، لدينا جميع البيانات التي نحتاجها لحساب إزاحة سريعة للتمرير إليه.

الحساب هو تقسيم قيمة targetX المطلقة من خلال تباعد العرض + . سيعطينا هذا العدد الدقيق للأصناف التي يمكننا وضعها داخل تلك المسافة.

1
const totalItems = Math.abs(targetX) / (width + spacing);

ثم ، تقريبًا أو لأسفل اعتمادًا على اتجاه ترقيم الصفحات ( دلتا ). هذا سيعطينا عدد العناصرالكاملة التي يمكننا ملاءمتها.

1
const totalCompleteItems = delta === 1
2
  ? Math.floor(totalItems)
3
  : Math.ceil(totalItems);

وأخيرًا ، اضرب هذا الرقم حسب العرض + التباعد لإعطائنا ميزة الإزاحة مع عنصر كامل.

1
return 0 - totalCompleteItems * (width + spacing);

تحريك ترقيم الصفحات

الآن بعد أن تم احتساب هدفنا إكس ، يمكننا تحريكه! لهذا ، سوف نستخدم العمود الفقري للرسوم المتحركة على شبكة الإنترنت ، tween .

بالنسبة للمبتدئين، "توين" هو اختصار للون. يتغير tween من قيمة إلى أخرى ، على مدى فترة زمنية محددة. إذا كنت قد استخدمت انتقالات CSS ، فهذا هو الشيء نفسه.

هناك عدد من المزايا (وأوجه القصور!) لاستخدام جافا سكريبت على CSS للفتيات. في هذه الحالة ، نظرًا لأننا نقوم أيضًا بتحريك sliderX مع الفيزياء ومدخلات المستخدم ، سيكون من الأسهل بالنسبة لنا البقاء في سير العمل هذا للون.

وهذا يعني أيضًا أنه في وقت لاحق يمكننا ربط شريط تقدم وسيعمل بشكل طبيعي مع جميع الرسوم المتحركة لدينا مجانًا.

نريد أولاً استيراد tween من Popmotion:

1
const { calc, css, easing, physics, pointer, transform, tween, value } = window.popmotion;

في نهاية وظيفة goto ، يمكننا إضافة tween لدينا الذي ينشط من currentX إلىtargetX :

1
tween({
2
  from: currentX,
3
  to: targetX,
4
  onUpdate: sliderX
5
}).start();

افتراضيا، Popmotion يحدد مدة ل 300 ميلي ثانية و تخفيف لeasing.easeOut . وقد تم اختيار هذه العناصر خصيصًا لتوفير إحساس سريع الاستجابة بالرسوم المتحركة التي تستجيب لمدخلات المستخدم ، ولكن لا تتردد في اللعب حولها ومعرفة ما إذا كنت ستقدم شيئًا يناسب مظهر علامتك التجارية بشكل أفضل.

مؤشر التقدم

من المفيد أن يكون لدى المستخدمين بعض المؤشرات حول مكان وجودهم في المكتبة الدوارة.لهذا ، يمكننا ربط مؤشر التقدم.

يمكن تصميم شريط التقدم الخاص بك بعدد من الطرق. بالنسبة إلى هذا البرنامج التعليمي ، قمنا بعمل div ملون ، ارتفاع 5px ، يتم تشغيله بين الأزرار السابقة والتالية. إنها الطريقة التي نعلق بها هذا الرمز الخاص بنا ونحرك الشريط المهم وهو محور هذا البرنامج التعليمي.

لم تشاهد المؤشر بعد لأننا صممناه في الأصل مع التحويل: scaleX (0) . نحن نستخدم تحويلًا على نطاق لضبط عرض الشريط ، لأننا ، كما أوضحنا في الجزء الأول ، التحويلات أكثر أداء من تغيير الخصائص مثل اليسار أو ، في هذه الحالة ، العرض .

كما يسمح لنا أيضًا بكتابة التعليمات البرمجية بسهولة التي تحدد المقياس كنسبة مئوية : القيمة الحالية لـ sliderX بين minXOffset و maxXOffset .

لنبدأ باختيار شريط div.progress-bar بعد اختيار السابق لدينا :

1
const progressBar = container.querySelector('.progress-bar');

بعد تحديد sliderRenderer ، يمكننا إضافة عارض شريط التقديم :

1
const progressBarRenderer = css(progressBar);

الآن دعونا تحديد وظيفة لتحديث مقياس شريط التقدم.

سنستخدم أحسب ظيفة تسمى getProgressFromValue . هذا يأخذ مجموعة ، في حالتنا دقيقة و maxXOffset ، ورقم ثالث. تقوم بإرجاع التقدم ، رقم بين 0 و1 ، من هذا الرقم الثالث ضمن النطاق المحدد.

1
function updateProgressBar(x) {
2
  const progress = calc.getProgressFromValue(maxXOffset, minXOffset, x);
3
  progressBarRenderer.set('scaleX', progress);
4
}

لقد كتبنا النطاق هنا كـ maxXOffset ، minXOffset متى يجب أن يتم عكس ذلك بشكل بديهي. . وذلك لأن العاشر هو قيمة سالبة، وmaxXOffset هو أيضا قيمة سالبة في حين minXOffset هو 0 . يعتبر الرقم 0 أكبر من الرقمين تقنيًا ، ولكن القيمة الأصغر تمثل في الواقع الحد الأقصى للإزاحة.السلبيات ، هاه؟

نريد تحديث مؤشر التقدم بالتوافق مع sliderX ، لذلك دعنا نغير هذا الخط:

1
const sliderX = value(0, (x) => sliderRenderer.set('x', x));

إلى هذا الخط:

1
const sliderX = value(0, (x) => {
2
  updateProgressBar(x);
3
  sliderRenderer.set('x', x);
4
});

الآن ، كلما تحديثات sliderX ، لذلك سوف شريط التقدم.

استنتاج

هذا كل شيء عن هذه الدفعة! يمكنك الحصول على أحدث رمز في CodePen . لقد أدخلنا بنجاح التمرير الأفقي والصفوف الفاصلة للصفحات وشريط التقدم.

دائري في حالة جيدة حتى الآن! في الدفعة الأخيرة ، سنأخذها خطوة أخرى. سنجعل لوحة المفاتيح بالكامل قابلة للوصول بشكل كامل لضمان أن أي شخص يمكنه استخدامها.

وسنضيف أيضًا بعض اللمسات المبهجة باستخدام أداة سحب نابضة بالزوجة عندما يحاول المستخدم تمرير العارضة المتحركة بعد تجاوزها باستخدام إما التمرير باللمس أو الحدود الفاصلة للصفحات.

اراك لاحقا!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.