English Title
简体标题
type
Post
status
Published
date
Apr 22, 2022
slug
youtube-for-notion-nextjs
summary
讓 YouTube Chapters 章節功能可以在我的 Blog 中,自由的跳轉播放,這樣使用者不用點擊每個時間點都跳到新的頁面,跳到 YouTube 產生體驗上的割裂感。
tags
useEffect
react.js
React Hook
YouTube
player
hashtag
Javascript
category
程式開發
blog
link
Property
Bilibili
TikTok
抖音
icon

⌚ 時光戳記

0:00 歡迎訂閱 🔔 按讚 👍 分享 🔥 與留言 💬 0:05 問題介紹 1:05 目標設定
1:23 技術使用 react-youtube next/router 1:45 完成效果 2:25 Notion 後台
在本站中,我常常會嵌入我拍好的 YouTube 影片,而為了讓觀看者有更好的觀看體驗,我會使用 YouTube Chapters 章節功能來標定影片不同時間點的位置。

問題說明

然而,這些時間點通常是在 YouTube 說明欄打上後,再複製到文章後台的,導致每個時間的標示都有連結本身,而連結本身都是連結到 YouTube 頁面的特定時間點,以 t=0s 這樣的形式表示。
令人討厭的是我們的內文明明就嵌有一個 YouTube 播放器,為什麼不能讓使用者在 Blog 中直接看我的影片呢?

目標:不刷新切換影片時間點!

今天,我的目標便是讓 YouTube Chapters 章節功能可以在我的 Blog 中,自由的跳轉播放,這樣使用者不用點擊每個時間點都跳到新的頁面,跳到 YouTube 產生體驗上的割裂感。
首先,我們要改裝我們的 react-notion-x 內的連結,當連結跟我的文章的 youtube 屬性有吻合的時候,抓取 t=0s 樣式的秒數,並用 query 改動網頁連結。
query 連結有改動的時候,YouTube 播放器自動地時間到目標時間。這個過程,我希望頁面不要有刷新。刷新雖然可以帶來閱讀數的增加,不過會使頻繁使用我的 Blog 用戶體驗不佳,產生割裂!

技術問題

問題一、 react-notion-x 的跳出 <a> 連結標籤

NotionNext 目前使用的 react-notion-x 版本比較舊一些,目前沒有新一點的版本有的 Next/link連結功能,使用的還會是一般 HTML 所使用的 <a> 標籤,不管 href 塞入什麼,都會造成頁面跳出與刷新。

問題二、 Next.js Shallow Routing

由於不想改動 react-notion-x 這個套件,我無法從底層將元件從 <a> 變成 <Link> 。當我們點擊連結時,<a> 在處理連結與觸發的時候,會整頁的刷新,而這是我們不想看到的!我要點擊時間只是想要跳到影片的段落位置,而非整頁刷新。其中 Next.js 提供一個功能叫做 “Shallow Routing ”,能夠在不刷新頁面的狀況下,改動 query
我嘗試將 Shallow Routing 各種寫法接寫過一遍,發現只要連結還是 <a> 頁面便會刷新。
既然, query 不行,那......
💡
想法一轉,我們不是有側欄的 Table of Content 可以點擊到不同段落而不會有刷新!
我們塞 hashtag 吧!

實作

畫一個 YouTube 播放器

react-youtube

這個插件我使用 react-youtube 這個 npm 套件,建了一個 16:9 的 div ,並在內放入我的播放器! playerVars 用來調控播放器的參數,目前內含 autoplaystartYTTime 是一個 state ,會隨著 hashtag 來更新秒數。
import YouTube from 'react-youtube'
<div className="video-player w-full" style={{ aspectRatio: '16/9' }}>
  <YouTube
    videoId={youtubeId}
    opts={{
      width: '100%',
      height: '100%',
      playerVars: {
        start: YTTime,
        autoplay: 1
      }
    }}
  />
</div>

取得 youtubeId

開啟播放器與否,我是由 post 是否有含 youtube 這個 property 來決定的!那來看看我怎麼從 post.youtube 來取得他的 youtubeId 吧!
當然,我可以從 post.youtube 用切字串的方式取得 v= 這個 youtube 連結的參數,不過既然是 URLparams 我們就用 javascript 的方式解決!
const YouTubeURL = new URL(post.youtube)
const params = new URLSearchParams(YouTubeURL.search)
youtubeId = params.get('v')

處理 <a> 連結

useEffect

我們先建一個只跑一次的 useEffect
useEffect(() => {
}, [])

getElements...

React 中,我們應該將所有的元件都切成一個一個獨立運作的 Component ,然而,我們今天要改動的元件卻是在 react-notion-x 中的元件,因不改動套件,我們使用基礎的 JavaScript 語法,抓取元件並對連結做改動。
const container = document?.getElementById('container')
const a = container?.getElementsByClassName('notion-link')
//---
item.href.includes('youtube')
item.href.includes('t=')
我一步一步抓取元件、取得連結並篩選只有與 YouTube 相關的連結。我們要對於 YouTube 連結的時間點抓取秒數。

更換連結位置

避免 <a> 連結將頁面跳到新頁,我將 targetrel 的參數設定為空值,href 則為 youtube-time 的時間點!
// 把連結換成 hash 並取消點擊連結開新頁
a[i].href = `#youtube-time=${urlTime}`
a[i].target = ''
a[i].rel = ''
這樣使用 hashtag 就可以自由切換 url ,但頁面不會跳轉!這是 html 一直以來都有的功能!

抓取 #HashTag 時間,改變播放器時間!

當 hash 改變,則...

我們運用 react componentuseEffect hookmount 元件,使用 hashevent listener 來確保 hash 改變的時候,會執行 state change
const onHashChanged = () => {
	// run when hash change!
}
window.addEventListener('hashchange', onHashChanged)
return () => {
  window.removeEventListener('hashchange', onHashChanged)
}

改變播放器時間

先抓取 hash ,因為有些標題使用到 hash ,我們確保他有 youtube-time 才去抓取時間,並設定 setYTTime 讓 YouTube 播放器跳轉到 hash 上的時間!
const linkHash = window.location.hash
if (linkHash.includes('youtube')) {
  setYTTime(parseInt(linkHash.replace(/\D/g, '')))
}
這邊,我們大致將不刷新切到時間點的功能做好了!不過,我們在點擊連結的時候,可能連結與播放器的位置有一段頁面上的距離。我們來讓它點擊後,會跑到播放器的位置!

賦予新 #HashTag 錨定位置

創立錨定點

創建一個 div ,它與 notion-header-anchor 標題的錨定點有同樣的 class ,繼承一些原有的設計。我為他加上 yt-anchor 來讓它有著一些獨特的性質。我們將錨定點 id 設為 youtube-time=5s 的形式來讓點擊 hashtag 後可以跳到這邊!
const newYTAnchor = document.createElement('div')
      newYTAnchor.id = `youtube-time=${urlTime}`
      newYTAnchor.classList.add('yt-anchor')
      newYTAnchor.classList.add('notion-header-anchor')

塞到播放器前面

const videoPlayer =
  document.getElementsByClassName('video-player')
if (videoPlayer) {
  videoPlayer[0].prepend(newYTAnchor)
}
我們將錨定點塞到 videoPlayer 前面,確保點擊不同的時光戳記,都會滑動到播放器的位置!

Future work

當我剛寫完我的 YouTube 插件後,發現 react 還有除了 react-youtube 外的另外一個插件,而且還更強大!它就是 react-player ! 看來要找時間再改寫並加入更多功能!
 
插件 Code 在這邊!如果大家喜歡這篇文章歡迎分享或是留言跟我交流喔!
 
全大運軟式網球個人男子雙打心得:一般男生第七NotionNext 加入側欄 Facebook Fan Page 小工具

留言區


如果你想使用 Facebook, Google, Twitter 帳號留言,或是匿名分享,可以使用 Disqus 留言。
擁有 Facebook 帳號的朋友可以使用 Facbook 原生社群插件留言。
若是有 Github 帳號可以使用 Giscus 留言!


  • Disqus
  • Facebook
  • Giscus
  • Cusdis