[實作] Youtube Search

功能

利用Youtube API,可以搜尋Youtube影片。

有查看上一頁和下一頁的功能,點擊標題連結可以在該頁撥放影片。

學習到的知識點

CSS

  • .clearfix

JS

  • $.get
  • $.each
  • fancy box

簡介

Demo

HTML

結構

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<body>
<div class="container">
<header>
<h1>Search<span> Videos</span></h1>
<p>Search all Youtube videos</p>
</header>
<section>
<form
id="search-form"
class="search-form"
name="search-form"
onsubmit="return search()"
>
<!-- 需注意這邊的按下enter時,會return function -->
<div class="fieldcontainer">
<input
type="search"
id="query"
class="search-field"
placeholder="Search Youtube..."
/>
<input type="submit" name="search-btn" id="search-btn" value="" />
</div>
</form>
<ul id="results"></ul>
<div id="buttons"></div>
</section>
<footer>
<p>Copyright &copy; 2021, All Right Reserved</p>
</footer>
</div>
<script src="./js/script.js"></script>
<script src="./js/jquery.fancybox.pack.js"></script>
<script>
$(document).ready(function () {
$(".fancybox").fancybox();
});
</script>
</body>

CSS

完整Css Code

clearFix

在使用 float 的時候經常會遇到圖片超出預設的寬度,但只要使用clearfix,就可以使圖片和容器寬度一樣。

1
2
3
.clearfix {
clear: both;
}

box-shadow

發現了一個網站可以直接複製做好的shadow做使用。

Beautiful CSS box-shadow examples

JS

Search Bar animation

這邊使用Chaining鏈式,做了searchBar的動畫,在JS裡控制 css的 animation。

做出一種當滑鼠點擊輸入框時,會產生伸縮的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//Searchbar Handler
$(document).ready(function () {
var searchField = $("#query");
var icon = $("#search-btn");

//Focus Handler
$(searchField).on("click", function () {
$(this).animate(
{
width: "100%",
},
500
);
$(icon).animate(
{
right: "10px",
},
500
);
});
// Blur Event Handler
$(searchField).on("blur", function () {
if (searchField.val() == "") {
$(searchField).animate(
{
width: "45%",
},
500
);
$(icon).animate(
{
right: "360px",
},
500
);
}
});

$("#search-form").submit(function (e) {
e.preventDefault();
});
});

取得Youtube API資料

利用網址可以取得的json資料。

取得的資料

$.get功能

  • part: 這個參數是為了避免大家呼叫 API 時得到太多不相關的資訊,所以用 part 來定義要取得的資料範圍。在 Search 的情況下,設定為 part:snippet
  • type:限制搜尋結果為 video、channel 或 playlist
  • q:搜尋關鍵字
  • key: 金鑰
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function search() {
// Clear Result
$("#result").html("");
$("#buttons").html("");

// Get Form Inupt
q = $("#query").val();

$.get(
"https://www.googleapis.com/youtube/v3/search",
{
part: "snippet,id",
q: q,
type: "video",
key: "AIzaSyDUQUDfpg_6iA_ycnD5yaAYLSPc495aa",
},
// 取得data裡的Token方便之後使用
function (data) {
var nextPageToken = data.nextPageToken;
var prevPageToken = data.prevPageToken;

// Log Data
console.log(data);
}
);
}

search函式,使用each讀取每一筆資料

目標為取得items的每一筆item,使用each方法。

1
2
3
4
5
6
7
8
9
10
11
12
$.each(data.items, function (i, item) {
// Get Ouput
var output = getOutput(item);

// Display Result
$("#results").append(output);
});

var buttons = getButtons(prevPageToken, nextPageToken);

// Display Buttons
$("#buttons").append(buttons);

getOutput函式

過濾資料,取得需要的部分,建立成output字串。

在這邊就可以得到影片與內容的資訊,然後更改video的樣式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// Build Output
function getOutput(item) {
// 過濾資料
var videoId = item.id.videoId;
var title = item.snippet.title;
var description = item.snippet.description;
var thumb = item.snippet.thumbnails.high.url;
var channelTitle = item.snippet.channelTitle;
var videoDate = item.snippet.publishedAt;

// Build Output String
// 建立output字串
var output =
"<li>" +
'<div class="list-left">' +
'<img src="' +
thumb +
'">' +
"</div>" +
'<div class="list-right">' +
"<h3>" +
title +
"</h3>" +
'<small>By <span class="cTitle">' +
channelTitle +
"</span> on " +
videoDate +
"</small>" +
"<p>" +
description +
"</p>" +
"</div>" +
"</li>" +
'<div class="clearfix"></div>' +
"";
// 一般function最後都需要return
return output;
}

產生下一頁與上一頁的Button

search()函式裡,有取得nextPageTokenprevPageToken的數值,所以在getButtons()函式可以直接調用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
var buttons = getButtons(prevPageToken, nextPageToken);

// Build the buttons
function getButtons(prevPageToken, nextPageToken) {
// 如果是沒有prevPageToken,就只需要顯示next page button
if (!prevPageToken) {
var btnoutput =
'<div class="button-container">' +
'<button id="next-button" class="paging-button" data-token="' +
nextPageToken +
'" data-query="' +
q +
'"' +
'onclick="nextPage();">Next Page</button></div>';
} else {
// 有prevPageToken 才會產生兩個Button
var btnoutput =
'<div class="button-container">' +
'<button id="prev-button" class="paging-button" data-token="' +
prevPageToken +
'" data-query="' +
q +
'"' +
'onclick="prevPage();">Prev Page</button>' +
'<button id="next-button" class="paging-button" data-token="' +
nextPageToken +
'" data-query="' +
q +
'"' +
'onclick="nextPage();">Next Page</button></div>';
}

return btnoutput;
}

有nextPageToken就會有兩個Button

nextPage函數使 next Button可以使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Next Page Function
function nextPage() {
var token = $("#next-button").data("token");
var q = $("#next-button").data("query");

// Clear Results
$("#results").html("");
$("#buttons").html("");

// Get Form Input
q = $("#query").val();

// Run GET Request on API
// 再做一次讀取資料
$.get(
"https://www.googleapis.com/youtube/v3/search",
{
part: "snippet, id",
q: q,
pageToken: token,
type: "video",
key: "AIzaSyDUQUDfpg_6iA_ycnD5yaAYLSPc495aa",
},
function (data) {
var nextPageToken = data.nextPageToken;
var prevPageToken = data.prevPageToken;

// Log Data
console.log(data);

$.each(data.items, function (i, item) {
// Get Output
var output = getOutput(item);

// Display Results
// 將讀取到的資料append到html
$("#results").append(output);
});

var buttons = getButtons(prevPageToken, nextPageToken);

// Display Buttons
$("#buttons").append(buttons);
}
);
}

prevPage函數使prev Button可以使用

功能和nextButton一樣,改變一些變數。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Prev Page Function
function prevPage() {
var token = $("#prev-button").data("token");
var q = $("#prev-button").data("query");

// Clear Results
$("#results").html("");
$("#buttons").html("");

// Get Form Input
q = $("#query").val();

// Run GET Request on API
$.get(
"https://www.googleapis.com/youtube/v3/search",
{
part: "snippet, id",
q: q,
pageToken: token,
type: "video",
key: "AIzaSyDUQUDfpg_6iA_ycnD5yaAYLSPc495aa",
},
function (data) {
var nextPageToken = data.nextPageToken;
var prevPageToken = data.prevPageToken;

// Log Data
console.log(data);

$.each(data.items, function (i, item) {
// Get Output
var output = getOutput(item);

// Display Results
$("#results").append(output);
});

var buttons = getButtons(prevPageToken, nextPageToken);

// Display Buttons
$("#buttons").append(buttons);
}
);
}

fancy box

fancy box 官網下載檔案,然後放到Project裡。

最後再更改一些地方就可以使用

引入這個版本的jquery,fancybox 才可以正常運行,筆者原先使用3.5.1版本就無法運行,會直接開一個新的頁面,並不是我們要的效果。

HTML

1
2
3
4
5
6
<!-- 1.11.1版本 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<!-- 引入檔案 -->
<script src="./js/jquery.fancybox.pack.js"></script>
<link rel="stylesheet" href="./css/jquery.fancybox.css" />
1
2
3
4
5
<script>
$(document).ready(function () {
$(".fancybox").fancybox();
});
</script>

JS

js的部分需要加上超連結,就可以在fnacybox打開影片。

因為css放在css資料夾裡,所以需要開啟jquery.fancybox.css去更改圖片的路徑才可以使用(叉號與圖片與Loading圖)。

1
2
3
4
5
'<h3><a class="fancybox fancybox.iframe" href="http://www.youtube.com/embed/' +
videoId +
'">' +
title +
"</a></h3>" +

後記

Youtube API和天氣API比起來,有許多很技巧性的方法像是each還有fancy box,目前尚未完全學會,之後會做細分成更多更小的筆記一一學習。

參考文章

vsc-initialized是什么

JQuery Chaining

.clearfix


[實作] Youtube Search
https://phoebeho.com/Portfolio/20210212/2019791752/
作者
Phoebe
發布於
2021年2月12日
許可協議