اذهب إلى المحتوى

الواجهات البرمجية للتعامل مع الصوت والفيديو في جافا سكريبت


ابراهيم الخضور

تضم لغة HTML عناصر مخصصة لتضمين الوسائط المتعددة إلى صفحاتك مثل <audio> و <video> والتي تأتي مزوّدة بواجهة برمجية مخصصة للتحكم بتشغيلها وتقديمها وتأخيرها. لهذا سنتعرف في هذا المقال على طرق تنفيذ بعض المهام الشائعة كإنشاء أدوات تحكم متخصصة باستخدام الواجهة البرمجية HTMLMediaElement التي توفر عدة ميزات للتحكم في تشغيل الصوت و الفيديو برمجيًا .

ننصحك قبل المتابعة في قراءة هذه المقالات أن:

عناصر HTML الخاصة بالصوت والفيديو

يسمح العنصران <video> و <audio> بإدراج مقاطع الصوت و الفيديو في صفحات الويب، وستبدو الطريقة النمطية ﻹنجاز اﻷمر كالتالي:

<video controls>
  <source src="rabbit320.mp4" type="video/mp4" />
  <source src="rabbit320.webm" type="video/webm" />
  <p>
    Your browser doesn't support HTML video. Here is a
    <a href="rabbit320.mp4">link to the video</a> instead.
  </p>
</video>

تعرض الشيفرة السابقة مشغل فيديو في صفحتك كالتالي:

وأكثر ما يثير الاهتمام في الشيفرة السابقة هي السمة controls التي تعرض أدوات التحكم الافتراضية مع مشغل الفيديو، وإن لم تستخدم هذه السمة فلن ترى عناصر التحكم على المشغل:

لهذه اﻷدوات إيجابيات، لكن من أبرز مشكلاتها هي اختلافها من متصفح إلى آخر وهذا أمر مربك إن حاولت دعم عدة متصفحات في شيفرتك. ومن المشكلات الكبيرة أيضًا أن أدوات التحكم اﻷصلية في معظم المتصفحات لا تدعم التحكم من خلال لوحة المفاتيح. ويمكن حل كلتا المشكلتين السابقتين بإخفاء أدوات التحكم الأصلية (عن طريق إزالة السمة controls) وبرمجة أدوات تحكم خاصة بك باستخدام HTML و CSS وجافا سكريبت. وسنلقي نظرة في اﻷقسام التالية على اﻷدوات البسيطة المتاحة لهذا الغرض.

الواجهة البرمجية HTMLMediaElement

تزّودك بعض مواصفات الواجهة البرمجية HTMLMediaElement بميزات تسمح لك بالتحكم في مشغلات الصوت و الفيديو برمجيًا مثل التوابع ()HTMLMediaElement.play و ()HTMLMediaElement.pause وغيرها. وهاتان الواجهتان متاحتان للاستخدام مع العنصرين <audio> و<video> فهما متطابقان من ناحية العمل. لهذا سنوضح طريقة استخدام هذه الواجهات من خلال المثال التالي:

يبدو مثالنا عندما يكتمل مشابهًا للتالي:

نقطة الانطلاق

حتى نبدأ العمل، عليك تنزيل الملف المضغوط الخاص بالمثال ثم تستخرج محتوياته في مجلد جديد على حاسوبك. أما إن حمّلت مستودع اﻷمثلة بأكمله، ستجد المثال في المسار javascript/apis/video-audio/start/.

إن حمّلت المثال على متصفحك سترى مشغل فيديو HTML نمطي مع أدوات التحكم الافتراضية.

التعرف على ملف HTML

عندما تفتح الملف index.html سترى عددًا من العناصر، وستلاحظ أن معظم الشيفرة تدور حول مشغل الفيديو وأدوات التحكم الخاصة به:

<div class="player">
  <video controls>
    <source src="video/sintel-short.mp4" type="video/mp4" />
    <source src="video/sintel-short.webm" type="video/webm" />
    <!-- fallback content here -->
  </video>
  <div class="controls">
    <button class="play" data-icon="P" aria-label="play pause toggle"></button>
    <button class="stop" data-icon="S" aria-label="stop"></button>
    <div class="timer">
      <div></div>
      <span aria-label="timer">00:00</span>
    </div>
    <button class="rwd" data-icon="B" aria-label="rewind"></button>
    <button class="fwd" data-icon="F" aria-label="fast forward"></button>
  </div>
</div>
  • وضعنا المشغل بأكمله داخل العنصر <div> حتى يُنسّق بالكامل عند الحاجة.
  • يحتوي العنصر <video> على عنصرين من النوع <source> كي نتمكن من تحميل تنسيقات مختلفة لمقطع الفيديو وفقًا للمتصفح الذي نستخدمه.
  • وربما تكون أدوات تحكم HTML هي اﻷكثر أهمية هنا:
  • لدينا أربعة أزرار <button> لتشغيل وإيقاف العرض مؤقتًا واﻹطفاء والتقديم للأمام والعودة للخلف.
  • خصصنا لكل زر سمات هي اسم صنف التنسيق class و data-icon لتحديد اﻷيقونة التي تُعرض على الزر (سنرى كيف ننفذ ذلك لاحقًا) و aria-label لتقديم وصف مفهوم عن عمل كل زر، وذلك لأننا لا نقدم عنوانًا مقروءًا ضمن وسم العنصر. ويُقرأ محتوى السمة aria-label من قبل قارئات الشاشة عندما ينتقل التركيز إلى العناصر التي تمتلك هذه السمة.
  • تضم الصفحة أيضًا مؤقتًا ضمن عنصر <div> يعرض الوقت المنقضي من مقطع الفيديو، ولتحسين تجربة المستخدم، زودنا المثال بآليتين لتحديد الوقت المنقضي: الأولى ضمن عنصر <span> يعطي الوقت المنقضي بالدقائق والثواني، والثانية ضمن عنصر <div> يضم شريط أفقي يزداد طوله عندما يتقدم عرض الفيديو. ولكي تأخذ فكرة عما ستكونه الصفحة بشكلها الكامل ألق نظرة هنا..

التعرف على ملف CSS

افتح اﻵن ملف CSS وألقِ نظرة عليه. لا يبدو هذا الملف معقدًا، لكننا سنشير إلى النقاط المهمة فيه. لاحظ بداية القاعدة controls.:

.controls {
  visibility: hidden;
  opacity: 0.5;
  width: 400px;
  border-radius: 10px;
  position: absolute;
  bottom: 20px;
  left: 50%;
  margin-left: -200px;
  background-color: black;
  box-shadow: 3px 3px 5px black;
  transition: 1s all;
  display: flex;
}

.player:hover .controls,
.player:focus-within .controls {
  opacity: 1;
}
  • بدأنا بالخاصية visibility لمجموعة أدوات التحكم المخصصة وضبطناها على hidden، لكننا سنضبطها لاحقًا عبر جافا سكريبت لتكون visible ونزيل السمة controls من العنصر <video>. وذلك كي يبقى المستخدم قادرًا على تشغيل الفيديو باستخدام أدوات التحكم الافتراضية في حال فشل تحميل شيفرة جافا سكريبت لسبب ما.
  • منحنا أدوات التحكم قتامة افتراضية opacity قيمتها 0.5، كي لا تشتت الانتباه عند عرض الفيديو، لكن عندما تمرر الفأرة فوق المشغّل أو تمنحه تركيز الدخل ستكون اﻷدوات كاملة القتامة.
  • نرتب اﻷزرار ضمن شريط التحكم باستخدام تخطيط الصندوق المرن display: flex لتسهيل ضبط مواقعها.

لنلق نظرة تاليًا على أيقونات اﻷزرار:

@font-face {
  font-family: "HeydingsControlsRegular";
  src: url("fonts/heydings_controls-webfont.eot");
  src:
    url("fonts/heydings_controls-webfont.eot?#iefix") format("embedded-opentype"),
    url("fonts/heydings_controls-webfont.woff") format("woff"),
    url("fonts/heydings_controls-webfont.ttf") format("truetype");
  font-weight: normal;
  font-style: normal;
}

button:before {
  font-family: HeydingsControlsRegular;
  font-size: 20px;
  position: relative;
  content: attr(data-icon);
  color: #aaa;
  text-shadow: 1px 1px 0px black;
}

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

نولد بعد ذلك محتوىً خاصًا لعرض اﻷيقونات على كل زر:

  • نستخدم المحدد before:: لعرض المحتوى قبل كل زر <button>.
  • نستخدم الخاصية content لضبط المحتوى الذي يعرض في كل حالة ليكون نفسه محتوى السمة data-icon. ففي حالة زر التشغيل مثلًا، سيكون محتوى السمة data-icon هو المحرف P (بشكله الكبير).
  • نطبق خط ويب السابق على اﻷزرار باستخدام الخاصية font-family، وسيكون الحرف P في هذا الخط عمليًا أيقونة التشغيل، وهكذا ستظهر على زر التشغيل أيقونة التشغيل.

إن الخطوط التي تعرض أيقونات جميلة ومفيدة ﻷسباب عديدة منها تقليل عدد طلبات HTTP لانك لن تحتاج إلى تحميل تلك اﻷيقونات على شكل ملفات صور، إضافة إلى إمكانية تكبير وتصغير اﻷيقونات بدقة وكذلك إمكانية استخدام خاصيات نصية لتنسيق تلك اﻷيقونات مثل color و text-shadow.

لنلق نظرة أيضًا على تنسيق المؤقت الزمني:

.timer {
  line-height: 38px;
  font-size: 10px;
  font-family: monospace;
  text-shadow: 1px 1px 0px black;
  color: white;
  flex: 5;
  position: relative;
}

.timer div {
  position: absolute;
  background-color: rgb(255 255 255 / 20%);
  left: 0;
  top: 0;
  width: 0;
  height: 38px;
  z-index: 2;
}

.timer span {
  position: absolute;
  z-index: 3;
  left: 19px;
}
  • ضبطنا قيمة الخاصية flex للعنصر timer. الخارجي على القيمة 5 لتشغل أكبر مساحة من شريط التحكم. كما ضبطنا خاصية الموقع بالشكل position:relative كي نتمكن من ضبط العناصر ضمن العنصر الخارجي كما نشاء وبالنسبة إلى حدوده وليس حدود العنصر <body>.
  • ضبطنا موقع العنصر <div> الداخلي ليكون مطلقًا position:absolute لكي يظهر مباشرة في أعلى العنصر <div> الخارجي. كما ضبطنا قيمة اتساع العنصر على الشكل width:0 كي لا يُرى العنصر إطلاقًا. وعندما يبدأ العرض نستخدم جافا سكريبت لزيادة اتساع العنصر.
  • ضطنا موقع العنصر <span> ليكون مطلقًا وبالتالي سيكون بالقرب من الطرف اﻷيسر لشريط المؤقت.
  • ضبطنا خاصية العلو z-index للكائن <div> الداخلي والكائن <span> كي يُعرض الشريط الزمني في الأعلى وتحته العنصر <div> الداخلي، ونضمن بذلك أنك سترى كل المعلومات ولن يَحجِب صندوق آخر.

إنجاز شيفرة جافا سكريبت

بعد أن حضرنا واجهتي HTML و CSS، لا بد من كتاب شيفرة اﻷزرار المخصصة للتحكم بمشغل الفيديو.

  1. أنشئ ملف جافا سكريبت جديد في نفس المجلد الذي يضم الملف index.html وسمِّه custom-player.js.
  2. ضع الشيفرة التالية أعلى الملف:
const media = document.querySelector("video");
const controls = document.querySelector(".controls");

const play = document.querySelector(".play");
const stop = document.querySelector(".stop");
const rwd = document.querySelector(".rwd");
const fwd = document.querySelector(".fwd");

const timerWrapper = document.querySelector(".timer");
const timer = document.querySelector(".timer span");
const timerBar = document.querySelector(".timer div");

أنشأنا في الشيفرة السابقة ثوابت لتكون مراجع إلى الكائنات التي نريد التعامل معها، ولدينا ثلاثة مجموعات:

  • العنصر <video> وشريط التحكم.
  • أزرار التحكم "تشغيل/إيقاف مؤقت play/pause" و "للأمام rewind" و "للخلف fast forward".
  • غلاف المؤقت الخارجي <div> والعنصر <span> الذي يعرض المؤقت والعنصر <div> الخارجي الذي يزداد اتساعه عندما يتقدم الفيديو.
  1. ضع اﻵن الشيفرة التالية تحت سابقتها:
media.removeAttribute("controls");
controls.style.visibility = "visible";

تزيل الشيفرة السابقة مشغل الفيديو الافتراضي الخاص بالمتصفح ويُظهر أدوات التحكم المخصصة:

تشغيل وإيقاف الفيديو مؤقتًا

سننجز اﻵن شيفرة التحكم بزر التشغيل و اﻹيقاف المؤقت:

  1. أضف بداية الشيفرة التالية في أسفل الشيفرة كي تُستدعى الدالة ()playPauseMedia عند النقر على زر التشغيل:
play.addEventListener("click", playPauseMedia);
  1. ولتعريف الدالة ()playPauseMedia، أضف الشيفرة التالية إلى أسفل الشيفرة السابقة:
function playPauseMedia() {
  if (media.paused) {
    play.setAttribute("data-icon", "u");
    media.play();
  } else {
    play.setAttribute("data-icon", "P");
    media.pause();
  }
}

نستخدم هنا عبارة if للتحقق من توقف تشغيل الفيديو، وتعيد الخاصية HTMLMediaElement.paused القيمة true عند توقف التشغيل مؤقتًا بما في ذلك عند ضبطته على القيمة 0 بعد تحميله أول مرة. عند ذلك نضبط قيمة السمة data-icon لزر التشغيل على u التي تعرض بدورها أيقونة التشغيل المؤقت عليه، وتستدعي التابع ()HTMLMediaElement.play لتشغيل الفيديو. وعند النقر على الزر مرة ثانية سيعود الزر كما كان، إذ تظهر أيقونة التشغيل وسيتوقف الفيديو بتنفيذ التابع ()HTMLMediaElement.paused.

إيقاف عرض الفيديو

  1. نضيف بداية الشيفرة التي تتعامل مع إيقاف تشغيل الفيديو تحت الشيفرة السابقة:
stop.addEventListener("click", stopMedia);
media.addEventListener("ended", stopMedia);

يضيف سطري الشيفرة مترصدي أحداث addEventListener للتعامل مع الحدث click الذي يوقف تشغيل الفيديو بتنفيذ الدالة ()stopMedia عند النقر على زر اﻹيقاف. ولا بد من إيقاف التشغيل أيضًا عند إنتهاء المقطع، لهذا نترصد أيضًا الحدث ended من خلال مترصد الحدث الثاني والذي ينفذ أيضًا الدالة ()stopMedia عند انتهاء مقطع الفيديو.

  1. نعرّف تاليًا الدالة ()stopMedia، بإضاف اﻷسطر التالية بعد الدالة ()playpauseMedia:
function stopMedia() {
  media.pause();
  media.currentTime = 0;
  play.setAttribute("data-icon", "P");
}

وبما أن الواجهة البرمجية HTMLMediaElement لا تقدم تابعًا مخصصًا ﻹيقاف عرض الفيديو، سنستخدم التابع ()pause ﻹيقاف التشغيل مؤقتًا ثم نضبط قيمة الخاصية currentTime على القيمة 0 ليعود الفيديو إلى البداية. فضبط قيمة هذه الخاصية (بالثواني) سينقل الموقع الحالي للفيديو إلى النقطة الزمنية المحددة. يبقى علينا فقط إظهار أيقونة التشغيل على زر التشغيل. وبصرف النظر عن وضع الفيديو سواءً كان قيد التشغيل أو أوقف مؤقتًا عند النقر على زر إيقاف التشغيل "Stop"، لابد أن تُظهر أن المشغل جاهز للعمل مجددًا.

التنقل بالفيديو إلى اﻷمام والخلف

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

  1. أضف مترصدي الحدث التاليين تحت تعريف المترصدين السابقين:
rwd.addEventListener("click", mediaBackward);
fwd.addEventListener("click", mediaForward);
  1. أضف الدالتين ()mediaBackWard و ()mediaForWard التاليتين تحت الدوال السابقة، وستصبح الشيفرة كالتالي:
let intervalFwd;
let intervalRwd;

function mediaBackward() {
  clearInterval(intervalFwd);
  fwd.classList.remove("active");

  if (rwd.classList.contains("active")) {
    rwd.classList.remove("active");
    clearInterval(intervalRwd);
    media.play();
  } else {
    rwd.classList.add("active");
    media.pause();
    intervalRwd = setInterval(windBackward, 200);
  }
}

function mediaForward() {
  clearInterval(intervalRwd);
  rwd.classList.remove("active");

  if (fwd.classList.contains("active")) {
    fwd.classList.remove("active");
    clearInterval(intervalFwd);
    media.play();
  } else {
    fwd.classList.add("active");
    media.pause();
    intervalFwd = setInterval(windForward, 200);
  }
}

هيأنا أولًا متغيرين intervalFwd و intervlRwd وسترى عملهما لاحقًا، كما ستلاحظ أن عمل الدالتين ()mediaBackWard و ()mediaForWard متطابق لكن بترتيب معكوس:

  1. يجب تصفير اﻷصناف والمجالات التي ضبطناها عند تنفيذ وظيفة التقديم السريع للأمام، لأننا لو نقرنا على زر rwd بعد النقر على الرز fwd من المفترض أن نلغي أي إعدادات خاصة بالتقديم السريع للمشغل fwd واستبدالها بإعدادت التراجع rwd، لأن المشغل سيخفق لو حاولنا النقر على كلا الزرين في نفس الوقت.
  2. استخدمنا عبارة if للتحقق من ضبط صنف الزر rwd ليكون active في إشارة إلى أن الزر قد نُقر للتو. ويتمتع كل عنصر بالخاصية classlist، وهي خاصية مفيدة تضم كل الأصناف التي يمتلكها العنصر وتقدم توابع ﻹزالة وإضافة اﻷصناف. وقد استخدمنا التابع ()classList.contains للتحقق من جود الصنف active ضمن أصناف الزر، وتعيد قيمة منطقية true/false.
  3. في حال كان active أحد أصناف العنصر rwd نزيله باستخدام التابع ()classList.remove ثم نلغي قيمة الفاصل الزمني الذي ضُبط مسبقًا عندما نقرنا على الزر ومن ثم نستخدم التابع ()HTMLMediaElement.play ﻹلغاء العودة للخلف وتشغيل الفيديو بشكل طبيعي.
  4. إن لم يمتلك الزر تلك الخاصية نضيفها إليه باستخدام التابع ()clasList.add ومن ثم نوقف الفيديو مؤقتًا باستخدام التابع ()HTMLMediaElement.pause. نضبط بعدها قيمة المتغير intervalRwd ليعادل القيمة المعادة من استدعاء الدالة ()setInterval. تُحدد هذه الدالة فترة زمنية معينة تنفذ بعد انقضائها الدالة التي تُمرر إليها كمعامل أول أما الفترة الزمنية فيحددها المعامل الثاني بالميلي ثانية. وهنا ننفذ الدالة كل 200 ميلي ثانية كي نعيد مشغل الفيديو إلى الخلف بوتيرة ثابتة. ولكي نوقف تنفيذ الدالة ()setInterval نستدعي الدالة ()clearIterval ممرين لها المتغير intervalRwd (الذي أسندت إليه الدالة ()setInterval).
  5. عرفنا أخيرًا الدالة ()windBackwrd والدالة ()windForward اللتان تمررا إلى ()setInterval، لهذا أضف الشيفرة التالية تحت الدوال السابقة:
function windBackward() {
  if (media.currentTime <= 3) {
    rwd.classList.remove("active");
    clearInterval(intervalRwd);
    stopMedia();
  } else {
    media.currentTime -= 3;
  }
}

function windForward() {
  if (media.currentTime >= media.duration - 3) {
    fwd.classList.remove("active");
    clearInterval(intervalFwd);
    stopMedia();
  } else {
    media.currentTime += 3;
  }
}

سنشرح تاليًا الدالة الأولى فقط لكون الدالتين متطابقتان من ناحية الشيفرة ومتعاكستان عملًا. وما فعلناه في الدالة ()windBackward هو التالي (تذكر أنه بمجرد تفعيل الفاصل الزمني الذي سيتراجع فيه المشغل إلى الخلف ستُستدعى هذه الدالة كل 200 ميلي ثانية):

  1. نبدأ الشيفرة بالعبارة if التي تتحقق أن المدة المنقضية من المقطع أقل من 3 ثانية، أي سيعود المشغل عند تراجعه إلى ما قبل نقطة البداية، وهذا ما يسبب سلوكًا غريبًا للمشغل. فلو كانت الحالة كذلك، نوقف تشغيل المقطع باستدعاء الدالة ()stopMedia ومن ثم نزيل الصنف active من قائمة أصناف الزر rwd ونمحي قيمة المتغير intervalRwd ﻹيقاف عملية التراجع. وفي حال أهملنا هذه الخطوة اﻷخيرة سيستمر المشغل بالتراجع إلى ما لا نهاية.
  2. إن كان الوقت المنقضي أكبر من 3 ثانية، نزيل ثلاث ثوانٍ من الوقت الحالي باستخدام التعليمة media.currentTime -=3، أي نعيد مشغل الفيديو إلى ما قبل ثلاث ثوان وذلك كل 200 ميلي ثانية.

تحديث الوقت المنقضي

آخر ما سننفذه ﻹنجاز أدوات التحكم المخصصة بمشغل الفيديو هو تحديد الوقت المنقضي من زمن المقطع. لذا نشغّل دالة تحدّث الوقت الذي نعرضه في كل مرة يقع فيها الحدث timeupdate المرتبط بالعنصر <video>. أما تواتر عملية وقوع هذا الحدث، فتعتمد على المتصفح وقوة معالج جهازك.

أضف اﻵن السطر التالي الذي يعرّف مترصد تحديث زمن التشغيل:

media.addEventListener("timeupdate", setTime);

ولتعريف الدالة ()setTime، أضف مايلي في أسفل ملف جافا سكريبت:

function setTime() {
  const minutes = Math.floor(media.currentTime / 60);
  const seconds = Math.floor(media.currentTime - minutes * 60);

  const minuteValue = minutes.toString().padStart(2, "0");
  const secondValue = seconds.toString().padStart(2, "0");

  const mediaTime = `${minuteValue}:${secondValue}`;
  timer.textContent = mediaTime;

  const barLength =
    timerWrapper.clientWidth * (media.currentTime / media.duration);
  timerBar.style.width = `${barLength}px`;
}

هذه الدالة طويلة، لهذا سنناقشها خطوة خطوة:

  1. نعمل بداية على تحديد الدقائق والثواني المنقضية من خلال قيمة HTMLMediaElement.currentTime.
  2. نهيئ بعد ذلك متغيرين إضافيين هما minuteValue و secondValue، ثم نستخدم التابع ()padStart لكي نمثّل قيمة الدقائق والثواني على شكل محرفين فقط حتى لو كانت القيمة رقمًا وحيدًا.
  3. أما الوقت الفعلي الذي سيُعرض فهو قيمة المتغير minuteValue تليه نقطتان متعامدتان ثم قيمة المتغير secondValue.
  4. نضبط قيمة المؤقت Node.textContent لتعادل قيمة الوقت الحالي وبالتالي ستُعرض هذه القيمة على واجهة المشغّل.
  5. نحدد طول عنصر <div> الداخلي (الذي سيعرض شريط تقدم مقطع الفيديو) من خلال تحديد اتساع عنصر <div> الخارجي (نأخذها من الخاصية clientWidth) ومن ثم ضرب هذه القيمة بالوقت الحالي HTMLMediaElement.currentTime ونقسم على المدة الكلية لمقطع الفيديو HTMLMediaElement.duration.
  6. نضبط قيمة اتساع العنصر <div> الداخلي ليعادل طول شريط تتبع تقدم الفيديو بعد إضافة القيمة "px" كي تشير إلى الاتساع مقدرًا بالبكسل.

إصلاح مشكلات التشغيل واﻹيقاف المؤقت للفيديو

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

أضف بداية الشيفرة التالية ضمن الدالة ()stopMedia:

rwd.classList.remove("active");
fwd.classList.remove("active");
clearInterval(intervalRwd);
clearInterval(intervalFwd);

أضف اﻵن نفس اﻷسطر في بداية الدالة ()playpauseMedia (وقبل عبارة if).

يمكنك اﻵن ازالة نفس الأسطر من الدالتين ()windBackwrd و ()windForward لأننا وضعنا هذه الوظيفة المشتركة بينهما في الدالة ()stopMedia.

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

الخلاصة

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

إليك أخيرًا بعض الاقتراحات التي تساعد في تحسين مثالنا:

  1. يختل عمل المؤقت إن كانت مدة المقطع أكثر من ساعة (فلن يعرض الساعات بل الدقائق والثواني فقط). هل يمكنك تعديل الشيفرة لتعرض الساعات أيضًا؟
  2. يمتلك العنصر <audio> نفس وظائف HTMLMediaElement وبالتالي يمكنك تشغيل المقاطع الصوتية بسهولة، جرب لك.
  3. هل يمكنك إيجاد طريقة الانتقال إلى مكان ما من المقطع بالنقر على شريط تقدم الفيديو (العنصر <div> الداخلي). وكتلميح يمكنك إيجاد x و y لزوايا الشريط من خلال التابع ()getBoundingClientRect وإيجاد إحداثيي موقع مؤشر الفأرة من خلال كائن الحدث الذي ينتج عن حدث النقر على المستند. إليك مثالًا:
document.onclick = function (e) {
  console.log(e.x, e.y);
};

ترجمة -وبتصرف- لمقال: Video and audio APIs

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...