從 Hooks 開始,讓你的網頁 React 起來系列 第 13 篇 - b05313fsldsp/dc-app GitHub Wiki

//dc-14 第 11 屆 iThome 鐵人賽 DAY 13 6 Modern Web 從 Hooks 開始,讓你的網頁 React 起來系列 第 13 篇 [Day 13 - 即時天氣] 建立一個即時天氣 App - 前置準備 11th鐵人賽 react reactjs

到目前為止鐵人賽已經接近一半,前面我們提到了在 React 中一定會使用到的 JavaScript 語法、JSX 的建立、條件渲染和迴圈在 JSX 中的使用、談到了組件的拆分、把資料透過 props 帶入組件內部,並且使用了useState 這個 React Hooks。

在前面的範例中還沒有透過 API 向外部服務串接資料,而在接下來的連續幾天,我們會藉由完成一個「即時天氣 App」的方式,來談到 API 資料的串接、說明 useEffect 的使用、並且會把開發的平台從 CodePen 轉移到 CodeSandBox。

了解 React 的專案架構
當我們在 CodeSandbox 開啟了 React 中案後,可以看到左邊包含了幾個資料夾和檔案,主要包含 public 和 src 這兩個資料夾:

public 資料夾
在 public 資料夾中主要是放靜態檔案,也就是不需要再經過任何前處理(preprocess)或編譯(compile)的檔案。

這裡可以看到一支 index.html,和 CodePen 時的 HTML 部分一樣,這支檔案內容很單純,主要就是 <div id="root"></div> 讓 React 知道要把內容渲染在哪個 div:

<!-- ./public/index.html -->
<body>
  <noscript>
    You need to enable JavaScript to run this app.
  </noscript>
  <div id="root"></div>
</body>

src 資料夾
src 資料夾則是之後最常會使用到的資料夾,在這裡面會放許多的 React 組件,這許多的 JS 檔通常會需要先透過 webpack 編譯打包成一支(或更多支)JS 檔讓 index.html 去使用。

可以檢視這個資料夾中的 index.js 檔,相信內容你並不陌生,就是一個名為 App 的 React 組件。其中比較不同的地方在於,現在我們是用 ES6 的 import 語法把需要用到的套件或 CSS 檔匯入進來使用:

// ./src/index.js
import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
如果過於 ES6 中 JavaScript 的模組系統還不太熟悉的話,建議可以花一些時間閱讀 MDN 上的 JavaScript modules 說明。

在 CodeSandbox 中使用第三方套件 和 CodePen 一樣,在 CodeSandbox 中也可以載入套件,它會自動去 npm 拉取指定的套件。如同下圖的操作,你可以在左側去修改套件的版本號碼、新增和刪除套件:

補充:npm 是一個開源 JavaScript 程式碼的平台,主要用來統整各種由 JavaScript 所撰寫的套件/函式庫,在這裡你將可以找到各式各樣透過 JavaScript 撰寫的工具。

//dc-

第 11 屆 iThome 鐵人賽 DAY 14 5 Modern Web 從 Hooks 開始,讓你的網頁 React 起來系列 第 14 篇 [Day 14 - 即時天氣] 把 CSS 寫在 JavaScript 中!? - CSS in JS 的使用

[Day 14 - 即時天氣] 把 CSS 寫在 JavaScript 中!? - CSS in JS 的使用 傳統的網頁開發上,我們會把所有的 CSS 樣式寫在一支或多支的 CSS 檔內,接著在 index.html 中透過 的方式讓整個網站都能夠套用到這支 CSS 所撰寫的樣式。

上述這種方式因為所有的樣式都是作用在整個網頁的環境下,常會發生不小心命名了同樣的 class 名稱,導致樣式相互影響或彼此覆蓋,又或者發生某些樣式權重不夠的情況而難以調整,因此在 class 的命名上常常需要非常留意小心,進而也出現了許多對於 class 命名的不同規範和設計模式。

為什麼要把 CSS 寫在 JS 中(CSS-in-JS)? 然而,現今前端框架中,因為可以把各個組件給拆分開來,每個不同功能的按鈕都可以是不同的組件,每個組件之間可以是獨立不互相干擾的,所以連 CSS 的樣式也都可以有組件的概念存在,也就是說,在某個組件內所撰寫的樣式,即使有相同 class 的命名,但在最後編譯後這些樣式都只會作用在該組件內,不會干擾到外層或其他組件的樣式。

這類把樣式連同組件寫在一起寫法稱作 CSS-in-JS,它的好處在於每個組件都是獨立可被重複使用,你不用再擔心改了 A 卡片的樣式卻不小心連 B 卡片的顏色也變了;你也不用再擔心把以為某支 CSS 檔案是多餘的,砍掉之後卻發生破版的情況,因為現在組件和樣式是綁在一起的,只要這個組件是完整的,那麼放到另一個地方去使用它時,外觀和功能也會是一樣的。

除此之外,既然 CSS 已經被放入的 JS 檔案中,如同把 HTML 寫在 JS 檔中的 JSX 一樣,這些 CSS 的樣式也將可以適用 JS 的語法。

透過把 CSS 寫在 JS 中的這種寫法,可以確保特定樣式只會作用在該組件之外,同時還可以把 JS 中的一些邏輯判斷放到 CSS 使用。

現在,就讓我們來看看怎麼使用帶有樣式的組件吧!

提醒:實務上會同時搭配上述兩種做法,有些樣式仍會撰寫在全域環境,讓整個網頁都可以套用到該樣式(例如、版型、主題、字體、...);針對個別組件則在撰寫只用在該組件內的樣式。

CSS-in-JS 套件的選擇 React 中要讓每個組件帶有獨立樣式的做法很多,非常多人選擇使用 styled-components(下圖右側)或 emotion(下圖左側)這兩套工具:

Imgur

styled-components 是從 2016 年就開始的專案,使用人數和 Github 星星數一直都非常多,而 emotion 則自 2017 年開始,可能是由於新版本的 styled-components 一直停留在 beta 而未正式發表的緣故,許多人開始轉而使用 emotion。

從 npm trends 的分析可以看到雖然 styled-components 仍然擁有最多的星星數,但在 8 月 25 日的時候正式出現死亡交叉,emotion 的下載量正式且持續的超過 styled-components:

Imgur

補充:在挑選套件時,可以透過 npm trends 把幾個具有相似功能的套件進行比較,通常可以看出一些趨勢和找到適合自己的。

實際上這兩個套件的用法上非常接近,Styled-Component 因為比較早起步且非常多人使用,網路上已經可以找到許多教學範例,因此在後面的練習中,我們就來嘗試看看後起之秀的 emotion 吧!

Imgur

在 CodeSandbox 中載入 Emotion 昨天我們已經在 CodeSandbox 開啟了一個全新的 React 專案,現在我們可以直接在 CodeSandbox 的左側點選 Add Dependency 來載入和 Emotion 相關的套件,主要有 @emotion/core 和 @emotion/styled 這兩個:

Imgur

建立並使用 Weather App Component WeatherApp.js 先在 ./src 資料夾中新增一支名為 WeatherApp.js 的檔案,接著透過函式來建立一個名為WeatherApp 的組件,比較不一樣的地方是現在因為我們把不同的組間拆成不同支 JS 檔撰寫,因此在檔案開頭的地方要透過 import 把 React 載入進來,在最後的地方則要透過 export 把這個組件匯出:

// ./src/WeatherApp.js import React from 'react';

const WeatherApp = () => { return

Weather

; };

export default WeatherApp; 整個畫面會像這樣:

Imgur

index.js 接著到 index.js 這支檔案來把剛剛寫好的 WeatherApp 載入進來,並把多餘不必要的程式碼移除。可以留意到這裡有一句 import './styles.css';,透過這種方式載入的 CSS 因為沒有縮限在某個組件內,因此是會作用到整個網頁的:

// ./src/index.js import React from 'react'; import ReactDOM from 'react-dom'; import WeatherApp from './WeatherApp';

// 這支 CSS 檔的樣式會作用到全域 import './styles.css';

function App() { return ; }

const rootElement = document.getElementById('root'); ReactDOM.render(, rootElement); 整個畫面會像這樣:

Imgur

styles.css 也就是說,如果有什麼樣式需要作用到整個網頁的話,就可以寫在 ./src/styles.css 這支檔案中。

這裡為了讓各個 HTML 元素在每個瀏覽器上看起來是一致的,我們先在 CodeSandbox 左下角「Add Resources」的地方貼上 https://unpkg.com/[email protected]/normalize.css 以載入 normalize.css:

Imgur

接著,為了之後可以把整個版面撐滿,然後再把顯示天氣的區域放在畫面的正中央,因此在 styles.css 的檔案中,可以再加上:

/* ./src/styles.css */ html, body { margin: 0; padding: 0; height: 100%; width: 100%; }

#root { height: 100%; width: 100%; } 撰寫 WeatherApp 的版面與樣式 接下來,就可以來撰寫 WeatherApp 的版面和樣式了。

打開 ./src/WeatherApp.js,先來撰寫第一個帶有樣式的 component。

傳統寫法 過去在撰寫樣式時我們會像這樣為有需要的 HTML 元素加上 className 來帶入樣式:

const WeatherApp = () => { return (

Weather

); }; 然後在 CSS 檔的地方去定義 .container 和 .weather-card 的樣式:

.container { background-color: #ededed; height: 100%; display: flex; align-items: center; justify-content: center; };

.weather-card { min-width: 360px; box-shadow: 0 1px 3px 0 #999999; background-color: #f9f9f9; }; 使用 emotion 撰寫 styled components 現在當我們要撰寫 CSS-in-js 的寫法時,會像下面的步驟這樣:

STEP 1:透過 import 將 emotion 套件載入 STEP 2:定義帶有 styled 的 component 第一次看到這種寫法,相信你會覺得非常神秘且不習慣,要建立一個帶有樣式的

標籤時,只需要使用 styled.div;如果要建立的是 則是使用 styled.button 其他則以此類推 接著在 styled.div 後面加上兩個反引號(和 Template Literals 用的符號相同),在兩個反引號之間就可以 直接撰寫 CSS 。實際上這裡的 styled.div 是一個函式,而在函式後面直接加上反引號一樣屬於 Template Literals 的一種用法,只是比較少情況會這樣使用。 STEP 3:幫剛剛定義好帶有的 styled 的 component 放入 JSX 中即可使用 import React from 'react';

// STEP 1:載入 emotion 的 styled 套件 import styled from '@emotion/styled';

// STEP 2:定義帶有 styled 的 component const Container = styled.divbackground-color: #ededed; height: 100%; display: flex; align-items: center; justify-content: center;;

const WeatherCard = styled.divposition: relative; min-width: 360px; box-shadow: 0 1px 3px 0 #999999; background-color: #f9f9f9; box-sizing: border-box; padding: 30px 15px;;

// STEP 3:把上面定義好的 styled-component 當成組件使用 const WeatherApp = () => { return (

Weather

); };

export default WeatherApp; 若想進一步了解在函式後面直接加上反引號的這種 Template Literal 用法,可以餐考這篇 JavaScript Template Literals and styled-components。

完成的畫面會像這樣:

Imgur

CodeSandbox 和 CodePen 一樣可以有 Debug 這種頁面方便除錯,只需要複製右邊網頁上方的網址貼在瀏覽器網址列上即可:

Imgur

在這個頁面打開瀏覽器的開發者工具可以看到,這些帶有樣式的組件,最後都會帶上特殊的 class 名稱,並且套用上所撰寫的 CSS 樣式,而這也就是為什麼不同組件之間的 CSS 樣式不會相互干擾的原因。即使這不同頁面中都定義了一個同樣名為 的 styled-component,但因為它們最終會帶上不同的 class 名稱,因此組件間的樣式並不會相互干擾:

Imgur

今天先讓我們完成到這裡,有需要的話可以到 Weather App - started template @ CodeSandbox 檢視完整的程式碼。明天會使用更多 emotion 來完成樣式並載入 SVG 圖案,把畫面像下面這樣完成,接著再透過中央氣象局的 API 拉取即時的資料來顯示。

Imgur

程式範例 Weather App - started template 參考資源 emotion @ emotion-js JavaScript Template Literals and styled-components:說明在函式後面直接加上反引號的這種 Template Literal 用法

留言 追蹤檢舉 上一篇 [Day 13 - 即時天氣] 建立一個即時天氣 App - 前置準備

下一篇 [Day 15 - 即時天氣] 就是這個畫面 - 使用 Emotion 為組件增添 CSS 樣式 系列文 從 Hooks 開始,讓你的網頁 React 起來 共 30 篇 目錄RSS系列文 訂閱系列文 314 人訂閱 26[Day 26 - 即時天氣] 切換顯示不同頁面 - 子層組件修改父層組件資料狀態的方式 27[Day 27 - 即時天氣] React 中的表單處理(Controlled vs Uncontrolled)以及 useRef 的使用 28[Day 28 - 即時天氣] 保存與更新使用者設定的地區資訊 - localStorage 與 useEffect 的搭配使用 29[Day 29 - 即時天氣] 寫網頁就是要炫耀啊,不然要幹麻?發布上 Github Pages 吧! 30[Day 30 - 臺灣好天氣] 發布上 Github Pages 不夠,還要變成手機 App!還有那些重要但故意先不告訴你的內容

//dc-15

第 11 屆 iThome 鐵人賽 DAY 15 4 Modern Web 從 Hooks 開始,讓你的網頁 React 起來系列 第 15 篇 [Day 15 - 即時天氣] 就是這個畫面 - 使用 Emotion 為組件增添 CSS 樣式 11th鐵人賽 react reactjs styled-components css-in-js

pjchender 團隊Wow Doge! 2019-10-01 23:24:43 4367 瀏覽

感謝 iT 邦幫忙與博碩文化,本系列文章已出版成書「從 Hooks 開始,讓你的網頁 React 起來」,首刷版稅將全額贊助 iT 邦幫忙鐵人賽,歡迎前往購書,鼓勵筆者撰寫更多優質文章。

老實說這幾天在寫鐵人賽時,發現花最多時間的常常是在找自己喜歡的設計畫面,因為喜歡好看的作品,但卻又不會設計,同時也不想要只是用簡陋的畫面說明程式語法...。好吧!廢話完畢,希望你會喜歡這 30 天中自己做出來的作品。

這次即時天氣的設計畫面主要是參考 imgur 上的圖片,另外則會使用 The Weather is Nice Today 提供的天氣 ICON 來完成。完成的畫面大概會像下面這樣:

Imgur

使用 Emotion 定義基本的 Styled Components 昨天已經把用來撰寫 Styled Components 的套件 emotion 載入專案當中,在 CodeSandbox 中你一樣可以透過 Fork 複製一份昨天的程式碼 Weather App - started template 在繼續開始今天的內容:

Imgur

這裡我們根據下圖拆分成不同的 HTML 區塊:

Imgur

在 Emotion 中基本 styled components 的使用如同昨天建立 和 的做法,這裡我們就繼續完成 裡面的結構和樣式,順便複習一下。

以 Location 區塊為例 以 Location 這個區塊為例,我們預期它會是個 div 元素,因此要建立帶有樣式的組件,只需要:

// 定義帶有樣式的 <Location /> 組件 // 在兩個反引號中放入該 Component 的 CSS 樣式 const Location = styled.divfont-size: 28px; color: #212121; margin-bottom: 20px;; 定義好之後,它就是一個 React 組件,可以直接把 放入 JSX 中:

Imgur

而它最後在 HTML 中呈現出來就會是帶有一個特殊 class name 的

,這個 class name(即下圖中的 css-a7vwns)則會對應到剛剛針對 所撰寫的 CSS 樣式:

Imgur

完成其他基本的 Styled Components 上面是用 Emotion 建立 Styled Components 最基本的方式。現在就讓我們把其他的 Styled Components 完成,如果你對於 CSS 的內容沒有太大興趣的話,可以直接把下面的程式碼複製到 CodeSandbox 中的 ./src/WeatherApp.js 這隻檔案:

import React from 'react'; import styled from '@emotion/styled';

const Container = styled.divbackground-color: #ededed; height: 100%; display: flex; align-items: center; justify-content: center;;

const WeatherCard = styled.divposition: relative; min-width: 360px; box-shadow: 0 1px 3px 0 #999999; background-color: #f9f9f9; box-sizing: border-box; padding: 30px 15px;;

const Location = styled.divfont-size: 28px; color: #212121; margin-bottom: 20px;;

const Description = styled.divfont-size: 16px; color: #828282; margin-bottom: 30px;;

const CurrentWeather = styled.divdisplay: flex; justify-content: space-between; align-items: center; margin-bottom: 30px;;

const Temperature = styled.divcolor: #757575; font-size: 96px; font-weight: 300; display: flex;;

const Celsius = styled.divfont-weight: normal; font-size: 42px;;

const AirFlow = styled.divdisplay: flex; align-items: center; font-size: 16x; font-weight: 300; color: #828282; margin-bottom: 20px;;

const Rain = styled.divdisplay: flex; align-items: center; font-size: 16x; font-weight: 300; color: #828282;;

const WeatherApp = () => { return ( 台北市 多雲時晴 23 °C 23 m/h 48% ); };

export default WeatherApp; 此時你應該會看到如下的畫面:

Imgur

目前還未載入任何和天氣有空 ICON。

在 React 中載入 SVG 圖片 上傳 SVG 圖片到 CodeSandbox 這裡為了讓圖片能夠擁有最佳的解析度,關於天氣的圖示我們會使用 SVG 而非 PNG,SVG 屬於向量圖,因此不論縮放到多大的尺寸都可以維持最佳的解析度,而不會出現像是 JPG 或 PNG 放到過大後出現方格的情形。

這裡使用的天氣圖示都來自 The Weather is Nice Today,其中因為有些 SVG 直接上傳到 CodeSandbox 呈現時有些問題,所以會先透過 Sketch 重新轉檔,轉檔後的圖片會放在 dropbox 上提供下載,你可以直接透過拖曳的方式,拉到 CodeSandbox 中。

先在 ./src 資料夾中新增一個 images 的資料夾,接著把 dropbox 上的圖檔下載到本機後,可以透過拖曳的方式把它們拉進去 images 資料夾中:

Imgur

Dropbox 內的天氣圖示會隨專案使用持續增加,但下載連結不會改變,有新圖示時可以在重新下載。

載入 SVG 圖示到 React 中 由於在 CodeSandbox 中是透過 create-react-app 這個工具建立起的 React 開發環境,相關的配置都已經設定,所以要把 SVG 載入 React 中的方式很簡單。

關於 create-react-app 這個建立專案的工具會在最後幾天說明,只需先知道透過這個工具可以快速建立好 React 的開發環境。

第一種方式:ReactComponent 第一種方式是把 SVG 當成一個 React 組件加以載入,因為變成了 React 組件,所以後續如果有需要改變 SVG 的顏色或做動畫都比較靈活。

寫法像這樣:

STEP 1:將 ./images/cloudy.svg 匯入,並將該組件命名為 Cloudy ,而 ReactComponent 是 create-react-app 提供的物件 STEP 2:在需要的地方就可以使用 // STEP 1:使用 import { ReactComponent as xxx } from xxx 載入 SVG import { ReactComponent as Cloudy } from './images/cloudy.svg'; import { ReactComponent as RainIcon } from './images/rain.svg';

const App = () => (

{/* STEP 2:直接使用該 Component */}
);

第二種方式:直接 import SVG 並搭配 img 這種方法因為是把 SVG 以圖檔的形式載入,因此後續比較難去修改 SVG 圖示的顏色、粗細或製作動畫等效果,但若單純只是要以圖檔呈現,使用這種方式較簡便:

STEP 1:將 ./images/cloudy.svg 匯入,匯入的內容會變成該圖檔的路徑 STEP 2:使用 的方式將 SVG 圖片掛入 // STEP 1:使用 import xxx from xxx 載入 cloudyIcon,會取得該圖檔路徑 import cloudyIcon from './images/cloudy.svg'; import rainIcon from './images/rain.svg';

const App = () => (

{/* STEP 2:透過 src 把 SVG 圖片呈現出來 */} cloudy icon rain icon
); ⚠️ 注意:上述這兩種載入 SVG 圖檔的方式都需要使用 create-react-app 來建立專案,或在 WebPack 中有對應的設定才可以。

在即時天氣 App 中載入 SVG 圖片 由於上述第二種直接 import SVG 圖片的方式實際上是取得該圖檔的路徑,但在 CodeSandbox 中該圖檔路徑會是錯誤的,進而有破圖的情況,因此在後面的範例中我們統一都會使用上述的第一種方式。

現在就讓我們來把相關的圖片載入進來:

// ./src/WeatherApp.js import React from 'react';

// 載入圖示 import { ReactComponent as CloudyIcon } from './images/cloudy.svg'; import { ReactComponent as AirFlowIcon } from './images/airFlow.svg'; import { ReactComponent as RainIcon } from './images/rain.svg'; import { ReactComponent as RedoIcon } from './images/redo.svg';

// ... 接下來就可以把這些圖式直接當成 Component 來使用,放入 JSX 中:

Imgur

現在的畫面會像這樣子:

Imgur

圖片帶進來後,因為沒有設定高,破版的有點嚴重。

對於在些 SVG 的組件來說,最後渲染到網頁的時候其實就是把 SVG 的程式碼放入 HTML 內,因此一樣透過 CSS 選擇器去選到對應的 SVG 後進行樣式的調整。這裡我們先調整一下 和 的部分。只須在當初定義 styled components 的地方去添加 CSS 修改 SVG 的樣式即可:

// ./src/WeatherApp.js import React from 'react'; // ...

const AirFlow = styled.div` display: flex; align-items: center; font-size: 16x; font-weight: 300; color: #828282; margin-bottom: 20px;

svg { width: 25px; height: auto; margin-right: 30px; } `;

const Rain = styled.div` display: flex; align-items: center; font-size: 16x; font-weight: 300; color: #828282;

svg { width: 25px; height: auto; margin-right: 30px; } `;

const WeatherApp = () => { // ... };

export default WeatherApp; 其中修改的部份如下:

Imgur

現在的畫面會長得像這樣子:

Imgur

可以看到在風速和雨量的部分大小已經調整好了,但我們還希望天氣的圖示還有「重新整理」的符號可以在小一點,我們接著來看可以怎麼做。

使用 Emotion 調整 Components 樣式 前面我們提到過怎麼使用 Emotion 來建立帶有樣式的 styled components,但 Emotion 不僅可以用來建立組件,還可以將原本就存在的組件添加樣式。

舉例來說,剛剛我們透過 import 載入的 SVG 是一個 React 組件,例如, 和 。現在如果我們想要為這個原本就存在的組件添加樣式時,可以這麼做:

// 透過 styled(組件) 來把樣式帶入已存在的組件中

const Cloudy = styled(CloudyIcon)/* 在這裡寫入 CSS 樣式 */ flex-basis: 30%;;

const Redo = styled(RedoIcon)/* 在這裡寫入 CSS 樣式 */ width: 15px; height: 15px; position: absolute; right: 15px; bottom: 15px; cursor: pointer;; 也就是說,原本是在 styled. 後面加上一個 HTML 標籤,現在則是放入一個 React 組件,然後就可以在裡面撰寫 CSS 樣式。

現在我們就把上面透過 Emotion 添加完樣式後的新組件放到 JSX 中,也就是把原本的 改成 ,原本的 改成 :

Imgur

大功告成,終於做出我們像要的即時天氣 App 畫面!

Imgur

明天我們會開始串接中央氣象局的資料,讓畫面不再只是假新聞!

今天完整的程式碼一樣可以到 CodeSandbox 中檢視 Weather APP with Emotion。

補充:Emotion 的更多用法 透過 props 將資料帶入 Styled Components 內 既然透過 Emotion 建立的 Styled Components 中仍然是個 React 的組件,就表示可以像第 11 天的內容一樣,透過 props 把資料傳入組件內。

舉例來說,現在如果想要將資料 theme 帶入建立好的 內,一樣只要利用像是 HTML 屬性的方式即可:

const WeatherApp = () => { return ( {/* ... /} 台北市 {/ ... */} ); }; 接著在使用 Emotion 定義 Location 這個 Styled Component 的地方,就可以透過 props 取得傳入的資料:

// 透過 props 取得傳進來的資料 // props 會是 {theme: "dark", children: "台北市"} const Location = styled.div${props => console.log(props)} font-size: 28px; color: #212121; margin-bottom: 20px;; 這個做有什麼用呢?當我們可以取得外部傳進來的資料時,就可以根據這個資料來決定要呈現的 CSS 樣式,例如,當 theme 為 dark 時就把文字顏色改成 #DADADA,否則顯示 #212121,就可以寫成這樣:

// 透過傳進來的資料決定要呈現的樣式 const Location = styled.divfont-size: 28px; color: ${props => props.theme === 'dark' ? '#dadada' : '#212121'}; margin-bottom: 20px;; 定義許多組件都會共用到的樣式 有時多個組件間還是可能有需要被共用的樣式,像是如果每個按鈕都有固定的外觀,只是不同按鈕組件的顏色有不同時,如果重複在每個按鈕組件都撰寫同樣的 CSS 樣式會變得有點多餘,而且若之後需要修改按鈕的外觀,還得要每支檔案一支一支改,但卻又不想定義 class 樣式來套用時,可以怎麼做呢?

在 Emotion 中可以把撰寫好的 CSS 樣式當作 JavaScript 函式保存起來,步驟如下:

從 @emotion/core 中匯入 Emotion 提供的 css 函式 定義帶有 CSS 樣式的函式 在 Styled Components 中套用定義好的樣式 // STEP 1:匯入 Emotion 提供的 css 函式 import { css } from '@emotion/core';

// STEP 2:將一批 CSS 樣式定義成 JavaScript 函式 const buttonDefault = () => cssdisplay: block; width: 120px; height: 30px; font-size: 14px; background-color: transparent; color: #212121;;

// STEP 3 在定義 Styled Components 時載入定義好的 CSS 樣式 // 和 CSS 一樣,同樣的樣式後面寫的會覆蓋前面寫的 const rejectButton = styled.button${buttonDefault} background-color: red;

const acceptButton = styled.button${buttonDefault} background-color: green; 這種作法不僅能夠讓組件共用某些樣式,一樣能夠透過 props 取得組件帶進來的資料,當有需要切換亮色/暗色主題的時候非常實用:

import { css } from '@emotion/core';

// 在共用樣式的函式中,一樣可以透過 props 取得外部傳來的資料 const buttonDefault = (props) => cssdisplay: block; width: 120px; height: 30px; font-size: 14px; background-color: transparent; color: ${props.theme === 'dark' ? '#dadada' : '#212121'};;

const rejectButton = styled.button${buttonDefault} background-color: red;;

const acceptButton = styled.button${buttonDefault} background-color: green;; 當然 Emotion 的用法還不只這些,這裡只提到一些蠻常用也蠻實用的一些功能,若想完整了解 Emotion 的更多功能,可以進一步參考 Emotion 官方文件。

程式範例 Weather APP with Emotion @ CodeSandbox 參考資源 天氣圖示下載 @ Dropbox Emotion @ emotion-js:Emotion 的官方文件 Adding Images, Fonts, and Files @ Create React App:說明如何在 React 中載入圖檔 JavaScript Template Literals and styled-components:說明在函式後面直接加上反引號的這種 Template Literal 用法 Weather App Design @ imgur The Weather is Nice Today @ iconfinder

留言4 追蹤檢舉 上一篇 [Day 14 - 即時天氣] 把 CSS 寫在 JavaScript 中!? - CSS in JS 的使用

下一篇 [Day 16 - 即時天氣] 定義並請求組件會使用到的資料 - useState 的更多使用 系列文 從 Hooks 開始,讓你的網頁 React 起來 共 30 篇 目錄RSS系列文 訂閱系列文 314 人訂閱 26[Day 26 - 即時天氣] 切換顯示不同頁面 - 子層組件修改父層組件資料狀態的方式 27[Day 27 - 即時天氣] React 中的表單處理(Controlled vs Uncontrolled)以及 useRef 的使用 28[Day 28 - 即時天氣] 保存與更新使用者設定的地區資訊 - localStorage 與 useEffect 的搭配使用 29[Day 29 - 即時天氣] 寫網頁就是要炫耀啊,不然要幹麻?發布上 Github Pages 吧! 30[Day 30 - 臺灣好天氣] 發布上 Github Pages 不夠,還要變成手機 App!還有那些重要但故意先不告訴你的內容

//dc-16

⚠️ **GitHub.com Fallback** ⚠️