0%

CSS3漸層

使用CSS裡面的linear-gradient()函數來建立一個漸層的背景。

預測的漸層是由top到bottom

1
background: linear-gradient(black, yellow)

要建立由左上到右下的漸層

1
background: linear-gradient(to right bottom, black, yellow)

要建立多種顏色漸層

1
background: linear-gradient(to right, black, blue, yellow)

多種顏色不同比例方向漸層

1
background: linear-gradient(145deg, green 25%, red 25%       80%, blue 80%)

簡單來說語法可以拆成方向顏色組兩類。

  • 方向可以是 to (right, left, top, bottom) 或是 to (right bottom, left top ……),甚至適用deg角度都可以

  • 顏色組則是愈漸層的顏色有哪些,同時也可以設定哪個顏色漸層部分要佔比較大的比例。 ex:上述的 green 25%, red 25% 80%, blue 80%就是綠色佔前25%,紅色佔中間25%到80%(也就是55%),藍色佔最後20%。

  • codepen參考連結

  • MDN參考文件連結

Hooks-useState

Functional Component上,我們都知道無法使用state和自定意函式,勢必要改成Class Component。而到了React 16.8版後,推出了Hooks,讓我們不必寫Class Component就可以使用state。這次先說明Hooks裡面的useState。

下方會以計數器來進行說明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//以Class Component攥寫
import React, { Component } from "react";

class App extends Component {
state = {
count: 0
};

addCount = () => {
this.setState({
count: this.state.count + 1
});
};

render() {
const { count } = this.state;
return (
<div>
<h1>{count}</h1>
<button onClick={this.addCount}>ADD</button>
</div>
);
}
}
module.exports = App;

上方code是傳統上以Class Component進行攥寫的。
下方code為改成Hooks的做法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//以Functional Component攥寫
import React, { useState } from "react";

const App = () => {
const [count, countFun] = useState(0);
const addCount = () => {
countFun(c => {
return c + 1;
});
};

return (
<div>
<h1>{count}</h1>
<button onClick={addCount}>ADD</button>
</div>
);
};
module.exports = App;

說明

1
const [count, countFun] = useState(0);

呼較useState並且給予初始的狀態(這邊的初始狀態是0),會給予一個array。array裡面的第一個值就是初始狀態(狀態並不一定是要object),第二個值是狀態的函式。

我們的目標是做一個計數器,所以countFun這個函式我們會設定成count+1。

1
2
3
4
5
6
7
8
9
10
11
12
const addCount = () => {
countFun(c => {
return c + 1;
});
};

return (
<div>
<h1>{count}</h1>
<button onClick={addCount}>ADD</button>
</div>
);

所以當button觸發onClick這個addCount的函示,會去觸發countFun這個函式。countFun可以直接指定數值等等(ex: countFun(count+1)),同樣的也可以給予一個函式,我們這邊將這個函式定義為count+1(這邊用c代表count,表示舊的state,新的state是c+1)。

  • useState不可以放在任何條件式裡面

補充

1
2
3
4
5
6
7
8
9
10
const [{num1, num2}, numFun] = useState({num1: 0, num2: 1});

//正確
const addNum1 = () => {
numFun((state) => ({...state, num1: state.num1 + 1}))
}
//錯誤
const addNum1 = () => {
numFun((state) => ({num1: state.num1 + 1}))
}

在以前處理state的值時,我們每次更新不一定需要將每個state的狀態寫出來,class會自動幫我們把缺少的state補齊。但在useState裡,則是要自己組合。

Component

在react的component中,大致上可以分為Class Component、Functional Component兩種。

  • Class Component是使用ES6 Class的寫法宣告他,同時也可以使用state和自定義的method。
  • Functional Component則是使用function的方式宣告他,但他沒有state且無法自定義method,也就是只有render的狀況使用。而其props則是透過函數傳遞進來。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Class Component
class App extends Component{
state = {
width: 0,
}

addWidth = () => {
...
}

render(){
const { width } = this.props;
return(
<div>
<div style={{width: `${width}`}}>
</div>
)
}
}
1
2
3
4
5
6
7
8
9
10
11
//Functional Component
const App = (props) => {
render(){
const { width } = this.props;
return(
<div>
<div style={{width: `${width}`}}>
</div>
)
}
}

另外還有一種叫做PureComponent,其寫法與Class Component相似,只要把extends後面改成PureComponent即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//PureComponent
class App extends PureComponent{
state = {
width: 0,
}

addWidth = () => {
...
}

render(){
const { width } = this.props;
return(
<div>
<div style={{width: `${width}`}}>
</div>
)
}
}

而PureComponent和Class Component主要是在效能上會有差異。

簡單來說如果傳入的props值不變或state值不變,PureComponent就不會重新render。但在Class和Functional Component都會重新render。

至於props和state是否改變,是透過shallow compare。
他只會比較props和state的第一層。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class App extends Component{

//state裡的width和border是第一層,color是第二層。
state = {
width: 0,
border: {
borderWidth: 1,
}
}

//此add function在Class Component會重新render,在PureComponent則不會
const add = () => {
const {border} = this.state;
border.borderWidth += 1;
this.setState({
border: border,
})
}
render(){
const { width } = this.props;
return(
<div>
<div style={{width: `${width}`}}>
</div>
)
}
}

小結

  • 若Component內不會使用到state和自定義method,可改用Functional Component。
  • PureComponet可以解決重複render之問題,但前提要確認state或props的值改變只會在第一層。

Form表單遇到多個相同name的解決方法

在以php為backend的狀況

在php中,我們可以將name得名稱設為 “xxx[]”,這樣在表單提交的時候可以獲得一個array的資料。如果沒有使用中括弧,在多個相同name提交的狀況下,只會獲得最後一個資料。

在以Node.js為backend的狀況

在Node.js為backend的狀況下,我們就無法使用中括弧的方法獲得array資料。但我們可以透過foreach或for迴圈的方法,自行將資料整理成array在觸發API或進行資料的處理。


Table欄位動態增加解決方法

innerHTML

直接以string的方式將html tag組合完畢,如

1
<tr><td>123</td></tr>

再透過innerHTML指定從哪個元素插入
但相對的如果欄位數量較多,在做組合時較為麻煩

透過table的insertRow和insertCell來解決

1
2
3
4
let table = document.getElementById("table");
let tr = table.insertRow(-1);
let td1 = td.insertCell(0);
td1.innerHTML = <span>RED</span>
  • 透過insertRow來指定從哪一列開始增加列
  • 0為從目前表格最上方,-1為表格最下方
  • insertCell來增加該列的欄位
  • 欄位內的內容可以透過innerHTML直接指定或透過createElement來生成

nginx在mac安裝以及簡易文件說明

在mac上安裝nginx可以使用brew進行安裝

1
brew install nginx

安裝完可以下

1
nginx

來啟動服務

從安裝完的畫面我們可以知道
nginx.conf這個重要的設定文件路徑為/usr/local/etc/nginx/nginx.conf


nginx.conf

我們先以原始的內容做說明
下方的#及為註解的部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#基本上就是啟動這個服務的用戶是誰,通常可以不進行設定
#user nobody;

#通常在直接作為伺服器的server上面,會將worker_processes設為server CPU的core數量
#也可以直接使用auto 讓Nginx進行偵測
worker_processes 1;

#下方為Nginx的錯誤日誌
#前方的error_log為關鍵字,不可更改
#logs/error.log為存放錯誤日誌的位置
#後方的notice info為錯誤日誌的等級,其關鍵字有[debug, info, notice, warn, error, crit, alert, emerg],debug為紀錄最詳細內容的關鍵字
#更詳細的內容可以參考nginx docs error_log的介紹
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#官方的文件是指"Defines a file that will store the process ID of the main process" 個人是很少用到
#pid logs/nginx.pid;

events {
#每個worker同時可以處理多少連線
worker_connections 1024;
}


http {

#透過include mime.types這隻檔案來設定MIME的設定
include mime.types;
#HTTP 裡面Content-Type的一種
default_type application/octet-stream;

#紀錄的格式
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';

#紀錄的位置
#access_log logs/access.log main;

#TCP優化部分
sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;

#開啟gzip壓縮
#gzip on;

#server部分主要設定我們虛擬主機的設定
#server部分可以包成檔案,如xxx.conf
#並放置在/etc/nginx/conf.d 資料架下
#並透過include /etc/nginx/conf.d/*.conf 將全部.conf欓讀入,
#同時也可以做到多個虛擬主機的配置
server {
# 監聽的IP和port number
listen 8080;
#網域名稱
server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

//默認的位置和開啟的檔案
location / {
root html;
index index.html index.htm;
}

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
#錯誤狀態時,要顯示什麼頁面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}


# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;

# location / {
# root html;
# index index.html index.htm;
# }
#}

# HTTPS配置
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;

# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;

# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;

# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;

# location / {
# root html;
# index index.html index.htm;
# }
#}
include servers/*;
}

  • 上方內容中我們要瞭解到每個config都是由directive組成,而directive又可以分成simple directive和block directive。
  • 簡單來說simple directive的結尾就是”;”。
    • ex: worker_processes 1;
  • block directive是使用”{}”所包起來。
    • ex: events {worker_connections 1024;}

文件說明

  • user nobody;

    • 基本上就是啟動這個服務的用戶是誰,通常可以不進行設定
  • worker_processes 1;

    • 通常在直接作為伺服器的server上面,會將worker_processes設為server CPU的core數量
    • 也可以直接使用auto 讓Nginx進行偵測
  • #error_log logs/error.log;

    #error_log logs/error.log notice;

    #error_log logs/error.log info;

    • 為Nginx的錯誤日誌
    • 前方的error_log為關鍵字,不可更改
    • logs/error.log為存放錯誤日誌的位置
    • 後方的notice info為錯誤日誌的等級,其關鍵字有[debug, info, notice, warn, error, crit, alert, emerg],debug為紀錄最詳細內容的關鍵字
    • 更詳細的內容可以參考nginx docs error_log的介紹
  • #pid logs/nginx.pid;

    • 官方的文件是指”Defines a file that will store the process ID of the main process”
  • 最底層的block directive會有event和http,同時這也被稱為main context。

  • 補充nginx啟動關閉之指令

    • 啟動: nginx
    • 快速停止nginx: nginx -s stop
    • 正常關閉nginx: nginx -s quit
    • 重新載入nginx設置: nginx -s reload
    • 查看全部nginx程序運行狀況: ps -ef|grep nginx
      • ps為查看全部程序的命令,-ef為全部程序的全部內容

安裝reactstrap之問題

在React中遇使用reactstrap套件使用bootstrap library,
參考了官方的教學進行安裝。

使用Create React App套版

1
2
3
npx create-react-app my-app
cd my-app
npm start

安裝Bootstrap

因create-react-app安裝完並不會有bootstrap,因此須額外安裝bootstrap。
官方教學文件安裝步驟為

1
2
npm install --save bootstrap
npm install --save reactstrap react react-dom

按照官方的教學步驟,在安裝bootstrap時,我會缺少typescript、jquery、popper.js三個套件
三個套件安裝完,可順利安裝完成bootstrap
但接下來安裝reactstrap會跑出已經安裝reactstrap,但卻無法呼叫使用

個人建議

1
2
3
4
5
6
7
8
9
//已有react和react-dom 不另外安裝
npm install --save reactstrap
//安裝缺少的套件 typescript
npm install --save typescript

//接下來安裝bootstrap
npm install --save bootstrap
//安裝缺少的套件 jquery
npm install --save jquery

安裝完成後即可順利使用

在React.js安裝bootstrap和node-sass


安裝bootstrap需要typescript、jquery、popper.js

均在project內安裝,非全域安裝
jquery與popper.js指定版本

1
2
3
$ npm install --save typescript
$ npm install --save jquery@1.9.1
$ npm install --save popper.js@1.14.7

其他虛擬機控制指令

vagrant supend
暫停虛擬機,可以使用vagrant up再啟動

vagrant halt
關閉虛擬機

vagrant destroy
刪除虛擬機,砍掉後可再透過vagrant up重新建立虛擬機


Vagrantfile文件說明

Vagrantfile內文件是使用ruby攥寫的,在原始的Vagrantfile內,有許多的註解,也因此若要進行修改,是十分方便的。以下會將Vagrantfile內的註解去除,進行簡單的說明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Vagrant.configure("2") do |config|

config.vm.box = "centos/7"

# config.vm.box_check_update = false

# config.vm.network "forwarded_port", guest: 80, host: 8080

# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

# config.vm.network "private_network", ip: "192.168.33.10"

# config.vm.network "public_network"

# config.vm.synced_folder "../data", "/vagrant_data"

# config.vm.provider "virtualbox" do |vb|
# vb.gui = true
#
# vb.memory = "1024"
# end

# config.vm.provision "shell", inline: <<-SHELL
# apt-get update
# apt-get install -y apache2
# SHELL
end

基本上在|config|後面都是虛擬機的相關設定。

  • Vagrant.configure(“2”),這個2是指Vagrant版本的意思。
  • config.vm.box = “centos/7”,這邊的box就是指映像欓是哪個。基本上box的命名都是 username/boxname,以centos/7為例,這個就是centos所提供的box,boxname就是7。
  • config.vm.box_check_update = false,這邊是指說在使用vagrant up啟動虛擬機時,要不要檢查此box是否有新的版本。
  • config.vm.network,這是指網路配置的部分。guest是指虛擬機的部分,host是指主機。
  • config.vm.synced_folder,這是指主機和虛擬機共用資料夾的部分。後面第一個參數是本機目錄位置,第二個參數為虛擬機目錄位置。預設會將虛擬機的/vagrant資料夾和本機 Vagrantfile所在的資料夾共享。
  • config.vm.provision,這是指虛擬機環境建立起來後會執行的事件,預設是安裝apache2套件。

為什麼要使用Vagrant

Vagrant是一款能夠幫我們快速部署各種環境架構的軟體,也可以幫我們管理我們的VM。傳統上如果我們要創建VM,我們需要先去找尋我們需要的OS並進行一些設定,VM運行後再去安裝我們需要的軟體。在Vagrant內,我們可以透過Vagrantfile去進行相關設定。


VirtualBox安裝與Vagrant安裝

Vagrant背後可以使用VirtualBox作為虛擬機,因此在使用Vagrant前,請先安裝VirtualBoxVagrant

  • 若要使用VMWare作為虛擬機,可在vagrantfile中更改。

Vagrant使用

Vagrant基本上是透過前面所提的Vagrantfile去完成一系列自動化完成的動作。我們可以透過vagrant init去初始化我們的Vagrantfile文件,或是透過vagrant init <boxname> 安裝在Vagrant Cloud已經定義好的box。以下我們以安裝centos7為例。

透過vagrant up運行虛擬機

我們可以到VirtualBox發現目前有一台虛擬機是啟動的狀況

至於要如何操控這台虛擬器,我們可以透過 vagrant status 查看vagrantfile所建立的虛擬機,再透過vagrant 所提供的ssh連上此虛擬機

VS code內使用Z Shell進行開發

在因工作的關係,最近需要使用Windows OS進行開發,然而在Windows內,並不能使用Z shell,也因此讓我在尋找是否有可以在Windows內使用Z Shell的方法。

在Windows OS裡面,我們都知道能使用的shell只有CMD和Power Shell,前者因時間久遠,許多的功能並不齊全,而後者雖然功能強大,但許多語法與我在macOS使用Z Shell的語法不同,造成使用體驗並不良好。

最近在Will 保哥的blog的文章發現WSL這套工具,因此有了這次的實作。以下會簡單說明如何在VS code透過WSL將Terminal改成Z Shell。關於WSL的安裝方法請參考上述的連結。


關於WSL Linux系統選擇

我個人是選擇Ubuntu 16.04,主要是以往在Linux環境下進行開發時就是使用此OS,至於像Ubuntu 18.04我想語法也不會有太大的差別。


安裝Z Shell和oh-my-zsh

在WSL安裝完畢且設定完帳號密碼後,完成後會是Ubuntu的Bash介面,我們要在此介面下安裝Z Shell和oh-my-zsh。

在安裝之前請記得先執行以下code進行更新

1
$ sudo apt update && sudo apt upgrade

安裝zsh、切換zsh

1
2
3
4
5
6
7
//安裝Z Shell
$ sudo apt-get install zsh

//切換bash -> zsh
$ which zsh
(/usr/bin/zsh)
$ chsh -s /usr/bin/zsh

安裝oh-my-zsh

1
2
3
4
5
6
7
8
9
//安裝oh-my-zsh
$ sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

//更改theme(可自行選擇)
//要使用vim nano哪種方法編輯都可以
$ vim ~/.zshrc
//在.zshrc文件中找到 ZSH_THEME="..."並更改要使用之主題
//我自己是使用astro(主題請自行google取得)
ZSH_THEME="astro"
  • 在.zshrc文件中同時可修改字體大小、字體等設定,同時一些highlight的套件也須透過.zshrc去設定

在VS code使用Z Shell

至settings.json設定,並加入下列指令

1
2
3
4
5
"terminal.integrated.shell.windows": "C:\\Windows\\System32\\bash.exe",
"terminal.integrated.shellArgs.windows": [
"-c",
"zsh"
],

如出現字元無法呈現或框框等圖案,或許是字體上出問題,請加入下列指令。

1
"terminal.integrated.fontFamily": "'Ubuntu Mono derivative Powerline'"

最終成果