wordpress_blog

This is a dynamic to static website.

JavaScript 入門篇 – 學徒的試煉

JavaScript 的前世今生

JavaScript 環境設定 (編輯器、jsbin、console)

編輯器功能

  1. 自動補全
  2. 下拉提示
// document - 選取這個網頁上的內容
// . - 去使用裡面相關 JavaScript 的功能
document.getElementById('footer');

編輯器 – 使用 Visual Studio Code

建構第一個 JS 環境

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
    <script src="js/all.js"></script>
</head>
<body>
    <h1>1234</h1>
</body>
</html>

JavaScript

alert("Hello world!!");

HTML、CSS、JavaScript 的關聯性

  • HTML – 內容
  • CSS – 樣式
  • JS – 行為

ID 寫法、textcontent

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
    <style>
        h1{color: red;}
    </style>
</head>
<body>
    // emmet ul>li*3>a{標題$}
    // 錨點
    <ul>
        <li><a href="#title1">標題1</a></li>
        <li><a href="#title2">標題2</a></li>
        <li><a href="#title3">標題3</a></li>
        <li><a href="page.html#title3">標題4</a></li>
    </ul>
    <h1 id="title1">標題一</h1>
    <p>lorem300</p>
    <h1 id="title2">標題二</h1>
    <p>lorem300</p>
    <h1 id="title3">標題三</h1>
    <p>lorem</p>

    <script src="js/all.js"></script>
</body>
</html>

page.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
    <script src="js/all.js"></script>
    <style>
        h1{color: red;}
    </style>
</head>
<body>
    // emmet ul>li*3>a{標題$}
    <ul>
        <li><a href="#title1">標題1</a></li>
        <li><a href="#title2">標題2</a></li>
        <li><a href="#title3">標題3</a></li>
    </ul>
    <h1 id="title1">標題一</h1>
    <p>lorem300</p>
    <h1 id="title2">標題二</h1>
    <p>lorem300</p>
    <h1 id="title3">標題三</h1>
    <p>lorem</p>
</body>
</html>

JavaScript

document.getElementById('title1').textContent = '修改後的標題';
// document - 目前你網頁上的主體
// .getElementById - 透過這樣的方式去指定裡面 id 的內容
// 指定裡面 id 的內容使用''或""的方式去讀取裡面的內容
// .textContent - JavaScript 其中一個語法
// 修改裡面的值 = ''或""來變成修改後的內容
<script src="js/all.js"></script>,因為瀏覽器渲染內容由上到下,因此要放在</body>的前面。

練習

  1. 錨點功能
  2. 利用上面所教的語法去修改 h1 裡面的內容

直譯器流程介紹

interpreter (解譯器) – 引擎
每個瀏覽器都有每個瀏覽器的 JavaScript 的引擎。
Chrome 的引擎 – V8

DOM (Document Object Model)
文件物件模型 – 提供了一個文件(樹)的結構化表示法,並定義讓程式可以存取並改變文件架構、風格和內容的方法。

JavaScript HTML DOM

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">

    <style>
        h1{color: red;}
    </style>
</head>
<body>
    <ul>
        <li><a href="#title1">標題1</a></li>
        <li><a href="#title2">標題2</a></li>
        <li><a href="#title3">標題3</a></li>
        <li><a href="page.html#title3">標題4</a></li>
    </ul>
    <h1 id="title1">標題一</h1>
    <p>lorem300</p>
    <h1 id="title2">標題二</h1>
    <p>lorem300</p>
    <h1 id="title3">標題三</h1>
    <p>lorem300</p>
    <script src="js/all.js"></script>
    <h1>js後的標題</h1>
    <p>1234</p>
</body>
</html>

JavaScript

alert('qq');

預期會先彈跳 all.js 的功能,h1、p是不會被渲染到的。

開發人員工具 – Console

變數

變數簡介

變數 – 常見資料型別

數字 字串 布林
35 “Hello world!!” true、false
// 數字
翻口袋 10,
35 -10 = 25
紅豆餅:35
你身上的錢:10
差多少:25

// 字串
我的名字叫做 小杰

對方在腦袋裡記住了 「我的名字」

很高興認識你,小杰

// 布林

true、false

餓或不餓

變數 number 介紹

// 變數寫法
// var - 宣告變數
// price - 變數名稱
// = - 指定內容
var price = 30;

all.js

var cookiePrice = 35;
alert(cookiePrice);
cookiePrice = 25;
alert(cookiePrice);

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <p>這一顆紅豆餅<em id="price"></em>元</p>
    <script src="js/all.js"></script>
</body>
</html>

JavaScript

var cookiePrice = 35;
document.getElementById('price').textContent = cookiePrice;

變數 string 介紹

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="gift">
        <img src="images/gift.png" width="150" height="150" alt="gift">
        <p><em id="myName"></em>:</p>
        <h2>祝你生日快樂</h2>
        <p class="sendName">小花</p>
    </div>
    <script src="js/all.js"></script>
</body>
</html>

CSS

/* CSS RESET */
/* CSS STYLES */
.gift{
    width: 300px;
    height: 300px;
    color: #fff;
    font-size: 18px;
    text-align: center;
    background: #14cc99;
    margin: 30px auto;
    border-radius: 5px;
    padding: 10px;
}
.gift p{
    text-align: left;
    padding: 0;
    margin: 10px 0;
}
.gift h2{
    font-size: 36px;
    margin: 20px 0;
    padding: 0;
}
.gift .sendName{
    text-align: right;
    font-size: 12px;
}

JavaScript

var polite = "Hello ";
var indexName = "小杰";
var totalPolite = polite + indexName;

document.getElementById('myName').textContent = totalPolite;

如何輸出內容?

JavaScript

var score = 90;
console.log(score);

變數規則

變數 注意事項

  • 開頭不能用數字
  • 不能用 – 跟 .
  • 不能使用關鍵字
  • 大小寫有分
  • 變數需有語意化 (建議)

變數 – 數字新增刪除修改

// 每一個內容都是半形,全形會出錯。

var cookiePrice = 35;
var myMoney = 15;
var total = cookiePrice - myMoney;

document.getElementById('cookiePriceId').textContent = cookiePrice;
document.getElementById('myMoneyId').textContent = myMoney;
document.getElementById('totalId').textContent = total;

undefined 介紹

已經賦予出來一個變數名稱,但是變數名稱內容是空值。

Chrome – Console

> var box = 20;
< undefined

// var box;
// box = 20;

函式

為什麼需要 function?

// 情境 - 顧客點餐
// 服務生:歡迎光臨,請問您要點什麼?漢堡剩下最後 8 個哦!
//  顧客:不用薯條,給我 8 個漢堡,再一杯可樂吧!
// 服務生:好的,總計是 420 元

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="wrap">
        <div class="wrap-inner">
            <h1>六角西餐廳 - 顧客點餐篇</h1>
            <p>服務生:<span id="greetId"></span></p>
            <p> 顧客:不用薯條,給我<em class="tag">8</em>個漢堡,再<em class="tag">1</em>杯可樂吧!</p>
            <p>服務生:好的,總計是<em id="totalId" class="tag"></em>元</p>
        </div>
    </div>
    <script src="js/all.js"></script>
</body>
</html>

JavaScript

// 打招呼
function greet(){
  var greetNote = '歡迎光臨,請問您要點什麼?漢堡剩下最後 8 個哦!'
  
  document.getElementById('greetId').textContent = greetNote;
  console.log(greetNote);
}
greet();

// 點餐回應
function order(hamNum,cokeNum){
  var total = (hamNum * 50) + (cokeNum * 20);
  document.getElementById('totalId').textContent = total;
  console.log(total);
}
order(8,1);

function 的寫法

函式寫法

宣告函式 函式名稱
function greet(){
  alert('歡迎光臨!');
  alert('請問你要點些什麼?');
}

// 執行函式
greet();
var price = 30;

function greet(){
  console.log('Hello');
  console.log('請問您想要點什麼?')
}

greet();

Chrome – Console

window

// 把 greet、price 記錄在 windows 裡面。
// 瀏覽器就可以記錄這個網頁所有的 JavaScript 的狀態。

function 帶參數

// 函式帶參數
                參數
function count(oneNum){
  var total = oneNum * 10;
  console.log('總數等於:'+total);
}
count(10);

範例1

function count(oneNum){
  var total = oneNum * 10;
  console.log("總價格:"+total+"元");
}

count(8);

範例2-1

function count(oneNum,twoNum){
  var total = oneNum + twoNum;
  console.log("總價格:"+total+"元")
}

count(8,2);

範例2-2

function count(oneNum,twoNum){
  var total = oneNum * twoNum;
  console.log("總價格:"+total+"元");
}
count(8,49);

全域與區域變數

全域變數

// 全域變數
var total;

function count(oneNum,twoNum){
  total = oneNum * twoNum;
  console.log("總價格:"+total+"元");
}

count(8,10);

console.log(total);

區域變數 – 執行完就銷毀了

function count(oneNum,twoNum){
  // 區域變數
  var total = oneNum * twoNum;
  console.log(total);
  console.log("總價格:"+total+"元")
}

count(8,10);

hoisting 、 var 觀念

function 有個 Hoisting(提升) 觀念。

// Hoisting 觀念

console.log(a);
var a = 3;
console.log(a);

count();

function count(){
  console.log('hello!');
}

// 還是習慣把這個 function 放在上面由上到下去做執行

function 計算機案例 (1)

function 計算機案例 (2)

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>顧客點餐篇</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="wrap">
        <div class="wrap-inner">
            <h1>六角西餐廳 ─ 顧客點餐篇</h1>
            <p>服務生:Hello,請問您想要點什麼?</p>
            <p> 顧客:給我 <input type="text" id="hamNumId"> 個漢堡,再 <input type="text" id="cokeNumId"> 杯可樂吧!</p>
            <p>服務生:<input type="button" id="countId" value="計算中">,好的,總計是<em id="totalId" class="tag"></em>元</p>
        </div>
    </div>
    <script src="js/all.js"></script>
</body>
</html>

CSS

/* CSS RESET */
/* CSS STYLES */
html{
    background: #000;
    font-family: MicrosoftJhengHeiRegular;
}
*,*:before,*:after{
    box-sizing: border-box;
}
.wrap{
    background: url(images/desktop.png) 50% 50%;
    max-width: 1049px;
    height: 420px;
    margin: 200px auto;
    padding-top: 50px;
}
.wrap-inner{
    background: rgba(0,0,0,.65);
    margin: 0 auto;
    width: 600px;
    color: #fff;
    padding: 50px;
}
.wrap-inner h1{
    text-align: center;
    font-size: 36px;
    margin-bottom: .5em;
}
.wrap-inner p{
    font-size: 16px;
    line-height: 24px;
}
.wrap-inner .tag{
    color: yellow;
}
.wrap-inner input[type=text]{
    width: 30px;
}

JavaScript

document.getElementById('countId').onclick = function(){
    // 事件 - onclick
    // 觸發到事件就會去執行裡面的內容
    var hamNum = document.getElementById('hamNumId').value;
    var cokeNum = document.getElementById('cokeNumId').value;
    alert(hamNum);
    alert(cokeNum);
}

function 計算機案例 (3)

typeof() – 用來判斷參數是什麼型別。

Chrome - Console

> typeof(3)
< "number"
> typeof('hello')
< "string"
> typeof(function(){alert('q')})
< "function"
> typeof({tom:'john'})
< "object"

parseInt() – 字串轉成數字。

// Chrome - Console

> var num = "3";
< undefined
> typeof(num)
< "string"
> num = parseInt(num)
< 3
> num
< 3
> typeof(num)
< "number"

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>顧客點餐篇</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="wrap">
        <div class="wrap-inner">
            <h1>六角西餐廳 ─ 顧客點餐篇</h1>
            <p>服務生:Hello,請問您想要點什麼?</p>
            <p> 顧客:給我 <input type="text" id="hamNumId"> 個漢堡,再 <input type="text" id="cokeNumId"> 杯可樂吧!</p>
            <p>服務生:<input type="button" id="countId" value="計算中">,好的,總計是<em id="totalId" class="tag"></em>元</p>
        </div>
    </div>
    <script src="js/all.js"></script>
</body>
</html>

CSS

/* CSS RESET */
/* CSS STYLES */
html{
    background: #000;
    font-family: MicrosoftJhengHeiRegular;
}
*,*:before,*:after{
    box-sizing: border-box;
}
.wrap{
    background: url(images/desktop.png) 50% 50%;
    max-width: 1049px;
    height: 420px;
    margin: 200px auto;
    padding-top: 50px;
}
.wrap-inner{
    background: rgba(0,0,0,.65);
    margin: 0 auto;
    width: 600px;
    color: #fff;
    padding: 50px;
}
.wrap-inner h1{
    text-align: center;
    font-size: 36px;
    margin-bottom: .5em;
}
.wrap-inner p{
    font-size: 16px;
    line-height: 24px;
}
.wrap-inner .tag{
    color: yellow;
}
.wrap-inner input[type=text]{
    width: 30px;
}

JavaScript

document.getElementById('countId').onclick = function(){
    var hamPrice = 50;
    var cokePrice = 20;
    var hamNum = parseInt(document.getElementById('hamNumId').value)*hamPrice;
    var cokeNum = parseInt(document.getElementById('cokeNumId').value)*cokePrice;
    document.getElementById('totalId').textContent = hamNum + cokeNum;
    console.log(hamNum+cokeNum);
}

function 搭配 return 寫法

// 計算漢堡的總價

function getHamPrice(num){
  var hamPrice = 50;
  var total = hamPrice * num;
  return total;
}

var tom = getHamPrice(10);
console.log(tom);

陣列與物件

陣列(Array)、物件(Object)

為什麼需要陣列?

更有效率的或者是更好維護的方式,來去紀錄有各個的東西。

陣列簡報介紹

農莊現在想協助地方的農夫做統計,希望卡斯柏的農場使用陣列、物件的格式。

// 農夫
var farmer = '卡斯柏';
// 有幾個玉米
var cornField = 8;
// 多個玉米田各有幾個玉米
var cornField = [8,5,6];
// 狗的名字分別是
var dogs = ['張姆士', '龐的'];
// 農場
var farmer = '卡斯柏';
var dogs = ['張姆士', '龐的']
var chick = 15;
var cornField = [8, 5, 6];
var broccoliField = [6,6,6,6];
var scarecrow = 9;

陣列寫法教學

var cornField = [8, 5, 6]
// 陣列第一個是0。

var cornField1 = cornField[0];

console.log(cornField1);
var cornField = [];
cornField.push(5);
cornField.push(8);
cornField.push(6);

cornField[0] = 10;

cornField[3] = 100;

// 陣列裡面的值有幾個
console.log('我總共有'+cornField.length+'個玉米田');

console.log(cornField);

物件簡報介紹

var farm = {
  // 屬性 (property): 值 (value)
  farmer: '卡斯柏',
  dogs: ['張姆士', '龐的'],
  chick: 15,
  cornField: [8, 5, 6],
  broccoliField: [6, 6, 6, 6],
  scarecrow: 9
}

物件寫法教學

var farm = {
  farmer: '卡斯柏',
  chick: 15,
  dog: ['張姆士','龐的']
};

farm.chick = 30;

var dog1 = farm.dog[0];

// 顯示農場的物件
console.log(farm);
// 顯示農場的小雞有幾隻
console.log(farm.chick);
// 第一隻狗的名字
console.log('我農場裡的第一隻狗叫'+dog1);
var house ={
  room: 3,
  father: 'tom',
  son: ['john','bob'],
  mom: 'mary'
}
// 第一個兒子
console.log(house.son[0]);

物件+function 運用技巧

物件可以放字串、數字、布林值還有可以放 function。

var farm = {
  farmer: '卡斯柏',
  chick: 15,
  duck: 3,
  dog: ['張姆士','龐的'],
  goDinner: function(){
    console.log(farm.farmer+',該回家吃晚飯);
  },
  poultryTotal: function(){
    var num = farm.chick + farm.duck;
    console.log('我的農場總共有'+num+'隻家禽');
  }
};

farm.goDinner();
farm.poultryTotal();

串接API、後端資料庫,會傳遞資料格式(JSON)到其他伺服器或服務。

物件+陣列設計流程

var farms = [
  {
    farmer: '卡斯柏'
  },
  {
    farmer: '小杰'
  }
]
console.log(farms[1].farmer);
// 物件和陣列的讀取方式
var farms = [{
  farmer: '卡斯柏',
  dogs: ['張姆士', '龐的'],
  chick: 15,
  cornField: [8, 5, 6],
  broccoliField: [6, 6, 6, 6],
  scarecrow: 9
}, {
  farmer: '查理',
  dogs: ['皮皮'],
  chick: 30,
  cornField: [18, 12],
  borccoliField: [8, 8, 8],
  scarecrow: 6
}];

// 第二個農場的狗,皮皮的資料
console.log(farms[1].dogs[0]);

控制判斷(運算子、if、switch)

以日常生活為例探討為何需要控制判斷

if – 讓程式幫你下判斷

– 人類具有判斷的能力,我們在饑餓的時候會去找東西吃。

條件 | 執行
飽足→什麼也不做
飢餓→進食

if (hungry <= 3) {
  eat('披薩');
} else if (hungry < 7 && hungry > 3) {
  eat('沙拉');
}

比較運算子:==、!==

等於 不等於 布林
== !== true、false
// Google Console
// = ,賦予一個值
// ==,比較的時候
> var myAge = 18;
< undefined
> var bAge = 18;
< undefined
> myAge == bAge
< true

比較運算子:==、!==,程式碼範例

var myMonth = 5;
var thisMonth = 10;
var birthdayCheck = myMonth == thisMonth;
console.log(birthdayCheck);
document.getElementById('birthdayId').textContent = birthdayCheck;

var nowPeople = 1;
var totalPeople = 2;
var allPeopleNoHereCheck = totalPeople !== nowPeople;
console.log(allPeopleNoHereCheck);
document.getElementById('peopleId').textContent = allPeopleNoHereCheck;

比較運算子:嚴謹模式 ===

判斷型別之後再去判斷內容的正確性,使用 === 。

// Chrome Console
> 1 == 1
< true
> 1 == "1"
< true
> 1 === "1"
< false
> '1' === '1'
< true
> true == 1
< true
> false == 0
< true

比較運算子:!= 與 !== 的差異

前面章節為確保資料嚴謹性,使用 == 和 !== 一同說明

為避免同學誤解,這邊增加說明 != 與 !== 的差異。

!= 是不等於,而 !== 是嚴謹模式的不等於,差別與前面章節提到的 == 和 === 是相同依據。

!= 在運算元不相等時返回 true

!== 則在運算元不相等或類型不相同時返回 true

舉例:

3 != '3' // false
3 !== '3' // true

比較運算子:>、<

大於 小於
> <
大於等於 小於等於
>= <=
// Chrome Console
> 80 > 10
< true
> 80 < 10
< false
> 80 >= 79
< true
> 80 >= 80
< true
> 80 > 80
< false
// Chrome Console
> 1250 > 1000
< true
> var myCost = 1250
< undefined
> myCost > 1000
< true

邏輯運算子:&&、||、!

And OR NOT
&& || !

And
我:你好,我要辦銀行帳戶
銀行專員:請問你有帶「身分證」、「印章」嗎?
我:我只有帶到身分證可以辦嗎?
銀行專員:不好意思,一定得兩個都帶才有辦法辦哦

OR
服務員:請問你機天的帳單有滿一千元,或是 VIP 嗎?有送禮!
我:我不是VIP,但剛好我有滿 1000 元耶!

var isID = true;
var isIN = false;
isID == true;
true
isID == true && isIn == true
false
> var isID = true;
> var isIn = true;
> isID == true && isIn == true;
< true
> var isID = true;
> var isIn = true;
> var isPaper = true;
> isID == true && isIn == true && isPaper == true;
< true

範例

> var billFull = 1200;
> var isVIP = false;
> billFull > 1000 || isVIP == true;
< true
> isVIP == true
< false
> billFull > 1000
< true

範例

> 2>3
< false
> !(2>3)
< true

邏輯運算子:範例程式碼

六角西餐廳 – 贈品篇

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>顧客點餐篇</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="wrap">
        <div class="wrap-inner">
            <h1>六角西餐廳 ─ 贈品篇</h1>
            <p>服務生:請問你是 VIP 嗎?帳單有滿千嗎?兩者達到可送贈品哦。</p>
            <p> 顧客:<em class="tag" id="andId"></em></p>
            <p>服務生:抱歉我記錯了,只要一個有達到就送贈品囉,你有嗎?</p>
            <p> 顧客:<em class="tag" id="orId"></em></p>
        </div>
    </div>
    <script src="js/all.js"></script>
</body>
</html>

JavaScript

var myBill = 1250;
var VIP = false;
var andCheck = myBill > 1000 && VIP == true;
// alert(andCheck);
var orCheck = myBill > 1000 || VIP == true;
// alert(orCheck);

document.getElementById('andId').textContent = andCheck;
document.getElementById('orId').textContent = orCheck;

if – 簡報介紹

控制判斷
if, else if, switch

// 以吃飯為範例
if(hungry == '飢餓'){ →判斷式
  eat(); →陳述式
 }

if(hungry == '飢餓')
hungry = '飽足' → false
hungry = '飢餓' → true → 進食 / eat();

if – 程式碼教學

var hungry == '飽足';
// console.log(hungry == '飢餓');
if(hungry == '飢餓'){
  console.log('我現在好餓');
}else{
  console.log('我現在一點都不想吃東西');
  console.log('我們走吧!');
}

else if 簡報介紹

以飽足感為例

很飽
不餓,但想吃東西 → 吃沙拉
餓到不行 → 吃披薩
var hungry = 8; // 1~10 的數值

if (hungry <= 3) {
  eat('披薩');
} else if (hungry < 7 && hungry > 3) {
  eat('沙拉');
}
// 飢餓度,小於等於 3 時吃披薩
// 介於 4 ~ 7 之間吃沙拉

hungry = 8; 什麼都不做
hungry = 5; 吃沙拉
hungry = 1; 吃披薩

else if – 程式碼教學

var hungry = 8;
// 飢餓程度 1~10
// hungry 改成 3 時會要吃披薩
// hungry 改成 5 時會要吃沙拉
// hungry 改成 6 時會要吃餅乾
// hungry 改成 9 時我超飽不想吃東西

function eat(food){
  console.log('我現在要吃'+food);
}
// console.log(hungry <= 3);
if(hungry <= 3){
  eat('披薩');
}else if(hungry <= 5 && hungry >3){
  eat('沙拉');
}else if(hungry == 6){
  eat('餅乾');
}else{
  console.log('我超飽不想吃東西');
}

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>顧客點餐篇</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="wrap">
        <div class="wrap-inner">
            <h1>六角西餐廳 ─ 飽足篇</h1>
            <p>飽足感:<em class="tag" id="hungryId"></em></p>
        </div>
    </div>
    <script src="js/all.js"></script>
</body>
</html>

JavaScript

var hungry = 9;
// 飢餓程度 1~10

function eat(food){
    document.getElementById('hungryId').textContent ="我現在要吃"+food;
}
if(hungry <= 3){
    eat('披薩');
}else if(hungry <= 5 && hungry > 3){
    eat('沙拉');
}else if(hungry==6){
    eat('餅乾');
}else{
    document.getElementById('hungryId').textContent ="我超飽不想吃東西";
}

switch – 簡報介紹

// 以喜好為例
var prefer = '拉麵';

function eat(food){
  console.log('我現在要去吃' + food);
}

switch (prefer){
  case '牛排':
    eat('牛排');
    break;
  case '生菜沙拉':
    eat('生菜沙拉');
    break;
  default:
    eat('拉麵');
    break;
}
switch(prefer) → 設立一個表達式 switch() 且包含一個條件。
case '生菜沙拉' → case: 後方會開始比對,如果符合就會執行相關連的程式碼
break → 每個 case:後方皆會補上 break; 來阻止已完成的區塊後方繼續執行。

switch – 程式碼教學

// 警戒狀態為例
var light = 'red';

switch(light){
  case 'red':
  alert('紅色警戒');
  alert('快跑!');
  break;

  case 'blue':
  alert('藍色警戒');
  break;

  // 都沒有以上狀況,使用 default
  default:
  alert('沒有任何資料');
  break;
}
var light = 'blue';
function lightFun(str){
    console.log('目前是'+ str +'警戒');
}

switch(light){
    case 'red':
    alert('紅色警戒');
    alert('快跑!');
    break;

    case 'blue':
    lightFun(light);
    break;
    
    // 都沒有以上狀況,使用 default
    default:
    alert('沒有任何資料');
    break;
}

跟 if 的差別是 switch 裡面的程式碼一定會跑。

default 放前面或後面都可以執行,不像是 if else 一定要放在最後面。

迴圈

為什麼需要學習迴圈?

var farms = [
  farmer: '卡斯柏',
  dogs: ['張姆士', '龐的'],
  chick: 15,
  cornField: [8, 5, 6],
  broccoliField: [6, 6, 6, 6],
  scarecrow: 9
}, {
  farmer: '查理',
  dogs: ['皮皮'],
  chick: 30,
  cornField: [18, 12],
  broccoliField: [8, 8, 8],
  scarecrow: 6
}];

// 語法
console.log(farms.length); → 取得陣列長度
// 2

console.log(farms[1].farmer); → 取得第 X 個陣列值
for (var i = 0; i < farms.length; i++) {
  console.log('第' + (i + 1) + ' 個農場主人是 ' + farms[i].farmer);
}
// "第 1 個農場主人是 卡斯柏"
// "第 2 個農場主人是 查理"

for 寫法

// 初始狀態;條件;更新內容
for (var i = 0; i < 3; i++){
  console.log(i);
}
// 九九乘法表
// 初始狀態;條件;更新內容
for (var i = 1; i < 10; i++){
  console.log(i+'*'+i+'='+ i*i);
  // "1*1=1"
  // "2*2=4"
}

for-array 寫法

範例一

var farms = [
  {
    farmer: '卡斯柏',
    field: 6
  },
  {
    farmer: '查理',
    field: 10
  }
]
var farmsTotal = farms.length;
for(var i=0;i<farmsTotal;i++){
  console.log(farms[i].farmer);
}

範例二

var farms = [
  {
    farmer: '卡斯柏',
    field: 6
  },
  {
    farmer: '查理',
    field: 10
  }
]
var farmsTotal = farms.length;
for(var i=0;i<farmsTotal;i++){
  console.log('第'+ (i+1) +'個農場主人是'+ farms[i].farmer);
  // 第1個農場主人是卡斯柏
  // 第2個農場主人是查理

for if 寫法

var farms = [
  {
    farmer: '卡斯柏',
    field: 6,
    chick: 200
  },
  {
    farmer: '查理',
    field: 10,
    chick: 50
  },
  {
    farmer: '約翰',
    field: 6,
    chick: 120
  }
]
// 撈出哪些的農場的小雞數量超過 100 隻以上

var farmsTotal = farms.length;

for(var i = 0;i<farmsTotal;i++){
  console.log(farms[i].chick);
  if(farms[i].chick>100){
    console.log(farms[i].farmer+'的小雞超過100隻以上');
  }
}

for – i++ 寫法

// Google Chrome Console
> var i = 0;
< undefined
> console.log(i)
  0
< undefined
> i = i+1
< 1
> i+=1
< 2
> i++
< 2
> i
< 3
>
// 練習
> var total = 501
< undefined
> total++
< 501
> total
< 502
> total+=1
< 503
> total
< 503
>

有三種寫法

  • i = i+1
  • i+=1
  • i++

for – 加總

var farms = [
  {
    farmer: '卡斯柏',
    field: 6,
    chick: 200,
    banana: 5000
  },
  {
    farmer: '查理',
    field: 10,
    chick: 50,
    banana: 1000
  },
  {
    farmer: '約翰',
    field: 6,
    chick: 120,
    banana: 3215
  }
]
// 計算今年的香蕉採收總數
var farmsTotal = farms.length;
var bananaTotal = 0;
for(var i = 0;i<farmsTotal;i++){
    bananaTotal+= farms[i].banana;
}

console.log('今年村子的香蕉採收量:'+bananaTotal);

for 與 break 運用

break – 中斷

當滿足中斷條件時,就離開迴圈。

var farms = [
  {
    farmer: '卡斯柏',
    field: 6,
    chick: 200,
    banana: 5000
  },
  {
    farmer: '查理',
    field: 10,
    chick: 50,
    banana: 1000
  },
  {
    farmer: '約翰',
    field: 6,
    chick: 120,
    banana: 3215
  }
]
// 我要找一個農場,買50隻小雞
var farmsTotal = farms.length;
for(var i = 0;i<farmsTotal;i++){
  if(farms[i].chick>=50){
    console.log(farms[i].farmer+'的農場小雞有50隻以上');
    farms[i].chick -= 50;
    console.log(farms[i].farmer+'的小雞剩下'+farms[i].chick);
    break;
  }
}
console.log(farms[0].chick);

json 格式介紹

WIKI – JSON :資料交換的格式

高雄市政府資料開放

JSON VIEW chrome 插件

下載連結

擷取 JSON 格式流程

var data = [{},{},{},{},{}]

console.log(data.length);

for – opendata 範例 (上)

以宗教為範例

var data = [{},{},{},{},{}];

// 撈出所有高雄市前鎮區的宗教
var total = data.length;
for(i=0;i<total;i++){
  if(data[i].District=='高雄市前鎮區'){
    console.log('宗教類別'+data[i].Religion+' 宗教名字:'+data[i].Name);
  }
}
// 把資料多行轉換成一行

全選資料後,案右鍵點選 Command Palette,輸入 Join Lines
// 資料為中文時
// 以農產交易價格為練習

var data = [{},{},{},{},{}...{}];

var dataTotal = data.length;
for(i=0;i<dataTotal;i++){
    if(data[i]["作物名稱"]=='酪梨'){
        console.log('交易日期:'+data[i]["交易日期"]+'市場名稱:'+data[i]["市場名稱"]+'作物名稱:'+data[i]["作物名稱"]);
        console.log('上價價格:'+data[i]["上價"]+'元/公斤'+'中價價格:'+data[i]["中價"]+'元/公斤'+'下價價格:'+data[i]["下價"]+'元/公斤'+'平均價格:'+data[i]["平均價"]+'元/公斤'+'交易數量:'+data[i]["交易量"]+'公斤');
    }
}

OPEN DATA 範例 (下)

OpenData.epa – 行政院環境保護署

// 以十分鐘雨量為範例

var data = [{},{},{},{},{}...{}];

// 測試資料是否能正常使用
console.log(data.length);

// 查詢10分鐘內哪個地區有下雨
var dataTotal = data.length;
for(var i = 0; i < dataTotal; i++){
  if(data[i].Rainfall10min > 0){
    var County = data[i].County;
    var Township = data[i].Township;
    var Rain = data[i].Rainfall10min;
    console.log(County+Township+':'+Rain);
  }
}

// 3個資料,過濾出想要的資料
// 可以用 codepen、jsbin 線上編譯器練習
// 以農產交易為練習
var data = [{},{},{},{},{}...{}];

var dataTotal = data.length;
for(var i = 0; i < dataTotal; i++){
  if(data[i]["作物名稱"] == '酪梨'){
    var date = '交易日期:' + data[i]["交易日期"];
    var name = '作物名稱:' + data[i]["作物名稱"];
    var place = '市場名稱:' + data[i]["市場名稱"];
    var num = '交易量:' + data[i]["交易量"];
    var price = '價格(元/公斤):' + '上價:' + data[i]["上價"] + '中價:' + data[i]["中價"] + '下價' + data[i]["下價"] + '平均價:' + data[i][平均價];
    var TWprice = '價格(元/斤):' + '上價:' + data[i]["上價"]*0.6 + '中價:' + data[i]["中價"]*0.6 + '下價:' + data[i]["下價]*0.6 + '平均價:' + data[i]["平均價"]*0.6;

    console.log(date+name+place+num);
    console.log(price);
    console.log(TWprice);
  }
}

DOM

什麼是 DOM ?

<!DOCTYPE html>
<html>
<head>
  <title>MyTitle</title>
</head>
<body>
  <h1>Header</h1>
  <a href="#">MyLink</a>
</body>
</html>

DOM – 文件物件模型

querySelector – 選擇單一元素

HTML

<h1 id="titleId" class="titleClass"><em></em></h1>

JavaScript

// 語法一
document.getElementById('titleId').textContent = "修改後的標題";
// 語法二
var el = document.getElementById('titleId');
el.textContent = '修改後的標題';
// querySelector

// 選擇 id
var el = document.querySelector('#titleId');
el.textContent = '選擇 id';
// 選擇 class
var el = document.querySelector('.titleClass');
el.textContent = '選擇 class';
// 選擇 class 裡面的 em
var el = document.querySelector('.titleClass em);
el.textContent = '選擇 class';

觀念:一個網頁上只能出現一個 id 名稱,不可以出現兩個。

querySelectorAll – 可重複選取多個元素

撈多筆資料可以使用 querySelctorAll。

HTML

<h1 class="titleClass"><em></em></h1>
<h1 class="titleClass"><em></em></h1>

CSS

#strId{
    color: blue;
    font-size: 48px;
}

JavaScript

var el = document.querySelectorAll('.titleClass em');
console.log(el);
// 是一個陣列
el[0].textContent = "第一個內容";
el[1].textContent = "第二個內容";

// 使用 for 迴圈
var elLen = el.length;

for(var i = 0;i<elLen;i++){
  el[i].textContent = 'for迴圈:'+i;
}

setAttribute – 增加標籤屬性

HTML

<h1 class="titleClass">
  <a href="#">增加標籤 href 屬性</a>
</h1>
<div class="str">增加標籤 id 屬性</div>

JavaScript

var el = document.querySelector('.titleClass a');
el.setAttribute('href','https://www.google.com.tw');

var el2 = document.querySelector('.str');
el2.setAttribute('id','strId');

// 取得標籤屬性的值
var el3 = document.querySelector('.titleClass a').getAttribute('href');
console.log(el3);

// 用 textContent 單純撈出裡面文字
var el4 = document.querySelector('.titleClass a').textContent;

// 用 innerHTML 撈出 HTML 的標籤的內容
var el5 = document.querySelector('.titleClass a').innerHTML;

// 用 innerHTML 只撈 titleClass
var el6 = document.querySelector('.titleClass).innerHTML;

插入 HTML 標籤的兩種方法

用 JavaScript 操控 HTML 的方法

innerHTML
  • 方法:組完字串後,傳進語法進行渲染
  • 優點:效能快
  • 缺點:資安風險,要確保來源沒問題
createElement
  • 方法:以 DOM 節點來處理
  • 優點:安全性高
  • 缺點:效能差

innerHTML 寫法 (上)

HTML

<div id="main"></div>

CSS

.blue{
  color: blue;
}

JavaScript

var el = document.getElementByIs('main');
el.innerHTML = '<h1 class="blue">Heading1 標題</h1>'
// 外面用單引號,裡面用雙引號。
var el = document.getElementById('main');
var str = '<h1 class="blue">Heading1 標題</h1>';
el.innerHTML = str+str;

節點 – 各個網頁結構,都是一個節點。

innerHTML 的特性,會把裡面的值給清空,再去賦予設定的值。

innerHTML 寫法 (下)

HTML

<ul class="list"><ul>

JavaScript

var el = document.querySelector('.list');
var link = 'https://www.google.com.tw';
var name = '卡斯柏';

el.innerHTML = '<li><a href="'+link+'">'+name+'</a></li>';

innerHTML 與 for 運用

HTML

<h1>每個農場的農夫名字</h1>
<ul class="list"></ul>

JavaScript

var farms = [
  {
    farmer: '卡斯柏',
    dogs: ['張姆士','龐的']
  },
  {
    farmer: '查理',
    dogs: ['皮皮']
  }
];

var el = document.querySelector('.list');
var farmLen = farms.length;
// 使用 console.log 來看所寫的程式碼是否正確
console.log(farmLen);
var str = '';
for(var i = 0;i<farmLen;i++){
  var content = '<li>'+ farms[i].farmer +'</li>';
  str+=content;
  console.log(str);
}
el.innerHTML = str;
練習一

HTML

<h1>每個農場的資料</h1>
<table class="list">
</table>

JavaScript

var farms = [
  {
    farmer: '卡斯柏',
    dogs: ['張姆士','龐的']
  },
  {
    farmer: '查理',
    dogs: ['皮皮']
  }
];

var el = document.querySelector('.list');
var farmLen = farms.length;

console.log(farmLen);

var str = '';
for(var i=0;i<farmLen;i++){
  var farmer = '<td>'+farms[i].farmer+'</td>';
  var dogs = '<td>'+farms[i].dogs+'</td>';
  var farm = '<tr>'+farmer+dogs+'</tr>';
  str+=farm;
  console.log(str);
}

var title = '<tr>'+'<th>'+'農夫名字'+'</th>'+'<th>'+'小狗名字'+'</th>'+'</tr>';
el.innerHTML = title + str;
練習二

HTML

<div class="wrap">
  <div class="container">
    <h1>市場交易價格</h1>
    <table class="list"></table>
  </div>
</div>

CSS

/* CSS STYLES RESET */
/* CSS STYLES SETTINGS START*/
html{
  font-family: sans-serif;
}
*,*:before,*:after{
  box-sizing: border-box;
}
/* CSS STYLES SETTINGS END */
.wrap{
  max-width: 1440px;
  margin: 0 auto;
  background: #97d077;
  padding: 20px 0;
  color: #111;
}
.wrap h1{
  font-size: 48px;
  text-align: center;
  padding: 30px 0;
}
.wrap h2{
  font-size: 32px;
  padding: 20px 0;
}
.list{
  margin: 0 auto;
  background: #67ab8f;
}
th, td{
  border: 1px solid #fff;
  padding: 10px;
  text-algin: center;
}

@media screen and (max-width: 569px){
  .container{
    overflow-x: auto;
  }
  .list{
    width: 768px;
  }
}

JavaScript

var data = [{},{},{},{},{},...{}];

var el = document.querySelector('.list');
var dataLen = data.length;

console.log(dataLen);

var str = '';
var strText = '';

for(var i=0;i<dataLen;i++){
  if(data[i]["作物名稱"] == '酪梨'){
    var date = data[i]["交易日期"];
    var name = data[i]["作物名稱"];
    var place = '<td>+data[i]["市場名稱"]+'</td>';
    var num = '<td>'+data[i]["交易量"]+'</td>';
    var topPrice = '<td>'+data[i]["上價"]+'</td>';
    var midPrice = '<td>'+data[i]["中價"]+'</td>';
    var lowerPrice = '<td>'+data[i]["下價"]+'</td>';
    var avgPrice = '<td>'+data[i]["平均價"]+'</td>';

    var numTW = data[i]["交易量"]*(5/3);
    var topTWPrice = data[i]["上價"] * 0.6;
    var midTWPrice = data[i]["中價"] * 0.6;
    var lowerTWPrice = data[i]["下價"] * 0.6;
    var avgTWPrice = data[i]["平均價"] * 0.6;

    numTW = numTW.toFixed(1);
    topTWPrice = topTWPrice.toFixed(1);
    midTWPrice = midTWPrice.toFixed(1);
    lowerTWPrice = lowerTWPrice.toFixed(1);
    avgTWPrice = avgTWPrice.toFixed(1);

    num = '<td>'+data[i]["交易量"]+' | '+numTW+'</td>';
    topPrice = '<td>'+data[i]["上價"]+' | '+topTWPrice+'</td>';
    midPrice = '<td>'+data[i]["中價"]+' | '+midTWPrice+'</td>';
    lowerPrice = '<td>'+data[i]["下價"]+' | '+lowerTWPrice+'</td>';
    avgPrice = '<td>'+data[i]["平均價"]+' | '+avgTWPrice+'</td>';

    var info = '<tr>'+place+num+topPrice+midPrice+lowerPrice+avgPrice+'</tr>';
    str+=info;
    var text = '<h2>'+date+' '+name+'</h2>';
  }
}

var title = '<tr>'+'<th width="20%">'+'市場名稱'+'</th>'+'<th>'+'交易量<br> (公斤) | (斤)'+'</th>'+'<th>'+'上價<br>(元/公斤) | (元/斤)'+'</th>'+'<th>'+'中價<br>(元/公斤) | (元/斤)'+'</th>'+'<th>'+'下價<br>(元/公斤) | (元/斤)'+'</th>'+'<th>'+'平均價<br>(元/公斤) | (元/斤)'+'</th>'+'</tr>';

el.innerHTML = text+title+str;

createElement 寫法

HTML

<h1 class="title>
  <em>title</em>
</h1>

CSS

.blue{
  color: blue;
}

JavaScript

// 新增一個元素 - createElement()
var str = document.createElement('em');
str.textContent = '字串內容';
str.setAttribute('class','blue');

// 增加子節點 - appendChild()
document.querySelector('.title').appendChild(str);

createElement – 不會刪除原本的內容,會新增在後面。

補充:JavaScript 動態建立 table 表格的方法

最原始的方法,依序建立元素。

var el1 = document.createElement('table');
var el2 = document.createElement('tbody');
var el3 = document.createElement('tr');
var el4 = document.createElement('td');
// 使用子節點 - appendChild()追加各個元素
el3.appendChild(el4);
el2.appendChild(el3);
el1.appendChild(el2);

createElement 與 for 運用

HTML

<h1>每個農場的農夫名字</h1>
<ul class="list"></ul>

JavaScript

var farms = [
  {
    farmer: '卡斯柏',
    dogs: ['張姆士','龐的']
  },
  {
    farmer: '查理',
    dogs: ['皮皮']
  }
];

var el = document.querySelector('.list');
var farmLen = farms.length;
console.log(farmLen);

for(var i=0;i<farmLen;i++){
  var str = document.createElement('li');
  console.log(farms[i].farmer);
  str.textContent = farms[i].farmer;
  el.appendChild(str);
}

XSS 跨網站指令碼注意事項 (Cross-site scripting)

使用 innerHTML 資安上的問題。

範例程式碼

HTML

<textarea name="" id="content" cols="30" rows="10"></textarea>
<input id="send" type="button" value="送出">
<div id="main"></div>

JavaScript

document.getElementById('send').onclick = function(){
  var str = document.getElementById('content').value;

  document.getElementById('main').innerHTML = str;
}

舉例:文字欄位填寫後送出

// 會被新增 script 惡意程式碼,竊取資料、攻擊網站。
Hello!!!
<script>
  alert('你被入侵了');
</script>

innerHTML 使用時機:可以信任的資料。

避免表單資料的送出使用 innerHTML 。

XSS:跨站指令攻擊 (Cross-site scriptint),是一種網站應用程式的安全漏洞攻擊,是代碼注入的一種。

event (事件)

什麼是 event (事件)?

HTML DOM Events

HTML DOM events allow JavaScript to register different event handlers on events in an HTML document.

Events are normally used in combination with functions, and the function will not be executed before the event occurs (such as when a user clicks a button).

event 物件 – 告知你當下元件資訊

用 onclick、或者其他事件綁定的時候,當你觸發那些事件時,console.log(e) 會提供你一些相關資訊。

範例程式碼

HTML

<input type="button" value="點擊" class="btn">

JavaScript

var el = document.querySelector('.btn');

el.onclick = function(){
  // 測試點擊事件功能是否能執行
  alert("hello");
}
var el = document.querySelector('.btn');
  // 參數:e 或者 event
el.onclick = function(e){
  // eg1
  console.log(e);
  // eg2
  console.log(e.x);
}

觀念篇 – 各種事件綁定的差異

範例程式碼

HTML

<input type="button" class="btn" value="點擊一">

<input onclick="現在已經不建議使用的onclick寫法" type="button" value="點擊二">

<input type="button" class="btn2" value="點擊三">

JavaScript

// 寫法一
var btn = document.querySelector('.btn');

btn.onclick = function(){
  alert('hello!');
}

// 寫法二
var btn2 = document.querySelector('.btn2');
    // 監聽
btn.addEventListener('click',function(){
  alert('hello!!');
},false);

addEventListener – 事件監聽

範例程式碼

HTML

<input type="button" value="點擊" class="btn">

JavaScript

var el = document.querySelector('.btn');
// 選擇事件,代入匿名function,false
// 監聽
el.addEventListener('click',function(e){
  alert('hello');
},false)

綁定事件的語法差異

onclick 跟 addEventListener 的差別:

  • onclick – 不能同時綁定兩個以上的事件
  • addEventListener – 可以同時綁定兩個以上的事件

HTML

<input type="button" class="btnOn" value="on點擊">
<input type="button" class="btnAdd" value="add點擊">

JavaScript

// onclick
var elOn = document.querySelector('.btnOn');
elOn.onclick = function(){
  alert('on點擊-1);
}

elOn.onclick = function(){
  alert('on點擊-2);
}

// addEventListener - 事件監聽
var elAdd = document.querySelector('.btnAdd');
elAdd.addEventListener('click',function(){
  alert('add點擊-1');
},false)
elAdd.addEventListener('click',function(){
  alert('add點擊-2');
},false)

講解不同的綁定事件方式,是因為還是有機會看到其他事件綁定方式。

Event Bubbling、Event Capturing 差異

程式碼範例

HTML

<body class="body">
  <div class="box"></div>

  <script src="js/all.js"></script>
</body>

CSS

.box{
  width: 100px;
  height: 100px;
  background: #000;
}

JavaScript

var el = document.querySelector('.box');
el.addEventListener('click',function(){
  alert('box');
  console.log('box');
},false);

var elBody = document.querySelector('.body');
elBody.addEventListener('click',function(){
  alert('body');
  console.log('body');
},false);

// false (事件氣泡:Event Bubbling) - 從指定元素往外層找
// true (事件捕捉:Event Capturing) - 從最外層找到指定元素
// 第三個參數不寫的話,預設是 false

stopPropagation – 中止冒泡事件

HTML

<body class="body">
  <div class="box"></div>

  <script src="js/all.js"></script>
</body>

CSS

.box{
  width: 100px;
  height: 100px;
  background: #000;
}

JavaScript

var el = document.querySelector('.box');
el.addEventListener('click',function(e){
  // 中止冒泡事件
  e.stopPropagation();
  alert('box');
  console.log('box');
},false);

var elBody = document.querySelector('.body');
elBody.addEventListener('click',function(){
  alert('你沒有點到box');
  console.log('你沒有點到box');
},false);

preventDefault – 取消預設觸發行為

HTML

<body class="body">
  <a class="link" href="https://www.google.com.tw" style="margin-top:1800px;display:block;">menu icon</a>
  <script src="js/all.js"></script>
</body>

JavaScript

var el = document.querySelector('.link');

el.addEventListener('click',function(e){
  // 取消元素的默認行為

  // 原本點連結會跳轉到指定網頁

  // submit 按鈕,先透過我的 js 去查詢表單有無錯誤,post來傳送
  e.preventDefault();
  console.log('test');
},false);

e.target – 了解目前所在元素位置

HTML

<div class="header">
  <ul style="padding-top:100px;border:1px solid #000;">
    <li><a href="#">123</a>
  </ul>
</div>

JavaScript

var el = document.querySelector('.header');

el.addEventListener('click',function(e){
  // 當下元素資訊
  console.log(e);
  // 目前所在元素位置
  console.log(e.target);
  // 目前所在元素位置的節點名稱
  console.log(e.target.nodeName);
},false);

change – 表單內容更動內容時觸發

程式碼範例

HTML

<select id="areaId">
  <option value="--請選擇地區--">--請選擇地區--</option>
  <option value="前鎮區">前鎮區</option>
  <option value="苓雅區">苓雅區</option>
</select>
<ul class="list"></ul>

JavaScript

var area = document.getElementById('areaId');
var list = document.querySelector('.list');
var country = [
  {
    farmer: '查理',
    place: '前鎮區'
  },
  {
    farmer: '卡斯柏',
    place: '苓雅區'
  },
  {
    farmer: '小花',
    place: '苓雅區'
  }
];

var len = country.length;
// 使用 console.log 來看所寫的程式碼是否可以執行
console.log(len);

function updateList(e){
  alert('測試事件監聽');
  var select = e.target.value;
  console.log(select);
  var str = '';
  for(var i=0;i<len;i++){
    console.log(country[i].farmer);
    if(select == country[i].place){
      str += '<li>'+country[i].farmer+'</li>';
    }
  }
  list.innerHTML = str;
}
area.addEventListener('change',updateList,false);

練習

HTML

<select id="areaId">
  <option value="請選擇地區">請選擇地區</option>
  <option value="中部地區">中部地區</option>
  <option value="南部地區">南部地區</option>
</select>
<ul class="list"></ul>

JavaScript

var area = document.getElementById('areaId');
var list = document.querySelector('.list');
var region = [
  {
    owner: '查理',
    place: '南部地區'
  },
  {
    owner: '卡斯柏',
    place: '南部地區'
  },
  {
    owner: '約翰',
    place: '中部地區'
  },
  {
    owner: '艾咪',
    place: '中部地區'
  },
  {
    owner: '傑克',
    place: '南部地區'
  },
  {
    owner: '雪莉',
    place: '南部地區'
  }
];

var len = region.length;
// console.log(len);
function updateList(e){
  // alert('測試監聽');
  var select = e.target.value;
  // console.log(select);
  var str = '';
  for(var i=0;i<len;i++){
    // console.log(region[i].owner);
    if(select == region[i].place){
      str += '<li>'+region[i].owner+'</li>';
    }
  }
  list.innerHTML = str;
}
area.addEventListener('change',updateList,false);

keyCode – 點擊鍵盤,射發火箭!

HTML

<div class="map">
  <img class="rocket rocket-1" src="./images/rocket.png">
  <img class="rocket rocket-2" src="./images/rocket.png">
  <img class="rocket rocket-3" src="./images/rocket.png">
</div>

CSS

/* CSS RESET */
/* CSS STYLES */
/* CSS STYLES */
html{
    height: 100%;
}
body{
    background-image: url('./images/map.png');
    background-repeat: no-repeat;
    background-size: 100% 100%;
    background-position: bottom;
}
.rocket{
    position: absolute;
    bottom: 0;
    transition: all 5s cubic-bezier(1, 0.08, 0, 1.19);
    /* ease、linear、ease-in、ease-out、ease-in-out */
}
.rocket-1{
    left: 30px;
}
.rocket-2{
    left: 330px;
}
.rocket-3{
    left: 630px;
}

chrome – console 可以調整 cubic-bezier 來看怎麼移動。

JavaScript

var body = document.body;

function goRocket(e){
    console.log(e.keyCode);
    switch(e.keyCode){
        case 49:
            document.querySelector('.rocket-1').style.bottom = '2000px';
            break;
        case 50:
            document.querySelector('.rocket-2').style.bottom = '2000px';
            break;
        case 51:
            document.querySelector('.rocket-3').style.bottom = '2000px';
            break;
        
    }
}

body.addEventListener('keydown',goRocket,false);

blur – 離開焦點時進行事件觸發

HTML

<div class="wrap">
  <div class="wrap-inner">
    <h1>六角西餐廳 - 顧客點餐篇</h1>
    <p>服務生:Hello,請問您想要點什麼?</p>
    <p> 顧客:給我<input type="text" id="hamNumId">個漢堡,再<input type="text" id="cokeNumId">杯可樂吧!</p>
    <p>服務生:<input type="button" id="countId" value="計算中">,好的,總計是<em id="totalId" class="tag"></em>元</p>
  </div>
</div>

CSS

/* CSS RESET */
/* CSS STYLES */
html{
  background: #000;
  font-family: 'MicrosoftJhengHeiRegular';
}
*,*:before,*:after{
  box-sizing: border-box;
}
.wrap{
  background: url(./images/desktop.png) 50% 50%;
  max-width: 1049px;
  height: 420px;
  margin: 200px auto;
  padding-top: 50px;
}
.wrap-inner{
  background: rgba(0,0,0,.65);
  margin: 0 auto;
  width: 600px;
  color: #fff;
  padding: 50px;
}
.wrap-inner h1{
  text-align: center;
  font-size: 36px;
  margin-bottom: .5em;
}
.wrap-inner p{
  font-size: 16px;
  line-height: 24px;
}
.wrap-inner .tag{
  color: yellow;
}
.wrap-inner input[type=text]{
  width: 30px;
}

JavaScript

function count(){
  var hamPrice = 50;
  var cokePrice = 20;
  var hamNum = parseInt(document.getElementById('hamNumId').value)*hamPrice;
  var cokeNum = parseInt(document.getElementById('cokeNumId').value)*cokePrice;
  document.getElementById('totalId').textContent = hamNum + cokeNum;
}
function checkContent(e){
  var str = e.target.value;
  if(str ==''){
    alert('此欄位不可為空');
  }
}
var el = document.getElementById('countId');
el.addEventListener('click',count,false);

// focus 所在焦點
// blur 離開焦點

var ham = document.getElementById('hamNumId');
ham.addEventListener('blur',checkContent,false);
var coke = document.getElementById('cokeNumId');
coke.addEventListener('blur',checkContent,false);

mouse – 當滑鼠滑入指定內容時觸發

範例一

HTML

<div class="box"></div>

CSS

/* CSS RESET */
/* CSS STYLES */
.box{
  width: 150px;
  height: 150px;
  background: green;
}

JavaScript

// mousemove - 當滑鼠滑入指定內容時觸發

var el = document.querySelector('.box');

el.addEventListener('mousemove',function(){
  alert('測試監聽事件');
},false);

範例二

HTML

<div class="box box1"></div>
<div class="box box2"></div>
<div class="box box3"></div>
<div class="box box4"></div>
<div class="box box5"></div>
<div class="box box6"></div>

CSS

.box{
  background: green;
  width: 15px;
  height: 15px;
  position: absolute;
}
.box1{
  top: 0px;
  left: 50px;
  animation: fontbulger 2s infinite;
}
.box2{
  top: 0px;
  left: 90px;
  animation: fontbulger 3s infinite;
}
.box3{
  top: 0px;
  left: 140px;
  animation: fontbulger 2.5s infinite;
}
.box4{
  top: 0px;
  left: 180px;
  animation: fontbulger 1.2s infinite;
}
.box5{
  top: 0px;
  left: 230px;
  animation: fontbulger 4s infinite;
}
.box6{
  top: 0px;
  left: 250px;
  animation: fontbulger 4s infinite;

JavaScript

var el = document.querySelectorAll('.box');

var Len = el.length;

for (var i=0;i<Len;i++){
  el[i].addEventListener('mousemove',function(e){
  alert('你輸了!');
  });
}

網頁座標 – 了解 screen、page、client 箇中差異

HTML

<div class="wrap">
  <div class="header">
    <p>
      screenX: <span class="screenX"></span>
      screeny: <span class="screenY"></span>
    </p>
    <p>
      pageX: <span class="pageX"></span>
      pageY: <span class="pageY"></span>
    </p>
    <p>
      clientX: <span class="clientX"></span>
      clientY: <span class="clientY"></span>
    </p>
  </div>
</div>

CSS

/* CSS RESET */
/* CSS STYLES */
html{
    height: 100%;
}
.wrap{
    max-width: 1920px;
    height: 5000px;
    background: url('./images/dark.png') bottom #404747 no-repeat;
}
.header{
    height: 100px;
    position: fixed;
    top: 0;
    width: 100%;
    color: #fff;
    text-align: center;
    background: slateblue;
}
.header p{
    padding: .5em;
}

JavaScript

var screenX = document.querySelector('.screenX');
var screenY = document.querySelector('.screenY');
var pageX = document.querySelector('.pageX');
var pageY = document.querySelector('.pageY');
var clientX = document.querySelector('.clientX');
var clientY = document.querySelector('.clientY');

function getPosition(e){
    screenX.textContent = e.screenX;
    screenY.textContent = e.screenY;
    pageX.textContent = e.pageX;
    pageY.textContent = e.pageY;
    clientX.textContent = e.clientX;
    clientY.textContent = e.clientY;
}

var el = document.body;
el.addEventListener('mousemove',getPosition,false);
  • screen:整個螢幕的解析度大小
  • page:整個網頁內容高度、寬度
  • client:瀏覽器視窗的大小

網頁座標 – 應用篇

HTML

<div class="wrap">
  <div class="header">
    <p>
      screenX: <span class="screenX"></span>
      screeny: <span class="screenY"></span>
    </p>
    <p>
      pageX: <span class="pageX"></span>
      pageY: <span class="pageY"></span>
    </p>
    <p>
      clientX: <span class="clientX"></span>
      clientY: <span class="clientY"></span>
    </p>
  </div>
</div>
<div class="mouseImg">
  <img src="images/pic.png" width="100">
</div>

CSS

/* CSS RESET */
/* CSS STYLES */
html{
  height: 100%;
}
body{
  cursor: none;
}
.wrap{
  max-width: 1920px;
  height: 5000px;
  background: url('./images/dark.png') bottom #404747 no-repeat;
}
.header{
  height: 100px;
  position: fixed;
  top: 0;
  width: 100%;
  color: #fff;
  text-align: center;
  background: slateblue;
}
.header p{
  padding: .5em;
}
.mouseImg{
  position: fiexe;
}

JavaScript

var screenX = document.querySelector('.screenX');
var screenY = document.querySelector('.screenY');
var pageX = document.querySelector('.pageX');
var pageY = document.querySelector('.pageY');
var clientX = document.querySelector('.clientX');
var clientY = document.querySelector('.clientY');

var mouseImg = document.querySelector('.mouseImg');

function getPosition(e){
    screenX.textContent = e.screenX;
    screenY.textContent = e.screenY;
    pageX.textContent = e.pageX;
    pageY.textContent = e.pageY;
    clientX.textContent = e.clientX;
    clientY.textContent = e.clientY;
    mouseImg.style.left = e.clientX + 'px';
    mouseImg.style.top = e.clientY + 'px';
}

var el = document.body;
el.addEventListener('mousemove',getPosition,false);

mouse CSS – 改變滑鼠圖片

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>JavaScript 入門篇 - 學徒的試煉</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <h1>mouse CSS 改變滑鼠圖片</h1>
</body>
</html>

CSS

*{
  cursor: url('../img/pic1.png), auto;
}

事件監聽優化篇 – 從父元素來監聽子元素內容

HTML

<ul class="list">
  <h2>Heading 2 - 標題</h2>
  <li>查理</li>
  <li>卡斯柏</li>
  <a href="#">網頁連結</a>
</ul>

CSS

/* CSS STYLES */
.list{
  padding: 50px;
  border: 10px solid #000;
}
a{
  color: blue;
}

localStorage – 瀏覽器資料儲存

什麼是 localStorage?

瀏覽器裡面的資料庫。

Google Chrome – Console – Application – Local Storage

業界常實作的功能

  • Local Storage
  • Session Storage
  • Cookies

舉例網站:博客來、萌典

Key Value
font-size 14
prev-id “萌”

setItem、getItem 基本操作

儲存資料 – setItem
取出資料 – getItem

JavaScript

var str = 'tom';

localStorage.setItem("myName",str);
console.log(localStorage.getItem('myName');

範例程式碼

HTML

<h2>請輸入你的姓名</h2>
<input type="text" class="textClass">
<input type="button" class="btnClass" value="點擊">
<input type="button" class="btnCall" value="點擊呼叫名字">

JavaScript

var btn = document.querySelector('.btnClass');
var call = document.querySelector('.btnCall');

function saveName(e){
  console.log('測試監聽');
  var str = document.querySelector('.textClass').value;
  console.log(str);
  localStorage.setItem('myName',str);
}

btn.addEventListener('click',saveName,false);
call.addEventListener('click',function(){
  var str = localStorage.getItem('myName');
  alert('你的名字叫做'+str);
},false);

透過 JSON.parse、JSON.stringify 來編譯資料

HTML

JavaScript

// 1.將 array 轉為 string - JSON.stringify()
// 2.將 string 轉為 array - JSON.parse()
// 學以上兩點是因為 Local Storage 只會保存、取出 string 資料

var country = [
  {farmer: '卡斯柏'};
];
var countryString = JSON.stringify(country);
console.log(countryString);
localStorage.setItem('countryItem',countryString);

var getData = localStorage.getItem('countryItem');
var getDataAry = JSON.parse(getData);

console.log(typeof(getData));
console.log(typeof(getDataAry));
console.log(getDataAry[0].farmer);

data-* – 透過 dataset 讀取自訂資料

HTML

<ul class="list">
  <li data-num="0" data-dog="3" class="listli">卡斯柏</li>
</ul>

Google Console

> document.querySelector('.list li').dataset
< DOMStringMap {num: "0", dog: "3"}
> document.querySelector('.list li').dataset.dog
< "3"

JavaScript

var list = document.querySelector('.list li');

// 確認點擊的農夫,以及相關的資訊
function checkList(e){
  console.log('測試監聽');
  var num = e.target.dataset.num;
  var dog = e.target.dataset.dog;
  console.log('農夫編號是'+num);
  console.log('有'+dog+'隻狗');
}

list.addEventListener('click',checkList,false);

dataset、array 運用

HTML

<ul class="list"></ul>

CSS

/* CSS STYLES */
.list{
  padding: 50px;
  background: #000;
  color: #fff;
}

JavaScript

監聽綁定之後,並不代表裡面的其他元素也會跟著做綁定。

一個網頁上有太多監聽的事件,會導致效能變的非常不好。

因此比較好的做法是去指定ul,然後去查詢。

var country = [
  {
    farmer: '卡斯柏'
  },
  {
    farmer: '查理'
  }
];
var list = document.querySelector('.list');

// 更新農場資料
function updateList(){
  var str = '';
  var len = country.length;
  for(var i=0;i<len;i++){
    str+='<li data-num="'+i+'">'+country[i].farmer+'</li>;
  }
  list.innerHTML = str;
}
updateList();

function checkList(e){
  console.log(e.target.nodeName);
  var num = e.target.nodeName;
  if(num !=="LI"){return};
  var str = e.target.dataset.num;
  console.log('您現在選擇的農夫是'+country[str].farmer);
}

list.addEventListener('click',checkList,false);

splice – 刪除 array 資料

Chrome – Console

> var colors = ['black','red'];
< undefined
> colors
< ["black", "red"]
> colors.push('yellow');
< 3
> colors
< ["black", "red", "yellow"]

// splice - 刪除 array 資料
// splice(從第幾筆開始,刪除幾筆)
> colors.splice(0,2);
< ["black", "red"]
> colors
< ["yellow"]

HTML

<ul class="list"></ul>

CSS

/* CSS STYLES */
.list{
  padding: 50px;
  background: #000;
  color: #fff;
}

JavaScript

var country = [
  {
    farmer: '卡斯柏'
  },
  {
    farmer: '查理'
  },
  {
    farmer: '約翰'
  }
];
var list = document.querySelector('.list');

// 更新農場資料
function updateList(){
  var str = '';
  var len = country.length;
  for(var i=0;i<len;i++){
    str+='<li data-num="'+i+'">'+country[i].farmer+'</li>';
    }
    list.innerHTML = str;
}
updateList();

// 確認點擊的農夫是誰
function checkList(e){
  var num = e.target.dataset.num;
  // console.log(e.target.nodeName);
  if(e.target.nodeName !== 'LI'){return};
  country.splice(num,1);
  updateList();
}

list.addEventListener('click',checkList,false);

localStorage 作業介紹

農場備忘(to do list),功能有兩種:

  • 新增備忘
  • 刪除備忘

localStorage 作業講解

HTML

<!DOCTYPE html>
<html lang="en zh-hant">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript - 學徒的試煉</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>

    <div class="wrap clearfix">
        <div class="img">
            <img class="logo" src="./images/logo.svg">
        </div>
        <div class="content">
            <div class="addList">
                <input type="text" class="text" placeholder="請填寫代辦內容" required>
                <input type="button" class="send" value="加入代辦">
            </div>
            <ul class="list"></ul>
        </div>
    </div>

    <script src="js/all.js"></script>
</body>

</html>

CSS

/* CSS RESET */
/* CSS STYLES */
html{
	background-color: #000;
	background-size: cover;
	height: 100%;
	width: 100%;
}
.wrap{
	width: 600px;
	margin: 0 auto;
	background: #fff;
	margin: 100px auto;
	padding: 1em;
	text-align: center;
}
.img{
	float: left;
	width: 200px;
}
.content{
	float: right;
	width: 350px;
	text-align: left;
}
.clearfix{
	overflow: auto;
	zoom: 1;
}
.list{
	margin: 0;
	padding: 50px 100px 100px 0;
	text-align: left;
	list-style: none;
}
.list li{
	border-bottom: 1px solid gray;
	padding: 10px 0;
}
.addList{
	margin-top: 20px;
}
.addList .text{
	padding: 10px;
	border: 2px solid rgba(73, 41, 10);
}
.addList .send{
	padding: 10px;
	cursor: pointer;
	background: #e8a874;
}

JavaScript

// 指定 DOM
var list = document.querySelector('.list');
var sendData = document.querySelector('.send');
var data = JSON.parse(localStorage.getItem('listData')) || [];

// 監聽與更新
sendData.addEventListener('click',addData,false);
list.addEventListener('click',toggleDone,false);
updateList(data);

// 加入列表,並同步更新網頁與 Local Storage
function addData(e){
    e.preventDefault();
    var txt = document.querySelector('.text').value;
    var todo = {
        content: txt
    };
    data.push(todo);
    updateList(data);
    localStorage.setItem('listData',JSON.stringify(data),false);
}

// 更新網頁內容
function updateList(items){
    str = '';
    var len = items.length;
    for(var i=0;i<len;i++){
        str += '<li><a href="#" data-index='+i+'>刪除</a><span> '+ items[i].content + '</span></li>';
    }
    list.innerHTML = str;
}

// 刪除代辦事項
function toggleDone(e){
    e.preventDefault();
    if(e.target.nodeName !== 'A'){return};
    var index = e.target.dataset.index;
    data.splice(index, 1);
    localStorage.setItem('listData',JSON.stringify(data),false);
    updateList(data);
}
網路資料觀念補充:

tagName 和 nodeName 的語意是一樣的,都是返回所包含標籤的名稱,例如上面的h2標籤,都是返回h2,但是tagName只能在元素標籤上使用,而nodeName則可以在所有的節點上使用。

瀏覽器功能探索 (BOM)

瀏覽器功能簡介

BOM (Browser Object Model)

開啟瀏覽器一個網頁的話(ex:Google Chrome、IE、Firefox),會開啟一個window的物件,來操作、讀取瀏覽器資訊。

window 裡面的各種效果:

  • history
  • frames
  • location
  • DOM (document)
  • screen
  • navigator

Chrome – Console

> window
< Window {window: Window, self: Window, document: document, name: "", location: Location, …}
> var str = 3;
< undefined
> str
< 3
> window.str
< 3

// 舉例
> window.screen
< Screen {availWidth: 1280, availHeight: 683, width: 1280, height: 720, colorDepth: 24, …}
> window.screen.width
< 1280

回上頁功能實作

history – 回上頁功能

HTML

// index.html
<h1>第一頁</h1>
<a href="b.html">連到第二頁</a>
<br>
<a href="#" id="next">下一頁(JS版)</a>

<script>
  document.getElementById('next').onclick = function(){
  window.history.forward();
  }
</script>
// b.html
<h1>第二頁</h1>
<input type="button" id="back" value="回到上一頁">

<script>
  document.getElementById('back').onclick = function(){
  window.history.back();
  }
</script>

CSS

body{
  background: #000;
}
h1{
  font-size: 48px;
  color: #fff;
}
a{
  font-size: 36px;
  color: #fff;
}

討論區:把 js 寫在同一頁,如何正常執行?

HTML

// index.html
<h1>第一頁</h1>
<a href="b.html">連到第二頁</a>
<br>
<a href="#" id="next">下一頁(JS版)</a>

<script src="js/all.js"></script>
// b.html
<h1>第二頁</h1>
<input type="button" id="back" value="回到上一頁">

<script src="ja/all.js"></script>

JavaScript

var next = document.getElementById('next');
var back = document.getElementById('back');

// 到index頁面,back為null,到b.html頁面,next為null
console.log(next,back);

if(next){
  next.onclick = function(){
    window.history.forward();
  }
}else{
  back.onclick = function(){
    window.history.back();
}

透過 JS 設計列印功能

列印功能常見應用在票券、QRCODE、訂單資訊、發票…等。

location 提供了很多讀取所在網址的相關資訊,並可以用來跳轉網址。

HTML

<input type="button" id="print" value="列印">
<input type="button" id="locat" value="瀏覽location資訊">
<input type="button" id="open" value="移動到google首頁">

<script src="js/all.js"></script>

JavaScript

// 列印功能
document.getElementById('print').onclick = function(){
  window.print();
}
// 瀏覽location資訊
document.getElementById('locat').onclick = function(){
  console.log(location);
  // 轉網址
  location.href = 'https://www.google.com.tw';
}
// 開啟網頁
document.getElementById('open').onclick = function(){
  window.open('https://www.google.com.tw');
}

動態擷取瀏覽器高度 – innerHeight

HTML

<div class="hero"></div>
<div class="section2">
  section2
</div>
<script src="js/all.js"></script>

CSS

.hero{
  height: 400px;
  background-image: url('./images/hero.jpg');
  background-size: cover;
  background-position: top center;
}
.section2{
  background: lightgreen;
  text-align: center;
  color: #fff;
  font-size: 80px;
  padding: 100px;

JavaScript

document.querySelector('.hero').style.height = window.innerHeight+"px";

window.onresize = function(){
  document.querySelector('.hero').style.height = window.innerHeight+"px";

JS 開發邏輯思維

JS 開發邏輯思維

共筆文件

JS 新手都能聽懂的開發邏輯思維養成
JS 初學者起手式:資料(model) > 事件(event) > 介面(View)

三個步驟來規劃 JS 網頁應用

  1. model:先處理好資料的新增、刪除、修改
  2. event:使用者行為觸發程式
資料
  1. 陣列物件規畫你的資料
  2. JS 記憶體儲存 (變數)
  3. LocalStorage
事件(event)

使用者行為觸發事件,一般都用 function 函式來規劃:

  1. 更新 model
  2. 更新 view

常見使用者行為

  1. 網頁預設載入 (init)
  2. 使用者行為
    • 滑鼠滑入
    • 點擊
畫面更新
  1. innerHTML
  2. appendChild
傳統 JS 寫法
Vue MVVM (資料>介面>介面>資料)
VuE MVVM
題目分享

JS 範例

99乘法表

資料:[‘2′,’3′,’4′,’5′,’6′,’7′,’8′,’9’]
觸發:init
畫面更新:innerHTML

時鐘

計算機

時區

AQI

60 秒倒數

BLOG
  • 針對此次分享寫 BLOG 分享
  • 何謂 MVC

講座 – JS 開發邏輯思維養成

// 講座筆記
1. 資料 (Model)
2. 事件 (Event)
3. 介面 (View)

// 首先需要先定義資料出來

// 資料太多

// 10筆資料
//  3筆資料

// 資料的新增、刪除、修改

// 事件

// click

// init() 抽象

// 介面
// 1. innerHTML
// 2. createElement
// 寫入 DOM 元素到網頁上

定義以下程式碼分別是以下哪一種?

  1. 資料 (Model)
  2. 事件 (Event)
  3. 介面 (View)

JavaScript

// 指定 dom
var list = document.querySelector('.list');
var sendData = document.querySelector('.send');
var data = JSON.parse(localStorage.getItem('listData')) || []; // → 1

// 監聽與更新
sendData.addEventListener('click', addData); // → 2
list.addEventListener('click', toggleDone);
updateList(data);

//加入列表,並同步更新網頁與 localstorage
function addData(e) {
  e.preventDefault();
  var txt = document.querySelector('.text').value;
  var todo = {
    content: txt
  };
  data.push(todo); // → 1
  updateList(data); // → 3
  localStorage.setItem('listData', JSON.stringify(data)); // → 1
}
// 更新網頁內容
function updateList(items) {
  str = '';
  var len = items.length;
  for (var i = 0; len > i; i++) {
    str += '<li><a href="#" data-index=' + i + ' />刪除</a> <span>' + items[i].content + '</span></li>';
  }
  list.innerHTML = str; // → 3
}
// 刪除代辦事項
function toggleDone(e) {
  e.preventDefault();
  if(e.target.nodeName !== 'A'){return};
  var index = e.target.dataset.index; // → 1
  data.splice(index, 1); // → 1
  localStorage.setItem('listData', JSON.stringify(data)); // → 1
  updateList(data); // → 3
}
Vue JS 範例

HTML

<!DOCTYPE html>
<html lang="en zh-hant">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript - 學徒的試煉</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>

    <div class="app">
        <input type="text" placeholder="請輸入代辦事項" @keyup.enter="addTodo(newTodo)" v-model="newTodo">
        <!-- @keyup.enter → 1 -->
        <h2>事項列表</h2>
        <ul>
            <li v-for="todo in todos">
                {{todo.content}}
                - <a href="#" @click.prevent="removeTodo(todo)">刪除</a>
            </li>
        </ul>
        <!-- v-for → 3 -->
        <!-- todos → 1 -->
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
    <script src="js/all.js"></script>
</body>

</html>

JavaScript

var app = new Vue({
  el: '.app',
  data:{
    todos:[], → 1
    newTodo:'' → 1
  },
  methods:{
    addTodo: function(todo){
      this.todos.push({content:todo,completed: false})
    },
    removeTodo: function(todo){
      this.todos.splice(this.todos.indexOf(todo), 1);
    }
  }
})

程式碼範例檢視是哪種定義。

Ex:99乘法表、時鐘、計算機、時區

// 不會寫的地方
1. 資料 (Model) - 抓時間資料、刪除第六筆資料
2. 事件 (Event)
3. 介面 (View) - 有20筆資料、跑for迴圈不會、某個CSS效果寫不出來、不會算角度

最終作業與總結

最終作業寄送變更

最終作業介紹

作業標示文件

圖片檔案下載

BMI 公式

高雄旅遊景點 API 說明

高雄旅遊景點 API

GitHub

JS 百題斬

測驗

問答區精彩討論

AJAX

什麼是 AJAX?

AJAX 是「Asynchronous JavaScript and XML」(非同步的 JavaScript 與 XML 技術)的縮寫,簡單說就是網頁不用重新整理,就能即時地透過瀏覽器去跟伺服器溝通,撈出資料。

Chrome 開發人員工具 – Network 講解,EX:Google

以奇摩信箱註冊網頁為範例講解 AJAX 運用技巧。

以 PCHOME 購買 MAC 為範例,如加入購物車,與後端確認產品剩餘數量。

以 GOOGLE 搜尋引擎來輸入查詢名稱,會下拉顯示其他延伸名稱。

透過 XMLHttpsRequest 物件跨瀏覽器撈資料

練習用的 JSON 連結

JavaScript

var xhr = new XMLHttpRequest();

// readyState
// 0 - 你已經產生一個XMLHttpRequest,但是還沒有連結你要撈的資料
// 1 - 你用了open(),但你還沒有把資料傳送過去
// 2 - 偵測到你有用 send
// 3 - loading (載入中)
// 4 - 你撈到資料了,數據已經完全接受到了

// open()的三個參數分別是,格式、要讀取的網址、同步與非同步
// 格式:get(讀取資料)、post(傳送資料到伺服器)
xhr.open('get','https://hexschool.github.io/ajaxHomework/data.json',true);
// null - 空的資料
xhr.send(null);

AJAX 非同步觀念 (上)

非同步與同步的觀念

JavaScript

var xhr = new XMLHttpRequest();

xhr.open('get','https://hexschool.github.io/ajaxHomework/data.json',true);

// true - 非同步,不等資料傳回來,就讓程式繼續往下跑,等到回傳才會自動回傳。
// false - 同步,會等資料傳回來,才讓程式碼繼續往下跑。

xhr.send(null);

console.log(xhr.responseText);

大部分會使用非同步,因為要撈取的資料龐大,所以大部分的時候我們都會使用true來去做設計。

AJAX 非同步觀念 (下)

網路資料:onload 事件用來設計當網頁載入完成後,觸發特定的 JavaScript 函式去執行特定的工作。

HTML

<div class=”message”></div>

JavaScript

var xhr = new XMLHttpRequest();

xhr.open('get','https://hexschool.github.io/ajaxHomework/data.json',true);
xhr.send(null);

// onload - 當確認跑完以後再去執行這個事件,會自動觸發這個事件的內容。
xhr.onload = function(){
  console.log(xhr.responseText);
  var str = JSON.parse(xhr.responseText);
  document.querySelector('.message').textContent = str[0].name;
}

// 1. 建立了一個 XMLHttpRequest
// 2. 傳送到對方伺服器要資料
// 3. 回傳資料到自己的瀏覽器
// 4. 拿到資料後再看要怎麼處理

HTTP狀態碼

Chrome – Network 中的 Status,以 Google 為講解

// 200 資料有正確回傳,有撈到
// 404 資料讀取錯誤,沒有撈到

var xhr = new XMLHttpRequest();

xhr.open('get','https://hexschool.github.io/ajaxHomework/data.json',true);
xhr.send(null);

xhr.onload = function(){
  console.log(xhr.responseText);
  if(xhr.status == 200){
    var str = JSON.parse(xhr.responseText);
    document.querySelector('.message').textContent = str[0].name;
  } else {
    console.log('資料錯誤!');
  }
}

什麼是 Cross-Origin Resource Sharing (CORS) ?

網路資料:
跨來源資源共用(Cross-Origin Resource Sharing (CORS))是一種使用額外 HTTP 標頭令目前瀏覽網站的使用者代理取得存取其他來源(網域)伺服器特定資源權限的機制。

CORS 偵測服務

練習用 JSON

練習用網站 (無提供CORS)

// CORS - 是否可以跨網域撈取資料
XHR status: 200 - 可以
XHR status: 0 - 不行

傳統表單輸入介紹

HTML

<form action="index.html">
  帳號:
  <input type="text" name="account">
  <br>
  密碼:
  <input type="password" name="password">
  <br>
  <input type="submit" value="送出">
</form>

表單送出後,這個網址上面的內容
後面接參數,?,連接多個內容時,會用&

AJAX POST 寫法 (提供 API 練習)

六角 POST API 連結

六角學院 AJAX 練習
注意,此範例僅供練習,並不會儲存用戶資料至資料庫(僅緩存)。

註冊
新增一個帳號。

Method: POST
URL: https://hexschool-tutorial.herokuapp.com/api/signup
Data:
{
  email: 'lovef2e@hexschool.com',
  password: '12345678'
}
Success Response:
{
  "success": true,
  "result": {},
  "message": "帳號註冊成功"
}
Error Response:
{
  "success": false,
  "result": {},
  "message": "此帳號已被使用"
}
登入
登入一個已存在的帳號。

Method: POST
URL: https://hexschool-tutorial.herokuapp.com/api/signin
Data:
{
  email: 'lovef2e@hexschool.com',
  password: '12345678'
}
Success Response:
{
  "success": true,
  "result": {},
  "message": "登入成功"
}
Error Response:
{
  "success": false,
  "result": {},
  "message": "此帳號不存在或帳號密碼錯誤"
}

這邊用 Console 練習

> var xhr = new XMLHttpRequest();
< undefined
> xhr
< XMLHttpRequest {onreadystatechange: null, readyState: 0, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
> xhr.open('post','https://hexschool-tutorial.herokuapp.com/api/signup',true);
< undefined
> xhr
< XMLHttpRequest {onreadystatechange: null, readyState: 1, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
> xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
< undefined
> xhr.send('email=learning123@gmail.com&password=123456');
< undefined
> xhr
< XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}

JavaScript

var xhr = new XMLHttpRequest();
xhr.open('post','https://hexschool-tutorial.herokuapp.com/api/signup',true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send('email=learning123@gmail.com&password=123456');

從 chrome 開發人員工具檢視 AJAX post

用圖片去做講解 get 跟 post 的差異。

get
瀏覽器 → 發出 XMLHttpRequest 請求 → 伺服器
伺服器 → 回傳資料 → 瀏覽器
post
格式是 content-type: application/x-www-form-urlencoded
瀏覽器 → 發出 XMLHttpRequest 請求 → 伺服器
'email=xx@gmail.com&password=1234'
伺服器 → 回傳資料 → 瀏覽器
{
  "success: true",
  "result: {},
  "message: "帳號註冊成功"
}
// 格式是 content-type: application/json
瀏覽器 → 發出 XMLHttpRequest 請求 → 伺服器
{
  "email": "xx@gmail.com",
  "password": "1234"
}
伺服器 → 回傳資料 → 瀏覽器
{
  "success: true",
  "result: {},
  "message: "帳號註冊成功"
}

用 Chrome – Network 可以看相關資訊。

AJAX JSON 傳遞

需轉成字串的內容。

HTML

<form action="index.html">
    帳號:
    <input type="text" name="account">
    <br>
    密碼:
    <input type="password" name="password">
    <br>
    <input type="submit" value="送出">
</form>

Google Console

var account = {
  email: 'xx@gmail.com',
  password: '1234'
}
var xhr = new XMLHttpRequest();
xhr.open('post','https://hexschool-tutorial.herokuapp.com/api/signup',true);
xhr.setRequestHeader('Content-type','application/json');
var data = JSON.stringify(account);
xhr.send();

AJAX 實務範例設計

HTML

帳號:
<input  type="text' class="account'>
<br>
密碼:
<input type="password" class="password">
<br>
<input type="button" class="send" value="送出">

JavaScript


var send = document.querySelector('.send');

send.addEventListener('click',signup,false);


function signup(){
    // alert('測試');
    var emailStr = document.querySelector('.account').value;
    var passwordStr = document.querySelector('.password').value;
    var account = {};
    account.email = emailStr;
    account.password = passwordStr;
    // console.log(account);

    var xhr = new XMLHttpRequest();
    xhr.open('post','https://hexschool-tutorial.herokuapp.com/api/signup',true);
    xhr.setRequestHeader('Content-type','application/json');
    var data = JSON.stringify(account);
    xhr.send(data);
    xhr.onload = function(){
        // console.log(xhr);
        var callbackData = JSON.parse(xhr.responseText);
        console.log(callbackData);
        var veriStr = callbackData.message;
        if(veriStr == "帳號註冊成功"){
            alert('帳號註冊成功!!');
        } else {
            alert('帳號註冊失敗!');
        }
    }
}

AJAX 作業設計

範例是註冊,作業設計練習登入。

資源補充

AJAX 章節練習完畢之後,若您還想額外多練習一些 API 串接的練習,可以參考 Ray 助教整理的 APIList 。

Google Map API

Google Map API 提醒

由於 Google Maps 更新開發條件,在初始設定上改用了付費制,不論是否達到Google地圖收費的標準,都得申請API key,並且綁定信用卡卡號。

由於申請 API 變得較為繁瑣,所以建議這章節先請學員跳過,往後面 ES6 章節投入。

什麼是 API ?

如何評估 API 的可用性

Google Map API 初始化與金鑰設定

Google Map API 原理介紹

增加標記

新增多個標記

標記 + 第三方 JSON 資料設計

繪製客製化 Google Map 樣式

客製化 Google Map 標記 icon

Google Map API 常見應用

Leaflet + OpenStreetMap 地圖應用

章節簡介

本章節為 2020 年發生新冠肺炎(武漢肺炎)時,台灣開發者們提供口罩地圖,以方便民眾購買口罩的教學應用。同學們可以藉由本章節的資源,來設計成口罩地圖介面,並提交最終作業給我們來檢視。

AJAX 與函式應用教學

Leaflet + OpenStreetMap 教學

學員範例作品

ECMAScript 6 入門 – let、const

ES 6 介紹

ES 6 – 提升 JS 程式碼品質最佳利器。

JavaScript compiler:Babel

window、var 特性

JavaScript

// 盡量避免汙染全域變數
// let、const
var a = 1;
console.log(a);
for(var i=0;i<3;i++){
  console.log(i);
}

Google Console

1
> window
< Window {window: Window, self: Window, document: document, name: "", location: Location, …}
a: 1
> window.a
< 1
> window
< Window {window: Window, self: Window, document: document, name: "", location: Location, …}
a: 1
history: History {length: 1, scrollRestoration: "auto", state: null}
i: 3

let – if、function 用法

範例一

JavaScript

// let 與 const 用來宣告區塊裡的變數
// 區塊 = {  }
if (3 > 2){
  let a = 1;
}

Google Console

> a
VM56:1 Uncaught ReferenceError: a is not defined
    at <anonymous>:1:1
> window
< Window {window: Window, self: Window, document: document, name: "", location: Location, …}

範例二

JavaScript

// let 與 const 用來宣告區塊裡的變數
// 區塊 = {  }
var a = 0;

// 函數式
function changeA(){
  let a = 0;
  console.log(a);
}
changeA();
console.log(a);

Google Console

1
0

let – for 用法

範例一

JavaScript

for(let i=0;i<3;i++){
  console.log(i);
}

Google Console

0
1
2
> i
VM176:1 Uncaught ReferenceError: i is not defined
    at <anonymous>:1:1

範例二

HTML

<ul class="list">
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ul>

JavaScript

const listLen = document.querySelectorAll('.list li').length;
for(let i=0;i<listLen;i++){
  document.querySelectorAll('.list li')[i].addEventListener('click',function(){
  alert(i+1);
  },false)
}

Google Console

// 使用 var 會影響到全域變數
> i
< 3
// 使用 let 會在區塊裡去做重新綁定的動作
> i
  VM246:1 Uncaught ReferenceError: i is not defined
    at <anonymous>:1:1

const 特性

JavaScript

// const 唯讀變數 - 不能去做修改
// 變數是不能被更改 - url網址
// {}、[] 是有辦法變更裡面的值
const obj = {
  url: 'https://www.google.com.tw';
};
obj.url = 'https://www.yahoo.com.tw';
console.log(obj.url);
const obj = {
    url: 'https://www.google.com.tw'
};
// 凍結裡面任何的內容
Object.freeze(obj);
obj.url = 'https://www.yahoo.com.tw';
console.log(obj.url);

let、const 注意事項與使用時機

範例一

JavaScript

// var 有向上提升的特性
// let、const
// 不可犯的錯誤,特性介紹
console.log(a);
let a = 3;
console.log(a);

Google Console

Uncaught ReferenceError: Cannot access 'a' before initialization
    at all.js:3

範例二

JavaScript

// 第二點,同個區塊上不能重複命名
// {}
let a = 1;
let a = 2;

// 不會變成全域變數、不會在window上面

Google Console

Uncaught SyntaxError: Identifier 'a' has already been declared

ECMAScript 6 入門 – 字串篇

Template literals – 輕鬆進行字串相加

HTML

<ul class="list">

</ul>

JavaScript

const list = document.querySelector('.list');
const imgUrl = 'images/logo.png';
const title = '六角學院';
// list.innerHTML = '<li><img src='+imgUrl+'></li>'

// 重音符:`
list.innerHTML = `<li><h2>${title}</h2><img src="${imgUrl}"></li>`;

編輯器與格式支援小技巧

Windows系統上的設定是:檔案→偏好→設定,點選 Open Settings (JSON)

  "emmet.includeLanguages": {
    "javascript": "html"
},
"emmet.triggerExpansionOnTab": true

Mac系統

"emmet.syntaxProfiles": {
  "javascript": "html"
}

JavaScript

const list = document.querySelector('.list');
const imgUrl = 'images/logo.png';
const title = '六角學院';

// emmet
list.innerHTML = `
  <li>
    <h2>${title}</h2>
    <img src="${imgUrl}" alt="">
  </li>
`

Vue.js 2.0 – 8小時線上影音課程

投入 Vue.js 前,你必須要會的基礎知識

想學 Vue.js,必須要先學會

  • HTML、CSS
  • 需要有基礎 JS 技能,此測驗達 85 分以上便有到門檻

開始進入 Vue.js 線上課程

官網教學

Vue.js 幼幼班起手式(上)

todolist 作業

Vue.js 幼幼班起手式(下)

從 Vue.js 初探 Web Component 的世界

vue-cli

Firebase

Vuex

作業1:颱風防災網