הפעלת סרטון באינטרנט לנייד

פרנסואה בופורט
פרנסואה בופורט

כיצד ליצור את החוויה הטובה ביותר של מדיה לנייד באינטרנט? קל! הכל תלוי במעורבות המשתמשים ובחשיבות שאתם נותנים למדיה בדף אינטרנט. אני חושב שכולנו מסכימים שאם וידאו הוא הסיבה לביקור של המשתמש, חוויית המשתמש צריכה להיות סוחפת ולעורר עניין מחדש.

הפעלת סרטון באינטרנט לנייד

במאמר הזה נסביר איך לשפר את חוויית המדיה ככל האפשר ולהפוך אותה לסוחפת יותר בזכות מגוון ממשקי ה-API לאינטרנט. לכן החלטנו לפתח חוויה פשוטה של נגן לנייד עם בקרים מותאמים אישית, מסך מלא והפעלה ברקע. אתם יכולים לנסות את הדוגמה עכשיו ולחפש את הקוד במאגר שלנו ב-GitHub.

פקדים מותאמים אישית

פריסת HTML
איור 1.פריסת HTML

כמו שאפשר לראות, פריסת ה-HTML שבה נשתמש בנגן המדיה היא די פשוטה: רכיב בסיס של <div> מכיל רכיב מדיה <video> ורכיב צאצא של <div> שמיועד לבקרי סרטונים.

פקדי הסרטונים שנעסוק בהם בהמשך, כוללים: לחצן הפעלה/השהיה, לחצן במסך מלא, לחצני דילוג אחורה וקדימה, וכמה רכיבים למעקב אחר הזמן, משך הזמן והזמן הנוכחיים.

<div id="videoContainer">
  <video id="video" src="file.mp4"></video>
  <div id="videoControls"></div>
</div>

קריאת מטא-נתונים של סרטון

קודם כל, נחכה עד שהמטא-נתונים של הסרטון נטענים כדי להגדיר את משך הסרטון ואת השעה הנוכחית, ולהפעיל את סרגל ההתקדמות. שימו לב שהפונקציה secondsToTimeCode() היא פונקציית עזר מותאמת אישית שכתבתי, שממירה מספר שניות למחרוזת בפורמט "hh:mm:ss" שמתאים יותר למקרה שלנו.

<div id="videoContainer">
  <video id="video" src="file.mp4"></video>
  <div id="videoControls">
    <strong>
      <div id="videoCurrentTime"></div>
      <div id="videoDuration"></div>
      <div id="videoProgressBar"></div>
    </strong>
  </div>
</div>
video.addEventListener('loadedmetadata', function () {
  videoDuration.textContent = secondsToTimeCode(video.duration);
  videoCurrentTime.textContent = secondsToTimeCode(video.currentTime);
  videoProgressBar.style.transform = `scaleX(${
    video.currentTime / video.duration
  })`;
});
מטא-נתונים של סרטון בלבד
איור 2. Media Player מציג מטא-נתונים של סרטון

הפעלה/השהיה של הסרטון

עכשיו, אחרי שהמטא-נתונים של הסרטון נטענים, נוסיף את הלחצן הראשון שמאפשר למשתמש להפעיל ולהשהות סרטון באמצעות video.play() ו-video.pause(), בהתאם למצב ההפעלה שלו.

<div id="videoContainer">
  <video id="video" src="file.mp4"></video>
  <div id="videoControls">
    <strong><button id="playPauseButton"></button></strong>
    <div id="videoCurrentTime"></div>
    <div id="videoDuration"></div>
    <div id="videoProgressBar"></div>
  </div>
</div>
playPauseButton.addEventListener('click', function (event) {
  event.stopPropagation();
  if (video.paused) {
    video.play();
  } else {
    video.pause();
  }
});

במקום להתאים את פקדי הסרטונים ב-event listener של click, אנחנו משתמשים באירועים של הסרטון play ו-pause. בזכות הגמישות של אירועי הבקרה שלנו (כפי שנראה בהמשך ב-Media Session API), אנחנו יכולים לסנכרן את אמצעי הבקרה שלנו אם הדפדפן מתערב בהפעלה. כשהסרטון מתחיל לפעול, אנחנו משנים את מצב הלחצן ל'השהיה' ומסתירים את פקדי הסרטון. כאשר הסרטון מושהה, אנחנו פשוט משנים את מצב הלחצן ל'הפעלה' ומציגים את פקדי הסרטון.

video.addEventListener('play', function () {
  playPauseButton.classList.add('playing');
});

video.addEventListener('pause', function () {
  playPauseButton.classList.remove('playing');
});

כשהזמן שצוין במאפיין currentTime בסרטון השתנה דרך האירוע timeupdate בסרטון, אנחנו מעדכנים גם את הפקדים המותאמים אישית אם הם גלויים.

video.addEventListener('timeupdate', function () {
  if (videoControls.classList.contains('visible')) {
    videoCurrentTime.textContent = secondsToTimeCode(video.currentTime);
    videoProgressBar.style.transform = `scaleX(${
      video.currentTime / video.duration
    })`;
  }
});

כשהסרטון מסתיים, פשוט משנים את מצב הלחצן ל'הפעלה', מגדירים את הסרטון currentTime בחזרה ל-0 ומציגים את פקדי הווידאו בינתיים. שימו לב שיש לנו גם אפשרות לבחור לטעון באופן אוטומטי סרטון אחר, אם המשתמש הפעיל תכונה מסוג כלשהו של 'הפעלה אוטומטית'.

video.addEventListener('ended', function () {
  playPauseButton.classList.remove('playing');
  video.currentTime = 0;
});

דילוג אחורה וקדימה

נמשיך ונוסיף את הלחצנים 'דילוג לאחור' ו'הרצה קדימה' כדי שהמשתמש יוכל לדלג בקלות על חלק מהתוכן.

<div id="videoContainer">
  <video id="video" src="file.mp4"></video>
  <div id="videoControls">
    <button id="playPauseButton"></button>
    <strong
      ><button id="seekForwardButton"></button>
      <button id="seekBackwardButton"></button
    ></strong>
    <div id="videoCurrentTime"></div>
    <div id="videoDuration"></div>
    <div id="videoProgressBar"></div>
  </div>
</div>
var skipTime = 10; // Time to skip in seconds

seekForwardButton.addEventListener('click', function (event) {
  event.stopPropagation();
  video.currentTime = Math.min(video.currentTime + skipTime, video.duration);
});

seekBackwardButton.addEventListener('click', function (event) {
  event.stopPropagation();
  video.currentTime = Math.max(video.currentTime - skipTime, 0);
});

כמו קודם, במקום לשנות את סגנון הסרטון ב-event listener של click הלחצנים האלה, נשתמש באירועים של הסרטון seeking ו-seeked שהופעלו כדי להתאים את בהירות הסרטון. מחלקת ה-CSS המותאמת אישית שלי seeking היא פשוטה כמו filter: brightness(0);.

video.addEventListener('seeking', function () {
  video.classList.add('seeking');
});

video.addEventListener('seeked', function () {
  video.classList.remove('seeking');
});

הנה מה שיצרנו עד כה. בקטע הבא נטמיע את הלחצן 'מסך מלא'.

מסך מלא

כאן נשתמש בכמה ממשקי API לאינטרנט כדי ליצור חוויה מושלמת וחלקה במסך מלא. כדי לראות איך זה עובד, ראו דוגמה.

כמובן שאין צורך להשתמש בכולן. בחרו את המילים שנראות לכם הגיוניות ושלבו אותן כדי ליצור תהליך מותאם אישית.

לא להפעיל מסך מלא באופן אוטומטי

ב-iOS, רכיבי video נכנסים באופן אוטומטי למצב מסך מלא כשהפעלה של מדיה מתחילה. מאחר שאנחנו מנסים להתאים את חוויית המדיה בדפדפנים לנייד ולשלוט בה ככל האפשר, מומלץ להגדיר את המאפיין playsinline של הרכיב video כך שיאלץ אותו לפעול בתוך השורה ב-iPhone ולא יעבור למצב מסך מלא בתחילת ההפעלה. שימו לב שאין לכך תופעות לוואי בדפדפנים אחרים.

<div id="videoContainer"></div>
  <video id="video" src="file.mp4"></video><strong>playsinline</strong></video>
  <div id="videoControls">...</div>
</div>

החלפת מצב של מסך מלא בעת לחיצה על לחצן

עכשיו, בזכות השימוש ב-Fullscreen API, אנחנו מונעים הצגה אוטומטית של מסך מלא. כשהמשתמש לוחץ על הלחצן "מסך מלא", אנחנו יוצאים ממצב מסך מלא באמצעות document.exitFullscreen(), אם המסמך נמצא כרגע בשימוש במצב מסך מלא. לחלופין, אפשר לבקש מסך מלא במאגר הווידאו באמצעות השיטה requestFullscreen(), אם היא זמינה, או חזרה ל-webkitEnterFullscreen() ברכיב הווידאו רק ב-iOS.

<div id="videoContainer">
  <video id="video" src="file.mp4"></video>
  <div id="videoControls">
    <button id="playPauseButton"></button>
    <button id="seekForwardButton"></button>
    <button id="seekBackwardButton"></button>
    <strong><button id="fullscreenButton"></button></strong>
    <div id="videoCurrentTime"></div>
    <div id="videoDuration"></div>
    <div id="videoProgressBar"></div>
  </div>
</div>
fullscreenButton.addEventListener('click', function (event) {
  event.stopPropagation();
  if (document.fullscreenElement) {
    document.exitFullscreen();
  } else {
    requestFullscreenVideo();
  }
});

function requestFullscreenVideo() {
  if (videoContainer.requestFullscreen) {
    videoContainer.requestFullscreen();
  } else {
    video.webkitEnterFullscreen();
  }
}

document.addEventListener('fullscreenchange', function () {
  fullscreenButton.classList.toggle('active', document.fullscreenElement);
});

החלפת מצב של שינוי הכיוון של מסך מלא על מסך

כשהמשתמש מסובב את המכשיר בפריסה לרוחב, אפשר להפעיל שיקול דעת לגבי כך ולבקש באופן אוטומטי מסך מלא כדי ליצור חוויה עשירה. לשם כך צריך להשתמש ב-Screen Orientation API, שעדיין לא נתמך בכל המקומות, ועדיין מופיע כתחילית בחלק מהדפדפנים באותו זמן. לכן זה יהיה השיפור המתקדם הראשון שלנו.

איך זה עובד? ברגע שנזהה את השינויים בכיוון המסך, בואו נבקש מסך מלא אם חלון הדפדפן מוגדר לרוחב (כלומר, הרוחב גדול מהגובה שלו). אם לא, נצא מהמסך המלא. זה הכול.

if ('orientation' in screen) {
  screen.orientation.addEventListener('change', function () {
    // Let's request fullscreen if user switches device in landscape mode.
    if (screen.orientation.type.startsWith('landscape')) {
      requestFullscreenVideo();
    } else if (document.fullscreenElement) {
      document.exitFullscreen();
    }
  });
}

נעילת המסך לרוחב בלחיצה על לחצן

מאחר שניתן לשפר את הצפייה בסרטון בפריסה לרוחב, ייתכן שנרצה לנעול את המסך בפריסה לרוחב כאשר המשתמש לוחץ על הלחצן 'מסך מלא'. אנחנו נשלב את Screen Orientation API קודם לכן עם כמה שאילתות מדיה כדי להבטיח שהחוויה הזו תהיה הטובה ביותר.

כדי לנעול את המסך במצב אופקי, כל מה שצריך זה להתקשר למספר screen.orientation.lock('landscape'). עם זאת, צריך לעשות זאת רק כשהמכשיר במצב תצוגה לאורך באמצעות matchMedia('(orientation: portrait)'), ואפשר להחזיק אותו ביד אחת באמצעות matchMedia('(max-device-width: 768px)'), כי זאת לא חוויה טובה למשתמשים בטאבלט.

fullscreenButton.addEventListener('click', function (event) {
  event.stopPropagation();
  if (document.fullscreenElement) {
    document.exitFullscreen();
  } else {
    requestFullscreenVideo();
    <strong>lockScreenInLandscape();</strong>;
  }
});
function lockScreenInLandscape() {
  if (!('orientation' in screen)) {
    return;
  }
  // Let's force landscape mode only if device is in portrait mode and can be held in one hand.
  if (
    matchMedia('(orientation: portrait) and (max-device-width: 768px)').matches
  ) {
    screen.orientation.lock('landscape');
  }
}

שינוי הכיוון של ביטול נעילת המסך במכשיר

ייתכן ששמת לב שחוויית מסך הנעילה שיצרנו כרגע לא מושלמת, כי אנחנו לא מקבלים שינויים בכיוון המסך כשהמסך נעול.

כדי לפתור את הבעיה, נשתמש ב-Device Orientation API, אם הוא זמין. ממשק ה-API הזה מספק מידע מהחומרה שמודדת את המיקום והתנועה של מכשיר בחלל: ג'ירוסקופ ומצפן דיגיטלי לציון הכיוון שלו ומד התאוצה למהירות. כשאנחנו מזהים שינוי בכיוון המכשיר, בואו נבטל את נעילת המסך באמצעות screen.orientation.unlock() אם המשתמש מחזיק את המכשיר במצב תצוגה לאורך והמסך נעול במצב פריסה לרוחב.

function lockScreenInLandscape() {
  if (!('orientation' in screen)) {
    return;
  }
  // Let's force landscape mode only if device is in portrait mode and can be held in one hand.
  if (matchMedia('(orientation: portrait) and (max-device-width: 768px)').matches) {
    screen.orientation.lock('landscape')
    <strong>.then(function() {
      listenToDeviceOrientationChanges();
    })</strong>;
  }
}
function listenToDeviceOrientationChanges() {
  if (!('DeviceOrientationEvent' in window)) {
    return;
  }
  var previousDeviceOrientation, currentDeviceOrientation;
  window.addEventListener(
    'deviceorientation',
    function onDeviceOrientationChange(event) {
      // event.beta represents a front to back motion of the device and
      // event.gamma a left to right motion.
      if (Math.abs(event.gamma) > 10 || Math.abs(event.beta) < 10) {
        previousDeviceOrientation = currentDeviceOrientation;
        currentDeviceOrientation = 'landscape';
        return;
      }
      if (Math.abs(event.gamma) < 10 || Math.abs(event.beta) > 10) {
        previousDeviceOrientation = currentDeviceOrientation;
        // When device is rotated back to portrait, let's unlock screen orientation.
        if (previousDeviceOrientation == 'landscape') {
          screen.orientation.unlock();
          window.removeEventListener(
            'deviceorientation',
            onDeviceOrientationChange,
          );
        }
      }
    },
  );
}

כמו שאפשר לראות, זו החוויה החלקה במסך מלא שרצינו לספק. כדי לראות את זה בפעולה, אפשר לעיין בדוגמה.

הפעלה ברקע

כשאתם מזהים שדף אינטרנט או סרטון בדף האינטרנט כבר לא גלויים, כדאי לעדכן את ניתוח הנתונים כך שישקף זאת. זה יכול להשפיע גם על ההפעלה הנוכחית, כמו בחירת טראק אחר, השהיה שלו או אפילו הצגת לחצנים מותאמים אישית למשתמש.

שינוי בהשהיית הסרטון בדף

בעזרת Page Visibility API, אנחנו יכולים לקבוע את החשיפה הנוכחית של הדף ולקבל התראות על שינויים בחשיפה. הקוד שלמטה משהה את הסרטון כאשר הדף מוסתר. זה קורה כשנעילת המסך פעילה או כשמחליפים כרטיסיות לפי מכונה.

מאחר שרוב הדפדפנים בנייד מציעים כעת בקרות מחוץ לדפדפן שמאפשרות להמשיך סרטון מושהה, מומלץ להגדיר התנהגות זו רק אם למשתמש מותר לפעול ברקע.

document.addEventListener('visibilitychange', function () {
  // Pause video when page is hidden.
  if (document.hidden) {
    video.pause();
  }
});

הצגה/הסתרה של לחצן ההשתקה בשינוי החשיפה של הסרטון

אם אתם משתמשים ב-Intersectionמיקום API החדש, תוכלו לקבל מידע מפורט יותר ללא עלות. ממשק ה-API הזה מיידע אתכם כשרכיב שנצפה נכנס לאזור התצוגה של הדפדפן או יוצא ממנו.

עכשיו נציג/להסתיר לחצן השתקה בהתאם לחשיפה של הסרטון בדף. אם הסרטון מופעל אך אינו מוצג כעת, לחצן השתקה קטן יוצג בפינה השמאלית התחתונה של הדף כדי להעניק למשתמש שליטה על צלילי הווידאו. האירוע volumechange בסרטון משמש לעדכון הסגנון של לחצן ההשתקה.

<button id="muteButton"></button>
if ('IntersectionObserver' in window) {
  // Show/hide mute button based on video visibility in the page.
  function onIntersection(entries) {
    entries.forEach(function (entry) {
      muteButton.hidden = video.paused || entry.isIntersecting;
    });
  }
  var observer = new IntersectionObserver(onIntersection);
  observer.observe(video);
}

muteButton.addEventListener('click', function () {
  // Mute/unmute video on button click.
  video.muted = !video.muted;
});

video.addEventListener('volumechange', function () {
  muteButton.classList.toggle('active', video.muted);
});

הפעלה של סרטון אחד בלבד בכל פעם

אם יש יותר מסרטון אחד בדף, מומלץ להפעיל רק סרטון אחד ולהשהות את הסרטונים האחרים באופן אוטומטי, כדי שהמשתמש לא יצטרך לשמוע כמה טראקים של אודיו מופעלים בו-זמנית.

// This array should be initialized once all videos have been added.
var videos = Array.from(document.querySelectorAll('video'));

videos.forEach(function (video) {
  video.addEventListener('play', pauseOtherVideosPlaying);
});

function pauseOtherVideosPlaying(event) {
  var videosToPause = videos.filter(function (video) {
    return !video.paused && video != event.target;
  });
  // Pause all other videos currently playing.
  videosToPause.forEach(function (video) {
    video.pause();
  });
}

התאמה אישית של התראות המדיה

באמצעות Media Session API, אפשר גם להתאים אישית את ההתראות של המדיה על ידי הוספת מטא-נתונים של הסרטון שפועל כרגע. הוא גם מאפשר לטפל באירועים שקשורים למדיה, כמו חיפוש או מעקב אחר שינויים, שעשויים להגיע מהתראות או ממקשי מדיה. כדי לראות זאת בפעולה, ראו דוגמה.

כאשר אפליקציית האינטרנט שלכם מפעילה אודיו או וידאו, ניתן כבר לראות התראה של מדיה במגש ההתראות. ב-Android, דפדפן Chrome עושה כמיטב יכולתו כדי להציג את המידע המתאים באמצעות כותרת המסמך ותמונת הסמל הגדולה ביותר שהוא יכול למצוא.

בואו נראה איך להתאים אישית את הודעת המדיה על ידי הגדרה של מטא-נתונים של סשן מדיה, כמו שם, אומן, שם האלבום וגרפיקה באמצעות Media Session API.

playPauseButton.addEventListener('click', function(event) {
  event.stopPropagation();
  if (video.paused) {
    video.play()
    <strong>.then(function() {
      setMediaSession();
    });</strong>
  } else {
    video.pause();
  }
});
function setMediaSession() {
  if (!('mediaSession' in navigator)) {
    return;
  }
  navigator.mediaSession.metadata = new MediaMetadata({
    title: 'Never Gonna Give You Up',
    artist: 'Rick Astley',
    album: 'Whenever You Need Somebody',
    artwork: [
      {src: 'https://dummyimage.com/96x96', sizes: '96x96', type: 'image/png'},
      {
        src: 'https://dummyimage.com/128x128',
        sizes: '128x128',
        type: 'image/png',
      },
      {
        src: 'https://dummyimage.com/192x192',
        sizes: '192x192',
        type: 'image/png',
      },
      {
        src: 'https://dummyimage.com/256x256',
        sizes: '256x256',
        type: 'image/png',
      },
      {
        src: 'https://dummyimage.com/384x384',
        sizes: '384x384',
        type: 'image/png',
      },
      {
        src: 'https://dummyimage.com/512x512',
        sizes: '512x512',
        type: 'image/png',
      },
    ],
  });
}

בסיום ההפעלה אין צורך 'לשחרר' את סשן המדיה כי ההתראה תיעלם באופן אוטומטי. חשוב לזכור ש-navigator.mediaSession.metadata הנוכחי יהיה בשימוש בכל הפעלה של הסרטון. לכן עליכם לעדכן את המידע, כדי לוודא שתמיד יוצג מידע רלוונטי בהתראה על המדיה.

אם אפליקציית האינטרנט מספקת פלייליסט, כדאי לאפשר למשתמש לנווט בפלייליסט ישירות מהתראת המדיה באמצעות סמלים מסוימים של 'הטראק הקודם' ו'הטראק הבא'.

if ('mediaSession' in navigator) {
  navigator.mediaSession.setActionHandler('previoustrack', function () {
    // User clicked "Previous Track" media notification icon.
    playPreviousVideo(); // load and play previous video
  });
  navigator.mediaSession.setActionHandler('nexttrack', function () {
    // User clicked "Next Track" media notification icon.
    playNextVideo(); // load and play next video
  });
}

חשוב לזכור שה-handlers של הפעולות במדיה יישמרו. המצב הזה דומה מאוד לדפוס של מאזין האירועים, למעט העובדה שטיפול באירוע פירושו שהדפדפן מפסיק לפעול כברירת מחדל ומשתמש בו כאות לכך שאפליקציית האינטרנט שלכם תומכת בפעולה במדיה. לכן, פקדי פעולות מדיה לא יוצגו, אלא אם תגדירו את ה-handler המתאים לפעולות.

דרך אגב, קל מאוד לבטל את ההגדרה של handler של פעולות במדיה, ממש כמו להקצות אותו אל null.

ב-Media Session API, אפשר להציג את סמלי ההתראות של המדיה 'דילוג לאחור' ו'דילוג קדימה' כדי לשלוט במשך הזמן שהמערכת מדלגת עליהם.

if ('mediaSession' in navigator) {
  let skipTime = 10; // Time to skip in seconds

  navigator.mediaSession.setActionHandler('seekbackward', function () {
    // User clicked "Seek Backward" media notification icon.
    video.currentTime = Math.max(video.currentTime - skipTime, 0);
  });
  navigator.mediaSession.setActionHandler('seekforward', function () {
    // User clicked "Seek Forward" media notification icon.
    video.currentTime = Math.min(video.currentTime + skipTime, video.duration);
  });
}

הסמל 'הפעלה/השהיה' תמיד מוצג בהודעת המדיה, והאירועים הקשורים מטופלים באופן אוטומטי על ידי הדפדפן. אם מסיבה כלשהי התנהגות ברירת המחדל לא פועלת, תוכלו לטפל באירועי המדיה 'הפעלה' ו'השהיה'.

מה שמעניין ב-Media Session API הוא שמגש ההתראות הוא לא המקום היחיד שבו מוצגים מטא-נתונים ופקדים של מדיה. התראת המדיה מסונכרנת באופן אוטומטי עם כל מכשיר לביש שהותאם. הוא גם מופיע במסכי הנעילה.

משוב