兩行以上的text-overflow加「…」

text-overflow 的一般用法

一般來說 text-overflow 用在文字只放了一行的情況下,搭配 white-space: nowrap 做使用

.box 本行保留核貸與否、詮釋、裁決及終止本活動辦法之權利。本行保留核貸與否、詮釋、裁決及終止本活動辦法之權利。本行保留核貸與否、詮釋、裁決及終止本活動辦法之權利。本行保留核貸與否、詮釋、裁決及終止本活動辦法之權利。本行保留核貸與否、詮釋、裁決及終止本活動辦法之權利。本行保留核貸與否、詮釋、裁決及終止本活動辦法之權利。
.box
 width: 300px
 border: 1px solid #000
 text-overflow: ellipsis
 overflow: hidden
 white-space: nowrap

如此作法,雖然能夠做出超過寬度的文字加「…」效果,但也只能適用於一行的範圍

兩行以上的作法

.box
 width: 300px
 border: 1px solid #000
 display: -webkit-box
 text-overflow: ellipsis
 overflow: hidden
 -webkit-line-clamp: 2
 -webkit-box-orient: vertical

更改 webkit-line-clamp 的數值,自由調整要顯示的行數

display: -webkit-box 的各家瀏覽器相容度

ChromeFireFoxSafariIEAndroidiOS
✔︎✔︎✔︎×✔︎✔︎

CSS原生模組化工具 @namespace

結論

在HTML架構上@namespace只能拆出htmlsvg兩種模組(以檔案類別拆),雞肋到等於沒有用。本文探討@namespace的設計初衷並解釋為何他在HTML架構上會如此沒用

CSS模組化

h1 我是首頁標題
p 我是首頁文字

模組化設計的考量重點為確保程式碼的「獨特性」,比如說在用首頁的CSS,因為首頁很多UI元件只會出現在首頁而已,其他頁面不需要用到,也怕其他頁面會不小心混到,所以市面上常見的做法是給class特殊前綴,就會變成

h1.homepage-heading 我是首頁標題
p.homepage-text 我是首頁文字

諸如上圖,將首頁的所有特殊樣式class都冠上.homepage-確保其他頁面在用CSS時不會沾到首頁的東西

理想中的namespace

一個完整的<html>需要包含xmlns宣告,因此會長成這樣
(HTML5表示:xmlns不寫也沒關係)

<html lang="zh-tw" xmlns="http://www.w3.org/1999/xhtml">

然後,在xmlns宣告中定義namespace,取名為homepage

<html lang="zh-tw" xmlns:homepage="http://www.w3.org/1999/xhtml">

接下來在CSS使用@namepsace宣告

@namespace homepage url(http://www.w3.org/1999/xhtml);
homepage|body {
    background: pink !important;
}

寫到這裡,我們預期他在首頁時由於吃到homepage的命名空間所以套用粉紅色背景,但在其他頁面時保持白色背景

實際上的namespace

很遺憾的是,由於HTML不提供xmlns的命名空間(可以設定,但等於沒效)
所以homepage有寫等於沒寫,所有頁面的背景也都會套成粉紅色了

目前namespace可以應用的範圍僅侷限在htmlsvg的區分而已,但svg會寫成共用class的人也很少,所以幾乎沒法派上用場

Quote Tag的多國語適應解法

<q> 是 CSS 2.1 標準的古早標籤,本意是用來提示引言(與多語系客製化),同時也能活用他客制接頭詞、接尾詞的特性,解決多國語常見的空格問題

多國語的空格問題

這是常見的紅字強調排版,通常會這樣處理

<p>
  我是一段字,而且想要<span class="txt-red">強調</span>某些內容
</p>
.txt-red
 color: red

這樣做在方塊字體系中沒什麼問題(中文、日文、韓文等),但在以空格區別單字的字母體系中(如英文、德文)就會發生以下事故

看官可以看到紅色的字跟前後文連在一起的事故發生了(汗)

神奇的<q>標籤

讓我們用神奇<q>改寫一次這個範例

<p>
  我是一段字,而且想要<q class="txt-red">強調</q>某些內容
</p>

<q>在沒定義quote時會給出蝌蚪上下引號框住內容,但這題不需要蝌蚪引號所以我們給他拿掉

q
 quotes: '' ''

然後,在英語的環境下則需要用上下各一個半形空白框住紅色字
為了區別語系差異所以加上lang選取器

<p lang="zh-TW">
  我是一段字,而且想要<q class="txt-red">強調</q>某些內容
</p>
<p lang="en-US">
 I am a paragraph and want to<q class="txt-red">emphasize</q>something
</p>
.txt-red
 color: red
 
q
 &:lang(zh-TW)
  quotes: '' ''
 &:lang(en-US)
  quotes: ' ' ' '

實務上多語系的切換往往是一頁一頁換,所以lang通常都會掛在最上層的<html>然後讓他一層一層繼承下去(CSS這樣一樣可以選到)

<html lang="zh-TW">

手機modal背景防滑

手機的modal背景防滑一直是個千古難題,在PC裝置適用的overflow: hidden在手機上卻不管用。

一般來說主流的作法有幾個

  • 禁止touch事件(缺點:modal如果自帶拉霸也會變得不能滑)
  • modal外層那塊灰的用position: fixed處理(缺點:當同時遇到<input>小鍵盤時會衍生手機端的fixed靈肉分離問題)
  • 紀錄好現在的scrollTop參數,只要body一滑,就套上那個參數(原地滑動0的概念)(缺點:某些機型的手機可以從下方可以往上滑呼叫出小功能面板,那一塊戳久了還是可以拖動背景)
  • 手指一碰到背景灰的就關閉modal(缺點:modal本體戳久了還是可以穿透碰到背景)

上述4個做法都會自帶其他bug,沒一個能夠真正解決到問題。但其實此問題可以透過巧妙的html排法+CSS解決

HTML排法

.content-area
 ul
  li 內容內容
  li 內容內容(以下放大概50個li,讓這頁長出拉霸)

然後,在<head>裡面塞入一個<meta>

<meta name="viewport" content="width=device-width">

CSS內容防滑實作

html
 margin: 0
 height: 100%
 
body
 margin: 0
 height: 100%
 
.content-area
 height: 100%
 overflow: hidden
 -webkit-overflow-scrolling: auto

htmlbodymargin: 0是為了解除原生賦予的外距(他會造成一點點的空間可以滑)。

精髓是從htmlbody,再到.content-area的父子三層都套上height: 100%
這樣設定後原本在手機端失效的overflow: hidden就變有效了(雖然還要搭配-webkit-overflow-scrolling: auto使用)

經過上述設定後,就成功防止內容被滑動了
但是,這樣的設定如果手機滑到一半才在中途加overflow: hidden那些
頁面會被強制跳到開頭,沒辦法固定在先前滑到一半的地方

固定在先前滑動到的地方

.content-area下面在新增.content-wrapper
並且把overflow-hidden那些掛在.content-wrapper

.content-area
 .content-wrapper
  ul
   li 內容內容
   li 內容內容(以下放大概50個li,讓這頁長出拉霸)

然後,讓原先長出拉霸的<body>取消拉霸(掛上overflow: hidden
將拉霸設定到.content-wrapper上面去

html
 margin: 0
 height: 100%
 
body
 margin: 0
 height: 100%
 overflow: hidden
 
.content-area
 height: 100%
 // overflow: hidden
 // -webkit-overflow-scrolling: auto

.content-wrapper
 height: 100%
 overflow: scroll
 
.no-scroll .content-wrapper
 overflow: hidden
 -webkit-overflow-scrolling: auto

Framework7 Core

Framework7是手機特化型的一套框架,他排除了一些在開發手機時常踩到的雷,比如popup開啟時背景防止滑動、輸入框點選時小鍵盤會蓋到輸入框自己、fixed元素過多時在輸入框操作會有視差位移的大bug

如何使用

Framework7 Core是以Vanilla JS為環境的套件,所以不需要使用React / Vue,本介紹連Webpack也不包,只描述簡單引入的方法

.
├── index.html (首頁)
├── pages
│   ├── news.html (最新消息)
│   └── about.html (關於我們)
├── app.js (Framework7設定檔)
├── router.js (路徑設定檔)
└── style.css (自訂的CSS)

範例網頁的架構有三頁

首頁 (index.html)
  ├── 最新消息 (news.html)
  └── 關於我們 (about.html)

Framework7最難的地方就是設換頁路徑(因為他是SPA)
這邊先留意起來

換頁設定

參考官網教學,建立index.html

<!DOCTYPE html>
<html>
  <head>
    <!-- Required meta tags-->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <!-- Color theme for statusbar (Android only) -->
    <meta name="theme-color" content="#2196f3">
    <!-- Your app title -->
    <title>My App</title>
    <!-- Path to Framework7 Library Bundle CSS -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/framework7/5.7.5/css/framework7.bundle.css">
    <!-- Path to your custom app styles-->
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <!-- App root element -->
    <div id="app">

      <!-- Your main view, should have "view-main" class -->
      <div class="view view-main">
        <!-- Initial Page, "data-name" contains page name -->
        <div data-name="home" class="page">

          <!-- Top Navbar -->
          <div class="navbar">
            <div class="navbar-bg"></div>
            <div class="navbar-inner">
              <div class="title">我是首頁</div>
            </div>
          </div>

          <!-- Bottom Toolbar -->
          <div class="toolbar toolbar-bottom">
            <div class="toolbar-inner">
              <!-- Toolbar links -->
              <a href="/news/" class="link">最新消息</a>
              <a href="/about/" class="link">關於我們</a>
            </div>
          </div>

          <!-- Scrollable page content -->
          <div class="page-content">
            <p>你好我是首頁</p>
          </div>
        </div>
      </div>
    </div>
    <!-- Path to Framework7 Library Bundle JS-->
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/framework7/5.7.5/js/framework7.bundle.js"></script>
    <script type="text/javascript" src="router.js"></script>
    <!-- Path to your app js-->
    <script type="text/javascript" src="app.js"></script>
  </body>
</html>

在Framework7裡面,換頁的路徑都要設定在app.js(或在本範例中額外拆出來放在router.js

app.js

var app = new Framework7({
    // App root element
    root: '#app',
    // App Name
    name: 'My App',
    // App id
    id: 'com.myapp.test',
    // Enable swipe panel
    theme: 'ios',
    // Add default routes
    routes: routes,
});

var mainView = app.views.create('.view-main');

theme可以填入iosmdaurora三種參數,建議填入不然他樣式在手機/電腦會長不一樣

router.js

var routes=[
    {
        //最新消息
        path: '/news/',
        url: 'pages/news.html',
        options: {
            transition: 'f7-parallax',
        },
    },
    {
        //關於我們
        path: '/about/',
        url: 'pages/about.html',
        options: {
            transition: 'f7-parallax',
        },
    },
]

換頁的動態寫在options裡面的transition,可提供的參數可以參考官網範例的Page Transitions這頁

最新消息 news.html

除了index.html以外的頁面html,只要放<div class="page">的內容就好

<div data-name="news" class="page">

    <!-- Top Navbar -->
    <div class="navbar">
        <div class="navbar-bg"></div>
        <div class="navbar-inner">
            <div class="title">最新消息</div>
        </div>
    </div>

    <!-- Scrollable page content -->
    <div class="page-content">
        <p>Coming Soon...</p>
    </div>
</div>

關於我們 about.html

<div data-name="about" class="page">

    <!-- Top Navbar -->
    <div class="navbar">
        <div class="navbar-bg"></div>
        <div class="navbar-inner">
            <div class="title">關於我們</div>
        </div>
    </div>

    <!-- Scrollable page content -->
    <div class="page-content">
        <p>本公司創立於西元100年</p>
    </div>
</div>

換頁demo

php除錯模式display_errors

透過啟用display_errors,php會把錯誤噴在網頁上,在開發模式下可以更快速的找出問題

檢視目前的display_errors狀態

開一個php檔案,並寫下

echo phpinfo();

在網頁中尋找display_errors這一項,狀態為On表示已開啟噴錯模式,狀態為Off代表關閉噴錯模式

修改php.ini設定檔

開啟以下檔案(作業系統:Mac)

/private/etc/php.ini

找出display_errors =這行,並且依照狀況在等號後面填入On / Off

修改後存檔,重啟Apache

Mac安裝php

開啟Apache

Mac內建php與Apache,只需要透過一些設定就能建置php開發環境
本指南適用於php版本5.6.30

sudo apachectl start

輸入完指令後,打開瀏覽器http://localhost,如果看到「It works!」即代表成功開啟了Apache

開啟httpd.conf檢視權限

Mac的php文件都放置在/Library/WebServer/Documents/之下
首先進去該路徑,並且在~/Documents/底下新增一個資料夾test/
接者在底下新增一個檔案index.php,隨意echo一些內容

回到瀏覽器,輸入http://localhost/test,網頁沒有如預期的出現「hey」的內容,而是出現了「Forbidden」的畫面

接者用文字編輯器(Sublime),開啟/etc/apache2/httpd.conf這個檔案
搜尋以下字串

#LoadModule php5_module libexec/apache2/libphp5.so

將最前方的#移除,使其成為

LoadModule php5_module libexec/apache2/libphp5.so

回到http://localhost/test,網頁能正常顯示了
※備註:php 7的話就是找這段LoadModule php7_module libexec/apache2/libphp7.so

MySQL與phpMyAdmin

Mac沒有附帶MySQL與phpMyAdmin,所以兩者需要去官網額外下載安裝

phpMyAdmin連線錯誤的解法

Mac作業系統沒辦法用localhost當主機名,必須改成用127.0.0.1當主機名
由於phpMyAdmin的config檔案裡預設是寫成連到localhost
所以必須手動進去config檔案,修改成127.0.0.1

config檔案

用文字編輯器(Sublime, VSCode)開啟以下檔案

/Library/WebServer/Documents/phpMyAdmin/libraries/config.default.php

找到檔案中的這一行

$cfg['Servers'][$i]['host'] = 'localhost';

並且改成

$cfg['Servers'][$i]['host'] = '127.0.0.1';

固網D-Link開External IP的方法

條件限制

  • 只能透過固網設定,行動網路因為會透過一層路由,所以沒法直接對外開放
  • 只能開localhost:80的內容,沒法開像是localhost:8080localhost:8000這樣複雜的port
    所以如果網站的port不是80的話,要先改成80

外部IP的功能

外部IP可以把自己這台電腦當作主機發佈給網際網路
所以網際網路上的任何人都能讀取自己電腦的localhost內容

步驟⑴ 設定固定IP

當電腦存取網路時,網路機器(有線網路 or WiFi)會給予該電腦一個IP
如果有另一台電腦也連上同一個網路,網路機器會在給那台電腦另一個IP

在未特別設定的情況下,IP會隨著每次接到網路時,而有不同的值
這時可以透過固定IP設定,強制佔用某個IP,讓該電腦每次連網時都使用同一個IP

查看目前的IP

打開系統偏好設定>網路,查看目前的浮動IP

記下來目前的IP是192.168.1.109
接著,打開D-Link的設定面板,網址列輸入192.168.1.1

【小提示】DSL-6740C的預設帳號密碼為
帳號:cht
密碼:chtvdsl

點選DCHP Server
進去後,可以看到EXISTING DCHP CLIENT列著一大排裝置
(下圖有經過修改所以只能看到一個裝置)
使用快速鍵Ctrl+F搜尋192.168.1.109(剛剛記起來的IP)
找到我們現在連的這台裝置

然後把IP Address、MAC Address分別填入下方的ADD STATIC IP ADDRESS裡面
填好後按Apply

這樣就完成了固定IP設定了,以後192.168.1.109這組IP就永遠給該電腦用了

步驟⑶ 開啟Virtual Server

上方選單先選ADVANCED,再從側選單選Virtual Server

依照上圖設定輸入

Enable Virtual Server Rules打勾
Name隨意取名
InterfaceWAN1_2
Internal startport80
Internal endport80
External startport80
External endport80
Protocol TypeBoth

大功告成

經過以上設定後,就打開了External Server
來試試看用External Server開專案的方法吧

⑴ 開localhost,設定port80

如果是python的話,要使用以下指令開啟localhost

python -m SimpleHTTPServer 80

如果是webpack的話,要去package.json,在webpack-dev-server後面加入port的描述,改好後重啟他

"dev-server": "webpack-dev-server --port 80"

如果是php的話,因為預設就是port: 80了,所以什麼都不用設定

⑵ 查看電腦的對外IP

開啟IP位置查詢網站,會看到一組數字為36.225.60.77
(每台電腦,每個時間進去看到的IP都不同)

然後用另一台裝置,連不同網路,網址列輸入36.225.60.77:80
可以神奇地看到原本應該是localhost的東西變成可以對外了

Gulp自動編譯增加CSS前綴

目的

自動編譯增加CSS前綴
手動編譯工具請參考這裏

檔案架構

.
├── css
│   └── styles.css
└── index.html

安裝node.js

去node.js官網下載node.js

安裝gulp

終端機cd到目前編輯的資料夾,輸入以下指令

npm init

不管他回啥都按enter
接著再輸入以下指令

npm install gulp -g

新增gulpfile.js

.
├── css
│   └── styles.css
├── index.html
└── gulpfile.js

再回到terminal輸入指令

npm install gulp gulp-autoprefixer --save-dev

編輯gulpfile.js

在gulpfile.js新增以下程式碼

var gulp=require('gulp');
var autoprefixer=require('gulp-autoprefixer');

gulp.task('style', function(){
    gulp.src('css/style.css')
        .pipe(autoprefixer())
        .pipe(gulp.dest('build'))
})

再到terminal輸入指令

gulp styles

編譯完成後,會出現build資料夾,裡面有styles.css,內容是自動完成前綴的CSS檔案
往後只要把html的<link>換成dist的CSS就能引入有完整前綴的檔案

<link ref="stylesheet" href="dist/styles.css" />

watch 存檔同時編譯

在gulpfile.js下方新增以下程式碼

gulp.task('watch', function(){
    gulp.watch('css/styles.css', ['styles']);
})

再回到terminal

gulp watch

就能看到系統會隨時監控style.css,只要一偵測到存檔,就會即時做編譯

Line Awesome

用法

跟FontAwesome4完全一樣,只要引入CSS,用i tag加上class就能使用 <head>引入CSS資源
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/line-awesome@1.3.0/dist/line-awesome/css/line-awesome.css" />
使用<i class="la">呼叫line awesome
i.la.la-exclamation

Line Aewsome取代Font Awesome

當目前的專案已經使用Font Awesome開發一段時間時,
全數手動更換class成Line Awesome會很花成本,
這時可以使用互換性的Line Awesome CSS,
只要替換CSS,不用更換class,就能全數更新成Line Awesome的icon 引入轉換用的CSS資源
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/line-awesome@1.3.0/dist/font-awesome-line-awesome/css/all.css" />
繼續使用Font Awesome的<i class="fa">
i.fa.fa-exclamation

參考資料

  • https://icons8.ru/line-awesome/howto
  • https://icons8.com/line-awesome

flex#11 應用:RWD排版與磚牆效果

RWD排版

利用flex-wrap與flex-grow / flex-basis達成不依靠@media做到RWD

.container
 .box.box1 one 😎
 .box.box2 two 🍕
 .box.box3 three 🍟
 .box.box4 four 👍
 .box.box5 five 👀
 .box.box6 six 💩
.box1
 background: #1abc9c
.box2
 background: #3498db
.box3
 background: #9b59b6
.box4
 background: #34495e
.box5
 background: #f1c40f
.box6
 background: #e67e22
 
.container
 display: flex
 border: 10px solid mistyrose
 flex-wrap: wrap
 
.box
 color: white
 text-align: center
 text-shadow: 4px 4px 0 rgba(0,0,0,0.1)
 padding: 10px
 flex-basis: 300px //效力等同於width: 300px
 flex-grow: 1

Display
▼1236px以上

▼900px~1235px

▼600px~899px

▼599px以下

磚牆效果

利用flex-direction、flex-wrap、flex-grow達成類似磚牆的排法

.container
 display: flex
 border: 10px solid mistyrose
 flex-direction: column
 flex-wrap: wrap
 height: 100vh
 
.box
 color: white
 text-align: center
 text-shadow: 4px 4px 0 rgba(0,0,0,0.1)
 padding: 10px
 flex-basis: 250px
 flex-grow: 1
 
.box3
 flex-grow: 5
 
.box4
 flex-basis: 100px

Display

one 😎
two 🍕
three 🍟
four 👍
five 👀
six 💩

flex#10 flex-basis, flex-grow, flex-shrink

解説

flexg屬性可以在拆分成以下3項

  • flex-basis:當flex item沒變形時,他的初始預設寬度(或是高度,當在cross-axis時)
  • flex-grow:當容器有多餘空間時,分配給flex item的空間比例
  • flex-shrink:當容器空間不足時,flex item犧牲體積的比例
.container
 .box.box1 one 😎
 .box.box2 two 🍕
.box1
 background: #1abc9c
.box2
 background: #3498db

.container
 display: flex
 border: 10px solid mistyrose
 
.box
 color: white
 text-align: center
 text-shadow: 4px 4px 0 rgba(0,0,0,0.1)
 padding: 10px
one 😎
two 🍕

flex-basis

當flex item沒變形時,他的初始預設寬度(或是高度,當在cross-axis時)

.box1
 background: #1abc9c
.box2
 background: #3498db

.container
 display: flex
 border: 10px solid mistyrose
 
.box
 color: white
 text-align: center
 text-shadow: 4px 4px 0 rgba(0,0,0,0.1)
 padding: 10px
 flex-basis: 400px
one 😎
two 🍕

設定為flex-basis: 400px後,每個item的寬度都變成400px了

flex-grow

套用以下設定

  • box1→flex-grow: 1
  • box2→flex-grow: 2

解説:假定容器寬度為1200px
在flex-basis的設定之下,box1、box2各寬400px
1200-400*2=300px,餘下的寬度為300px

flex-grow總數為1+2=3
300px/3=100px
因此

box1的寬度變為400px+100px=500px
box2的寬度變為400px+200px=600px

【注意】由於flex屬性同時包含了flex-grow / shrink
所以如果今天設定是

  • box1→flex: 1
  • box2→flex: 2

box1寬度會等於1/31200px=400px
box2寬度會等於2/3
1200px=800px

.box1
 background: #1abc9c
.box2
 background: #3498db

.container
 display: flex
 border: 10px solid mistyrose
 
.box
 color: white
 text-align: center
 text-shadow: 4px 4px 0 rgba(0,0,0,0.1)
 padding: 10px
 flex-basis: 400px

.box1
 flex-grow: 1
.box2
 flex-grow: 2
one 😎
two 🍕

基於上述算式,box2只比box1大一點點而已。
並且,由於沒有指定flex-shrink
當容器寬度小於2者的flex-basis加總時(例:容器為700px),
2個flex-item會變成一樣大。

flex-shrink

flex-shrink只會在容器空間不夠時有作用
容器空間過多時不會起作用
(flex-grow的相反)

計算方式也是grow的相反

  • box1→flex-shrink: 1
  • box2→flex-shrink: 2

解説:假定容器寬度為500px
在flex-basis的設定之下,box1、box2各寬400px
500-400*2=-400px,不足400px

flex-grow總數為1+2=3
300px/3=100px
因此

box1的寬度變為400px-100px=300px
box2的寬度變為400px-200px=200px

.box1
 background: #1abc9c
.box2
 background: #3498db

.container
 display: flex
 border: 10px solid mistyrose
 
.box
 color: white
 text-align: center
 text-shadow: 4px 4px 0 rgba(0,0,0,0.1)
 padding: 10px
 flex-basis: 400px

.box1
 flex-shrink: 1
.box2
 flex-shrink: 2
one 😎
two 🍕

在寬度足夠時看會沒差,需要把螢幕條小在看。
條小後,會看到box2比box1大一點點

總結

flex屬性集合了flex-grow, flex-shrink, flex-basis三種屬性
當我們使用flex: 1時,其實代表的是flex: 1 1 auto

  • flex-grow: 1
  • flex-shrink: 1
  • flex-basis: auto

flex#9 flex

flex屬性

flex屬性,指定在flex item上面。描述當flex container有剩餘空間(或不夠的空間)時要如何分配
flex屬性僅代表等分比例原則,不是px也不是%

  • flex: 1→1份
  • flex: 2→2份(flex1的二倍)
  • flex: 3→3份(flex1的三倍)

未指定flex屬性時

.container
 .box.box1 one 😎
 .box.box2 two 🍕
 .box.box3 three 🍟
 .box.box4 four 👍
 .box.box5 five 👀
 .box.box6 six 💩
.box1
 background: #1abc9c
.box2
 background: #3498db
.box3
 background: #9b59b6
.box4
 background: #34495e
.box5
 background: #f1c40f
.box6
 background: #e67e22
.box7
 background: #e74c3c
.box8
 background: #bdc3c7
.box9
 background: #2ecc71
.box10
 background: #16a085
 
.container
 display: flex
 border: 10px solid mistyrose

.box
 color: white
 text-align: center
 text-shadow: 4px 4px 0 rgba(0,0,0,0.1)
 padding: 10px
one 😎
two 🍕
three 🍟
four 👍
five 👀
six 💩

flex容器有剩餘空間,flex item沒有填滿剩餘空間

flex: 1

若指定所有flex item為1,則會

  • flex item會填補容器的空白
  • 所有flex item寬度變一樣
.box1
 background: #1abc9c
.box2
 background: #3498db
.box3
 background: #9b59b6
.box4
 background: #34495e
.box5
 background: #f1c40f
.box6
 background: #e67e22
.box7
 background: #e74c3c
.box8
 background: #bdc3c7
.box9
 background: #2ecc71
.box10
 background: #16a085
 
.container
 display: flex
 border: 10px solid mistyrose

.box
 color: white
 text-align: center
 text-shadow: 4px 4px 0 rgba(0,0,0,0.1)
 padding: 10px
 flex: 1
one 😎
two 🍕
three 🍟
four 👍
five 👀
six 💩

flex item填滿容器,並且均等長

flex進階指定

套用以下指定

  • box1→flex: 1
  • box2→flex: 2
  • box3→flex: 1
  • box4→flex: 1
  • box5→flex: 3
  • box5→flex: 3
.box1
 background: #1abc9c
.box2
 background: #3498db
.box3
 background: #9b59b6
.box4
 background: #34495e
.box5
 background: #f1c40f
.box6
 background: #e67e22
.box7
 background: #e74c3c
.box8
 background: #bdc3c7
.box9
 background: #2ecc71
.box10
 background: #16a085
 
.container
 display: flex
 border: 10px solid mistyrose

.box
 color: white
 text-align: center
 text-shadow: 4px 4px 0 rgba(0,0,0,0.1)
 padding: 10px
 flex: 1

.box2
 flex: 2

.box5
 flex: 3
one 😎
two 🍕
three 🍟
four 👍
five 👀
six 💩

box1為1等分 ∴寬度為1/9
box2為2等分 ∴寬度為2/9
box3為1等分 ∴寬度為1/9
box4為1等分 ∴寬度為1/9
box5為3等分 ∴寬度為3/9
box6為1等分 ∴寬度為1/9

總長為1+2+1+1+3+1=9

Catalina 在根目錄(Macintosh HD)編輯的方法

關閉SIP

輸入以下指定確認SIP是否開啟

csrutil status

//回傳enabled表示SIP為開啟的撞狀態,需要關閉SIP
//回傳disabled表示SIP為關閉狀態,不需關閉SIP(跳過關閉SIP的步驟)

如SIP為enabled狀態,執行以下步驟關閉SIP

  1. 電腦關機
  2. 關機後,按住開機鍵,同時按住Cmd+R(按住直到螢幕出現apple logo後才放開)
  3. 進入復原模式,選擇使用者後,按下一步
  4. 選擇上方的「工具程式」,選「終端機」
  5. 輸入以下指令
    csrutil disable
  6. 重新開機

解除根目錄唯讀

  1. 終端機輸入csrutil status,確認回傳為disabled
  2. 輸入sudo mount -uw /
  3. 輸入sudo killall Finder
  4. 輸入cd /System/Library/Extensions
  5. 輸入sudo mv AppleThunderboltNHI.kext AppleThunderboltNHI_kext.bak

flex#8 align-self

說明

  • align-items指定全體的flex item沿著cross-axis對齊情況
  • align-self指定個別的flex item沿著cross-axis對齊情況(可以覆蓋align-items的指定)

align-self: auto (default)

預設值:不指定(繼承align-items)

.container
  display: flex
  border: 10px solid mistyrose
  height: 100vh
  align-items: baseline //指定整體

.box2
  padding-bottom: 200px
.box6
  padding-bottom: 0
.box9
  padding-bottom: 50px
  align-self: auto
1
2
3
4
5
6
7
8
9
10

align-self: flex-end

對齊cross-axis的底部
現在cross是由上至下↓↓↓,所以是靠下對齊

.container
  display: flex
  border: 10px solid mistyrose
  height: 100vh
  align-items: baseline //指定整體

.box2
  padding-bottom: 200px
.box6
  padding-bottom: 0
.box9
  padding-bottom: 50px
  align-self: flex-end
1
2
3
4
5
6
7
8
9
10

align-self: flex-end

對齊cross-axis的中部
現在cross是由上至下↓↓↓,所以是靠中對齊

.container
  display: flex
  border: 10px solid mistyrose
  height: 100vh
  align-items: baseline //指定整體

.box2
  padding-bottom: 200px
.box6
  padding-bottom: 0
.box9
  padding-bottom: 50px
  align-self: flex-end
1
2
3
4
5
6
7
8
9
10

align-self: baseline

對齊cross-axis的上部
現在cross是由上至下↓↓↓,所以是靠上對齊

.container
  display: flex
  border: 10px solid mistyrose
  height: 100vh
  align-items: baseline //指定整體

.box2
  padding-bottom: 200px
.box6
  padding-bottom: 0
.box9
  padding-bottom: 50px
  align-self: flex-end
1
2
3
4
5
6
7
8
9
10

flex#7 align-content

注意事項

  • flex-wrap需要為wrap
  • 只考慮與cross-axis的關係

範例

align-content: stretch (default)

效果:填滿cross-axis

.container
 .box.box1 1
 .box.box2 
  |2
  br
  |:)
 .box.box3 3
 .box.box4 4
 .box.box5 5
 .box.box6 6
 .box.box7 7
 .box.box8 8
 .box.box9 9
 .box.box10 10
.box
  color: white
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px
  width: 30%

.container
  display: flex
  border: 10px solid mistyrose
  height: 100vh
  flex-wrap: wrap
  align-content: stretch
1
2
🙂
3
4
5
6
7
8
9
10

align-content: flex-start

集中於上方

.box
  color: white
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px
  width: 30%

.container
  display: flex
  border: 10px solid mistyrose
  height: 100vh
  flex-wrap: wrap
  align-content: flex-start
1
2
🙂
3
4
5
6
7
8
9
10

align-content: flex-end

集中於下方

.box
  color: white
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px
  width: 30%

.container
  display: flex
  border: 10px solid mistyrose
  height: 100vh
  flex-wrap: wrap
  align-content: flex-end
1
2
🙂
3
4
5
6
7
8
9
10

align-content: space-between

平均分散

.box
  color: white
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px
  width: 30%

.container
  display: flex
  border: 10px solid mistyrose
  height: 100vh
  flex-wrap: wrap
  align-content: space-between
1
2
🙂
3
4
5
6
7
8
9
10

align-content: center

集中於中間

.box
  color: white
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px
  width: 30%

.container
  display: flex
  border: 10px solid mistyrose
  height: 100vh
  flex-wrap: wrap
  align-content: center
1
2
🙂
3
4
5
6
7
8
9
10

補充:讓「10」也可以水平置中

使用justify-content: center

.box
  color: white
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px
  width: 30%

.container
  display: flex
  border: 10px solid mistyrose
  height: 100vh
  flex-wrap: wrap
  align-content: center
  justify-content: center
1
2
🙂
3
4
5
6
7
8
9
10

flex#6 align-items

定義
justify-content會沿著cross-axis對齊

快速複習

  • 【預設】flex-direction: row,cross-axis為由由上至下↓↓↓
  • flex-direction: column,cross-axis為左至右→→→

重點

  • 外層wrapper要有足夠的空間(否則align-items沒空間發揮)
  • 每個item嘗試使用不同的高度(以便看出效果差異)

cross-axis為由上至下時(預設)

align-items: stretch(預設)

效果:填滿

.container
  display: flex
  border: 10px solid mistyrose
  height: 400px
  align-items: stretch

.box1
  font-size: 30px
 
.box3
  font-size: 150px
1
2
3
4
5
6
7
8
9
10

align-items: center

集中在中間

.container
  display: flex
  border: 10px solid mistyrose
  height: 400px
  align-items: center
1
2
3
4
5
6
7
8
9
10

align-items: flex-end

集中於下方

.container
  display: flex
  border: 10px solid mistyrose
  height: 400px
  align-items: flex-end
1
2
3
4
5
6
7
8
9
10

align-items: flex-start

集中於上方(貼齊上緣)

.container
  display: flex
  border: 10px solid mistyrose
  height: 400px
  align-items: flex-start
1
2
3
4
5
6
7
8
9
10

align-items: baseline

集中於上方(items自己置中對齊)

.container
  display: flex
  border: 10px solid mistyrose
  height: 400px
  align-items: baseline
1
2
3
4
5
6
7
8
9
10

cross-axis為由左至右時(flex-direction: column)

align-items: stretch(預設)

填滿

.box
  color: white
  font-size: 20px
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px

.container
  display: flex
  border: 10px solid mistyrose
  flex-direction: column
  align-items: stretch

.box1
  font-size: 30px
 
.box3
  font-size: 40px
 
.box4
  font-size: 50px
1
2
3
4
5
6
7
8
9
10

align-items: center

集中於中間

.container
  display: flex
  border: 10px solid mistyrose
  flex-direction: column
  align-items: center
1
2
3
4
5
6
7
8
9
10

align-items: flex-end

集中於右側(貼齊右側)

.container
  display: flex
  border: 10px solid mistyrose
  flex-direction: column
  align-items: flex-end
1
2
3
4
5
6
7
8
9
10

align-items: flex-start

集中於左側(貼齊左側)

.container
  display: flex
  border: 10px solid mistyrose
  flex-direction: column
  align-items: flex-start
1
2
3
4
5
6
7
8
9
10

flex#5 justify-content

定義

justify-content會沿著main-axis對齊

快速複習

  • 【預設】flex-direction: row,main-axis為由左至右→→→
  • flex-direction: column,main-axis為由上至下↓↓↓

main-axis為由左至右的情況下(Default)

justify-content: flex-start (default)

items會擠在左邊

.container
  display: flex
  border: 10px solid mistyrose
  justify-content: flex-start
1
2
3
4
5
6
7
8
9
10

justify-content: flex-end

items會擠在右邊

.container
  display: flex
  border: 10px solid mistyrose
  justify-content: flex-end
1
2
3
4
5
6
7
8
9
10

justify-content: center

items會擠中間

.container
  display: flex
  border: 10px solid mistyrose
  justify-content: center
1
2
3
4
5
6
7
8
9
10

justify-content: space-between

第1個item擠在左邊,最後1個item擠在右邊,中間的items均分

.container
  display: flex
  border: 10px solid mistyrose
  justify-content: space-between
1
2
3
4
5
6
7
8
9
10

justify-content: space-around

手法近似於每個item得到一樣的margin-left跟margin-right。
由於第2-9個item的兩邊會重疊鄰居的margin,所以空隙為2倍。
第1個與第10個item的margin沒有鄰居加持,所以與邊界的空隙只有1倍。

.container
  display: flex
  border: 10px solid mistyrose
  justify-content: space-around
1
2
3
4
5
6
7
8
9
10

main-axis為由上至下的情況下(flex-direction: column)

2個注意事項

  • 需要指定min-height
  • 每個item不能給太高(加總高須低於min-height)

justify-content: flex-start

items都擠在上方

.box
  color: white
  font-size: 20px
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px

.container
  display: flex
  border: 10px solid mistyrose
  flex-direction: column
  min-height: 700px
  justify-content: flex-start
1
2
3
4
5
6
7
8
9
10

justify-content: flex-end

items都擠在下方

.container
  display: flex
  border: 10px solid mistyrose
  flex-direction: column
  min-height: 700px
  justify-content: flex-end
1
2
3
4
5
6
7
8
9
10

justify-content: center

items都擠在中間(狀似孤島)

.container
  display: flex
  border: 10px solid mistyrose
  flex-direction: column
  min-height: 700px
  justify-content: center
1
2
3
4
5
6
7
8
9
10

justify-content: space-between

首尾貼緊上下的均分

.container
  display: flex
  border: 10px solid mistyrose
  flex-direction: column
  min-height: 700px
  justify-content: space-between
1
2
3
4
5
6
7
8
9
10

justify-content: space-around

上下等距的均分

.container
  display: flex
  border: 10px solid mistyrose
  flex-direction: column
  min-height: 700px
  justify-content: space-around
1
2
3
4
5
6
7
8
9
10

【GCP】introduction to APIs

目的

利用GCP建立一個API

建立JSON檔案

開啟GCP平台,打開Cloud Shell

輸入以下指令,編輯value.json

nano values.json

進入編輯模式後,貼上以下內容
※<YOUR_BUCKET_NAME>請換成自訂的任意名字,命名須遵守這篇文章

{  "name": "<YOUR_BUCKET_NAME>",
   "location": "us",
   "storageClass": "multi_regional"
}

結束編輯模式:Ctrl+X
確定儲存:Y
結束:Enter

取得API認證

OAuth 2.0 playground
選擇「Cloud Storage JSON API V1」
並選擇之下的「https://www.googleapis.com/auth/devstorage.full_control」

選好後,按下藍色按鈕「Authorize APIs」

接者,完成Step2跟Step3,並複製Access token序號

建立Cloud Storage Bucket

回到GCP Cloud Shell,輸入以下指令

ls

會看到回傳2份檔案:README-cloudshell.txt values.json

繼續輸入以下指令
※<YOUR_TOKEN>請貼上剛剛複製的OAuth Access token序號

export OAUTH2_TOKEN=<YOUR_TOKEN>

輸入以下指令
※<YOUR_PROJECT_ID>請貼上專案ID

export PROJECT_ID=<YOUR_PROJECT_ID>

執行以下程式,建立bucket

curl -X POST --data-binary @values.json \
    -H "Authorization: Bearer $OAUTH2_TOKEN" \
    -H "Content-Type: application/json" \
    "https://www.googleapis.com/storage/v1/b?project=$PROJECT_ID"

檢視建立好的Cloud Storage Bucket

選單→Storage→Browser

並點選專案名,就可看到建立好的Cloud Storage Bucket

上傳媒體檔案至API

  1. 找一張圖片,儲存為demo-image.pn
  2. 點選Cloud Sheel右上角的「…」menu處,選擇「upload file」
  3. 執行以下程式,找尋媒體路徑,並且複製回傳的絕對路徑
    realpath demo-image.png
  4. 執行以下指令
    ※<DEMO_IMAGE_PATH>請代換成剛剛複製貼上的路徑

    export OBJECT=<DEMO_IMAGE_PATH>
  5. 執行以下指令
    ※<YOUR_BUCKET>代換成這隻Bucket的名稱(value.json裡面的name)

    export BUCKET_NAME=<YOUR_BUCKET>
  6. 執行以下指令,上傳媒體至Cloud Storage Bucket
    ※<YOUR_BUCKET>代換成這隻Bucket的名稱(value.json裡面的name)

    curl -X POST --data-binary @$OBJECT \
        -H "Authorization: Bearer $OAUTH2_TOKEN" \
        -H "Content-Type: image/png" \
        "https://www.googleapis.com/upload/storage/v1/b/$BUCKET_NAME/o?uploadType=media&name=demo-image"
  7. 接者,可以在預覽主畫面上,看到上傳成功的媒體

flex#4 flex-order

說明

  • 預設值:order: 0
  • order的數字只具相對意義,order5的會排在order10的前面。但是當頁面上只存在一個order時,給定order1的效力等同於order50
  • 指定order後,畫面上的順序雖然被改變了,但是滑鼠反藍選取的順序依舊會照html排列,所以會看到選取的地方被中斷

order為正數時:會排到右邊

.container
  display: flex

.box
  flex: 1 // 填滿一行

.box3
  order: 1

.box7
  order: 2
1
2
3
4
5
6
7
8
9
10

order為負數時:會排到左邊

.container
  display: flex

.box
  flex: 1 // 填滿一行

.box3
  order: -1

.box7
  order: -2
1
2
3
4
5
6
7
8
9
10

flex#3 flex-wrap

flex-wrap: nowrap (預設)

不拆行(所有flex item擠在一排裡面)
即便指定了寬度,flex container也會以擠在一起為原則,盡量達成指定的寬度

.container
  display: flex
  border: 10px solid goldenrod
  flex-wrap: nowrap
 
.box
  color: white
  font-size: 100px
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px
  width: 300px
1
2
3
4
5
6
7
8
9
10

flex-wrap: wrap

拆行(flex item超過寬度的話會掉下來)
會遵守width

.container
  display: flex
  border: 10px solid goldenrod
  flex-wrap: wrap
 
.box
  color: white
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px
  width: 300px
1
2
3
4
5
6
7
8
9
10

flex-wrap: wrap-reverse

反轉cross-axis
本來是由上到下↓↓↓
現變成由下到上↑↑↑

.container
  display: flex
  border: 10px solid goldenrod
  flex-wrap: wrap-reverse
 
.box
  color: white
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px
  width: 300px
1
2
3
4
5
6
7
8
9
10

讓flex-item可以無縫填滿外層

  • 寬度算好
  • 使用box-sizing: border-box
.container
  display: flex
  border: 10px solid goldenrod
  flex-wrap: wrap
 
.box
  color: white
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px
  box-sizing: border-box
  width: 33.33%
1
2
3
4
5
6
7
8
9
10

flex-item之間留個空隙

  • 空隙用margin指定
  • 寬度用calc算好
.container
  display: flex
  border: 10px solid goldenrod
  flex-wrap: wrap
 
.box
  color: white
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px
  margin: 10px
  box-sizing: border-box
  width: calc(33.33% - 20px)
1
2
3
4
5
6
7
8
9
10

flex#2 flex-direction

flex-direction: row (預設)

main axis: 由左至右 →→→
cross axis: 由上至下 ↓↓↓

.container
  display: flex
  border: 10px solid goldenrod
 flex-direction: row
1
2
3
4
5
6
7
8
9
10

flex-direction: column

main axis: 由上至下 ↓↓↓
cross axis: 由左至右 →→→

.container
  display: flex
  border: 10px solid goldenrod
 flex-direction: column
1
2
3
4
5
6
7
8
9
10

flex-direction: row-reverse

main axis: 由右至左 ←←←

.container
  display: flex
  border: 10px solid goldenrod
 flex-direction: row-reverse
1
2
3
4
5
6
7
8
9
10

flex-direction: column-reverse

main axis: 由下至上 ↑↑↑

.container
  display: flex
  border: 10px solid goldenrod
 flex-direction: column-reverse
1
2
3
4
5
6
7
8
9
10

flex#1 CSS flexbox

無使用flex時

.container
 .box.box1 1
 .box.box2 2
 .box.box3 3
 .box.box4 4
 .box.box5 5
 .box.box6 6
 .box.box7 7
 .box.box8 8
 .box.box9 9
 .box.box10 10
.box
  color: white
  font-size: 100px
  text-align: center
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1)
  padding: 10px

.box1
  background: #1abc9c
.box2
  background: #3498db
.box3
  background: #9b59b6
.box4
  background: #34495e
.box5
  background: #f1c40f
.box6
  background: #e67e22
.box7
  background: #e74c3c
.box8
  background: #bdc3c7
.box9
  background: #2ecc71
.box10
  background: #16a085

Display

1
2
3
4
5
6
7
8
9
10

使用display: flex

外層元素會拉成一列
內層元素會變成flex-item

.container
  display: flex
  border: 10px solid goldenrod
1
2
3
4
5
6
7
8
9
10

使用display: inline-flex

外層元素會拉成一列,但不會全部填滿一列
內層元素會變成flex-item

.container
  display: inline-flex
  border: 10px solid goldenrod
1
2
3
4
5
6
7
8
9
10

JavaScript easing

說明

  1. 設定好自訂動畫函數,input固定間隔值的數字,動畫函數的output會是一個動畫曲線
  2. 用setInterval寫動畫執行函數。參數意義如下
    ele:element
    b:before(初期值)
    c:change(終點值)
    t:timing(目前的時間戳)
    d:duration(這個動畫總共要有幾秒)
.box
.box
.box
.box
.box
.box
.box
.box
.box
.box
.box
.box
.box
.box
.box
.box
.box
.box
.box
.box
button(onclick="move()") click me
.box
 background: teal
 width: 200px
 height: 100px
 margin: 40px
//easing函數
function easeOut(t, d){
  return 1 - Math.pow(1-(t/d), 5);
}

function smoothScroll(ele, b){
  var c=-ele.scrollTop;
  var start = Date.now();
  var total = 1400; //毫秒
  var d = 1;

  timer = window.setInterval(function() {
    var t = (Date.now() - start) / total;
    var result = easeOut(t, d);
    var y = b + result * c;
    ele.scrollTop = y;
    if (t >= d) { 
      clearInterval(timer);
    }
  }, 16);
}

function move(){
 if(document.body.scrollTop!==0){
  //Safari
  smoothScroll(document.body, pageYOffset)
 }else{
  //Chrome, FF, IE
  smoothScroll(document.documentElement, pageYOffset)
 }
}

easing 函數介紹

easing out類(開始快,結束慢)

easing out by pow (指數)

function easeOutPow(t, d){
  return 1 - Math.pow(1-(t/d), 5);
}

easing  out by quad (2倍)

function easeOutQuad(t) { 
  return t*(2-t)
}

easing  out by cubic (3倍)

function easeOutCubic(t) { 
  return (--t)*t*t+1 
}

easing  out by quart (4倍)

function easeOutQuart(t) {
  return t*t*t*t
}

easing  out by quint (5倍)

function easeOutQuint(t) {
 return 1+(--t)*t*t*t*t
}

easing in類(開始慢,結束快)

easing in by pow (指數)

function easeInPow(t, d){
  return Math.pow((t/d), 5);
}

easing in by quad (2倍)

function easeInQuad(t) { 
  return t*t 
}

easing in by cubic (3倍)

function easeInCubic(t){ 
  return t*t*t 
}

easing in by quart (4倍)

function easeInQuart(t) { 
  return t*t*t*t 
}

easing in by quint (5倍)

function easeInQuint(t) { 
  return t*t*t*t*t 
}

ease in and out類(開始慢,中間快,結束慢)

easing in by pow (指數)

function easeInOutPow(t, d){
  return t<.5 ? Math.pow((t/d)*1.8, 6.5) : 1 - Math.pow((1-(t/d))*1.8, 6.5);
}

easing in by quad (2倍)

function easeInOutQuad(t) { 
  return t<.5 ? 2*t*t : -1+(4-2*t)*t 
}

easing in by cubic (3倍)

function easeInOutCubic(t) { 
  return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1
}

easing in by quart (4倍)

function easeInOutQuart(t) { 
  return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t 
}

easing in by quint (5倍)

function easeInOutQuint(t) { 
  return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t
}

參考資料

https://gist.github.com/gre/1650294

SMIL 動態控制

SVG <animate>的動態控制屬性

結束後保持變化後的狀態 fill=”freeze”

效果類似animation-fill-mode: forwards;

svg(viewbox="-50 -50 100 100")
 circle(cx=0,cy=0,r=10)
  animate(attributeName="r" dur="5s" values="10;40" fill="freeze")
svg
 width: 240px
 border: solid 2px

JS控制動畫開始

  1. 用參數控制SVG動畫一開始先停止
  2. 用JS method喚醒動畫
svg(viewbox="-50 -50 100 100")
 circle(cx=0,cy=0,r=10)
  animate#myAni(attributeName="r" dur="2s" values="10;30;10" begin="infinite" repeatCount="indefinite")
button(onclick="myAni.beginElement()") click me
svg
 width: 240px
 border: solid 2px

Safari bug:transform-origin不會生效

若使用CSS Animation Keyframes設定動畫的話,則transform-origin可以在safari正常使用的,
但在SMIL設定<animate>,則safari的transform-origin屬性不知為何沒有作用,會造成動畫扭曲

IIFEs

function statements

function statements在執行前會先透過Hoisting儲存在記憶體,
所以可以提前執行不會有問題。

greeting(); //可以被提前執行

function greeting(){
  console.log('Good');
}

function expressions

function expressions執行前不會進記憶體,
所以提前執行會出問題。

greeting(); //→不會理你

var greeting=function(){
 console.log('GOOD');
}

IIFEs

透過function expressions建立函式,並且立刻執行它。

沒用IIFEs時

var greeting=function(){
 console.log('GOOD'); 
}

//Console Panel
//Nothing

使用IIFEs時

var greeting=function(){
console.log('GOOD'); 
}();
//會立刻執行

//Console Panel
//GOOD

Form相關事件

簡介

埋在form裡面的<input type=”submit” />以及<button>,只要按下就會觸發form執行

reportvalidity()

手動觸發「檢核」提示

form#myForm
 input(type="text" required)
 input(type="submit")
 
button(onclick="myForm.reportValidity()") click me

checkValidity()

檢查表單檢核有沒有過,有通過的話回傳true,沒通過的話回傳false

form#myForm
 input(type="text" required)
 input(type="submit")
//Console Panel
myForm.checkValidity()

reset()

清空表單的input內容

form#myForm
 input(type="text" required)
 input(type="submit")
//Console Panel
myForm.reset() //清空內容

PHP陣列取值

name如果命名成xxx[]的話,傳到PHP會直接變成陣列
適合用在很多checkbox時

<form action="ttt.php" method="post">
    <input type="checkbox" name="user[]" value="草莓" id="strawberry" />
    <label for="strawberry">草莓</label>
    <input type="checkbox" name="user[]" value="橘子" id="orange" />
    <label for="orange">橘子</label>
    <input type="checkbox" name="user[]" value="香蕉" id="banana" />
    <label for="banana">香蕉</label>
    <br>
    <br>
    <input type="submit" name="your_submit" />
</form>

<?php 

if(!empty($_POST['your_submit'])){
  for ($i=0; $i < count($_POST['user']); $i++) { 
    echo $_POST['user'][$i].'<br>';
  }
}

?>

Reference and Copy

By Value: Number, String, Boolean

Number

let age=100;
let age2=age;
console.log(age, age2); //100 100

age=200;
console.log(age, age2); //200 100

String

let name='wes';
let name2=name;
console.log(name, name2); //'wes' 'wes'

name='wesley';
console.log(name, name2); //'wesley' 'wes'

Boolean

let isGood=true;
let isGood2=isGood;
console.log(isGood, isGood2); //true true

isGood=false;
console.log(isGood, isGood2); //false true

By Reference: Object, Array, Function

const players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
const team = players;
console.log(players, team);
// ["Wes", "Sarah", "Ryan", "Poppy"]
// ["Wes", "Sarah", "Ryan", "Poppy"]

team[3]='Luis';
console.log(players, team);
// ["Wes", "Sarah", "Ryan", "Luis"]
// ["Wes", "Sarah", "Ryan", "Luis"]

//teams[3]的「team」是Reference,所以初始一但被更新,複製的也會被更新

Reference中的例外:該如何讓被複製的array不受初始變更的影響

方法1:slice

const fruits=['apple', 'banana', 'orange', 'grape'];
const fruits2=fruits.slice();

fruits[3]='mango';
console.log(fruits, fruits2);
// ["apple", "banana", "orange", "mango"]
// ["apple", "banana", "orange", "grape"]

方法2:New Array+contact

const fruits=['apple', 'banana', 'orange', 'grape'];
const fruits3=[].concat(fruits);

fruits[3]='mango';
console.log(fruits, fruits3);
// ["apple", "banana", "orange", "mango"]
// ["apple", "banana", "orange", "grape"]

方法3:ES6 Spread

const fruits=['apple', 'banana', 'orange', 'grape'];
const fruits4=[...fruits];

fruits[3]='mango';
console.log(fruits, fruits4);
// ["apple", "banana", "orange", "mango"]
// ["apple", "banana", "orange", "grape"]

方法4:Array.from

const fruits=['apple', 'banana', 'orange', 'grape'];
const fruits5=Array.from(fruits);

fruits[3]='mango';
console.log(fruits, fruits5);
// ["apple", "banana", "orange", "mango"]
// ["apple", "banana", "orange", "grape"]

多層物件中的淺拷貝

當1個物件他有很多層時

透過assign改第1層:不會改到初始物件

const wes={
 name: 'wes',
 age: 100,
 social: {
  twitter: '@webos',
  facebook: 'wesbos.developer'
 }
}

const dev=Object.assign({}, wes);
dev.name='wesley';
console.log(wes, dev);
// Object {
//   name: 'wes',
//   age: 100,
//   social: {
//    twitter: '@webos',
//    facebook: 'wesbos.developer'
//  }
// }
// Object {
//   name: 'wesley',
//   age: 100,
//   social: {
//    twitter: '@webos',
//    facebook: 'wesbos.developer'
//  }
// }

透過assign改第2層:會一起改到初始物件

const wes={
 name: 'wes',
 age: 100,
 social: {
  twitter: '@webos',
  facebook: 'wesbos.developer'
 }
}

const dev2=Object.assign({}, wes);
console.log(wes, dev);
// Object {
//   name: 'wesley',
//   age: 100,
//   social: {
//    twitter: '@coolman',
//    facebook: 'wesbos.developer'
//  }
// }
// Object {
//   name: 'wesley',
//   age: 100,
//   social: {
//    twitter: '@coolman',
//    facebook: 'wesbos.developer'
//  }
// }

原因:assign指能對第1層做深拷貝,其他第2層以下還是淺拷貝

多層物件的多重深拷貝(clone deep)

使用這招前請三思是否有必要多重深拷貝

const wes={
 name: 'wes',
 age: 100,
 social: {
  twitter: '@webos',
  facebook: 'wesbos.developer'
 }
}

const dev3=JSON.parse(JSON.stringify(wes));
dev3.social.twitter='@coolman';
console.log(wes, dev3);
// Object {
//   name: 'wesley',
//   age: 100,
//   social: {
//    twitter: '@wesbos',
//    facebook: 'wesbos.developer'
//  }
// }
// Object {
//   name: 'wesley',
//   age: 100,
//   social: {
//    twitter: '@coolman',
//    facebook: 'wesbos.developer'
//  }
// }

debounce

當執行某些event時(比如說scroll event),瀏覽器會執行很多次,這時可以用debounce function,限制他只能每xx毫秒執行一次,以節省效能

未使用debounce時

function goScroll(){
  console.count('gogogo');
}

window.addEventListener('scroll', goScroll);

//此時滑動螢幕捲軸,會發現後台被執行了很多次

使用debounce function減輕效能負擔

function debounce(func, wait = 20, immediate = true) {
  var timeout;
  return function() {
    var context = this, args = arguments;
    var later = function() {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
}

function goScroll(){
  console.count('gogogo');
}

window.addEventListener('scroll', debounce(goScroll, 50));
//debounce的第2個參數可以定義多久毫秒執行1次,若沒填的話此範例預設是每20秒執行1次。

【CSS】卡片翻面效果

<div class="photo">
    <div class="front">第一張卡片</div>
    <div class="back">第二張卡片</div>
</div>
.front {
  width: 300px;
  height: 350px;
  backface-visibility: hidden;
  transition: 0.6s;
  transform-style: preserve-3d;
  position: absolute;
  top: 0;
  left: 0;
  background-color: red;
}
.back {
  width: 300px;
  height: 350px;
  backface-visibility: hidden;
  transition: 0.6s;
  transform-style: preserve-3d;
  position: absolute;
  top: 0;
  left: 0;
  transform: rotateY(-180deg);
  background-color: green;
}
.photo:hover .back {
  transform: rotateY(0deg);
}
.photo:hover .front {
  transform: rotateY(180deg);
}

Class add and remove

此寫法為達成以下目的(常應用於選單收合)

  • A開啟時,點了B,打開B時要順便收起A
  • A開啟時,點了A,要收起A
.box apple
.box orange
.box grape
.box blue
.box gray
.box
 width: 200px
 height: 100px
 background-color: #eee
 text-align: center
 line-height: 100px
 transition-duration: 0.5s
 
.box.teal
 background-color: teal
 color: #fff
const boxes=document.querySelectorAll(".box");

boxes.forEach(box => box.addEventListener("click", checkall)
)

function checkall(){
 const nowTeal=document.querySelector(".teal");
 
 if(nowTeal){
  nowTeal.classList.remove("teal");
 }
 
 if(nowTeal==this){
  this.classList.remove("teal");
 }else{
   this.classList.add("teal");
 }

}

highchart 5角圖

<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<div id="container"></div>
#container
 min-width: 400px
 max-width: 600px
 height: 400px
 margin: 0 auto
const spiderData=[
    {
        tag: '住宅',
        value: 5
    },
    {
        tag: '醫療',
        value: 2
    },
    {
        tag: '食品安全',
        value: 5
    },
    {
        tag: '教育',
        value: 1
    },
    {
        tag: '\t',
        value: 0
    },
]

const maxValue=Math.max(...spiderData.map(el => el.value));

Highcharts.chart('container', {

    chart: {
        polar: true,
        type: 'line',
        margin: [40, 0, 0, 0],
    },

    credits: {
        enabled: false
    },

    title: {
        text: ''
    },

    pane: {
        size: '100%'
    },

    exporting: { 
        enabled: false 
    },

    xAxis: {
        categories: spiderData.map((el) => {
            if(el.value===maxValue){
                return `<div style="color: red">${el.tag}<div>`;
            }else{
                return el.tag;
            }
        }),
        tickmarkPlacement: 'on',
        lineWidth: 0,
    },

    yAxis: {
        gridLineInterpolation: 'polygon',
        lineWidth: 0,
        min: 0,
        tickPositions: [0, 1, 2, 3, 4, 5],
        endOnTick: true,
    },

    tooltip: {
        enabled: false,
    },

    series: [{
        showInLegend: false,
        data: spiderData.map(el => el.value),
        pointPlacement: 'on',

    }]

});

CODEPEN

【CSS】字體設定

日文楷體

  • Mac會顯示「游教科書體」
  • Windows會顯示「標楷體」
h1 游教科書あっ!レポートレポート
h1
 font-family: YuKyo-Medium, STKaiti, DFKai-sb
 font-weight: normal

Display

游教科書あっ!レポートレポート

中文襯線體

  • Mac會顯示「宋體-繁」
  • Windows 英數字顯示「News Time Roman」,中文顯示「新細明體」
h1 這是一段中文字查詢頁面
h1
 font-family: 'Songti TC', 'Times New Roman', 'PMingLiu'
 font-weight: normal

Display

這是一段中文字查詢頁面

highchart 儀表圖

<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/solid-gauge.js"></script>
<div id="container-speed" class="container"></div>
.container {
  min-width: 310px; 
  max-width: 400px; 
  height: 300px; 
  margin: 0 auto;
}

tspan {
  font-size: inherit;
  color: inherit;
}

.verybad {
  color: #C00000;
  border-color: #C00000;
}

.bad {
  color: #E16100;
  border-color: #E16100;
}

.neutral {
  color: #FFC000;
  border-color: #FFC000;
}

.good {
  color: #D8Bf1A;
  border-color: #D8Bf1A;
}

.verygood {
  color: #9BBB59;
  border-color: #9BBB59;
}

.badge {
  font-size: 12px;
  border: 1px solid;
  border-radius: 3px;
  padding: 1px 2px;
  vertical-align: middle;
}

.voice-num {
  vertical-align: middle;
}
const testData=[43];

var speedOptions={

    chart:{
        type: 'gauge',
        plotBackgroundColor: null,
        plotBackgroundImage: null,
        plotBorderWidth: 0,
        plotShadow: false,
    },
        
    title: {
        text: '網路聲量'
    },
  
    pane: {
        startAngle: -90,
        endAngle: 90,
        background: null
    },
  
    exporting: { 
        enabled: false 
    },
  
    credits: {
        enabled: false
    },
        
    plotOptions: {
        gauge: {
            dataLabels: {
                borderColor: "none",
                useHTML: true,
                style: {
                    fontSize: "20px",
                }
                
            },
            dial: {
                baseLength: '0%',
                baseWidth: 10,
                radius: '100%',
                rearLength: '0%',
                topWidth: 1
            }
        }
    },
           
    // the value axis
    yAxis: {
        labels: {
            y: 10
        },
        tickPositions: [-50, 0, 50],
        minorTickLength: 0,
        min: -50,
        max: 50,
        plotBands: [{
            from: -50,
            to: 50,
            // color: '#C00000', // red
            color: {
                linearGradient: { x1: 0, x2: 1, y1: 0, y2: 0 },
                stops: [
                    [0.2, '#C00000'],
                    // #E16100
                    [0.5, '#FFC000'],
                    //#D8Bf1A
                    [0.7, '#9BBB59'],
                ]
            },
            thickness: '50%'
        }]
    },
    
    series: [{
        name: 'Speed',
        data: testData,
        dataLabels: {
            formatter: function(){
                let badge='';
                switch(true) {
                    case (this.y<-34):
                        //-35 -36 -37
                        badge='非常負面';
                        break;
                    case (this.y<-4):
                        //-34 -33 -32 ... -5
                        badge='較負面';
                        break;
                    case (this.y<5):
                        //-4 -3 ... 3 4
                        badge='中立';
                        break;
                    case (this.y<35):
                        //5 6 ... 33 34
                        badge='較正面';
                        break;
                    case (this.y<50):
                        badge='非常正面';
                }
            
                return `${this.y}分 ${badge}`
            }
        }
    }],
 
    tooltip: {
        enabled: false,
    },
 
};
Highcharts.chart('container-speed', speedOptions);

// -5 ~ +5 中立
// 5 ~ 35  較正面
// 35 ~ 50 非常正面

CODEPEN

 

Git ssh設定

mac https://qiita.com/shizuma/items/2b2f873a0034839e47ce

Mac

移動至ssh的資料夾
cd ~/.ssh
如果是首次使用ssh的話,.ssh folder裡面會沒有東西,要生成金鑰 (第二次以後使用的話,就不用再產生金鑰了)
$ssh-keygen -t rsa
下了這行↑指令後,Terminal會問3個問題,都打Enter就好 之後,copy電腦裡面的金鑰匙,並貼上Github 複製金鑰的指令:
pbcopy < ~/.ssh/id_rsa.pub

Win10

控制台 > 系統及安全性 > 系統 > 點選「進階系統設定」
進階 > 環境變數
選「Path」 > 編輯
新增 > 複製git/urs/bin的路徑貼上去
切換到終端機,找到.ssh資料夾
cd .ssh
產生ssh key
ssh-keygen
接下來不管Terminal回啥,按Enter,一共按3次Enter 之後,.ssh資料夾會產生「id_rsa」、「id_rsa.pub」2份檔案 複製id_rsa.pub的內容,輸入以下指令
cat id_rsa.pub
然後複製Terminal回傳的東西,並且貼上github

【JavaScript】appendChild

append虛擬元素時

#newBlock
 width: 100px
 height: 100px
 background: teal
const newBlock=document.createElement('div');
newBlock.id='newBlock';
document.appendChild(newBlock.cloneNode(true));
cloneNode代表無限複製,如果沒有用這個引數,他只會做出「搬移」(僅複製一次的效果)

append現有元素時

#nowBlock
hr
#newland
#nowBlock
 width: 100px
 height: 100px
 background: teal
newLand.appendChild(nowBlock.cloneNode(true))

localStorage

可以在瀏覽器存資料的方式,類似cookies。

  • 字串:可以存字串,讀取出來也是字串
  • 數字:可以存數字,但讀出來會變成字串
  • JSON:不能直接存JSON,要轉成string再存,讀出來也是字串化的JSON
const testJSON={
  color: 'red',
  count: 3,
  food: 'apple'
}

//寫localStorage一定要這樣寫,不能寫成localStorage.fruit
//要先轉成string後再存
localStorage['fruit']=JSON.stringify(testJSON);

//讀取
console.log(localStorage['fruit']) 
//"{"color":"red","count":3,"food":"apple"}"

//再轉成JSON繼續使用
console.log(JSON.parse(localStorage['fruit']))
//{color: 'red', count: 3, food: 'apple'}

closest

往parent找最近的元素。
children, sibling, parent’s sibling 都不會找到。

用法

<h1>我是標題</h1>
<table>
  <tbody>
    <tr id="myTr">
      <td>測試資料</td>
    </tr>
    <tr>
      <td>測試資料</td>
    </tr>
  </tbody>
</table>
myTr.closest('table') //回傳table這個元素
myTr.closest('td') //null //無法尋找子層
myTr.closest('tr') //null //無法尋找兄弟層
myTr.closest('h1') //null //無法尋找父層的兄弟

列印CSS

@media print指定於列印時觸發的CSS。

※chrome debug方法:
More tools→Rendering→Emulate CSS media→print

指定頁碼

@page {
  @bottom-center {
    content: "第" counter(page) "頁";
  }
}

列印邊界

使用@page可以指定預設列印邊界。但使用者仍可透過自訂列印邊界改掉它

@page {
  margin-bottom: 10mm;
}

Boostrap

Bootstrap內建有列印後隱藏的class

<div class="hidden-print">這段文字會被隱藏</div>

print()事件

print()事件可以呼叫列印行為

window.print()

元素位置與座標

clientHeight / clientWidth

※inline元素會回傳0
回傳的寬 / 高,不包含border, margin, scrollbar的width

offsetHeight / offsetWidth

※inline元素會回傳0
回傳的寬 / 高,不包含margin,會包含border, scrollbar的width

scrollHeight / scrollWidth

有scrollbar時:回傳被隱藏的內容的高 / 寬,不包含border, margin
無scrollbar時:scrollHeight == clientHeight

clientTop

元素內層與外層之間的距離 (就是border的寬度)

offsetTop

元素到網頁最上方的距離(越過瀏覽器視窗,到body最上面)

scrollTop

回傳元素捲了多少px
元素捲到最底部時:scrollTop + clientHeight = scrollHeight

getBoundingClientRect()

回傳値包含小數點,client三兄弟只能回傳整數
回傳目標元素到可視範圍之間的距離
※iOS Safari等手機瀏覽器,網址bar會時而隱藏時而浮出,會導致數值變來變去

用法:#element.getBoundingClientRect().top

※注意
在mobile裝置上使用getBoundingClientRect()時
需與scrollX / scrollY併用
因為,手機瀏覽器的網址列,有時會浮出,有時會消失。
getBoundingClientRect()不會計算到這個情況

參考文章:http://uhyo.hatenablog.com/entry/2017/03/15/130825

function getAbsolutePosition(elm){
  const {left, top} = elm.getBoundingClientRect();
  return {
    left: left + window.scrollX,
    top: top + window.scrollY,
  };
}

pointer-events: none

目的

讓元素可以被穿透

.box
 .back
 .front 
  |hover
  br
  |me
.box
 width: 300px
 height: 300px
 position: relative
 
.back
 background-color: teal
 width: 100px
 height: 100px
 &:hover
  background-color: darkgreen
 
 
.front
 background-color: skyblue
 width: 100px
 height: 100px
 position: absolute
 top: 0
 left: 50px
 opacity: 0.5
 pointer-events: none

Display

.
hover
me

【JavaScript】Item Picker

結構

  • 用select標籤做items,size的值給大一點讓item-box可以變長
  • 已選取item的背景色要用線性漸層
  • #mySelect.options[i] 可以回傳#mySelect的第i個選項
  • #mySelect.selectedIndex可以回傳目前被選取的序列
table.item-picker
 tr
  th 未加入功能清單
  th
  th 已加入功能清單
 tr
  td
   select(size="6" name="source1").pick-list
    option(value="0") 平台資訊審核
    option(value="1") 手續費審核
    option(value="2") 使用者管理
    option(value="3") 角色管理
  td
   button.add →
   br
   button.delete ←
  td
   select(size="6" name="target1").pick-list
    option(value="4") 平台資訊設定
    option(value="5") 手續費設定
    option(value="6") 顧客約定管理
$dark: #439E96
$turquoise: #50BBB6
$light: #E7F2F1
$black: #596D6C
$gray: #CCE0DE

*
 // border: 1px solid #000

// .iten-picker
//  overflow: auto
 
.add,.deduct
 display: block


 
table
 margin-top: 100px
 margin-right: auto
 margin-left: auto
 text-align: center
 
th
 color: $turquoise
 font-size: 16px
td
 select
  width: 150px
  font-size: 14px
  color: $black
  border-radius: 3px
  border-style: dashed
  &:focus
   outline: none
   box-shadow: 0px 1px 10px 0px #cce0de
  option
   padding: 2px 10px
   transition: color 0.5s
   &:checked
    background: $gray linear-gradient(0deg, $gray 0%, $gray 100%)
   &:hover
    color: $turquoise
  &:focus
   option
    &:checked
     background: $turquoise linear-gradient($turquoise 0%, $turquoise 100%)
     color: #fff
    
button
 transition-duration: 0.5s
 height: 30px
 width: 30px
 border-radius: 100%
 text-align: center
 border-color: $gray
 color: $turquoise
 outline: none
 
 &:hover
  background-color: $turquoise
  color: #fff
  border-color: $turquoise
const sourceItem=document.querySelector("select[name='source1']");
const targetItem=document.querySelector("select[name='target1']");
const addbtn=document.querySelector(".add");
const deletebtn=document.querySelector(".delete");

addbtn.addEventListener("click", function(){
 const theItem=sourceItem.options[sourceItem.selectedIndex]
 if(theItem){
  sourceItem.removeChild(theItem);
  targetItem.appendChild(theItem);
 }
 
});

deletebtn.addEventListener("click", function(){
 // targetItem.focus();
 const theItem=targetItem.options[targetItem.selectedIndex]
 if(theItem){
   targetItem.removeChild(theItem);
   sourceItem.appendChild(theItem);
 }

 
});

Display

CODEPEN

【CSS】px to rem

px rem
10px 0.625rem
11px 0.6875rem
12px 0.75rem
13px 0.8125rem
14px 0.875rem
15px 0.9375rem
16px 1rem
17px 1.0625rem
18px 1.125rem
19px 1.1875rem
20px 1.25rem
21px 1.3125rem
22px 1.375rem
23px 1.4375rem
24px 1.5rem
25px 1.5625rem
26px 1.625rem
27px 1.6875rem
28px 1.75rem
29px 1.8125rem
30px 1.875rem
31px 1.9375rem
32px 2rem
33px 2.0625rem
34px 2.125rem
35px 2.1875rem
36px 2.25rem
37px 2.3125rem
38px 2.375rem
39px 2.4375rem
40px 2.5rem
41px 2.5625rem
42px 2.625rem
43px 2.6875rem
44px 2.75rem
45px 2.8125rem
46px 2.875rem
47px 2.9375rem
48px 3rem
49px 3.0625rem
50px 3.125rem
51px 3.1875rem
52px 3.25rem
53px 3.3125rem
54px 3.375rem
55px 3.4375rem
56px 3.5rem
57px 3.5625rem
58px 3.625rem
59px 3.6875rem
60px 3.75rem
61px 3.8125rem
62px 3.875rem
63px 3.9375rem
64px 4rem

【Angular】service引入外部資料

外部資料檔案與接口

  • 建立mock-members.ts
import { Member } from './member';

//外部からアクセルできるようにexport
export const MEMBERS: Member[] = [
  {id: 11, name: '武山学'},
  {id: 12, name: '初音ミク'},
  {id: 13, name: '桐山零'},
  {id: 14, name: '三角竜之'},
  {id: 15, name: '羽生結弦'},
  {id: 16, name: '佐々木希'},
  {id: 17, name: '松崎はとり'},
  {id: 18, name: '半沢直樹'},
  {id: 19, name: '伊藤幸'},
  {id: 20, name: '桜田深雪'}
];
  • 建立member.service.ts
import { Injectable } from '@angular/core';
import { Member } from './member';
import { MEMBERS } from './mock-members';

//Componentから読み込むことをできるため、@Injectableを使う
@Injectable()
export class MemberService {
  //プロパティーやメソッドを定義する
  getMembers(): Member[]{
    return MEMBERS;
  }
}
//serviceで共通化の処理をできる。各ComponentからこのServiceを読み込むことで共通化を実現する

修改app.component.ts

import { Component } from '@angular/core';
import { Member } from './member';
import { MemberService } from './member.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  providers: [ MemberService ]
  //app.componentでMemberServiceを使うという宣言
})

// プロパティーを定義する
export class AppComponent  {
  title='自社社員名簿';
  members: Member[]; 
  // Member型の配列にする
  selectedMember: Member;

  //AppComponentでMemberServiceを利用することができます
  constructor(private memberService: MemberService){
    // this.memberService = memberService;
    // 暗黙的に代入されます
  }
  //上記引用方法はDependency Injection(DI)です
  
  onSelected(member: Member): void {
    this.selectedMember=member;
  }

 //追加したMemberServiceを実行するメソッドを定義
  getMembers(): void {
    this.members=this.memberService.getMembers();
  }
}

Life Cycle

Life Cycle: 當元件被建構出來時、元件資料被變更時、元件被移除時會執行的callback

利用Life Cycle,當元件資料變更時呼叫service的getMembers()

引入interface、並執行在class上

import { Component, OnInit } from '@angular/core';

//...

export class AppComponent implements OnInit {

//...
//constructor( ...

ngOnInit():void {
    //constructorが実行された後、初期化時に呼ばれるcallback
    this.getMembers();
  }

【Angular】分割元件

定義元件

  • 在app資料夾建立新檔案,檔名為「member-detail.component.ts」
  • 在member-detail.component.ts新增以下內容
import {Component} from '@angular/core';
//angular coreからComponentというモジュールをインポートします

//Componentのメタデータを定義する
//<member-detail></member-detail>として使います
@Component({
  selector: 'member-detail',
  templateUrl: './member-detail.component.html' 
})
// ※@Component裡面不能放註解否則會壞掉
//HTMLテンプレートを定義する


export class MemberDetailComponent {

}

建立共用Class(將Class獨立出來)

  • 新增member.ts檔案
  • 在member.ts新增以下內容
export class Member {
  id: number;
  name: string;
}
//クラスをpublicにする
  • 在member-detail.component.ts的第二行新增以下內容,引入member.ts
import {Member} from './member';

引入外部Property

使用input。修改member-detail.component.ts為以下內容

import { Component, Input } from '@angular/core'; //データを渡す
//Input は外部のデータを参照するためのモジュールです
import { Member } from './member';

//<member-detail [member]="selectedHero"></member-detail>として使います
@Component({
  selector: 'member-detail',
  templateUrl: './member-detail.component.html'
})

export class MemberDetailComponent {
  //memberというプロパティーを定義、型をMemberに指定
  @Input() member: Member;
}

app.module.ts 新增以下內容

import { MemberDetailComponent } from './member-detail.component';
//引入MemberDetailComponent
declarations: [ ..., ..., MemberDetailComponent ],
//declarations也新增MemberDetailComponent

app.component.html最後一行新增以下內容

<member-detail [member]="selectedMember"></member-detail>

【Angular】事件綁定與ngIf

基本用法

<li (click)="onSelected(member)">
  • onclik → onclick事件
  • onSelected(member) → 綁定的handler函數,定義會寫在app.component.ts

Typescript定義

export class Member {
  id: number;
  name: string;
}

//Member クラスのようにプロパティーを強制する
const MEMBERS: Member[] = [
  {id: 11, name: '武山学'},
  {id: 12, name: '初音ミク'},
  {id: 13, name: '桐山零'},
  {id: 14, name: '三角竜之'},
  {id: 15, name: '羽生結弦'},
  {id: 16, name: '佐々木希'},
  {id: 17, name: '松崎はとり'},
  {id: 18, name: '半沢直樹'},
  {id: 19, name: '伊藤幸'},
  {id: 20, name: '桜田深雪'}
];

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})


export class AppComponent  {
  title='自社社員名簿';
  members = MEMBERS; 
  // 選択している社員を保存するため、保存用のプロパティーを定義する
  selectedMember: Member;
  // selectedMember只有在onselected觸發後,才會有值。一開始的時候沒有值
  onSelected(member: Member): void {
    this.selectedMember=member;
  }
}

HTML模板與Ngif

<h1>{{title}}</h1>
<h2>社員一覧</h2>

<ul class="members">
<!-- クリックイベントを設定する -->
  <li *ngFor="let member of members" (click)="onSelected(member)">
    <spanclass="badge">{{member.id}}</span>
    {{member.name}}
  </li>
</ul>
<!-- selectedMemberがまだ選択されてない時はエラーになる -->
<!-- selectedMemberがまだ選択された時のみ、以下のHTMLを表示する -->
<div *ngIf="selectedMember">
<!-- selectedMemberの値がある場合、コンテンツを表示する -->
  <h2>{{selectedMember.name}}</h2>
  <div>
    <label>id: </label>{{selectedMember.id}}
  </div>
  <div>
    <label>name: </label>
    <input type="text" [(ngModel)]="selectedMember.name"placeholder="名前">
  </div>
</div>

屬性綁定

當onclick觸發事件後,綁定class在元素上


<h1>{{title}}</h1>
<h2>社員一覧</h2>

<ul cl
ass="members">
<!-- クリックイベントを設定する -->
<li *ngFor="let member of members" (click)="onSelected(member)" [class.selected]="member === selectedMember">
<!-- []に書かれたものはHTMLの属性値の指定 -->
<!-- class名を指定しています。class="selected"を追加するための書き方 -->
<!-- ngForで回しているmember変数を、選択済みのselectedMemberになる時、class="selected"を追加する -->
<spanclass="badge">{{member.id}}</span>
{{member.name}}
</li>
</ul>
<div *ngIf="selectedMember">
<h2>{{selectedMember.name}}</h2>
<div>
<label>id: </label>{{selectedMember.id}}
</div>
<div>
<label>name: </label>
<inputtype="text" [(ngModel)]="selectedMember.name"placeholder="名前">
</div>
</div>

【Angular】Ngfor 迴圈

用途

可以迴圈生成HTML片段

物件設定

export class Member {
  id: number;
  name: string;
}

//Member クラスのようにプロパティーを強制する
const MEMBERS: Member[] = [
  {id: 11, name: '武山学'},
  {id: 12, name: '初音ミク'},
  {id: 13, name: '桐山零'},
  {id: 14, name: '三角竜之'},
  {id: 15, name: '羽生結弦'},
  {id: 16, name: '佐々木希'},
  {id: 17, name: '松崎はとり'},
  {id: 18, name: '半沢直樹'},
  {id: 19, name: '伊藤幸'},
  {id: 20, name: '桜田深雪'}
];

//資料的設定一定要在@Component上方,否則會噴錯
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})


// プロパティーを定義する
export class AppComponent  {
  title='自社社員名簿';
  members = MEMBERS; 
  
}

HTML模板

ngFor語法:let <自定義的名稱(可自訂)> of <變數名(固定)>

<h1>{{title}}</h1>
<h2>社員一覧</h2>
<ul>
  <li *ngFor="let member of members">
    <spanclass="badge">{{member.id}}</span>
    {{member.name}}
  </li>
</ul>

【Angular】雙向綁定

意涵

input元素⇄JS物件

  • input元素的值會由JS物件決定
  • 當input發生輸入,新的值會重設JS物件的值

定義Property

export class Member {
  id: number;
  name: string;
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})

// プロパティーを定義する
export class AppComponent  {
  title='自社社員名簿';
  // クラスを型として指定。IDとnameのプロパティーをオブジェクトに強制したい
  member: Member={
    id: 1,
    name: '山田太郎'
  }
}

設定HTML模板

<h1>{{title}}</h1>
<h2>{{member.name}}</h2>
<div>
  <label>id: </label>
  <span>{{member.id}}</span>
</div>
<div>
  <label>name: </label>
  <!-- <span>{{member.name}}</span> -->
  <!-- 雙向綁定 -->
  <input type="text" [(ngModel)]="member.name"placeholder="名前" />
</div>

Ng Model設定

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
//moduleを追加
import {FormsModule} from '@angular/forms';

import { AppComponent }  from './app.component';

@NgModule({
    imports:      [ 
        //FormsModuleを配列に追加
        BrowserModule, 
        FormsModule 
    ],
    declarations: [ 
        AppComponent 
    ],
    bootstrap:    [ 
        AppComponent 
    ]
  })
export class AppModule { }

【TypeScript】interface

用法

interface(接口),可以強制定義class的屬性名稱,數量,型別

定義class

//インターフェイスは定義だけで実装がない、クラスのようなものですものです
//クラスに特定な機能を実装を強制する目的で利用されます

interface Animal {
    name: string;//「name」というプロパティーをクラスに強制する
    legs: number;
    isCry: boolean; 
    cry(): void;
}


class Dog implements Animal {
    name: string='Maru';
    legs: number=4;
    isCry: boolean=true;
    cry(): void{
        if (this.isCry) {
            console.log('bow, wow!');
        }
    }
}

定義物件

interface Animal {
    name: string;
    legs: number;
    isCry: boolean; 
    cry(): void;
}

let Dog: Animal {
    name: 'Maru',
    legs: 4,
    isCry: true,
    cry() {
        console.log('bow, wow!');
    }
}

類似的方法

當覺得不需要使用interface小題大作,卻又想強制定義屬性時,可以使用以下的方法

let Dog: { name: string, legs: number } = {
 name: 'Maru',
 legs: 4,
}

【TypeScript】Generics 泛型

用法

透過參數客製化class,是TypeScript獨有的機能

傳統的寫法

class NumberStore{
    data: number;
}

class StringStore{
    data: string;
}

//型チェックができません
class AnyStore{
    data: any
}

使用泛型的寫法

//Tという文字は自由に名付けられる
class Store<T>{
    data: T;
    getStore(): T{
        return this.data;
    }
}

let stringStore=new Store();
stringStore.data = 'X';
console.log(stringStore.getStore()); //'X'

let numberStore = new Store();
numberStore.data = 100000;
console.log(numberStore.getStore()); //100000

函數的泛型

function hello<T>(keyword: T) {
 console.log(`Log: ${keyword}`);
}

hello<string>('Hello Ian!'); //'Log: Hello Ian!'
hello<number>(1000000000);//'Log: Hello 1000000000'

指定2個以上的泛型參數

class Component<T, U>{
    name: T;
    created: U;
}

let component = new Component<string, number>();
component.name = 'app';
component.created = Date.now();

【JavaScript】getter / setter

getter跟setter都是寫在物件底下的function方法

getter

給物件綁定訪問時(Access)可取得的函數

var obj = {
 log: ['example','test'],
 get latest() {
 if (this.log.length == 0) {
   return undefined;
  }else{
   return this.log[this.log.length - 1];
  }
 }
}

console.log(obj.log); //['example', 'test']
console.log(obj.latest); // "test"

setter

setter可以設定參數,然後讓物件回傳不同的值

//language 是一個物件
var language = {
  set current(name) {
    this.log.push(name);
  },
  log: []
}

language.current = 'EN'; //透過setter設定參數
console.log(language.log); // ['EN']

language.current = 'FA'; //透過setter設定參數
console.log(language.log); // ['EN', 'FA']

【WordPress】常用函數

bloginfo:網站的各項重要資料

 變數  意義
 bloginfo(‘name’)  網站名
 bloginfo(‘url’)  網址
 bloginfo(‘charset’)  網址
 bloginfo(‘description’)  網站描述
 bloginfo(‘stylesheet_url’)  style.css 檔案所在的路徑

wp_title() 網站當前頁面名稱

其他

 變數  意義
 language_attributes()  網站語系
 is_home()

post相關函數

※的函數需要在the_post()的底下才能作用

 變數  意義
 have_post()  回傳目前有沒有文章 回傳值:true / false
 the_post()  處理一件文章
 ※the_title()  文章標題
 ※the_permalink()  文章網址
 ※the_category(“, “)  顯示分類,各分類之間用「, 」分隔
 ※the_author()  顯示作者
 ※comments_popup_link (“無留言時”,  “一則留言時”, “多留言時”) 當跳出留言的功能啟動的話,導入留言視窗 若無啟動留言功能,則不顯示
 ※edit_post_link(“編輯連結的標題”, ” 標題前的字符”, ” 標題後的字符”) 以管理員或作者身分登入時才顯示。顯示一個可以用來編輯當前文章的編輯連結
 ※the_ID() 導入每篇文章的 ID

_e(“字串”)

讓中間的字串支援多國語系翻譯

posts_nav_link()

若超過10篇文章,則顯示分頁連結
posts_nav_link(“中間的字符”, “往前的文字”, “往後的文字”)

wp_list_cats()

文章分類顯示函數,裡面需填入字串。參數之間用【&】連結

  • sort_column=name→分類按字符順序排列
  • optioncount=1→顯示每個分類含有的文章數
  • hierarchial=0→不按照層式結構顯示子分類

 

 

 

 

【Angular】TypeScript class

用法

  • 列別名稱通常用「大駝峰式命名」
  • 函數與變數通常用「小駝峰式命名」
class 類別名 {
    訪問修飾符 屬性名: 型別=値;

    constructor(參數: 型別) {
        this.屬性名2='屬性名2'; //這行可以透過private 建構子參數省略不寫
    }

    函數(參數: 型別): 回傳値型別{
        console.log(this.屬性名='屬性名');
    }
}

訪問修飾符的種類

  1. public
    外部可存取,無指定訪問修飾符時為default設定
  2. protected
    原生類別或派生類別可存取
  3. private
    僅限原生類別可存取

※TypeScript最終還是JavaScript,指定訪問修飾符可以讓開發時檢查程式碼,如果硬要無視他,仍然可以執行。

範例

//定義類別
class Animal { 

    // 屬性名
    age: number = 10;

    // 建構子
    constructor(private isCry: boolean, private legs: number) {
        //這邊參數用private代表默認代入↓
        //this.isCry=isCry;
    }

    // 函數
    cry(): void {
        if (this.isCry) { 
            console.log(`legs: ${this.legs}`)
        }
    }

}

//使用類別
let dog = new Animal(true, 4);
//因為有定義函數
dog.cry(); //'legs: 4';

getter / setter

class Animal {
    private _age: number = 10;

    //取得上方private _age的值
    get age(): number {
        //除了取得值以外也可以進行處理
        // console.log(this._age);

        return this._age;
    }

    //要用跟getter相同的method名
    set age(value: number) {
        //除了取得值以外也可以進行處理
        // console.log(this._age);

        if (value < 0) { throw new Error('age cannot > 10')
        }
        this._age = value; //設定_age的值
    }
}

let dog = new Animal();
console.log(dog.age); //dog.age=10;
dog.age = 11; //set dog.age=11;

繼承

以舊有class為基礎,定義新的class

建構新的Method

class Animal{
    age: number = 10;

    constructor(private isCry: boolean, private legs: number) {
        
    }

    cry(): void {
        if(this.isCry) {
            alert('legs: ' + this.legs);
        }
    }
}

// あるクラスを基に別のクラスを定義することは継承と言います
// Animalクラスを継承してしてDogクラスを定義する
class Dog extends Animal {
    cry(): void {
        if (this.isCry) {
            alert('bow, wow!');
        }
    }
}

let dog = new Dog(true, 4);
dog.cry();

沿用舊有Method

class Animal{
    age: number = 10;

    constructor(private isCry: boolean, private legs: number) {
        
    }

    cry(): void {
        if(this.isCry) {
            alert('legs: ' + this.legs);
        }
    }
}

class Dog extends Animal {

    // constructor() {
           //也可以用super定義constructor的繼承
    //     super();
    // }

    cry(): void {

        // 親のクラスにアクセスためのOBJです
        super.cry();
        //処理を追加することも可能です
        console.log('hello!');
    }
}

let dog = new Dog(true, 4);
dog.cry();

 

 

【CSS】Color Name

REF: W3Schools

Color Name HEX Display
White #FFFFFF
Ivory #FFFFF0
LightYellow #FFFFE0
Yellow #FFFF00
Snow #FFFAFA
FloralWhite #FFFAF0
LemonChiffon #FFFACD
Cornsilk #FFF8DC
SeaShell #FFF5EE
LavenderBlush #FFF0F5
PapayaWhip #FFEFD5
BlanchedAlmond #FFEBCD
MistyRose #FFE4E1
Bisque #FFE4C4
Moccasin #FFE4B5
NavajoWhite #FFDEAD
PeachPuff #FFDAB9
Gold #FFD700
Pink #FFC0CB
LightPink #FFB6C1
Orange #FFA500
LightSalmon #FFA07A
DarkOrange #FF8C00
Coral #FF7F50
HotPink #FF69B4
Tomato #FF6347
OrangeRed #FF4500
DeepPink #FF1493
Fuchsia #FF00FF
Magenta #FF00FF
Red #FF0000
OldLace #FDF5E6
LightGoldenRodYellow #FAFAD2
Linen #FAF0E6
AntiqueWhite #FAEBD7
Salmon #FA8072
GhostWhite #F8F8FF
MintCream #F5FFFA
WhiteSmoke #F5F5F5
Beige #F5F5DC
Wheat #F5DEB3
SandyBrown #F4A460
Azure #F0FFFF
HoneyDew #F0FFF0
AliceBlue #F0F8FF
Khaki #F0E68C
LightCoral #F08080
PaleGoldenRod #EEE8AA
Violet #EE82EE
DarkSalmon #E9967A
Lavender #E6E6FA
LightCyan #E0FFFF
BurlyWood #DEB887
Plum #DDA0DD
Gainsboro #DCDCDC
Crimson #DC143C
PaleVioletRed #DB7093
GoldenRod #DAA520
Orchid #DA70D6
Thistle #D8BFD8
LightGray #D3D3D3
LightGrey #D3D3D3
Tan #D2B48C
Chocolate #D2691E
Peru #CD853F
IndianRed #CD5C5C
MediumVioletRed #C71585
Silver #C0C0C0
DarkKhaki #BDB76B
RosyBrown #BC8F8F
MediumOrchid #BA55D3
DarkGoldenRod #B8860B
FireBrick #B22222
PowderBlue #B0E0E6
LightSteelBlue #B0C4DE
PaleTurquoise #AFEEEE
GreenYellow #ADFF2F
LightBlue #ADD8E6
DarkGray #A9A9A9
DarkGrey #A9A9A9
Brown #A52A2A
Sienna #A0522D
YellowGreen #9ACD32
DarkOrchid #9932CC
PaleGreen #98FB98
DarkViolet #9400D3
MediumPurple #9370DB
LightGreen #90EE90
DarkSeaGreen #8FBC8F
SaddleBrown #8B4513
DarkMagenta #8B008B
DarkRed #8B0000
BlueViolet #8A2BE2
LightSkyBlue #87CEFA
SkyBlue #87CEEB
Gray #808080
Grey #808080
Olive #808000
Purple #800080
Maroon #800000
Aquamarine #7FFFD4
Chartreuse #7FFF00
LawnGreen #7CFC00
MediumSlateBlue #7B68EE
LightSlateGray #778899
LightSlateGrey #778899
SlateGray #708090
SlateGrey #708090
OliveDrab #6B8E23
SlateBlue #6A5ACD
DimGray #696969
DimGrey #696969
MediumAquaMarine #66CDAA
RebeccaPurple #663399
CornflowerBlue #6495ED
CadetBlue #5F9EA0
DarkOliveGreen #556B2F
Indigo #4B0082
MediumTurquoise #48D1CC
DarkSlateBlue #483D8B
SteelBlue #4682B4
RoyalBlue #4169E1
Turquoise #40E0D0
MediumSeaGreen #3CB371
LimeGreen #32CD32
DarkSlateGray #2F4F4F
DarkSlateGrey #2F4F4F
SeaGreen #2E8B57
ForestGreen #228B22
LightSeaGreen #20B2AA
DodgerBlue #1E90FF
MidnightBlue #191970
Aqua #00FFFF
Cyan #00FFFF
SpringGreen #00FF7F
Lime #00FF00
MediumSpringGreen #00FA9A
DarkTurquoise #00CED1
DeepSkyBlue #00BFFF
DarkCyan #008B8B
Teal #008080
Green #008000
DarkGreen #006400
Blue #0000FF
MediumBlue #0000CD
DarkBlue #00008B
Navy #000080
Black #000000

【CSS】outline

説明

outline位在border外面

.box
.box
 width: 300px
 height: 200px
 background-color: mistyrose
 border: 2px solid hotpink
 outline: 1px solid red

Display

.

FireFox的outline bug

如果裡面的東西超出box的話,outline也會被撐開
※其他瀏覽器不會有這個問題

.box
 .inner
.box
 width: 300px
 height: 200px
 background-color: mistyrose
 border: 2px solid hotpink
 outline: 1px solid red

.inner
 background-color: moccasin
 height: 300px
 width: 100px 

Display

解決方法

改用box-shadow做出outline的效果

.box
 .inner
.box
 width: 300px
 height: 200px
 background-color: mistyrose
 border: 2px solid hotpink
 // outline: 1px solid red
 box-shadow: 0 0 0 1px red
 
.inner
 background-color: moccasin
 height: 300px
 width: 100px

Display

.

【JavaScript】select元素相關操作

#mySelect.options

回傳選項清單

select#mySelect
 option apple
 option banana
 option grape
console.log(mySelect.options)
//回傳所有options的集合
//型態為HTMLOptionsCollection

#mySelect.selectedIndex

回傳目前被選取到的index

select#mySelect
 option apple
 option banana
 option grape
console.log(mySelect.selectedIndex)
//0

【Angular】TypeScript 函式與參數

參數與回傳値的型別定義

TypeScript的函式寫法有以下需求

  1. 必須指定參數型別
  2. 必須指定回傳値型別
function hello(name: string, number: number): string{ //這邊指定回傳值型別
 return `hello ${name} and ${number}`;
}

console.log(hello("blank", 100)); //hello blank and 100

如果函式沒有回傳値的話,回傳値的型別為「void」

function hello(name: string): void{
 return `hello ${name}`;
}

console.log(hello("blank")); //hello blank

省略指定參數

參數的冒號「:」前面加問號「?」表示這個參數可以省略

function hello(name?: string): string{
    return `hello ${name}`;
}

console.log(hello()); //hello undefine
//如果沒有設問號的話,使用hello()時,括號裡面一定要放參數。直接使用hello()的話會造成錯誤。

函式內定義參數

可以在定義函式時就指定好參數內容

function hello(name: string = 'Taro'): string{
    return `hello ${name}`;
}

console.log(hello()); //hello Taro

指定複數參數

參數前面多加「…」就可以指定數個同類型的參數

function sum(...values: number[]) { 
    let total = 0;
    for (let i: number = 0; i < values.length; i++) { 
        total += values[i];
    }

    return total;
}

console.log(sum(10, 100, 10000, 100000)); //110110

 

【Angular】TypeScript型別宣告

説明

宣告字串

var title: string = 'Angular';
//title = 10000 ←不可以把變數的型態改成數值

title = 'Angular4'; //如果用var宣告的話就可以改變文字內容

宣告數值

var num: number = 9;

宣告布林值

var isOpen: boolean = true;

宣告陣列

文字陣列

var array: string[] = ['name', 'email', 'body'];

數字陣列

var numbers: number[] = [1, 5, 7];

混合陣列

var data: [number, string, number] = [0, 'apple', 99]

宣告物件

var options: { [key: string]: string; } = {name: 'gggg'} 
//key可以自己換別的字

宣告任意型別

任意型別類似JavaScript的一般變數,宣告後可以改變他的型別。

var something: any = 'go'; //最初宣告為任意型別,給定型別為字串

something = 2000; //改變型別為數值
something = false; //改變型別為布林值

用了any的話,型別就不會被檢查。所以一般推薦少用為妙。

不給定型別也可以

不給型別的話,TypeScript會自己辨認型別。

var aaa = "string";

//aaa = 1000 //還是不能更動型別,所以這樣會error

宣告複數型別

var sample: string | number;

sample = "aaaaa";
sample = 100000; //這個變數可以代入字串或數值

型別轉換

function log(message: string) { 
 return `text content is ${message}`
}

log('ggg') //text content is ggg;

//轉換參數型別為任意型別
log(<any>1000); //text content is 1000

【Angular v4】環境架設

下載檔案

  1. Angular quickstart
  2. node.js

環境建置

  1. 安裝node.js
  2. 解壓縮quickstart
  3. 依序輸入這3個指令
    cd 指向quickstart路徑
    npm install
    npm start

檔案編輯

  • app/component.ts→定義元件
  • index.html→定義首頁
  • main.ts→啟動Web APP
  • style.css→定義全體Web APP的樣式

編輯元件

打開app/component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
   <h1>Hello {{name}}</h1> //變數用2個大括弧包起來
   <h2>text</h2>
  `,
  styles: [` //撰寫style
   h1 {
    color: red;
  }
  h2 {
    color: bluec;
   }
 `]
})

export class AppComponent{ 
 name = 'Fist Angular Application'; //定義變數內容 
}

【JavaScript】假的scroll-bar

步驟

  1. 隱藏原生的scroll-bar
  2. 用CSS做出一個假的bar
  3. 算出scroll-bar的長度
  4. 當發生滑動時,改變bar的top

隱藏原生的scroll-bar

  • 外層定義一個box,裡面要有假的bar與內容wrapper
  • 外層box設overflow: hidden
  • 內層wrapper設padding-left,這樣真正的scroll-bar就會超出外層box而被卡掉
.box#box
 .scroll-bar#bar
 .wrapper#wrapper
 img.items#items(src="https://ianchen.thisistap.com/wp-content/uploads/OOD.jpg" width="300px")
.box
 border: 1px solid #000
 width: 300px
 height: 300px
 overflow: hidden
  
.wrapper
 width: 100%
 height: 100%
 overflow-y: scroll
 padding-right: 28px

Display

用CSS做出一個假的bar

利用絕對定位將假bar定位在box的右上方

.box#box
 .scroll-bar#bar
 .wrapper#wrapper
.box
 border: 1px solid #000
 width: 300px
 height: 300px
 overflow: hidden
 position: relative
  
.wrapper
 width: 100%
 height: 100%
 overflow-y: scroll
 padding-right: 28px

.scroll-bar
 width: 8px
 height: 84px
 border-radius: 30px
 background-color: #7F7F7F
 position: absolute
 top: 0px
 right: 2.5px

Display

.

算出scroll-bar的長度

scroll-bar的兩種可能性

  1. 內容items的高度 小於 外層box的高度→不會出現scroll-bar
  2. 內容items的高度 大於 外層box的高度→出現scroll-bar
    scroll-bar的長度公式:外層box高度×(外層box高度÷內容items高度)
window.addEventListener("load", function(){
 
 if(items.clientHeight>=box.clientHeight){
  bar.style.display="none"; //如果內容items高度小於外層box,隱藏scroll-bar
 }else{
  bar.style.height=box.clientHeight * (box.clientHeight / items.clientHeight) + "px";
  //外層box高度×(外層box高度÷內容items高度)
 }
 
})

當發生滑動時,改變bar的top

  1. 當內容wrapper發生滑動→scroll事件
  2. 改變bar的top值→但是top值的MAX不是100
    計算top值的公式:目前items可視範圍離外層wrapper有多遠÷(items高度−wrapper高度)×(wrapper高度−bar高度)

 

 

 

customize scroll-bar

scrollbar height =
box.clientHeight * (box.clientHeight / content.offsetHeight)

【JavaScript】requestAnimationFrame

功能

楨率高的動畫函數。
setInterval最小時間單位是1毫秒,如果需要短時間大幅度的動態效果,則setInterval會顯得吃力。
這時就可以使用requestAnimationFrame

解説

requestAnimationFrame的callback函數的【第一個參數】會變成時間戳(=記錄當下的時間)

requestAnimationFrame(step);

function step(ggg){
 console.log(ggg); //會回傳當下的時間,但只會回傳一次
}

如果想要讓時間戳一直回傳過來,就要在callback函式裡面呼叫requestAnimationFrame

requestAnimationFrame(step);

function step(ggg){
 console.log(ggg);
 
 requestAnimationFrame(step); //會一直回傳時間戳過來
}

動畫的概念:

  1. 定義初始時間値,與變動時間値
  2. 紀錄毎次變動時間 減去 初始時間的相差値
  3. 相差値會越來越大
    requestAnimationFrame(step);
    
    //定義初始時間値
    let start=null;
    
    function step(ggg){
     if(start==null){
      start=ggg; //在一開始的時候帶入時間初始値
     }
     let passed=ggg-start; //算出現在時間與初始時間的相差値
     console.log(start); //會回傳初始時間値
     console.log(passed); //會回傳經過的時間
     requestAnimationFrame(step);
    }
  4. 用這個相差値帶入style的參數,就可以做出動態效果
    button(onclick="requestAnimationFrame(step)") click me
    #animatebox
    #animatebox
     width: 300px
     height: 200px
     background-color: teal
     opacity: 0
    let start=null;
    
    function step(ggg){
     if(start==null){
      start=ggg;
     }
     let passed=(ggg-start)/1000; //透明的値是0~1,用除數把數値縮小
     console.log(passed);
     
     animatebox.style.opacity=passed;
     
     if(passed<1){
      requestAnimationFrame(step); //如果透明値大於1停止動畫
     }
     
    }

範例

【JavaScript】event.target

説明

配合click / mouserover事件使用,指出目前的target元素

.outer(onclick="action()")
 .inner
 span click me
.outer
 background-color: #eee
 width: 200px
 height: 40px
 text-align: center
 .inner
 line-height: 40px
 display: inline-block
function action(){
 console.log(event.target);
}

應用例:收合選單

如果選單的標題與內容不小心寫在同一層級,
事件又想要綁在最外層的元素,
可以配合contains鎖定事件觸發的目標。

ul
 li(onclick="show(this)")
 .title 第一層選單 click me
 .content 這是第一層選單的內容
 br
 |內容...
 br
 |內容...
 br
 |內容...
 li(onclick="show(this)")
 .title 第二層選單 click me
 .content 這是第二層選單的內容
 br
 |內容...
 br
 |內容...
 br
 |內容...
ul
 display: inline-block
li
 list-style: none
 background-color: LightCyan 
 color: teal
 .title
 padding: 5px 10px
 .content
 background-color: Teal
 color: #fff
 padding: 5px 10px
 display: none
 .content.show
 display: block
function show(th){
 if(event.target.classList.contains("title")){
 th.children[1].classList.toggle("show");
 }
}

Display

  • 第一層選單 click me
    這是第一層選單的內容
    內容…
    內容…
    內容…
  • 第二層選單 click me
    這是第二層選單的內容
    內容…
    內容…
    內容…

【JavaScript】事件屬性的參數

説明

【事件屬性】
設定事件時,不使用事件綁定(addEventListener)
而將事件直接寫在tag的on事件屬性裡面

this的用法

  1. ATTR的括弧裡面要寫this(要寫完整的this,不能任意命名)
  2. function內要放第一個變數,變數名稱自定義,不能用this
.element(onclick="getAction(this)") click me
function getAction(th){
 console.log(th);
}

//"<div class='element' onclick='getAction(this)'>click me</div>"

※注意

如果在function裡面直接用this,會變成叫出window (global)

.element(onclick="getAction(this)") click me
function getAction(th){
 console.log(this);
}

//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}

event的用法

  1. function內直接用event就好
.element(onclick="getAction()") click me
function getAction(m){
 console.log(event);
}

//MouseEvent {isTrusted: true, screenX: 47, screenY: 162, clientX: 47, clientY: 65, …}

【JavaScript】customize select-picker

説明

利用JS與CSS,自定義select-picker的style

  1. 用<select>跟<option>做出真選單
  2. 隱藏掉<select>(隱藏真選單)
    〔JS部分〕
  3. 讀取真選單<select>的內容,抓到後會是NodeList形式,給它轉換成陣列
  4. 換成陣列後,用mapping method,填充成<li>option內容</li>的形式
  5. 做出一個假的option wrapper / open-bar,然後把<li>們放進去

範例

引用函式庫:FontAwesome

.selector
 select
 option 台灣
 option 香港
 option 柬埔寨
 option 越南
 option 緬甸
 option 澳洲
 option 美國
 option 中國
 option 澳洲
 option 法國
 option 印尼
 option 英國
br
br
.selector
 select
 option good
 option apple
 option orange
 option red
 option beauty
 option view
 option nonono
 option yes
 option nice
.selector
 select
  display: none
 
.select-picker
 .open-bar
  width: 190px
  height: 30px
  line-height: 30px
  padding-left: 10px
  border-radius: 3px
  border: 1px solid gray
  user-select: none
  &:after
   content: "\f0d7"
   font-family: "FontAwesome"
   float: right
   margin-right: 10px
 
 .items
  max-width: 650px
  display: none
  border: 1px solid #000
  padding: 15px
  margin: 0
  position: absolute
  z-index: 999
  background-color: #fff  

 .item
  width: 120px
  display: inline-block
  height: 25px
  list-style: none
  padding: 5px 15px
 
 .items.items-show
  display: block
  display: inline-block
  
 .item.item-active
  background-color: #eee 
const selector=document.querySelectorAll(".selector");

selector.forEach(wrapper => {
 
 const RawData=wrapper.querySelector("select");
 const options=Array.from(RawData.children).map((item, n) => `<li class="item" onclick="select(${n}, this)">${item.textContent}</li>`).join("");
 
 //Create Content
 wrapper.innerHTML+=
  `<div class="select-picker">
    <div class="open-bar" onclick="showBlock(this)">${RawData.options[RawData.selectedIndex].text}</div>
     <ul class="items">
     ${options}
     </ul>
   </div>
  </div>`;

 
});


function showBlock(e){
 e.parentNode.children[1].classList.toggle("items-show");
}


function select(index, ele){
 
 const RawData=ele.closest(".selector").children[0];
 const itemActive=ele.closest(".selector").querySelectorAll(".item-active");
 
 
 if(itemActive.length>0) {
  itemActive[0].classList.remove("item-active");
 }
 RawData.selectedIndex=index;
 ele.parentNode.parentNode.children[0].textContent=RawData.options[RawData.selectedIndex].innerHTML;
 ele.parentNode.classList.remove("items-show");
 ele.classList.add("item-active");
}

Display

【HTML】disabled

説明

disabled是input相關屬性,可以讓input的內容無法編輯、修改。

  • 若text input裡面有文字(value內容),則使用者無法修改
  • 若radio button / checkbox預設為勾選,則使用者無法取消勾選
  • 若radio button / checkbox預設為不勾選,則使用者無法勾選他

範例

text

<input type="text" value="fixed text" disabled />

radio button

<input name="rd-dis" type="radio"checked disabled/>
<label>radio one</label>
<input name="rd-dis" type="radio" disabled/>
<label>radio two</label>




checkbox

<input type="checkbox" checked disabled/>
<label>checkbox one</label>
<input type="checkbox" disabled/>
<label>checkbox two</label>




select

<select disabled>
 <option>apple</option>
 <option>orange</option>
 <option>banana</option>
</select>

 

【JavaScript】JS的位置

説明

在HTML檔案中,JS不論是寫在頁面上,或是用檔案引入,都建議放在body後面。

理由:HTML文件的讀取方式是由上而下,如果寫在body前面的話,網頁還沒讀完JS就執行了,所以DOM會抓不到東西。

但若一定要寫在body前面的話,可以在JS內容外面加上一層load事件,讓網頁全部讀完後,再執行JS。

window.addEventListener("load", function(){

 //這邊放入JS內容。

});

【Bootstrap】selector

説明

用以Bootstrap為基底的函式庫做出美觀的selector picker

【必裝的函式庫】

jQuery.js(jQuery要放在最上面)
bootstrap.js
bootstrap.css
bootstrap-select.js
bootstrap-select.css

範例

用法:使用 <select> ,並且帶上 selectpicker 的 class

select.selectpicker
 option one
 option two
 option three

Display

CODEPEN

【CSS】漸層色塊

漸層原理説明

撰寫漸層時,要指定多組參數。每一組參數要有〖顏色〗與〖%數〗

.box
.box
 width: 500px
 height: 200px
 //left: 指定〖從左〗開始漸層 
 background: linear-gradient(left, DarkGreen 20%, MediumSeaGreen 70%)

▼示意圖

  • 第1組參數:〖起始色〗深綠色、〖%數〗20%
    0%~20% →深綠色純色區
  • 第2組參數:〖終色〗淺綠色、〖%數〗70%
    20%~70%→漸層區域
    70%~100%→淺綠色純色區

色塊

漸層區的定義是「第1個%」與「第2個%」之間的區塊,
所以如果「第2個%」指定跟「第1個%」一樣的數字,就無法產生漸層區,會形成色塊。

線性漸層色塊

.lg-box
.lg-box
 width: 300px
 height: 100px
 border: 1px solid #000
 background: linear-gradient(Left, Teal 50%, transparent 50%)

Display

圓形漸層色塊

圓形漸層如果參數指定的剛剛好一樣,會有顏色轉換處會有鋸齒產生,所以需要預留數%的漸層空間

.rd-box
.rd-box
 width: 200px
 height: 200px
 border-radius: 100%
 border: 1px solid #000
 background: radial-gradient(Teal 49.5%, transparent 50%)//預留0.5%的漸層空間

Display

【CSS】radio style

説明

自由撰寫radio input的樣式,但是保有 checked 的功能

【架構】

  • <label>裡面要有 2 個東西:<input type=”radio”>、<div class=”radio-widget”>
    ※這樣點到label裡面任何一處,<input type=”radio”>都會被觸發
  • radio-widget是假的radio,在〔.radio-widget〕做出勾選前的樣式
  • 在〔input[type=”radio”]:checked+.radio-widget〕撰寫勾選後的樣式

參考:input label 應用漸層色塊
衍生:checkbox style

範例

label.radio-label
 input(type="radio" name="rd" id="rd1" value="1" checked)
 .radio-widget
 | option 1

label.radio-label
 input(type="radio" name="rd" id="rd2" value="2" checked)
 .radio-widget
 | option 2

label.radio-label
 input(type="radio" name="rd" id="rd3" value="3" checked)
 .radio-widget
 | option 3
.radio-label
 margin: 0px 5px

 //原本的radio設不顯示
 input[type="radio"]
  display: none
 
 //這邊寫選取後的效果
 input[type="radio"]:checked+.radio-widget
  border-color: #50BBB6
  background: radial-gradient(#50BBB6 44%, transparent 50%)
  
.radio-widget
 width: 20px
 height: 20px
 border: 1px solid #eee
 border-radius: 100%
 position: relative
 margin-right: 5px
 background: radial-gradient(#eee 20%, #fff 25%)
 

.radio-widget, input
 display: inline-block
 vertical-align: top

【CSS】checkbox style

説明

自由撰寫checkbox的樣式,但是保有 checked 的功能

【架構】

  • <label>裡面要有 2 個東西:<input type=”checkbox”>、<div class=”checkbox-widget”>
    ※這樣點到label裡面任何一處,<input type=”checkbox”>都會被觸發
  • checkbox-widget是假的checkbox,在〔.checkbox-widget〕做出勾選前的樣式
  • 在〔input[type=”checkbox”]:checked+.checkbox-widget〕撰寫勾選後的樣式

參考:input label 應用
衍生:radio style

範例

label.checkbox-label
 input(type="checkbox" value="1")
 .checkbox-widget
 | checkbox 1

label.checkbox-label
 input(type="checkbox" value="1")
 .checkbox-widget
 | checkbox 2

label.checkbox-label
 input(type="checkbox" value="1")
 .checkbox-widget
 | checkbox 3
.checkbox-label
 .checkbox-widget, input
  display: inline-block
  vertical-align: top
 
 
 //在這裡刻出自訂樣式的checkbox
 .checkbox-widget 
  width: 20px
  height: 20px
  margin-right: 5px
  background-color: #fff
  border: 1px solid #eee
  border-radius: 4px
  text-align: center
  &:after
   content: "✔︎"
   color: #fff
 
 //原本的checkbox設不顯示
 input[type="checkbox"]
  display: none

 //選取後的樣式
 input[type="checkbox"]:checked+.checkbox-widget          
  background-color: #50BBB6 
  border-color: #50BBB6

【CSS】smooth

説明

滑順滾動的屬性,讓網頁內引導<href=”#id”>的動作可以滑順地跳下來

瀏覽器支援度→Can I Use …

範例

方法一:指定CSS

a(href="#title")
 button click me

//這邊填充很多個br
h1#title title
*
 scroll-behavior: smooth

Display

方法二:指定JavaScript

button(onclick="scrollIt()") click me
function scrollIt(){
 
 window.scroll({
  top: 0,
  left: 0,
  behavior: "smooth"
 });

 
}

Display

【CSS】border-collapse 表格消除空隙

情況

table 預設的 style 方格與方格之間會有空隙
(在table, td, th都有設定border的情況下會很明顯)

解決:border-collapse

table
 tr
  th Items
  th Price
 tr
  td Apple
  td $10
 tr
  td Orange
  td $15
table, td, th 
 border: 1px solid black
 
table
 border-collapse: collapse

Display

沒有加border-collapse的情況

Items Price
Apple $10
Orange $15

有使用border-collapse的情況

Items Price
Apple $10
Orange $15

【JavaScript】smalot-bootstrap-datetimepicker

説明

這是一套基於BS的函式庫,可以快速製作時間選擇器的小元件。

【必裝的函式庫】

屬性介紹

format【字串形式】

意義
p am / pm
P AM / PM
s 秒(沒有0開頭)
ss 秒(有0開頭)
i 分(沒有0開頭)
ii 分(有0開頭)
h 時(沒有0開頭,24小時制)
hh 時(有0開頭,24小時制)
H 時(沒有0開頭,12小時制)
HH 時(沒有0開頭,12小時制)
d 日期(沒有0開頭)
dd 日期(有0開頭)
m 數字月份(沒有0開頭)
mm 數字月份(有0開頭)
M 英文月份簡寫
MM 英文月份全名
yy 西元年(末二位數)
yyyy 西元年(四位數)

StartView / MinView 【數字形式】

在「只選擇月份」或是「只選擇日期」的情況下,預設的介面卻可以指定到某天的分鐘,會不太適合。
可以透過調整這2個參數達成更精準的控制

  • StartView:一開始選擇時間的介面〔預設:2〕
  • MinView:最後選擇時間的介面〔預設:0〕
意義
0 【選分鐘】hour view
1 【選小時】day view
2 【選日期】month view
3 【選月份】year view
4 【選年份】10-year view

範例:選擇日期

.input-append.date.form_datetime(data-view='hour')
 input(size='16', type='text', value='', readonly='', placeholder='2017-11-15 16:35')
 span.add-on
 i.fa.fa-calendar
$(".form_datetime[data-view='hour']").datetimepicker({
 format: "yyyy-mm-dd", //這邊可以自訂時間表示的格式
 autoclose: true,
 minView: 3
 });

範例:選擇時與分

.input-append.date.form_datetime(data-view='hour')
 input(size='16', type='text', value='', readonly='', placeholder='2017-11-15 16:35')
 span.add-on
 i.fa.fa-calendar
$(".form_datetime[data-view='hour']").datetimepicker({
 format: "yyyy-mm-dd hh:ii",
 autoclose: true
 });

範例:選擇月份

.input-append.date.form_datetime(data-view='year')
 input(size='16', type='text', value='', readonly='', placeholder='2017-11')
 span.add-on
 i.fa.fa-calendar
$(".form_datetime[data-view='year']").datetimepicker({
 format: "yyyy-mm",
 autoclose: true,
 startView: 4,
 minView: 3
 });

Display

CODEPEN

 

 

【CSS】height transition

説明

CSS展開動畫:點選收起來的選單→觸發動作開啓選單

開啓狀態下的選單區塊,高度寫inherit的話,無法完成動態效果,所以要用max-height的方式完成

.outer 收合的選單 (hover me)
 .inner
  p 選單内部
  p 選單内部
  p 選單内部
.outer
  background-color: #E7F2F1
  display: inline-block
  padding: 10px
  &:hover
   .inner
   max-height: 150px
   //不用精準設定到元素高度,元素只會展開到他自己的高度。數字可以抓大一點,數字越大展開的速率越快。
 
.inner
 background-color: #439E96
 padding: 0px 10px
 margin: 5px
 max-height: 0
 overflow: hidden
 transition-duration: 0.5s

Display

收合的選單 (hover me)

選單内部

選單内部

選單内部

【JavaScript】load HTML 外部載入HTML

用途

在一個HTML檔案的部分區域引入其他外部HTML

▼示意圖

上圖使用了2個外部HTML,檔案結構如下

  • 主頁面〔index.html〕
  • 主選單(橫條選單)〔main-nav.html〕
  • 側選單(直條選單)〔verti-nav.html〕

在主頁面〔index.html〕頁面中,引入2個選單HTML〔main-nav.html〕&〔verti-nav.html〕

native JS 方法

const xhr=new XMLHttpRequest();
xhr.open("GET", "../verti-navs.html", true);
xhr.send();

xhr.onreadystatechange=function(){
 if(xhr.readyState==4 && xhr.status==200){

    document.querySelectorAll(".verti-nav")[0].innerHTML = xhr.responseText;

    }
};

jQuery 方法:load

$(".verti-nav").load("verti-navs.html");

觀看環境

外部載入HTML、ajax等做法會涉及到檔案之間的溝通,所以無法普通地在本機電腦打開觀看。需要透過以下的環境打開檔案。

觀看環境一:localhost

將電腦設定成虛擬主機(localhost),有以下幾種方法
  • 安裝XAMPP
  • 使用Webpack+Node.js
  • 利用終端機內建的python設定localhost環境

以下介紹用終端機設定localhost環境的方法

cd /Users/Desktop/web 
#指定要打開的資料夾

python -m SimpleHTTPServer 9099

輸入完畢後開啟瀏覽器,打開網址:http://localhost:9099
就會跳出index.html的頁面

觀看環境二:FireFox

FireFox也支援檔案之間的溝通。
但是,必須要先從index.html打開,再用index.html連到其他的頁面。否則FF會抓不到根目錄。

JS的撰寫方式

針對load進來的選單HTML撰寫JS時,有時會發生選單相關JS沒有被執行到的狀況。(特別在localhost環境下觀看時)

原因:JS的語言特性會偷跑,如果所有HTML的JS都要統一管理成同一份檔案,必須考慮到瀏覽器載入HTML的順序,再安排JS的撰寫位置。

一般來說,瀏覽器載入檔案的順序會是這樣:

  1. 主HTML檔案
  2. JS檔案
  3. load進來的選單HTML
    (因為選單load進來的動作是由JS控制,所以JS一定會比選單HTML早一步執行)

※因為JS檔案(內含選單相關JS)在選單HTML存在前就被載入了,所以當JS執行的時候並不存在選單HTML,導致JS的程式無效。

解決:

  1. 將選單相關JS寫在XMLHttpRequest的動作裡面。
  2. 並且增加一條判斷式:如果response存在,才執行選單JS
const xhr=new XMLHttpRequest();
xhr.open("GET", "../verti-navs.html", true);
xhr.send();

xhr.onreadystatechange=function(){
 if(xhr.readyState==4 && xhr.status==200){

    document.querySelectorAll(".verti-nav")[0].innerHTML = xhr.responseText;
    if(xhr.responseText){
       //這邊撰寫選單相關JS

     }
  }
};

【JavaScript】change event

説明

<input>狀態改變時→觸發事件
【例】下拉式選單:變更選項→觸發事件
【例】核取方塊:勾選 / 取消勾選→觸發事件

label Choose a color
 select#sel(name="colors" onchange="selShow()")
 option(value="Nothing") Select One...
 option(value="red") RED
 option(value="blue") BLUE
 option(value="green") GREEN 
#changeStatus
function selShow(){
 changeStatus.textContent=`You selected ${sel.value}`
}

Display

【JavaScript】transitionend event

説明

transitionend event:漸變結束後→觸發事件

#box(ontransitionend="transShow()") hover me
p#transStatus
#box
 border: 1px solid #000
 display: inline-block
 transition-duration: 0.5s
 &:hover
  font-size: 30px
function transShow(){
 transStatus.textContent="Transition is Done"
}

Display

hover me

【JavaScript】keydown and keyup event

説明

  • keydown event:鍵盤按下時→觸發動作
  • keyup event:鍵盤按下後鬆開→觸發動作

 

p Press any key
p#pressStatus
window.addEventListener("keydown", function(e){
 pressStatus.textContent=`Key code of ${e.keyCode} is pressed`;
})

window.addEventListener("keyup", function(){
 pressStatus.textContent=`Now you left the key`
})

Display

Press any key

【JavaScript】focus and blur event

説明

  1. focus event:聚焦(點選到)該元素→觸發事件
    ※可以用滑鼠點選觸發focus,某些情況下也可以用鍵盤選取(Tab鍵),觸發focus
  2. blur event:focus的相反,離開該元素後→觸發事件
input#getText(type="text")
button(onclick="getFocus()") Get focus
button(onclick="loseFocus()") Lose focus
function getFocus(){
 getText.focus();
}

function loseFocus(){
 getText.blur();
}

Display

【JavaScript】mouse event series

説明

  • mousedown:滑鼠按下去的瞬間→觸發事件
  • mouseout:滑鼠離開→觸發事件
  • mouseup:滑鼠按下、離開的瞬間→觸發事件

 

p Try to draw it ↓↓
canvas#canvas(width="300", height="300")
#canvas
 width: 300px
 height: 300px
 border: 1px solid #000
let isDrawing=false;
let lastX=0;
let lastY=0;
const ctx=canvas.getContext("2d");

function draw(e){
 if(!isDrawing){
  return;
 }

 ctx.beginPath();
 ctx.moveTo(lastX, lastY);
 ctx.lineTo(e.offsetX, e.offsetY);
 ctx.strokeStyle="#000000";
 
 [lastX, lastY]=[e.offsetX, e.offsetY];
 
 ctx.stroke();
}

//滑鼠按下→開始畫圖,計算起始座標
canvas.addEventListener("mousedown", (e) => {
 isDrawing = true;
 [lastX, lastY]=[e.offsetX, e.offsetY];
});

//滑鼠移動→繼續畫圖
canvas.addEventListener("mousemove", draw);
//滑鼠放掉→停止畫圖
canvas.addEventListener("mouseup", () => isDrawing = false);
//滑鼠離開→停止畫圖
canvas.addEventListener("mouseout", () => isDrawing = false);

Display
Try to draw it ↓↓

【JavaScript】mousemove event

説明

滑鼠移動→觸發事件

#screenBox Hover me
#locate
#screenBox
 width: 300px
 height: 200px
 background-color: #eee
 text-align: center
 line-height: 200px
 color: rgba(0,0,0,0.5)
screenBox.addEventListener("mousemove", function(e){
 locate.textContent=`Mouse locate is (${e.offsetX}, ${e.offsetY})`
})

Display

Hover me

【JavaScript】Parent, Children, Silbing

選取母元素

#parentBox
 .child A Box
 .child B Box
#parentBox
 width: 500px
 height: 500px
 background-color: #eee
 text-align: center
 line-height: 500px

 
.child
 width: 100px
 height: 100px
 display: inline-block
 line-height: 100px
 background-color: #beddcd
const childs=document.querySelectorAll(".child");
childs[0].parentNode; //會選到parentBox

選取子元素

※HTML, CSS 沿用上例

children Method 是 NodeList 形式(即便只有一個子元素),所以要向使用 querySelectorAll 的時候一樣,指定 index

parentBox.children[0]; //會選到A Box

選取相鄰元素

※HTML, CSS 沿用上例

Native JavaScript 沒有辦法直接指定相鄰元素(jQuery 的話可以使用sibling()),所以只能先回到母元素→再指定子元素

const childs=document.querySelectorAll(".child");

childs[0].parentNode.children[1]; //會選到B Box

【Git】忽略檔案

目的

更新版本的時候,讓某些檔案不要被更新上去(忽略更新)

方法

在本地數據庫新增【.gitignore】檔案。
之後用文字編輯器(Sublime / notepad)開啟【.gitignore】,
並且輸入指令。

※輸入gitignore忽略指令的方法:
①用文字編輯器打開【.gitignore】
②輸入指令
③存檔

$ touch .gitignore

//在選定的數據庫資料夾裡面,新增忽略指定檔案

【.gitignore指令】忽略檔案

直接輸入要忽略的檔案
[例]要忽略index.html這個檔案

index.html

【.gitignore指令】忽略特定類型的所有檔案

米字號【*】+副檔名
[例]忽略所有html檔案

*.html

【.gitignore指令】忽略資料夾

正斜線【/】+資料夾名稱
[例]忽略css這個資料夾

/css

 

 

【Git】數據庫

流程示意圖

建立本地數據庫:git init

//在選定的資料夾上
$ git init

設好本地數據庫後,該資料夾內的資料的變更・新增・刪除,都會被記錄下來。

加入索引:git add

檔案都建立好・改好後,要提交紀錄。
提交前,先加入索引。

$ git add .
//目前資料夾的所有內容都會被加入索引
//【.】是全部的意思


$ git add index.html
//加入單獨檔案

検査狀態:git status

$ git status

//資料有加入索引的話,會顯示綠字
//資料沒有加入索引的話,會顯示紅字

提交版本更新:git commit -m ‘修改紀錄’

確認索引沒問題後,提交版本更新

$ git commit -m "update-1"

//提交完成後,用git status查詢,會出現nothing,表示這個資料夾裡面已經沒有東西需要被更新了

査詢紀錄:git log

查詢版本更新的次數、狀況等

$ git log

//會回傳這個資料夾的版本次數、作者、時間、版本名

【Git】Command Line 命令提示字元

【Windows】打開Git Bash,輸入命令提示字元
※cd 是 Command的意思

移動路徑:cd 路徑

移動到C槽

cd c:
//user@DESKTOP-L659N78 MINGW64 /c

移動到桌面的Git資料夾:C:\Users\user\Desktop\Git
↑這個是直接複製資料夾的路徑,

cd c/Users/user/Desktop/Git

//Git選取子資料夾的符號是【正斜線:/】,但是Windows顯示的子資料夾卻是【反斜線:\】

另一種方法:把資料夾直接拖拉到Git Bash視窗上面。
Git Bash會直接讀到這個資料夾的路徑。

展開列表(看資料夾裡面的檔案):ls

※ls→list

cd ls
//會回傳這個資料夾裡面的檔案

回母資料夾:cd ..

桌面上的Git資料夾→桌面

user@DESKTOP-L659N78 MINGW64 /c/users/user/desktop/git (master)

cd ..
user@DESKTOP-L659N78 MINGW64 /c/users/user/desktop/(master)

建立新資料夾:mkdir 資料夾名稱

※mkdir→make directory

mkdir hi
//電腦就會跑出一個新的資料夾

建立新檔案:touch 檔名

touch hello.txt
//該資料夾底下就會出現hello.txt這個檔案

建立開發者資訊

建立開發者資訊,
日後建立 / 修改檔案到Git時,會沿用建立者 / 修改者的姓名及基本資訊。

//設定email
git config --global user.email "這邊輸入email"

//設定姓名
git config --global user.name "這邊輸入姓名"

//檢查有沒有輸入成功
git config --list
//會回傳一堆資料,檢查user.email / user.name這2個欄位

變更遠端倉庫網址

git remote set-url origin https://xxxxxx.git

 

 

【JavaScript】滑鼠相關屬性

滑鼠相關屬性

clientX & clientY

定位基準:視窗長&寬
視窗長&寬→window.innerHeight / Width
※視窗的範圍:瀏覽器的畫面,扣掉上方網址列的部分。
如果把瀏覽器畫面,視窗也會跟著變小

▼示意圖▼

intro.addEventListener("mousemove", function(e){
   console.log(e.clientX, e.clientY);
 }
)

offsetX & offset Y

定位基準:目標元素的長&寬
目標元素的長&寬:id.clientHeight / Width

▼示意圖▼

intro.addEventListener("mousemove", function(e){
   console.log(e.offsetX, e.offsetY);
 }
)

pageX & pageY

定位基準:整個頁面的長&寬
整個頁面的長&寬:document.body.clientHeight / Width
※【沒設定頁面寬的情況】瀏覽器的寬度拉小,整個網頁頁面的寬度也會跟著變小(被壓縮了)
※【有設定頁面寬的情況】瀏覽器的寬度拉小,整個網頁頁面的寬度不會跟著變小(會出現橫向的卷軸)

▼示意圖▼

intro.addEventListener("mousemove", function(e){
   console.log(e.pageX, e.pageY);
 }
)

screenX & screenY

定位基準:電腦畫面的長&寬
電腦的長&寬:screen.height / width
※電腦整個畫面:上方有包含網址列,下方有包含工具列
※跟clientX / Y 的差別:定義的外圍是電腦畫面,所以即便拉小瀏覽器視窗,也不會有任何影響

▼示意圖▼

intro.addEventListener("mousemove", function(e){
   console.log(e.screenX, e.screenY);
 }
)

【JavaScript】load事件 網頁打開後馬上觸發

説明

網頁一載入→觸發事件
【例】表單填入網頁:頁面一打開,焦點就對準輸入格。

範例

寫法一

監聽load事件

input#input(type="text" placeholder="input something...")
window.addEventListener("load", function(){
 input.focus();
})

寫法二

使用window.load

window.onload=input.focus();

Display

【JavaScript】Event Listener 監聽事件一覽

用法

①透過特定event觸發動作

用法基礎篇

目標物.addEventListener("特定的event", 
 function(){
  //這邊寫要觸發的動作
 }
)

②操控目標元素完成某動作

用#button按鈕操控,讓超連結#theURL被點擊

a#theURL(href="ianchen.thisistap.com") 超連結
br
button(onclick="openURL()") click it and open the URL
//onclick的用法參見下方
function openURL(){
 theURL.click();
}

Display

超連結

③ON+EVENT名稱:用HTML直接呼叫 function

基礎範例

HTML用法:on+event名=”函式名()”
※如果要呼叫event的話,需要使用這種形式:on+event名=”函式名(event)”

【例如】click event & makeItBigger function
→onclick="makeItBigger()" 
//這個東西放在HTML tag裡面
//記得要另外寫makeItBigger這個函式

【上述用法等同】
id.eventListener("click", makeitBigger());

滑鼠相關監聽事件

  1. click event:滑鼠按下→觸發事件
  2. mousemove event:滑鼠移動→觸發事件
  3. mousedown event:滑鼠按下去的瞬間→觸發事件
  4. mouseout event:滑鼠離開→觸發事件
  5. mouseup event:滑鼠按下、離開的瞬間→觸發事件

打字相關監聽事件

  1. focus event:聚焦(點選到)該元素→觸發事件
    ※可以用滑鼠點選觸發focus,某些情況下也可以用鍵盤選取(Tab鍵),觸發focus
  2. blur event:focus的相反,離開該元素後→觸發事件
  3. keydown event:鍵盤按下時→觸發動作
  4. keyup event:鍵盤按下後鬆開→觸發動作
  5. input event:輸入文字→觸發動作

其他監聽事件

  1. transitionend event:漸變結束後→觸發事件
  2. change event:<input>狀態改變時→觸發事件
    【例】下拉式選單:變更選項→觸發事件
    【例】核取方塊:勾選 / 取消勾選→觸發事件

 

【JavaScript】input相關Method

value

偵測文字輸入框的內容

input#input(type="text")
br
#show
window.addEventListener("keyup", function(){
 show.textContent=`What you input is "${input.value}"`;
})

Display

What you input is

checked


監測核取方塊被點選的狀態。並且傳回布林值

input#checkbox(type="checkbox")
br
p#ckeckStatus
btn.addEventListener("click", function(){
 ckeckStatus.innerHTML=`ckecked status: ${checkbox.checked}`;
})

Display


【EXCEL】PivotTable 樞紐分析表

説明

將清單形式的資料整理成表格,
可以自訂縱軸與橫軸的欄位。

範例:研討會人數統計

原始資料名單

場次 負責業務 參加者姓名 更新日期 性別 素食 / 葷食
台北 A組 Mary 9月23日 素食
台中 B組 Moko 9月23日 素食
高雄 B組 Cherry 9月23日 素食
台北 A組 Apple 9月24日 素食
台北 A組 Banana 9月25日 素食
台中 B組 Grape 9月25日 素食
高雄 C組 Vegetable 9月25日 葷食
高雄 A組 Blue 9月25日 葷食
台中 A組 Sky 9月26日 葷食
台中 C組 Ocean 9月26日 葷食
台北 C組 Autumn 9月26日 葷食

建立樞紐分析表步驟:

    1. 選取資料範圍
    2. 標籤塊【插入】→樞紐分析表→確定
    3. 本次分析:場次與負責業務的人數相對關係
    4. 【場次】拉向列方格
    5. 【欄位】拉向欄方格
    6. 【參加者姓名】拉向値方格

※名單更新→同步更新樞紐分析表的資料

EXCEL的樞紐分析表無法即時同步更新(Google Sheet的就可以)
但是,名單更新後,可以手動點選以下路徑,更新樞紐分析表資料

樞紐分析表工具→標籤塊【分析】→重新整理

範例:業績報告(使用加總功能)

原始資料名單

日期 訂單號 客戶 産品 數量 金額
9月23日 A0001 Bank Banana 1  $        1,000
9月23日 A0002 Bank Apple 10  $        5,000
9月23日 A0003 Bank Banana 3  $        3,000
9月24日 A0004 Bank Banana 5  $        5,000
9月24日 A0005 Bakery Apple 3  $        1,500
9月26日 A0006 Bakery Banana 1  $        1,000
9月26日 A0007 Bakery Apple 1  $            500
9月26日 A0008 School Apple 1  $            500
9月26日 A0009 School Apple 2  $        1,000
9月26日 A0010 School Orange 1  $        3,000
9月26日 A0011 School Orange 3  $        9,000
9月29日 A0012 Council Orange 5  $      15,000
9月29日 A0013 Council Mango 1  $      10,000
9月29日 A0014 Council Mango 5  $      50,000

建立樞紐分析表:分析客戶、産品的銷售金額關係。

  • 【産品】拉向列方格
  • 【客戶】拉向欄方格
  • 【金額】拉向値方格
  • ※點選樞紐分析表儲存格→右鍵→摘要値方式→加總

 

【JavaScript】Contains Method

説明

  1. 判斷節點(Node)裡面有沒有含有檢索的內容。
  2. 若有,回傳true
  3. 若無,回傳false

範例

#p.hi 123
console.log(p.classList.contains("hi"));
//true

進階:防止選取子元素

母選單設定點選→觸發子選單展開・收合的function,但因為子選單包在母選單底下,所以在子選單打開的狀況下,點選子選單內容,會觸發function,造成子選單收合

解決方法:在function裡面增加contains條件(選取子選單的class),防止子選單觸發

.nav
 ul
 li.first
 |list 01 click
 ul.second
 li.not-choose list 02
 li.not-choose list 02
 li.not-choose list 02
 li.not-choose list 02
 li.first
 |list 01 click
 ul.second
 li.not-choose list 02
 li.not-choose list 02
 li.not-choose list 02
 li.not-choose list 02
 li.first
 |list 01 click
 ul.second
 li.not-choose list 02
 li.not-choose list 02
 li.not-choose list 02
 li.not-choose list 02
 li.first
 |list 01 click
 ul.second
 li.not-choose list 02
 li.not-choose list 02
 li.not-choose list 02
 li.not-choose list 02
 li.first
 |list 01 click
 ul.second
 li.not-choose list 02
 li.not-choose list 02
 li.not-choose list 02
 li.not-choose list 02
.second
 max-height: 0px
 overflow: hidden
 transition-duration: 0.5s
 
.open
 max-height: 100px
// if(e.target.classList.contains("list02")==true) return;
// // 讓他不要選到children
const firsts=document.querySelectorAll(".first");

firsts.forEach(first => first.addEventListener("click", function(e){
 //讓他不要選到children
 if(e.target.classList.contains("not-choose")==true) return;
 this.children[0].classList.toggle("open")
 
 
}))

Display

Facebook Pixel

官方文件

  1. 基本用法【PageView】
  2. 轉換率追蹤【Purchasing Event】
  3. 事件與參數用法【Event & Parameter】

範例

基本用法:導入PageView

<script> 
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod? 
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n; 
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0; 
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window, 
document,'script','//connect.facebook.net/en_US/fbevents.js'); 
fbq('init', '這邊放入FB頁面的ID'); 
fbq('track', 'PageView'); 
</script> 

<noscript> 
 <img height="1" width="1" style="display:none" 
src="https://www.facebook.com/tr?id=這邊放入FB頁面的ID&amp;ev=PageView&amp;noscript=1" /> 
</noscript>

進階用法:轉換率追蹤

<script> 
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod? 
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n; 
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0; 
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window, 
document,'script','//connect.facebook.net/en_US/fbevents.js'); 
fbq('init', '這邊放入FB頁面的ID'); 
fbq('track', 'PageView');  
fbq('track', 'Purchase', {currency: '這邊放幣值', value: 這邊放金額}); 
//物件參數還可以設其他的,但是上面2個是必須指定。
//詳細參考事件與參數用法 
</script> 


<noscript> 
<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=這邊放入FB頁面的ID&amp;ev=PageView&amp;noscript=1" />  //↓如果有2個事件的話(例如本例),就要指定2組img tag
<img height="1" width="1" border="0" alt="" style="display:none" 
src="https://www.facebook.com/tr?id=107593379985738&amp;ev=Purchase&amp;cd[value]=這邊放金額&amp;cd[currency]=這邊放幣值" />  
//【&amp;】是&的轉換字元,用來連結Purchase事件的物件資料。
//因為本例只有2組物件參數,所以用了一個&amp;連結彼此
//若使用更多物件參數,就需要追加&amp;連接
//用法請參考轉換率追蹤 </noscript>

除錯方法

  1. 準備好FB Pixel程式碼
  2. 下載Chrome外掛程式:Facebook Pixel Helper
  3. 用CODEPEN打開一個PEN,把程式碼貼在HTML的地方
  4. 用Facebook Pixel Helper檢查程式碼有沒有成功執行(成功會有綠色的勾勾)

 

【HTML】ruby tag 注音表記

説明

顯示國字的注音(或是日文的假名)

範例

基本用法

  • 文字主體ーrb tag (ruby body)
  • 注音標示ーrt tag (ruby text)
ruby
 rb 木霊 //文字主體
 rt こだま //注音標示

Display

木霊こだま

跨瀏覽器用法

有瀏覽器無法讀取ruby tag時,可以使用以下方法解決

  • rp tag (ruby parentheses)包覆rt tag
ruby
 rb 木霊
 rp (
 rt こだま
 rp )

Display

木霊(こだま)

【CSS】z-index

條件

  1. 內元素絕對定位(所有)
  2. 外元素相對定位
  3. 目標元素指定index

※z-index的數值代表優先度。
數字大,表示優先顯示的強度越強(排在前面)
數字小,表示優先顯示的強度越低(隱藏在後面)←反向操作:設負數讓元素被蓋住

範例

沒有設index的情況下,HTML下面的元素會蓋掉上面的元素

.box1
.box2
body
 position: relative //外元素相對定位

.box1,.box2
 width: 200px
 height: 200px
 border: 1px solid #eee
 
.box1
 background-color: #73c6a8
 position: absolute //內元素絕對定位
 
.box2
 background-color: #73c0c6
 position: absolute //內元素絕對定位

 margin-top: 50px
 margin-left: 50px

Display

.
.

 

 

 

 

 

 

綠色方塊的HTML在上面,藍色方塊的HTML在下面。
所以藍色方塊優先顯示,蓋掉綠色方塊

設定z-index,優先顯示目標元素

.box1
.box2
body
 position: relative //外元素相對定位

.box1,.box2
 width: 200px
 height: 200px
 border: 1px solid #eee
 
.box1
 background-color: #73c6a8
 position: absolute //內元素絕對定位
 z-index: 1
 
.box2
 background-color: #73c0c6
 position: absolute //內元素絕對定位

 margin-top: 50px
 margin-left: 50px

Display

.
.

 

 

 

 

 

 
設定index為1,優先顯示綠色方塊

【Vue.js】ready指令 API串接

説明

用ready串接後台API

範例

API載入純文字

#app
 p {{text}}
const vm=new Vue({
 el: "#app",
 data: {
  text: ""
  },
 ready: function(){
  $.ajax({
   url: "https://awiclass.monoame.com/api/command.php?type=get&name=notifydata",
   success: function(res){
    vm.text=res;
    }
   })
  }
 
})

Display

哈囉!! 這邊是你用AJAX載入的純文字公告!!

API載入JSON

要先轉換成JSON格式,否則會變成純字串

#app
 ul
  li(v-for="item in items") 【{{item.name}}】${{item.price}}
const vm=new Vue({
 el: "#app",
 data: {
  items: []
  },
 ready: function(){
  $.ajax({
   url: "https://awiclass.monoame.com/api/command.php?type=get&name=itemdata",
   success: function(res){
    vm.items=JSON.parse(res); //轉換成JSON格式
    }
   })
 }
 
})

Display

  • 【吹風機】$300
  • 【麥克筆】$9000
  • 【筆記型電腦】$54555
  • 【Iphone 9】$32000
  • 【神奇海螺】$5000
  • 【PSP1007】$2000
  • 【鍵盤】$3500

【JavaScript】Ajax

説明

jQuery版本
使用原生的JavaScript串接Ajax

  1. 建立HTTPRequest請求  new XMLHttpRequest()
  2. 建立回應函式  onreadystatechange
  3. 確認readyState、status(HTTP狀態碼)OK
  4. 執行回應動作,回應的值為responseText
  5. 定義後端api網址與method  open()
  6. 前端傳送資料  send()

readyState

 值  狀態  說明
 0  UNSET  尚未讀取
 1  OPENED  讀取中
 2  HEADERS_RECEIVED  已下載完畢
 3  LOADING  資訊交換中
 4  DONE  成功

status

status為200,表示成功

HTTP狀態碼一覽

範例

JavaScript版

p#p
const xmlhttp=new XMLHttpRequest();

xmlhttp.onreadystatechange=function(){
 if(this.readyState==4 && this.status==200){
  p.textContent=this.responseText; //API連成功的動作
 }
};

xmlhttp.open("GET", "https://awiclass.monoame.com/api/command.php?type=get&name=notifydata");//API網址
xmlhttp.send();

Display

哈囉!! 這邊是你用AJAX載入的純文字公告!!

jQuery版

p#p
$.ajax({
 url: "https://awiclass.monoame.com/api/command.php?type=get&name=notifydata",
 success: function(res){
  p.textContent=res;
 }
})

Display

哈囉!! 這邊是你用AJAX載入的純文字公告!!

用ajax取得header, menu等共用HTML

#header
var headerXhr=new XMLHttpRequest();

headerXhr.open('GET', 'header.html', true);
headerXhr.send();

headerXhr.onreadystatechange=function(){
    if(headerXhr.readyState==4 && headerXhr.status==200){
        header.innerHTML = headerXhr.responseText;
    }
};

用ajax傳送JSON

TIPS: 先把JSON轉成string格式,再傳送

var xmlhttp=new XMLHttpRequest();

xmlhttp.open('POST', 'http://9.102.60.125:5000/api/bbinqcan', true);
xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xmlhttp.onreadystatechange=function(){

    if(xmlhttp.readyState==4 && xmlhttp.status==200){
        res.textContent=xmlhttp.responseText;
    }
};

xmlhttp.send(
        //checkedJSON是一個JSON格式的變數
    JSON.stringify(checkedJSON);
)

【Vue.js】v-on

説明

methods寫在JS裡面,v-on寫在HTML裡面。
功能類似原生JS的addEventListener。

範例

#app
 button(v-on:click="show") click me
 p#vueText some text
#vueText
 color: #fff
var vm=new Vue({
 el: "#app",
 methods: {
 show: function(){
  vueText.style.color="#000"
  }
 }
})

Display

some text

【JavaScript】子物件指定

説明

JS中有2種方式可以指定子物件。

方法一:dot連接

常用方法,利用dot連接母物件與子物件

const obj={
 akasha: 222,
 typhoon: 15151515,
 tks: "33333333"
}

console.log(obj.akasha); //222

方法二:中括號

母物件後面用中括號,中括號裡面可以用字串指定,或是用變數代換

const obj={
 akasha: 222,
 typhoon: 15151515,
 tks: "33333333"
}

//字串指定法
console.log(obj["akasha"]); //222

/*****************************/

//變數代換法
const typ = "typhoon";
console.log(obj[typ]); //15151515

 

【Vue.js】v-if

使用方法

①data物件裡面建立會用到布林値的變數
②用v-model操控使用者變更布林値
③v-if=”變數名稱”,當布林値為真,顯示某些元素

範例

當核取方塊被點選,就會顯示下方文字

#app
 label Show text
 input(type="checkbox" v-model="show")
 p the value of show is {{show}}
 hr
 p(v-if="show") Hey the box is clicked !!
var vm=new Vue({
 el: "#app",
 data: {
 show: false
 }
});

Display

the value of show is false


【Vue.js】v-model 雙向綁定

說明

v-model的功能:
使用者輸入資料→JS物件同步更新→及時渲染

用法:v-model=”變數名稱”

範例

同步更新文字

#app
 label 姓名:
 input(v-model="name")

/********************/

h4 您好,{{name}}
var vm=new Vue({
 el: "#app",
 data: {
  name: "陳怡安"
 }
});

同步更新style

#app
 label 顏色:
 input(v-model="color")
/********************/

p 下面這個方塊的顏色是【{{color}}】
.block(style="background-color: {{color}}")
.block
 border: 1px solid #000
 width: 40px
 height: 40px
var vm=new Vue({
 el: "#app",
 data: {
  color: "#C0C999"
 }
});

陣列用法

#app
 p 喜歡的書:
 //渲染3次
 div(v-for="(id, book) in books")
  label 【{{id+1}}】
 //印出書名
  input(v-model="book")
 
/******************/
p 喜歡的書
 ul 
 li(v-for="book in books") {{book}}
var vm=new Vue({
 el: "#app",
 data: {
  books: ["雨天的艾莉絲", "鋼鍊", "天地明察"]
 }
});

Display

CODEPEN

 

【Vue.js】v-for

基本用法

v-for=”項目 in 陣列”

#app
 ul
  li(v-for="item in shoplist") {{item}}
var vm=new Vue({
 el: "#app",
 data: shoplist: ["apple", "banana", "papaya"]
});

Display

  • apple
  • banana
  • papaya

物件形式與存取編號

編號用id表示

#app
 ul
  li(v-for="(id, item) in shoplist2") {{id+1}}. {{item.name}}
  br
  |${{item.price}}

//陣列的編號從0開始計算,但是一般商品的編號要從1開始,所以id+1
var vm=new Vue({
 el: "#app",
 data: shoplist2: {
 name: "apple",
 price: 1000,
 origin: ["美國", "日本"]
 },
 {
 name: "banana",
 price: 500,
 origin: ["台灣", "韓國", "菲律賓"]
 },
 {
 name: "papaya", 
 price: 300,
 origin: ["亞特蘭提斯", "印度"]
 }
});

Display

  • 1. apple
    $1000
  • 2. banana
    $500
  • 3. papaya
    $300

使用第二層v-for

#app
 ul
  li(v-for="(id, item) in shoplist2") 【編號】{{id+1}} 
  br
  |【品名】{{item.name}}
  br
  |【價錢】${{item.price}}
  br
  |【生產地】
  span(v-for="place in item.origin") </br>{{place}}
var vm=new Vue({
 el: "#app",
 data: shoplist2: {
 name: "apple",
 price: 1000,
 origin: ["美國", "日本"]
 },
 {
 name: "banana",
 price: 500,
 origin: ["台灣", "韓國", "菲律賓"]
 },
 {
 name: "papaya", 
 price: 300,
 origin: ["亞特蘭提斯", "印度"]
 }
});

Display

  • 【編號】1
    【品名】apple
    【價錢】$1000
    【生產地】
    美國
    日本
  • 【編號】2
    【品名】banana
    【價錢】$500
    【生產地】
    台灣
    韓國
    菲律賓
  • 【編號】3
    【品名】papaya
    【價錢】$300
    【生產地】
    亞特蘭提斯
    印度

 

 

【CSS】Width fix the list text

問題背景

<li>在不指定寬度的情況下,會自動填滿整行。
如果把border叫出來,就會很明顯。
例如:

  • 填滿整行的li
  • 填滿整行的li

可以佐以排版技巧來解決這個問題。

橫向排列:inblock

橫向排列只要指定display就可以解決問題

ul
 li 橫向排列不填滿
 li 橫向排列不填滿
 li 橫向排列不填滿
li
 border: 1px solid #000
 display: inline

Display

  • 橫向排列不填滿
  • 橫向排列不填滿
  • 橫向排列不填滿

縱向排列:float

使用float完成縱向排列

ul
 li 縱向排列不填滿
 li 縱向排列不填滿
 li 縱向排列不填滿
ul
 float: left

li
 border: 1px solid #000

Display

  • 縱向排列不填滿
  • 縱向排列不填滿
  • 縱向排列不填滿

 

注意:周邊元素必須指定clear

如果不指定clear的話,會變成這樣↓↓

  • 縱向排列不填滿
  • 縱向排列不填滿
  • 縱向排列不填滿

這段文字想要放在清單下方,但是跑到左邊來了QQ

 

 


解決法:周邊的元素指定clear。

ul 
 li 縱向排列不填滿 
 li 縱向排列不填滿 
 li 縱向排列不填滿 

p 這段文字想要放在清單下方,成功。
ul
 float: left
li
 border: 1px solid #000

p 
 clear: both 
 //該元素的左邊(left)、右邊(right)、兩邊(both)都不可以有任何東西,若有的話,該元素會自動往下移。

Display

  • 縱向排列不填滿
  • 縱向排列不填滿
  • 縱向排列不填滿
這段文字想要放在清單下方,成功

【Vue.js】變數代換

説明

Vue.js是前端框架,用JS解決HTML資料處理。
→技術文件

HTML:寫模板
JS:代入資料
→解決①HTML重複撰寫太多②資料即時更新問題

應用

引入Vue.js

<head>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.js"></script>
</head>

建立模板與代入資料

#app
//指定Vue作用區域
 h1 Vue.js 使用大括號與變數代換
 hr
 p 我的名字叫做{{name}},來自{{city}}
 //用兩個大括號{{}}建立模板
 br
 |最近正在學習如何使用{{lang}},
 br
 |他其實就像是一個{{text}}
 p Vue.js的代換可以用物件來表示,甚至陣列來判斷。
//建立一個Vue, 即時監測資料更新狀況
var vm=new Vue({
 el: "#app", //指定作用區域
 data: { //用物件形式存放資料
 name: "陳怡安",
 city: "基隆市",
 lang: "Vue.js",
 text: "資料置換法",
 notation: "兩個大括號{{變數名稱}}",
 }
})

Display

我的名字叫做陳怡安,來自基隆市
最近正在學習如何使用Vue.js,
他其實就像是一個資料置換法

Vue.js的代換可以用物件來表示,甚至陣列來判斷。
只要在裡面用兩個大括號{{變數名稱}}包起來就可以了。

陣列與v-for列表渲染

#app
 p 我的技能有:
 /**************
 非v-for法
 ul 
  li {{skills[0]}}
  li {{skills[1]}}
  li {{skills[2]}}
  li {{skills[3]}}
 ****************/
 //v-for法
 ul
  li(v-for="skill in skills") {{skill}}
  //skill 可以自己命名
  //skills要根據vue撰寫的内容指定
var vm=new Vue({
 el: "#app",
 data: {
 skills: ["程式開發", "網頁設計", "翻譯", "口譯"],
});

Display

我的技能有:

  • 程式開發
  • 網頁設計
  • 翻譯
  • 口譯

 使用物件資料

#app
 p 我踏入網頁設計已經有{{infos.year}}年了,希望可以持續進步。
var vm=new Vue({
 el: "#app",
 data: {
 infos:{
 year: 1
  },
 }
});

Display
我踏入網頁設計已經有1年了,希望可以持續進步。

代入HTML程式碼

使用3組大括號代入HTML程式碼

#app
 p Vue.js除了預設帶入是一般的純文字以外,三組大括號可以代入HTML原始碼
 div {{{html}}}
.block
 width: 100px
 padding: 10px
 border: 1px solid #000
var vm=new Vue({
 el: "#app",
 data: {
  html: "<div class='block'>代入HTML</div>"
  //雙引號内的HTML字串裡面要改單引號
 }
});

Display

代入HTML

globalCompositeOperation 合成效果

説明

對canvas產生圖層混合的效果。
類似CSS的mix-blend-mode

範例

canvas#canvas(width="800", height="800")
html, body
 margin: 0
 padding: 0
 overflow: hidden
const ctx=canvas.getContext("2d");


ctx.fillStyle="#FFA500";
ctx.fillRect(400, 400, 100, 100);

//合成效果一覽
ctx.globalCompositeOperation="multiply";

ctx.fillStyle="#f7f4c8";
ctx.fillRect(450, 450, 100, 100);

Display
Display

destructuring assignment 分離指派式

説明

可以將陣列或物件的資料取出成獨立變數。
※通常用來大量指定變數,可以一行寫完。

範例

/********
以前的寫法
const a=1;
const b=2;
*********/

/***ES6新寫法***/
[a, b]=[1, 2]
//可以簡潔地指定一坨變數。

console.log(a, b)//1 2

canvas stroke 描繪線條

步驟

  1. 建立路徑
    beginPath()
  2. 設定線條寬度(可省)
    lineWidth=”5″
  3. 設定顏色(可省)
    strokeStyle=”green”
  4. 開始
    moveTo(0, 100)
  5. 結束
    lineTo(300, 100)
  6. 畫出線來
    stoke()

範例

canvas#canvas(width="300", height="150")
const ctx=canvas.getContext("2d");
canvas.width=window.innerWidth;
canvas.height=window.innerHeight;

//draw a line
ctx.beginPath();//start to draw a line
ctx.lineWidth="5";//set line width
ctx.strokeStyle="green";//set color
ctx.moveTo(0, 100);//start point
ctx.lineTo(300, 100);//end point
ctx.stroke();//draw it

Display

const

const 的特性

  1. 不可以被修改(再指定)
  2. 如果有block,在block裡面可以被改,但是回到外面會變回初始值

cant’t be updated & defined

const width=100;

width=200;
console.log(width);//100
//不可被修改

block scope

let points=50;
const winner=false;


if(points>40) {
 const winner=true;
 console.log(winner);//true
 //只有在block內部,才能夠被更改
}

console.log(winner);//false
//在外部則不會被更改,呈現初始值

By Value or By Reference

當資料類型為By Value時〔Number, String, Boolean〕
以const宣告的變數是不能被再指定的(即等於不能被改)

//錯誤示例
const name='Ian';
name='Chen'; //←ERROR!!

但若資料類型是By Reference時〔Object, Array〕,
以const宣告後可以用push, object.item=xxx等方式修改其值。
但一樣不能進行再指定的動作

//正確示例
const fruits=['apple', 'banana', 'orange'];
console.log(fruits); //['apple', 'banana', 'orange']

fruits.push('grape');
console.log(fruits); //['apple', 'banana', 'orange', 'grape']
//錯誤示例
const colors=['red', 'blue', 'green'];
colors=['pink', 'black', 'white'] //←ERROR!!

let

block

block是指大括弧 {} 裡面。
像是if述句,for述句,function裡面都是block

  • global scope→任何地方都能被改
  • block socpe→在if述句,for述句,function裡面可以被改(大括號包起來的地方),在外面還是回到初始值
  • function scope→只有在function裡面才可以被改

let 的特性

  1. 可以被修改
  2. 如果有block,在block裡面可以被改,但是回到外面會變回初始值

updated & defined

let width=100;

width=200;
console.log(width);//200
//可被修改

block scope

let points=50;
let winner=false;


if(points>40) {
 let winner=true;
 console.log(winner);//true
 //只有在block內部,才能夠被更改
}

console.log(winner);//false
//在外部則不會被更改,呈現初始值

var

var的特性

  1. 可以被重新定義(redefined)
  2. 可以被更新(updated)
  3. 若存在於函式內(function),就是函式變數(function scope),只能在函式內部被存取、修改。
  4. 若沒再函式內,會變成全域變數(global scope),不論在函式內或是外面都可以被存取,修改。

redefined and updated

var width=100;
console.log(width);//100

width=200;
console.log(width);//200
//可被修改

function scope

function setWidth() {
 var width = 100;
 console.log(width);//100
}

setWidth();
console.log(width);//nothing
//width只能在setWidth裡面作用

global scope

var width;
function setWidth() {
 width = 100;
 console.log(width);//100
}

setWidth();
console.log(width);//100
//width 在任何地方都能被修改或存取
let points = 50;
var winner = false;

if(points > 40) {
 var winner = true
 console.log(winner);//true
}

console.log(winner);//true
//因為if不是function,所以winner變成全域變數
//能在任何地方被修改與存取

建立canvas

説明

canvas 是一種強大的繪圖功能。
透過 HTML 與 JS 的使用 (主要是 JS )
可以在瀏覽器上繪製任何向量圖型。
跟 SVG 有點像,但用途更多元。

步驟解説

設定 HTML 與 CSS

canvas#canvas(width="800", height="800")
//呼叫canvas,然後給一個id,設定畫布長寬
//這邊設定的長800寬800會成為指定向量元素的絶對定位參考

html, body
 margin: 0
 overflow: hidden
//讓邊界不會多出來

定義 context 與長寬

context 是作畫的畫布。
圖形都要畫在 context 上面。

//定義context
const ctx=canvas.getContext("2d");//平面圖型用2d

//定義長寬
canvas.width=window.innerWidth;
canvas.height=window.innerHeight;//設定畫布=全螢幕

開始作畫(添加圖形元素)

  1. 先設定顏色
  2. 再設定圖形
//填色
ctx.fillStyle="#FFA500";


//畫正方形
ctx.fillRect(400, 400, 100, 100);
//※顏色要在最上面,否則正方形會變成黑的

游標

説明

  1. 用 CSS 刻出游標樣式
  2. 抓取滑鼠位置
  3. 游標的位置隨著滑鼠移動而改變

範例

#cross
#cross
 position: absolute
 &:before,&:after
 content: ""
 display: block
 width: 60px
 height: 15px
 background-color: #fff
 position: absolute
 left: 50%
 top: 50%
 transform: translate(-50%,-50%) rotate(45deg)
 &:after
 transform: translate(-50%,-50%) rotate(-45deg)
window.addEventListener("mousemove", function(evt){
 
 var x=evt.pageX;
 var y=evt.pageY;
 
 cross.style.left=x+"px";
 cross.style.top=y+"px";
})

Display

CODEPEN

splice() 陣列項目刪除

説明

刪除或增添陣列項目

範例

刪除項

陣列.splice(編號,刪除幾項)

【例】arr.splice(1, 1)
→從 arr[1] 開始刪除1項
→刪掉 arr[1]

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
fruits.splice(1, 1)//從fruits[1]開始,刪掉1項。

console.log(fruits);//["Banana", "Lemon", "Apple", "Mango"]

增添項

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
fruits.splice(1, 1, "Melon")//從fruits[1]開始,刪掉1項,插入“Moko”

console.log(fruits);//["Banana", "Melon", "Lemon", "Apple", "Mango"]

 

slice() 保留部分陣列項目

定義

指定陣列編號範圍,返回一組新的陣列

【必須値】開始,結束
※返回的値不會包含結束的編號,但會包含開始的那個編號

範例

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];

const sl=fruits.slice(0, 2);
//return//fruits[0], fruits[1];
console.log(sl);//["Banana", "Orange"]

【省略結束値】回報至最末項

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];

const sl=fruits.slice(2);
//等於fruits.slice(2, fruits.length);
//return fruits[2], fruits[3], fruits[4]
console.log(sl);//["Lemon", "Apple", "Mango"]

擷取多範圍

fruits共有5項資料。
保留【第1項】【第3~5項】。

多條件要用中括號[]包起來。
條件之間用逗號, 連結。
並且加上spread operator轉換成array形式。

const fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];

const sl=[
 ...fruits.slice(0, 1),
 ...fruits.slice(2)
];

console.log(sl);
//["Banana", "Lemon", "Apple", "Mango"]

陣列相關方法2

Ref: JavaScript30

some()  確認有沒有人符合條件

給予條件→找出是否有一個人(或以上)符合條件。

//共用陣列資料
const people = [
 { name: 'Wes', year: 1988 },
 { name: 'Kait', year: 1986 },
 { name: 'Irv', year: 1970 },
 { name: 'Lux', year: 2015 }
];

確認是否有人已滿19歳

/*****【方法一】function*************/
const isAdult1=people.some(

function(person){
 //getFullYear?
 const currentYear=new Date().getFullYear();
 if(currentYear-person.year>=19){
 return true;
 }
}
 
);


/*****【方法二】arrow function*******/
const isAdult2=people.some(person => new Date().getFullYear()-person.year>=19);
console.log(isAdult2);//true

every()  確認是否全員符合條件

給予條件→找出是否所有人都符合條件。

確認是否全員都滿19歳

const everyAdult=people.every(person => new Date().getFullYear()-person.year>=19);

console.log(everyAdult);//false

find()  找出特定的項目

//共用陣列資料
const comments = [
 { text: 'Love this!', id: 523423 },
 { text: 'Super good', id: 823423 },
 { text: 'You are the best', id: 2039842 },
 { text: 'Ramen is my fav food ever', id: 123523 },
 { text: 'Nice Nice Nice!', id: 542328 }
];

找出id為【823423】的留言

const comment=comments.find(comment => comment.id===823423);

console.log(comment);
/**
Object {
  id: 823423,
  text: "Super good"
}
**/

findIndex 找出特定項目的陣列編號

【※注意】陣列編號由 0 開始算。編號 0 為第1項、編號 1 為第 2 項。

找出id為【823423】的陣列編號

const index=comments.findIndex(comment => comment.id===823423);

console.log(index);//1 ←comments[1];

splice 刪除特定編號的陣列

參考文章
【※注意】只能指定編號刪除。

comments.splice(1, 1);

//然後comments就會少一項了。但不保留沒刪除前的内容。

slice 摘取陣列

參考文章

也可以達到刪除特定項目陣列的效果。
但方法是擷取保留項目,像是指定列印頁數。

共5頁的資料→只列印【第1頁】、【第3-5頁】→最後印出來的資料就會少了第2頁

用slice可以同時保留刪除前的陣列與刪除後的陣列。

const newComments=[
 ...comments.slice(0, 1),//only return comments[0]
 ...comments.slice(2)//omit end value
 //保留slice[0], slice[2-4]→等於去掉slice[1]
]; 

console.log(newComments);
/**
const newC=[
 ...comments.slice(0, 1),//only return comments[0]
 ...comments.slice(2)//omit end value
];
**/

 

搜尋器

Reference: JavaScript 30

先備知識

範例

form.search-form
 input.search(type='text', placeholder='City or State')
 ul.suggestions
 li Filter for a city
 li or a state
html
 box-sizing: border-box
 background: #ffc600
 font-family: 'helvetica neue'
 font-size: 20px
 font-weight: 200

*
 box-sizing: inherit
 &:before, &:after
 box-sizing: inherit

input
 width: 100%
 padding: 20px

.search-form
 max-width: 400px
 margin: 50px auto

input.search
 margin: 0
 text-align: center
 outline: 0
 border: 10px solid #F7F7F7
 width: 120%
 left: -10%
 position: relative
 top: 10px
 z-index: 2
 border-radius: 5px
 font-size: 40px
 box-shadow: 0 0 5px rgba(0, 0, 0, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.19)

.suggestions
 margin: 0
 padding: 0
 position: relative
 /*perspective:20px;
 li
 background: white
 list-style: none
 border-bottom: 1px solid #D8D8D8
 box-shadow: 0 0 10px rgba(0, 0, 0, 0.14)
 margin: 0
 padding: 20px
 transition: background 0.2s
 display: flex
 justify-content: space-between
 text-transform: capitalize
 &:nth-child(even)
 transform: perspective(100px) rotateX(3deg) translateY(2px) scale(1.001)
 background: linear-gradient(to bottom, #ffffff 0%, #EFEFEF 100%)
 &:nth-child(odd)
 transform: perspective(100px) rotateX(-3deg) translateY(3px)
 background: linear-gradient(to top, #ffffff 0%, #EFEFEF 100%)

span.population
 font-size: 15px

.details
 text-align: center
 font-size: 15px

.hl
 background: #ffc600

.love
 text-align: center

a
 color: black
 background: rgba(0, 0, 0, 0.1)
 text-decoration: none
const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';

const cities=[];

//blob用來指稱原始資料
//轉換成JSON資料
fetch(endpoint)
 .then(blob => blob.json())
 .then(data => cities.push(...data))

function find(word, cities){
 
 return cities.filter(place => {
 const regex=new RegExp(word, "gi");
 return place.city.match(regex) || place.state.match(regex)
 })

}

function commas(x){
 return x.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
}


function display(){
 const match=find(this.value, cities);
 const html=match.map(place => {
 const regex=new RegExp(this.value, "gi");
 const cityName=place.city.replace(regex, `<span class="hl">${this.value}</span>`);
 const stateName=place.state.replace(regex, `<span class="hl">${this.value}</span>`);
 
 return `
 <li>
 <span class="name">${cityName}, ${stateName}</span>
 <span class="population">${commas(place.population)}</span>
 </li>
 `
 }).join("");
 
 
 suggestions.innerHTML=html;
}

const search=document.querySelector(".search");
const suggestions=document.querySelector(".suggestions");


search.addEventListener("change", display);
search.addEventListener("keyup", display);

Display

CODEPEN

regex【i】不區別大小寫

功能

讓字串不區分大小寫,也能通過正規表達式檢査。
應用實例:搜尋不用區分大小寫,也能找到同樣的内容。

類似的東西:regex【g】找出所有

範例

方法一【/i】

i代表 insensitive ,對大小寫不敏感。

const regex=/apple/i;

const str1="APPLE";
const str2="Apple";
const str3="apple";

str1.match(regex);//["APPLE"]
str2.match(regex);//["Apple"]
str3.match(regex);//["apple"]
//不論大小寫(或混用)都能通過驗證

方法二【new RegExp】

使用時機:需要檢査的字串不是固定値,而是變數時(像是使用者鍵入的搜尋字詞)

寫法跟【/i】不同,但是效果相同。

const regex=new RegExp("apple", "i");

const str1="APPLE";
const str2="Apple";
const str3="apple";

str1.match(regex);//["APPLE"]
str2.match(regex);//["Apple"]
str3.match(regex);//["apple"]

fetch

介紹

fetch,是ajax之外取得外部資料的一種方式
使用promise物件架構

補充:ajax

範例

取得圖片

img#img
const moko="https://scontent-tpe1-1.xx.fbcdn.net/v/t1.0-9/15355572_1410266889006372_4764767806658769471_n.jpg?oh=39e4da3e9a9956f349b6c701556544ff&oe=593B04D9"


fetch(moko)
 .then(blob => blob.blob())
 .then(myb => img.src=URL.createObjectURL(myb))

//fetch發送請求
//使用blob獲得圖片的內容
//再從blob獲得URL,放到img的src之中

Display

取得JSON資料(有function的情況下)

button#btn click me
ul#ul
const endpoints="https://awiclass.monoame.com/api/command.php?type=get&name=tododata";

const tododata=[];

fetch(endpoints)
 .then(blob => blob.json())
 .then(data => tododata.push(...data))//要用spread把nodeList轉成array

function show (){
 ul.innerHTML=tododata.map(place => `<li>${place.name}</li>`).join("");//join("")把陣列轉換成字串,並且將分隔取代為無
}

btn.addEventListener("click", show)

Display

CODEPEN

取得JSON資料(無function的情況下)

沒有function的情況下,JS無法用內接陣列的方式,讀取外部URL的JSON。
因此,方法改寫如下,

ul#ul
const endpoints="https://awiclass.monoame.com/api/command.php?type=get&name=tododata";

// const tododata=[];

fetch(endpoints)
 .then(blob => blob.json())
 .then(data => {
 ul.innerHTML=data.map(place => `<li>${place.name}</li>`).join("");
})

Display

CODPEN

onclick

功能

onclick 是 HTML 的屬性,等於 JavaScript 的 click 事件

範例

button#btn(onclick="scale()") click me
/******
onclick="scale()"等於這個
btn.addEventListener("click", scale);
******/

function scale(){
 btn.style.transform="scale(2)";
 btn.style.transformOrigin="left top";
}

Display

jQuery AJAX

功能

不刷新頁面也能完成前後端的溝通。

  • HTML + PHP + MySQL :必須刷新頁面
  • HTMP + Ajax + PHP + MySQL:不必刷新頁面

以 Facebook 的按讚功能為例
使用者按讚→資料庫更新讚數→網頁顯示讚數+1

透過 Ajax 的輔助,這一連串的動作都可以不刷新網頁而達成。
使用者不必中斷滑到一半的閱讀體驗。

結構

  • form tag,使用 HTTP Method
  • 引入 jQuery
  • 準備處理資料庫溝通的 php 檔案,跟 HTML 放在同一個資料夾底下
  • 準備好 MySQL 資料表

範例

前端

//HTTP Method
form(method="POST")
 input(type="text" placeholder="email")
 input(type="password" placeholder="password")
 input(type="submit")
 p
const email=document.querySelectorAll("input")[0];
const password=document.querySelectorAll("input")[1];
const submit=document.querySelectorAll("input")[2];
const alert=document.querySelector("p");


submit.addEventListener("click", function(e){
 //clear submit default
 e.preventDefault();
 $.ajax({
 type: "POST",//對應 form 的 method
 url: "insert.php",//指定 php 檔案
 data: {
 //要傳送的值。php超全域變數: js變數
 email: email.value, 
 password: password.value
 },
 //若傳送成功
 success: function(re){
 //若php回應值=="success"
 if(re=="success"){
 alert.textContent="register successful"
 }else{
 alert.textContent="register fail"
 }
 }
 });
})

後端

+----------+------+-----+---------------+
| Field    | Type | Key | Extra         |
+----------+------+-----+---------------+
| ID       | int  | PRI | auto_increment|
| email    | text |     |               |
| password | text |     |               |
+----------+------+-----+---------------+
<?php

mysql_connect("localhost", "root", "");//MySQL連線
mysql_select_db("register");//選擇資料庫

//$_POST['email']與$_POST['password']是ajax定義好的超全域變數
//防止隱碼注入攻擊
$_POST['email']=mysql_escape_string($_POST['email']);
$_POST['password']=mysql_escape_string($_POST['password']);

//帳號與密碼寫入資料庫
$save=mysql_query("INSERT INTO member (email, password) VALUES('$_POST[email]','$_POST[password]')");


if(!$save){
 
 echo "fail";//若寫入失敗回傳fail

}else{
 
 echo "success";//成功則回傳success
}


?>

 

程式碼上色函式庫 highlight.js

功能

程式碼上色,可以用 syntax 找相關的英文資源 ,這個函式庫可以將部落格的程式碼文字依照關鍵字、註解等上不同顏色。

使用方法

  1. 引入 css 與 js 函式庫
  2. 依照規範撰寫pre tag 與 code tag
  3. 寫進指定 js 碼

※css有各種style。

一般網頁

外引CDN函式庫的方法

引入 js 與 css 函式庫

<head>
 
 //引入css,這裡選擇tomorrow style
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/styles/tomorrow.min.css" />

 //引入js
 <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js"></script>
</head>

依照規範撰寫 pre 與 code

  1. pre tag 裡面包一層 code tag
  2. <code class=”程式語言名”>
//以寫css碼為例
<pre>
 <code class="css">
  pre {
  border: 1px solid #eee;
  width: 400px;
 }
 </code>
</pre>

寫進指定 js

function custom(){
 hljs.initHighlightingOnLoad();
}
custom();

Display

CODEPEN

WordPress

header.php→引入 css 與 js 函式庫、寫入指定 js

<head>

//在head tag之間加上下面這3行
<!--highlight.js-->
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/styles/tomorrow.min.css">
 <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js"></script>

</head>

<body <?php body_class(); ?>>

//在<body>下面加上這段script
<script>
hljs.initHighlightingOnLoad();
</script>

文章編輯:text editor→依照規範撰寫 pre 與 code

//以寫css碼為例
<pre>
 <code class="css">
  pre {
  border: 1px solid #eee;
  width: 400px;
 }
 </code>
</pre>

Display

CODEPEN

 

 

match() 與 test()

功能

兩者都是搭配正規表達式的Method

match()

字串.match(正規表達式);
//回傳比對出的部分字串結果
//若比對不到東西,則回傳null

const str="apple";
const check=/[a-c]/;

str.match(check);//["a"]

test()

正規表達式.test(字串);
//有比對到回傳true,沒有則回傳false

const str="apple";
const check=/[a-c]/;

check.test(str);//true

setInterval

功能

設定每隔一段時間執行一次動作,可以模擬動畫效果
缺點:只能處理能夠數值化的CSS屬性(width, opacity, scale, rotate等等),不能完成顏色漸變等效果

button(onclick="show()") click me
br
br
#box show up
#box
 width: 200px
 height: 100px
 background-color: #aaffe2
 text-align: center
 line-height: 100px
function show(){
 //pos是變動的透明度數值
 var pos=0;
 //setInterval(動作, 毫秒)→每隔幾毫秒,執行一次動作
 const id=window.setInterval(function(){
 
 if(pos>=1){
 //如果pos夠大了,清掉Interval,阻止繼續增加下去
 clearInterval(id);
 pos=0;
 }else{
 pos+=0.1;
 box.style.opacity=pos;
 }
 
 }, 50)
}

show up

正規表達式

説明

正規表達式,是專門用來處理字串邏輯的條件語法。
常常用在 input 表單上,檢査使用者輸入的内容有沒有符合特定格式。
諸如信用卡號格式驗證,密碼強度驗證等等。

相關方法:match(),test()

語法

宣告正規表達式

正規表達式的前後要各用1個斜線/包起來(有點像字串需要用”包起來)。

const str="abcde";
const check=/abc/;

str.match(cri);//["abc"]
//回傳 被找到的字串
if(str.match(cri)){
 console.log(true);
 //↑通常驗證表單會寫成這個形式,裡面放通過驗證後的動作
}else{
 console.log(false)
}//true

尋找某區間内文字

設定檢索區間: [a-e]
a為開始値,e為終止値。

const str="apple";
const check=/[a-c]/;//尋找有沒有 a,b,c 這3個字母
//※寫成/[a-c]/g會比較好(下面會説明)
//※也可以比對多重區間(下面説明)

str.match(check)//["a"]

if(str.match(cri)){
 console.log(true);
}else{
 console.log(false);
}//true ←但只有 a 有被找到而已,pple並沒有被找到

/*****注意*****
※這個例子match是寬鬆尋找方法,只要有1個字元被找到,就會跑出true
*************/

尋找全部【/g】

參考這篇文章

一般情況下,match只會1次比對一個字串字元而已,所以回傳値只會吐出第1項符合的字元。
如果要叫他吐出所有,就要使用/g←放在正規表達式的最後面

※但如果是用 if(str.match(check)) 的話不使用 /g 也沒差

const str="apple";
const check=/[a-e]/;
const check2=/[a-e]/g;//尋找全部寫法


str.match(check);//["a"]
str.match(check2);//["a", "e"]←這樣寫就可以一條一條找出所有符合的字元了

/****比對多重區間***/
const check3=/[a-eo-p]/g//←直接接下去加入就好

str.match(check3);//["a", "p", "p", "e"]

尋找數字與數字字符【\d】

有2種方法可以找到數字

  • 設定 0-9 的區間
  • 正規字符【\d】
const str="apple123";
const check=/[0-9]/g
const check2=/\d/g; //\d效果同等於[0-9]


str.match(check);//["1", "2", "3"]
str.match(check2);//["1", "2", "3"]

檢査數字長度

使用大括號{}指定該字元必須出現幾次

const str="123456";
const check=/\d{4}/;//{4}表示數字(\d)要連續出現4次←4位數字

str.match(check);//["1234"]

if(str.match(check)){
 console.log(true);
}else{
 console.log(false);
}//ture
/*****
str="123456"→true
str="1234"→true
str="12"→false

只有當str不足4位數字時才會回報false(match找不到匹配値,回傳null)
str滿足或超過4位數都會回傳true
※那要怎麼寫手機號碼驗證!←下面告訴你
*****/

設定嚴格的條件:使用開始【^】與結束【$】字符

在上例中可以發現,只有當字串不滿足條件時才會報 false ,剛好符合或超過條件的清況都會回報 true 。

但某些情況下,我們需要非常精確的格式,比如

  • 手機號碼必須是 10 位數字
  • 信用卡號必為 4位數-4位數-4位數-4位數
  • 身份證字號為 1大寫英文 + 9 為數字

所以我們必須更進階地規定條件,不足或超出條件者都必須是 false。

以下為嚴格化寫法

  • 在開頭加入開始字符^
  • 結尾加入結束字符$
//驗證手機號碼
const str1="0912345678";
const str2="0912";
const str3="09123456789999"
const check=/^\d{10}$/;

str1.match(check); //["0912345678"]
str2.match(check); //null
str3.match(check); //null

//進階:規定前2碼為09

const check2=/^09\d{8}$/; //指定09跟後面的8碼條件不用任何東西連接,直接加上就行

str1.match(check2); //["0912345678"]

英數字集符號【\w】

如同 \d 為 [0-9] 的簡寫一般,
\w 則為 [a-zA-Z0-9_] 的簡寫。

可以檢查所有英文大小寫字母,底線,以及數字

const str="ianchen_0419";

const check=/\w/g;
const check2=/[a-zA-Z0-9_]/g;
//這兩個效果一樣

str.match(check);//["i", "a", "n", "c", "h", "e", "n", "_", "0", "4", "1", "9"]
str.match(check2);//["i", "a", "n", "c", "h", "e", "n", "_", "0", "4", "1", "9"]

 

可有可無的條件【?】

『使用者名稱可以包含減號-』

這樣的情況下,不論字串有無減號-,皆可滿足條件。
因此減號-是一個可有可無的條件。

在減號-後面加上問號 ? ,便可以構成可有可無的驗證式

const str1="ianchen";
const str2="ian-chen";
const str3="ian--chen";
const str4="-ianchen";
const str5="ianchen-";

const check=/\w-?\w/;
const check2=/^\w-?\w$/;
//用check2的話5個str都會是null,因為check2必須是【1字母 + 有無底線皆可 + 1字母】的組合才行。


str1.match(check);//["ia"]
str2.match(check);//["ia"]
str3.match(check);//["ia"]
str4.match(check);//["-i"]
str5.match(check);//["ia"]
//結論:5種情況都可以true

比對特殊字元:前置反斜線\

Regex特殊字元【.^$?】

這些字元都是Regex特殊字符,帶有特殊的意義。
若要單純比對這些符號,必須前置反斜線\以做區別。

const str1="$";
const str2="^";
const str3=".";
const str4="?";

const check1=/\$/;
const check2=/\^/;
const check3=/\./;
const check4=/\?/;

str1.match(check1);//["$"]
str2.match(check2);//["^"]
str3.match(check3);//["."]
str4.match(check4);//["?"]

比對很多次【+】

重複比對【+】前面的東西很多次

const str="ianchen_0419";
const check=/\w+/;
//重複比對英文字元(←【+】前面的)很多次,直到比對不了為止

str.match(check);//["ianchen_0419"]

有後面再比對前面【?=】

a(?=b)→如果有找到b的話,再檢查前面有沒有a,並且比對出a
【?=b】要使用括號包起來

const str1="ianchen0419";
const str2="ianchen"
const str3="0419ianchen";
const check=/[a-z]+(?=\d)/;
//後面有數字的話,再比對前面有沒有英文
//然後把所有的英文都找出來【+】

str1.match(check);//["ianchen"]
str2.match(check);//null ←這個因為後面找不到數字所以沒辦法比對英文
str3.match(check);//null ←這個因為數字前面沒有英文所以一樣無法

沒有後面再比對前面【?!】

a(?!b)→如果沒有找到b的話,再檢查前面有沒有a,並且比對出a
【?!b】要使用括號包起來

使用情境:給數字加上分隔逗號,每3碼加一個逗號,但是要從最末位往前數(所以要確保後面沒有落單的數字)

【例】1,234,567,890

const str1="ianchen0419";
const str2="ianchen"
const str3="0419ianchen";
const check=/[a-z]+(?!\d)/;
//後面沒有數字的話,再比對前面有沒有英文
//然後把所有的英文都找出來【+】

str1.match(check);//null ←這個因為後面有數字了所以不能比對前面的英文
str2.match(check);//["ianchen"]
str3.match(check);//["ianchen"]

找出英文邊界【\b】

※前提,英文句子要用空格隔開單字

【\b\w】→找到每個單字字首
【\w\b】→找到每個單字字尾

const str="this is a apple";//必須要有空格
const check1=/\b\w/g;//找字首
const check2=/\w\b/g;//找字尾

str.match(check1);//["t", "i", "a", "a"]
//"this is a apple"

str.match(check2);//["s", "s", "a", "e"]
//"this is a apple"

找出非英文邊界【\B】

用途:數字,符號等等

const str="1234567890";
const check1=/\B\d{3}/g;//每3個字斷開(從後面開始數)
const check2=/\d{3}\B/g;//每3個字斷開(從前面開始數)


str.match(check1);//["234", "567", "890"]
str.match(check2);//["123", "456", "789"]

英文數字逗點

【例】1234567890→1,234,567,890

function commas(x){
 return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
 //①從最末位往前數3碼(後面沒有數字的話,比對出3個數字)
 //②一直數一直數
 //③符合①就給他分隔符號
 //④\B比對非英文字的邊界,如果沒有\B的話會變成",123,456,789"
 //取代所有分隔符號為","

}

線上練習網站:RegexOne

CSS not selector

指定不要選到某class的元素

語法::not(.your-class)
h1.h1 h111
h1.h2 h222
h1.h3 h333
h1:not(.h1)
 color: red

指定不要選到某attribute的元素

抓取attribute名稱的範例
h1.h1(data-h1) h111
h1.h2(data-h2) h222
h1.h3(data-h3) h333
h1:not([data-h1])
 color: red
抓取attribute名稱+內容的範例
h1.h1(data-heading="h1") h111
h1.h2(data-heading="h2") h222
h1.h3(data-heading="h3") h333
h1:not([data-heading="h1"])
 color: red

多重條件

h1.h1 h111
h1.h2 h222
h1.h3 h333
h1
 color: red
 
h1:not(.h2):not(.h3)
 color: black

JavaScript Array methods 陣列相關方法1

本篇介紹的method

filter()[👧, 👦, 👩, 👨, 👵, 🧓] => [👦, 👨, 🧓]原本的陣列有 6 個,後來變成 3 個
map()[👧, 👦, 👩, 👨, 👵, 🧓] => [👧🏿, 👦🏿, 👩🏿, 👨🏿, 👵🏿, 🧓🏿]陣列內容都變成不一樣的顏色了(但數量一樣是 6 個)
sort()[👧, 👦, 👩, 👨, 👵, 🧓] => [👧, 👩, 👵 👦, 👨, 🧓]陣列的順序改變了
reduce()[👧, 👦, 👩, 👨, 👵, 🧓] => 👨‍👩‍👧陣列被綜合成一個東西了

本篇使用到的共用物件

const inventors = [
 { first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 },
 { first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 },
 { first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 },
 { first: 'Marie', last: 'Curie', year: 1867, passed: 1934 },
 { first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 },
 { first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 },
 { first: 'Max', last: 'Planck', year: 1858, passed: 1947 },
 { first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 },
 { first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 },
 { first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 },
 { first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 },
 { first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 }
 ];

filter() 把陣列的數量變少,但是內容不變

filter() 裡面放一個函數,filter() 可以物件→物件,也能夠陣列→陣列

應用:篩選出出生於 16 世紀的投資客(出生年介於 1500 到 1600 之間)

const arr1=inventors.filter(function(item){
 if(item.year>=1500 && item.year<1600){
  return true;
 }
})

console.log(arr1); //[{ first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 }, { first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 }]

ES6 應用:箭頭函數(省略 return

const arr1=inventors.filter(item => item.year>=1500 && item.year<1600);

console.log(arr1); //[{ first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 }, { first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 }]

map() 陣列數量固定,但裡面內容置換

map() 可以物件→陣列,也可以陣列→陣列

應用:列出所有投資客的全名(first + last

const arr1=inventors.map(item => `${item.first} ${item.last}`);

console.log(arr1); //["Albert Einstein", "Isaac Newton", "Galileo Galilei", "Marie Curie", "Johannes Kepler", "Nicolaus Copernicus", "Max Planck", "Katherine Blodgett", "Ada Lovelace", "Sarah E. Goode", "Lise Meitner", "Hanna Hammarström"]

sort() 更動陣列順序

sort() 可以物件→物件,也能夠陣列→陣列
  • return 1:往後移動
  • return -1:往前移動

應用①:將投資客由老排到年輕(出生年數字越大代表越年輕,所以要越往後移動)

sort() 裡面的函數可以塞兩個參數,第一個值代表比較的第一個人、第二個值代表比較的第二個人,sort() 會幫忙把所有排列組合都列出來
const arr1=inventors.sort(function(a, b){
 if(a.year>b.year){
  return 1; //如果a的年紀比b小,a往後擺
 }else{
  return -1;
 }
});

console.table(arr1); //結果會出來一個由老排到小的物件

ES6 應用:箭頭函數 + if 簡寫

const arr1=inventors.sort((a, b) => a.year>b.year ? 1 : -1)

console.table(arr1);

應用②:將投資客的名字 (firstname) 開頭字母由A排到Z

const arr1=inventors.sort((a, b) => a.first>b.first ? 1 : -1)

console.table(arr1);

reduce() 將陣列內容輸出為單一值

reduce() 可以物件→單一值,也可以陣列→單一值

應用①:計算所有投資客總共活了多久

  • reduce() 裡面的函數的第一個參數為「累加器 accumulator」,第二個參數為「迭代中的元素 currentValue
  • reduce() 裡面的第二個值為一個數字,表示「累加器初始值 initialValue」(通常填 0
const value=inventors.reduce(function(total, item){
 return total += (item.passed-item.year);
}, 0)

console.log(value); //861

ES6 應用:箭頭函數

const value=inventors.reduce((total, item) => total += (item.passed-item.year), 0)

console.log(value); //861

應用②:統計各個交通工具出現的次數

//原始資料
const data = ['car', 'car', 'truck', 'truck', 'bike', 'walk', 'car', 'van', 'bike', 'walk', 'car', 'van', 'car', 'truck' ];
var value=data.reduce((obj, item)=>{
 obj[item]++;
 return obj;
},{
 car: 0,
 walk: 0,
 truck: 0,
 bike: 0,
 van: 0
})

console.log(value); // {bike: 2, car: 5, truck: 3, van: 2, walk: 2}

符號分割字串 split()

字串的分割

split() 裡面填入一個字串形式的值,這個值用來切割其他要拿來切割的字串
var str='2020/01/01';
console.log(str.split('/')); //["2020", "01", "01"]

陣列=>字串的分割

陣列可以搭配 map() 轉換成字串在分割,但分割後的格式會變成陣列中的陣列
var arr=['2020/01/01 15:00', '2020/04/04 13:00', '2020/03/03 09:00'];
var arr2=arr.map(item => item.split(' '));
console.log(arr2); //[["2020/01/01", "15:00"], ["2020/04/04", "13:00"], ["2020/03/03", "09:00"]]
或乾脆只抓取分割後的某部分,組成新的陣列
var arr=['2020/01/01 15:00', '2020/04/04 13:00', '2020/03/03 09:00'];
var arr2=arr.map(item => {
 var [date, time]=item.split(' ');
 return date;
})
console.log(arr2); //["2020/01/01", "2020/04/04", "2020/03/03"]

shift() 切出第一個字串

var str="2020/01/01"
console.log(str.split('/').shift()); //"2020"

pop() 切出最後一個字串

var str="2020/01/01"
console.log(str.split('/').pop()); //"01"

EXCEL函數 vlookup

函數說明

vlookup用途會縱向比對。
通常使用的情境是當手上有一個「固定資料索引」,比方說一個中日文顏色詞彙對照表好了,內容可能類似

A欄(中文)B欄(日文)
紅色レッド
藍色ブルー
黃色イエロー
粉紅色ピンク
白色ホワイト
黑色ブラック
綠色グリーン
咖啡色ブラウン

大概像這樣,就是一個索引表,這張索引表不會出現重複的顏色
然後,某天你從主管手上收到一份清單,清單裡面充滿了各式顏色的中文詞彙
主管請你把C欄全都翻成日文,並貼到D欄上去

C欄(各式顏色)D欄(要翻成日文貼上)
紅色
紅色
紅色
粉紅色
粉紅色
黑色
綠色

C欄因為是一份真實情況下會有的資料集(可能是服飾的顏色清單)
所以他不會按照順序排列,也會有一堆重複的顏色出現
比如「紅色」就重複了4次,粉紅色也重複了2次

D欄的製作,當然也能土法煉鋼地逐欄搜尋其對應的日文,然後一個一個手動貼到D欄上去。
或者,也能使用vlookup,讓函數自動幫你找比對,自動幫忙生成D欄

用法及參數

在D欄下面的第一個儲存格輸入函數=vlookup
這隻函數一共有4個參數

  • 第1個參數:需要比對的那一欄(本例中為C欄)
  • 第2個參數:資料索引表那坨(本例中為A~B欄)
  • 第3個參數:比對答案值要參考的欄位是資料索引表的第幾欄(本例因為A~B欄中,A欄是第1欄,B欄是第2欄,B欄是我們要找的日文,所以要填2
  • 第4個參數:填0,表示資料索引表找無的話回傳N/A
C欄(各式顏色)D欄(要翻成日文貼上)
紅色=vlookup(C:C, A:B, 2, 0)
紅色
紅色
粉紅色
粉紅色
黑色
綠色

第一個儲存格寫好公式後,一路往下拉到底,就能一口氣比對好整張表格了

科技部大專院生研究計畫 心得分享

題目

我的題目是『年齡因素對日語學習之影響——探討台灣小學生、國中生、高中生的日語教與學』。
構想是日文老師的打工經驗 ,我遇過各種年齡的學生、小學國中高中都有,但小學生學習成效最好!我想可能是因為我自製教材有關,其他學生我都是用「大家的日本語」授課,所以我想探討各年齡層適合的教學法以及教材。
我的指導教授宗禾老師說過

日文研究分成三類:文學,教育,語學 文學好切入,適合大學生寫
教育需要教學經驗跟實際學生,有點門檻
語學研究難度高,是教授等級

< p class=”has-text-align-left”>實際上徵選比率還蠻平均的,文學多一點,教育最少。

審查通過關鍵

題目(想解決的問題)是審查通過的關鍵,一定要把握兩個大原則:

  • 前瞻性→類似的研究不多,所以我的研究很有意義
  • 需求性 →很多人被這個問題困擾著,並且能證明這一點

如果題目符合上面兩點,並且在研究動機具體說明,大概就十拿九穩了。
但通常,構想來自課堂的題目沒有1.也沒有2.(如果是人文學科的話)
所以我覺得生活經驗很重要

困難點

第一個困難是理論部分,我的題目很難找到相關資料,特別在『各年齡學習者適合的教材』上,幾乎一無所獲。
所以這點也變成實驗的目的。
第二個跟我設計的實驗有關:質性研究法,一對一教學紀錄與訪談。所以…需要經過打工學生的同意進行錄音,臉皮要很厚XD。
再來一週3個學生真的吃不消…非常非常的忙!!

心得

交稿前修改時,發現審查前的前半,與合格後寫的後半,語氣截然不同。
前半寫得很急躁,句子寫很長都沒斷句,語氣很重,一副很想要通過的樣子。
後半語氣就相當悠哉了(茶)。

心得分享簡報