2019年12月6日

[WebAPIs] Picture In Picture of Video

keywords: video, WebAPIs

TL;DR

新技術一定有風險,瀏覽器有支援有不支援(目前只有 Chrome 預設是支援的),使用前應詳閱公開說明書!
// 檢驗瀏覽器有無支援 Picture In Picture API
if ('pictureInPictureEnabled' in document) {
  // 有支援...
}

// 進入 video 的 PIP 模式
videoElement.requestPictureInPicture().catch((error) => {
  // 錯誤處理...
});

// 離開 video 的 PIP 模式
document.exitPictureInPicture().catch((error) => {
  // Error handling
});
這篇文章內容主要整理自 An Introduction to the Picture-in-Picture Web API @ CSS Tricks

Picture In Picture 是什麼?

Video 元素的 Picture in Picture 模式可以讓影片獨立出來播放(下圖上方),甚至可以在其他頁籤繼續觀看原本的影片(下圖下方):
Imgur

進入和離開 Picture In Picture

// 進入 Picture In Picture
videoElement.requestPictureInPicture().catch((error) => {
  // Error Handling
});

// 離開 Picture In Picture
document.exitPictureInPicture().catch((error) => {
  // Error Handling
});

事件(Events)

videoElement.addEventListener('enterpictureinpicture', () => {
  notice.textContent = 'Enter Picture-in-Picture mode';
});

videoElement.addEventListener('leavepictureinpicture', () => {
  notice.textContent = 'Exit Picture-in-Picture mode';
});

在 PIP 的視窗上測做或增加功能鍵

只要透過 navigator.mediaSession.setActionHandler 就可以在 PIP 的視窗上操作不同的功能鍵:
// 當使用者點擊特定操作鍵時
navigator.mediaSession.setActionHandler('play', function() {
  // User clicked "Play" button.
});
navigator.mediaSession.setActionHandler('pause', function() {
  // User clicked "Pause" button.
});

同時也可以增加原本上面沒有顯示的功能鍵:
// 在 PIP 的視窗上增加前一部、後一部的功能鍵
navigator.mediaSession.setActionHandler('previoustrack', () => {
  // Go to previous track
});

navigator.mediaSession.setActionHandler('nexttrack', () => {
  // Go to next track
});
Imgur

在使用者前鏡頭的畫面呈現於 PIP 上

同樣地,也可以將裝置前置鏡頭的畫面呈現於 PIP 的視窗上,程式碼的部分可以參考 CSS Tricks 上的這個 CodePen:
## 避免瀏覽器使用 PIP 功能
在 HTML 的 <video> 標籤中加入 disablePictureInPicture 即可:
<video disablePictureInPicture controls src="video.mp4>"></video>

程式範例

參考資料

2019年11月20日

[WebAPIs] Web Share API 的使用 - navigator.share

keywords: WebAPIs, mobile, navigator.share

TL;DR

// 判斷瀏覽器是否支援 Web Share API
if (navigator.share) {
  // navigator.share 會回傳 Promise
  navigator.share({
    title: 'Web Fundamentals',
    text: 'Check out Web Fundamentals — it rocks!',
    url: 'https://developers.google.com/web',
  })
  .then(() => console.log('Successful share'))
  .catch((error) => console.log('Error sharing', error));
}

Web Share API 的說明

用手機瀏覽網頁的時候,不知道你有沒有注意過,當你按下分享按鈕時它會跳出一個選單,讓你可以選擇要分享到哪個 App 的選單,像是這樣:
Web Share API
這個功能過去需要透過點擊手機瀏覽器上的「分享」後才會出現:
Web Share API
但現在透過 Web Share 這個 API 也可以輕鬆達到這個功能,讓使用者在點擊網頁上的按鈕後就跳出這個「分享選單」,如此就有機會省去使用那種帶有一堆 Facebook、Line、Twitter、Pinterest 按鈕的第三方套件,進一步減少頁面載入時間。
現在就來看看怎麼使用吧!

Web Share API - navigator.share

適用瀏覽器

Web Share API 的使用方式很簡單,但要注意的是這主要是適用在手機上的功能,畢竟電腦上沒有這種分享選單(目前除了 Mac 的 Safari 可用),不過即使電腦不支援此 API 的使用,還是可以很容易做出替代方案(fallback)。
看到下圖瀏覽器支援性的一大片紅字感覺很恐怖,但目前(2019-11-20)其實主要的手機瀏覽器(Chrome, Safari)都適用,Mac 上的 Safari 亦可:
Web Share API
目前實測在三星內建的瀏覽器上可以使用,但分享成功後的回傳訊息不太正確。

使用方式

使用方式很簡單:
// navigator.share 會回傳一個 Promise

// 下面的欄位可以不用全部填寫,可以只分享網址,也可以只分享文字
const sharePromise = navigator.share({
  url: 'https://pjchender.blogspot.com',    // 要分享的 URL
  title: 'PJCHENder 那些沒告訴你的小細節',      // 要分享的標題
  text: '好多眉眉角角啊'             // 要分享的文字內容
});
navigator.share() 會回傳一個 Promise (代表你可以搭配 async...await 使用),這個 Promise 會在使用者完成點擊某個 App 分享後被完成(fulfilled);若使用者取消分享或帶入的參數有錯誤時,則會被拒絕(reject)。
使用時有幾點需留意一下:
  1. Web Share API 只能使用在有 HTTPS 的網站或者是測試時的 localhost,若想玩玩看這個 API 就可以到帶有 HTTPS 的 CodePen 上試試看。
  2. 需要透過使用者主動的行爲(user activation)才能觸發,例如,點擊事件。

範例程式碼

來看一下範例程式碼吧,也可以直接看 CodePen
See the Pen Web Share API by PJCHEN (@PJCHENder) on CodePen.

HTML

先建立最基本的一個按鈕:
<div class="center-center">
  <button>Share<i class="fas fa-share-alt"></i></button>
  <p class="result"></p>
</div>

JavaScript

  1. 透過 document.querySelector() 選擇和 DOM 有關的元素
  2. 建立使用者點擊分享時要帶入的資訊,不用每一項都填寫,也可以只分享文字或網址
  3. Web Share API 需要使用者主動的行為才能觸發, 所以透過 addEventListener 監聽使用者點擊 click 事件
  4. 透過 navigator.share 來使用 Web Share API
  5. 當使用者拒絕分享或發生錯誤時要顯示的訊息
// STEP 1:選擇和 DOM 有關的元素
const btn = document.querySelector('button');
const result = document.querySelector('.result');

// STEP 2:建立使用者點擊分享時要帶入的資訊
const shareData = {
  url: 'https://pjchender.blogspot.com', // 要分享的 URL
  title: 'PJCHENder 那些沒告訴你的小細節', // 要分享的標題
  text: '好多眉眉角角啊', // 要分享的文字內容
};

// STEP 3:當使用者點擊按鈕時
btn.addEventListener('click', async () => {
  try {
    // STEP 4:使用 Web Share API
    await navigator.share(shareData);
    result.textContent = '感謝你的的分享';
  } catch (err) {
    // STEP 5:使用者拒絕分享或發生錯誤
    const { name, message } = err;
    if (name === 'AbortError') {
      result.textContent = '您已取消分享此訊息';
    } else {
      result.textContent = err;
      console.log('發生錯誤', err);
    }
  }
});
如此就完成這個簡單的範例了。
這個範例的按鈕樣式是修改自 AyooluwaCodePen
來看一下實作的結果:
Web Share API
以 Line 為例,傳送出去的訊息內容如下:
Web Share API
See the Pen Web Share API by PJCHEN (@PJCHENder) on CodePen.

替代處理與其他(fallback)

對於不支援 Web Share API 的瀏覽器則可以透過判斷 navigator.share 是否存在來進行替代方案:
if (navigator.share) {
  // 使用 Web Share API
} else {
  // 替代方案寫在這...
}
舉例來說,在 CSS Tricks 的 How to Use the Web Share API 文章中提供了非常精緻的替代處理畫面:
Imgur
可以參考這個作者的 CodePen 範例。
如果不想這麼複雜的話,替代方案也可以是點擊按鈕後複製網址(Copy Link)給使用者自行分享即可。複製到剪貼簿的方式同樣有對應的 WebAPIs 可以支援,有需要可以參考先前整理的筆記 [WebAPIs] Copy to clipboard 複製到剪貼簿

範例程式碼:當瀏覽器不支援時讓按鈕變成複製功能

這裡提供實際的範例可以作為參考:
// 選擇和 DOM 有關的元素
const btn = document.querySelector('button');
const result = document.querySelector('.result');

// 當使用者點擊分享時要帶入的資訊
const shareData = {
  url: 'https://pjchender.blogspot.com', // 要分享的 URL
  title: 'PJCHENder 那些沒告訴你的小細節', // 要分享的標題
  text: '好多眉眉角角啊', // 要分享的文字內容
};

btn.addEventListener('click', () => {
  // 判斷瀏覽器是否支援 Web Share API
  if (navigator.share) {
    handleNavigatorShare();
  } else {
    handleNotSupportNavigatorShare();
  }
});

// 當瀏覽器支援 Web Share API 時
async function handleNavigatorShare() {
  try {
    await navigator.share(shareData);
    result.textContent = '感謝你的的分享';
  } catch (err) {
    // 使用者拒絕分享或發生錯誤
    const { name } = err;
    if (name === 'AbortError') {
      result.textContent = '您已取消分享此訊息';
    } else {
      result.textContent = err;
      console.log('發生錯誤', err);
    }
  }
}

// 當瀏覽器不支援 Web Share API 時,點下去變成複製
function handleNotSupportNavigatorShare() {
  const contentToCopy = document.querySelector('#content-to-copy');
  contentToCopy.value = shareData.url;
  contentToCopy.setAttribute('type', 'text'); // 不是 hidden 才能複製
  contentToCopy.select();

  try {
    const successful = document.execCommand('copy');
    const msg = successful ? '成功' : '失敗';
    alert(`${shareData.url} - 複製${msg}`);
  } catch (err) {
    alert('Oops, unable to copy');
  }

  /* unselect the range */
  contentToCopy.setAttribute('type', 'hidden');
  window.getSelection().removeAllRanges();
}

參考文章

2019年11月16日

[Samsung] 沒辦法看訊息通知?讓 Bixby Routines 朗讀通知給你聽

平常在開車或是工作時,並不是非常方便看手機,這種時候若收到 Line 或者簡訊通知時,常常都只聽得到通知卻不知道也不方便點開來看內容,這時候就會很希望手機的語音助理能夠把通知直接念出來讓我知道,至少可以知道是不是有急著需要處理的事情。
其實這個功能已經內建在三星這個看似毫無作用的 Bixby Routine 中了,這篇文章中就來看看可以怎麼樣使用。如果懶得看文字的話可以直接參考這個影片:

進入 Bixby Routine

要進入 Bixby Routine 可以從「設定」-->「進階功能」-->「Bixby Routines」中找到:
Bixby 朗讀通知功能
接著點擊上方的新增,可以為這個 routine 取個名稱,例如這裡我叫「唸給我聽」:
Bixby 朗讀通知功能
接著就可以設定「如果⋯則⋯」,這裡我先設定手動啟動(即,已輕觸開始按鈕),平常我也會設成一旦連接到藍芽耳機就啟動:
Bixby 朗讀通知功能
按下完成儲存後,像是這種需要手動開啟的 routine,會詢問你要不要新增到桌面上,點選是支後桌面上就會多了啟動和關閉這個 Routine 的按鈕:
Bixby 朗讀通知功能

當你希望手機擁有朗讀通知的功能時,例如開車、工作時,只要點選這個按鈕,一旦有收到推播通知,手機就會念出來給你聽。

Bixby Routines 的更多功能

這裡雖然是透過 Bixby Routines 來達到朗讀通知的功能,但實際上 Bixby Routines 可以做到更多的功能,它可以設定「當你到公司時則⋯」、「當你回家時則⋯」,可以是開啟 WIFI、開啟某個應用程式等等,功能還蠻多樣的話,善用它的話覺得會是個相當方便好用的功能。
若還不清楚怎麼操作的話,一樣可以回頭參考示範影片:

2019年9月3日

[Mac] 如何透過 iMovie 輸出高畫質影片(4k, 1080p)

iMovie 的專案會依據「第一部」匯入到時間軸中的媒體,以此決定這個影片最後可以輸出成多高的解析度,因此若你最後想輸出成 4K 的影片,只需要:
  1. 先到網路上下載一部 4k 的影片(參考影片下載連結
  2. 新增一個全新的專案(專案一定要是全新的,因為是以第一個匯入時間軸的媒體來決定最後輸出的解析度)
  3. 將 4k 影片匯入媒體後,拖曳到時間軸內,成功的話,在右邊齒輪(設定)的地方點一下,會看到解析度出現 4k 選項:
iMovie
  1. 接著,如果原本已經有編輯好的內容,可以複製貼在時間軸後面
  2. 把第一個放入時間軸的 4k 影片移除
  3. 選擇匯出成 4k 影片:
iMovie
專案一定要是全新的,因為是以第一個匯入時間軸的媒體來決定最後輸出的解析度

示範操作影片

參考資料

2019年8月31日

[多圖] 三星 Samsung S10+ Plus 與 Note 10 選擇困難?相機拍照、螢幕與效能比較心得

keywords: samsung, camera, s10+, s10plus, note10, performance, screen
imgur
最近剛好有機會同時入手三星(Samsung)的 S10+ Plus 和 Note 10(不是 Note 10+),可以分享一下這兩隻使用上的心得。
直接說結論:相較於 Note10,S10+ 的螢幕真的無可挑惕,色彩的呈現和解析度都非常棒;而 Note10 則是在 App 的安裝速度上有較明顯的提升。兩隻在主鏡頭的拍攝略有差異,主要體現在 Note 10 的成像有更明顯的對比,因此天空會更藍一些,較為吸睛,但有時對比太重會有色偏或修圖感較重的情況(覺得和這幾年 iPhone 成像對比也變強有些相似);S10+ 則中規中矩,在顏色的呈現上和原本的色彩比較接近。
台灣上市的 S10+ CPU 使用的是三星自家的 exynos 9820;Note 10 則是使用 高通 Qualcomm 855

螢幕(screen)

以前對於螢幕都沒有特別的感覺(不論是小米、三星、LG、HTC),至少不會讓我馬上感覺到「怪怪的」,但這次用了 Note10 之後,第一次感覺到螢幕真的有差異(差異的大小每個人感受不同),特別是和 S10+ 相比,可能眼睛有點被 S10+ 的螢幕給慣壞了。
這兩隻螢幕在色溫上的差異蠻明顯的。打開白屏的情況下就可以很明顯看得出來。將同一張照片放到這兩隻手機上時,可以看到很明顯的顯色不同。這也導致有時候在 Note 10 上看的相片在拿到 S10+ 或上傳到 MAC 後卻又是另一種感覺,也就是說同一張照片在手機上和電腦上色彩看起來會不太一樣
若想看螢幕的色溫差異可以參考 ptt 的這篇文章:[問題] 請問Note10+螢幕是預設偏黃嗎
對我個人來說 Note10 上的白色會給我沒那麼乾淨的感覺,並有些許偏黃,然後成像解析度也沒那麼清晰的感覺,和之前同樣是 1080p 的手機相比,之前的手機反倒不會給我這種感覺。
有網友表示可以在顯示的地方,把「背景效果」調成「鮮豔」,並到「進階設定」的地方將綠色拉到底,紅色降兩格會比較接近原本的白色,有需要的朋友可以試試看:
s10+ vs note10
因為每個人的感受和每台手機差異可能不同,建議如果在意的人可以到現場看實機感受一下
不論 Note 10 或 Note 10+ 似乎都有人反映這樣的情況,但每個人感受和每台手機的差異不同,可以看在 Mobile 01, pttfb 社團內都有不止一篇以上的討論
Note10 在螢幕的表現上偏黃,但因為每個人的感受和每台手機差異可能不同,如果在意的人可以到現場看實機感受一下。

效能(performance)

不看任何跑分軟體或數字的話,從主觀使用感受上對我來說沒有什麼差異,日常使用都不會有什麼卡頓的情況,遊戲順暢度給我的感覺也差不多
硬要比較的話,下載並安裝同一款 App 時 Note 10 花費的時間比較少,且在玩遊戲時 Note10 會再更流暢一些;但當我在用影片編輯軟體操作時,S10 + 的輸出速度則明顯較快。
簡單的說,我覺得高通在多工任務時處理得比較好,因此在 App 的切換上或同時運作多個 App 時比較流暢;而獵戶座在單槍匹馬的執行上速度更快,讓他不要分心乖乖一次做一件事他會做得更好。發熱程度的話,兩者在玩遊戲時都會有明顯發熱的感受。
日常使用都不會有什麼卡頓的情況,遊戲順暢度給我的感覺也差不多

相機拍照(camera)

主鏡頭

雖然 S10+ 和 Note 10 用的是相近相機模組,但兩者成像上仍有所差異,但我覺得沒有孰優孰劣,端看自己喜歡怎麼樣的風格
這兩隻手機拍出來的照片可以用成像的對比度簡單地區分出來。相較於以往三星手機飽和度相對較高的情況來說,這次 Note 10 的相片則是對比度較高,具體來說,會使得天空更藍一些、文字則會有加粗的效果,整體來說相片是更吸睛的,但有些時候對比度過高時會有色偏的情況,原本的紅色變得更深,或者是給人較強的修圖感。
S10+ 的相片則比較中規中矩,相較之下顏色比較準確,白色和文字的呈現上會比較乾淨一些,但也使得直接輸出的相片和 Note 10 相比沒那麼吸睛。
從下面這一系列的照片中可以蠻清楚看到上面的結論,可以先看一下你比較喜歡哪一邊的色彩,最後會在公布左邊和右邊各式哪台手機所拍:
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
s10+ vs note10
答案揭曉,左邊的照片都是使用 S10+ 所拍攝,右邊的照片則是使用 Note 10 進行拍攝,不知道你比較喜歡哪一個呢?
若想要看完整的圖片可以到此 Google 相簿
兩者用的雖然是相似的鏡頭模組,但成像上仍有所差異,S10 + 中規中矩、顏色較準確;Note 10 對比度高、照片較吸睛、但有時修圖感較強。我覺得沒有孰優孰劣,端看自己喜歡怎麼樣的風格。

前鏡頭(自拍鏡頭)

在前鏡頭方面 S10+ 和 Note 10 的成像方式可以說和主鏡頭是完全反過來。
S10+ 對比較強烈,在光線充足的情況下色彩較豐富,但有時會對比拉得太高,讓相片本身很不自然,這種情況在開啟廣角時更佳明顯。Note 10 在顏色上則比較自然舒服些,但相對的色彩表現上比較沒那麼豐富。完全取決於個人喜好和感受。
這裡避免傷眼就不附上自拍的照片,有興趣可以再去 Youtube 找相關的影片。

延伸閱讀

2019年8月11日

三星全面屏手勢操作,一個滑動手勢快速動作(關閉螢幕、返回上一頁)- One Hand Operation +

imgur
keywords: swipe gesture, samsung, one hand operation, lock screen, back
最近把手機換到三星,一開始一直有個地方很不習慣,之前在小米的 MIUI 上有提供了非常簡單易用的全面屏手勢,簡單來說就是把安卓傳統下方的三個功能鍵隱藏之外,只要透過「手勢」就可以做出回上一頁(從左右其中一側的螢幕向內撥)、回到主頁面、顯示應用程式清單頁的功能。
但是一開始換到三星手機時找不到這個功能,雖然一樣有全面屏的設定,但其實只是把下方三個功能鍵的區塊變成「一條線」,使用方式和傳統的操作方式幾乎一樣。對於大螢幕的手機來說,每此回到上一頁還需要把手指放到最下方真的很不方便,要嘛就變成需要雙手操作。
另一點不習慣的是電源鍵位置實在有點高,每次要關閉螢幕常要勾很久,而先前用的手機可以放置「關閉螢幕」的按鈕在桌面上,等於可以不用使用到電源鍵就可以做到關閉螢幕的功能。
這兩個功能讓我在一開始切換過來時很不適應,直到我發現三星有推出自己的手勢功能 App - One Hand Operation + 後覺得實在是太好用了,這個官方推出的 App 比先前 MIUI 上的還強大,因為它可以自行設定多種手勢對應到多種功能,而這個 App 也等於一次解決了兩個主要讓我不習慣的問題。
現在看看完成後可以怎麼操作,我設定只要從螢幕兩側往內下方滑動就會「關閉螢幕」、往內水平滑動就會「回到上一頁」、往內上方滑動則分別進行「調整螢幕亮度」和「螢幕截圖」的功能,實際操作起來會像這樣:


可以留意影片中左右側會出現一個「箭頭符號」,表示正在進行全面屏的手勢操作:
imgur

安裝 One Hand Operation +

imgur
首先就是要安裝官方提供的 One Hand Operation+,下載下來後就可以設定你想要哪個手勢對應到哪個工作就可以了。
下載三星官方 One Hand Operation+ @ Play Store

設定滑動手勢

設定的部分可以分成三個部分:
  • 滑動手勢對應功能:在對應功能裡可以設定不同的滑動手勢想要對應到什麼樣的功能,其中包括關閉螢幕、回到上一頁、螢幕截圖、調整音量、調整螢幕量度等等,可以說能夠調整非常多的東西。在後面會在做一些說明。
  • 滑動手勢可感應的區域:在這裡你可以選擇一般的情況下要不要看到手勢可感應區
    • 透明度」設成「最高」表示看不到,設成「最低」則會看到曲面螢幕兩邊出現白線。
    • 大小」表示可感應區的「高度」,基本我設成到幾乎整個曲面螢幕除了不要蓋到「側螢幕面板」的控制區。
    • 位置」則是感應區的高低,一樣是看個人習慣,我習慣設到最低是因為我都是握手機底部。
    • 寬度」表示可感應區的寬度大小,當感應區太大,有些人會覺得容易誤觸滑動手勢,感應區太小則可能會不容易感應到,這個部分端看自己的習慣。
  • 其他:這裡可以設定觸發手勢操作時要不要發出震動(震動級數),還有就是當感應到滑動手勢時需要拖曳拖長的距離才算數(滑動距離
提示:側螢幕面板若想移動該位置區域,可以按住 0.5 秒後即可對其進行拖曳。
swipe gestrue

滑動手勢對應功能

在滑動手勢的對應功能中,可以設定非常多的手勢和對應的功能,像是可以除了向內上滑、向內水平滑、向內下滑外,還可以設定左右對應到不同的功能(左控點、右控點)、滑動後停一下(滑動並按住)要做什麼事,但自己實際使用後,建議還是可以設定幾個比較「直觀」且「常用」的就好,而且最好左右的手勢功能是對稱的,例如,向內水平滑動都是「上一頁」。不然如果每次操作時都還要先想一下這個動作應該要用什麼手勢的話,覺得這個功能對你的方便性就沒這麼高了。
 提示:建議還是可以設定幾個比較「直觀」且「常用」的就好,而且最好左右的手勢功能是對稱的,才不會變得太會複雜而失去原本方便的目的。
one hand operation

快速工具

其中「快速工具」中甚至可以設定像是工具箱的內容:

one hand operation

滑動並按住

如果行有餘力的話,還可以設定滑動並按住對應的功能,但我自己設了幾天之後就關掉了,因為發現記不了這麼多XD:

one hand operation

心得

設定好之後你就可以用這些手勢快速的操作,我自已是設定「關閉螢幕」、「上一頁」、「螢幕截圖」和「調整亮度」這幾個我非常常用到的功能,算是整個補足了換機過來後不習慣的地方,如果你原本就是三星的用戶,但還沒使用這個全面屏手勢的功能的話,可以下載這個 One Hand Operation + 來試試看!

2019年7月28日

[Vue] 整合 Vue style guide, eslint-plugin-vue 和 VSCode

Vue Style Guide 中對於 Vue 專案的程式風格提供了許多建議,但有些時候在撰寫程式時還需要額外留意這些撰寫風格反而變成一種負擔,好在這時候 Vue 提供了好用的 eslint-plugin-vue (@vue/cli-plugin-eslint),透過 eslint 可以幫我們檢查哪些程式碼中的內容是不符合 Style Guide 所建議的,並且予以修正。
同時搭配上 VSCode 後,可以在存檔後自動根據 eslint 的建議來重新編排程式碼,不只省下了許多需要調整撰寫風格的認知負擔,更重要的是省下了許多時間,可以專注在程式開發上。
在這篇文章中就說明如何根據 Vue Style Guide 一併整合 eslint-plugin-vue 與 VSCode,可以先來看一下完成的畫面:
eslint-plugin-vue

安裝 eslint-plugin-vue

建立專案

這裡快速的透過 Vue CLI 的工具快速建立專案:
# 這裡使用的 Vue CLI 版本為 3.9.3
$ vue create vue-project

安裝用於 Vue 的 eslint 設定檔套件

接著透過 Vue CLI 安裝 eslint-plugin-vue:
# 若要直接透過 npm 安裝,可以參考官方說明
$ vue add @vue/cli-plugin-eslint
接著會請你選擇要使用的 ESLint 設定檔,這裡可以根據團隊或自己撰寫 JavaScript 的習慣去選擇,舉例來說這裡選擇 Standard(也就是 Standard JS 的風格規範):
eslint-vue-plugin
接著會進一步詢問有沒有需要額外個功能。這裡我只選第一項:
eslint-plugin-vue

設定 eslint 並修改程式碼

建立 eslint 設定檔

由於在 Vue Style Guide 中針對不同撰寫風格有不同的重要程度,透過 eslint 的設定檔可以選擇這個專案想要使用的建議程度。
先在根目錄的地方建立 .eslintrc.js 檔,在這支檔案可以根據你的需求進行設定:
// ./.eslintrc.js
module.exports = {
  extends: [
    // 在這裡可以添加你想要使用的風格規範,例如:
    // 'eslint:recommended',
    'plugin:vue/recommended'
  ],
  rules: {
    // 在這裡可以針對特定的規則進行覆蓋或添加,例如
    // 'vue/no-unused-vars': 'error'
  }
}
其中 extends 的部分有幾種選項可以根據自己或專案的需要進行調整:
// ./.eslintrc.js
{
  "extends": "plugin:vue/base",         // 受到的規範最少
  "extends": "plugin:vue/essential",
  "extends": "plugin:vue/strongly-recommended",
  "extends": "plugin:vue/recommended"   // 最嚴謹,完全依照建議
}
簡單來說,plugin:vue/recommended 會套用幾乎所有在 Vue Style Guide 中的建議,因此會使用到最多規則,也最不用自己動腦調整,其次是 plugin:vue/strongly-recommended,如果你希望受到 Vue Style Guide 的規範最少,則可以選 plugin:vue/base
關於每一項設定的詳細規則可以參考 eslint-plugin-vue rules 的說明。
另外,因為這裡使用的是 Standard JS 的撰寫風格(vue/standard),並希望使用 ESLint 提供的建議(eslint:recommended),所以另外添加兩個規範;同時,因為專案中會使用到較新的 JavaScript 語法,因此需要定義 parserOptions 以使用比較新的 JavaScript 語法。最後的 .eslintrc.js 會長像這樣子:
// ./.eslintrc.js

module.exports = {
  extends: [
    // add more generic rulesets here, such as:
    'eslint:recommended',
    'plugin:vue/recommended',
    '@vue/standard'
  ],
  rules: {
    // override/add rules settings here, such as:
    // 'vue/no-unused-vars': 'error'
  },
  parserOptions: {
    parser: 'babel-eslint',
    ecmaVersion: 2017,
    sourceType: 'module'
  }
}

執行 eslint 修改程式碼

剛剛我們透過 Vue CLI 安裝好 eslint-plugin-vue 之後,預設它會在 package.json 中添加了 lint 的指令,因此現在可以在終端機直接執行 npm run lint
$ npm run lint
執行後,會自動修改程式碼的撰寫風格,可以看到原本的檔案已經被調整成符合 Vue Style Guide 的建議,並且自動存檔
plugin-eslint-vue
同時,終端機也會列出所有不符合 Vue Style Guide 規範的部分,也就是需要人工調整的部分:
eslint-plugin-vue
這個警告很明顯的是在 Vue Style Guide 的 Prop definitions 中有提到,希望 Props 能盡量定義的詳細,這裡因為沒有告知 msg 這個屬性是 required 的,表示這個 props 有可能不存在,因此它會建議你要帶入預設值。
因此只需要把原本 HelloWord.vue 的程式碼根據建議加上預設值(default):
<!-- ./src/components/HelloWorld.vue  -->
<template>
  <!-- ... --->
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: {
      type: String,
      default: 'Hello Vue'
    }
  }
}
</script>
存檔後再執行一次 npm run lint 則顯示沒有任何錯誤!
eslint-plugin-vue
透過 npm run lint 之後,eslint-plugin-vue 會自動幫我們修正程式碼撰寫風格、HTML 標籤內的屬性順序、Vue 方法的排序等等都調整成 Vue Style Guide 的建議並存檔。但有些部分是它沒辦法自動處理的,這時候還是需要回去檢視這些部分。要留意的是,這些部分不去修正不代表你的程式碼會無法正確執行,而是沒有符合 Vue 的建議,而這些建議之所以存在,通常就是為了提升程式碼的可維護性和減少看能犯錯的機會。

整合 VS Code

最後,由於每次都要執行 npm run lint 稍微還有些麻煩,我們可以把 eslint 直接整合在 VSCode 中,當存檔的時候,就會自動轉換成建議的 Vue Style Guide 的撰寫風格。

安裝 Vue 和 Eslint 套件

Vetur

Vetur 套件可以算是在使用 VS Code 撰寫 Vue 時必配的套件,最明顯的是沒有它的話在撰寫 .vue 的時候程式碼不會有高亮的效果,但它實際上還做了很多其他的事。
vetur

ESLint

接著要安裝微軟官方提供的 ESLint 這個套件來將 VS Code 和 ESLint 整合在一起。
eslint

設定 settings.json

打開 settings.json 設定頁

首先進入 VSCode 的設定頁(MAC 可以按快捷鍵 CMD + ,):
imgur
因為現在 VSCode 預設是使用 UI 的方式進行設定,若想要直接編輯 settings.json 檔,可以在搜尋欄中搜尋 launch 然後:
vscode
然後點選在 settings.json 內編輯:
settings.json
接著就可以看到 settings.json 的檔案:
settings.json

添加相關設定

settings.json 中加入下面的設定,讓 eslint 可以針對 .vue 檔進行檢驗(預設只會針對 .js.jsx 的檔案):
// VSCode settings.json
{
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    { "language": "vue", "autoFix": true }
  ],
}
同時,如果你希望存檔時可以自動排版,則可以加上:
// VSCode settings.json
{
  "eslint.autoFixOnSave": true,
}
另外,因為安裝了 ESLint,因此就不需要 Vetur 針對 template 提供的驗證,一樣在 settings.json 加上如下的設定:
// VSCode settings.json
{
  "vetur.validation.template": false
}
完整的 settings.json 檔案如下:
{
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    { "language": "vue", "autoFix": true }
  ],
  "eslint.autoFixOnSave": true,
  "vetur.validation.template": false,
}

大功告成

到這裡就大功告成了,只要在你想按下存檔的時候,VS Code 就會自動根據 ESLint 中的設定重新排版程式畫面,若有警告或錯誤的程式碼,則會在程式碼下方以波浪符號提示:
eslint-plugin-vue

參考資源