iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 4
0
Modern Web

以經典小遊戲為主題之ReactJS應用練習系列 第 4

Day04 - Tic Tac Toe篇:頁面佈局規劃及棋盤實現

工具介紹:styled-components

我在React裡面撰寫CSS常用的工具是styled-components,一般來說,CSS的限制是他沒有變量、循環和函數等邏輯,所以我們很難在撰寫純CSS的時候做出複雜的變化,為了解決這個問題,開始出現了在JS上編寫CSS的做法, styled-components 是其中一種解決方案。

使用styled-components的好處有很多,例如它可以幫助我們將樣式寫成更具語義化的組件的形式,提高可讀性。另外有一個我很喜歡的功能,就是可以將React的參數用props的方式傳入來控制樣式,所以頁面的樣式就能夠透過改變這些參數來做更隨心所欲的變化,這兩個部分在今天這個單元都會使用到。

而且因為CSS的作用域是全局的,所以很容易產生衝突,特別是在專案更複雜的時候。但是使用styled-components會為我們生成的React元件產生隨機的className,重複使用這些元件的時候隨機的className也會不同,因此能夠避免元件之間className的衝突,順利的解決CSS全局作用域的問題。

styled-components
CSS Evolution: From CSS, SASS, BEM, CSS Modules to Styled Components
Styled Components:讓樣式也成為組件

頁面佈局規劃

Day03 準備好資料之後,我們要開始規劃一下我們的頁面,下面這個圖是我想像當中的頁面雛形。
layout-draft

為了讓想像不再是想像,而是能變成實體,我先開始做出整個程式的骨幹。
我延用create-react-app他原本的App.js來當作背景,並包覆<TicTacToe />元件
TicTacToe-component

tictactoe-main-draft

為了方便呈現,我先給了每個元件border屬性
add-border

Grid & Flex

為了要做出想像圖的layout,我會喜歡用grid和flex這兩個CSS的屬性。

  • flex可以幫助我們靈活的做出自適應的單一軸向排版
  • grid的強項則是在網格狀的排版提供了很方便的操作。
    當頁面比較複雜的時候,我會用grid先把網格狀的佈局定位好,再來用flex調整局部的單一軸向排版。下面分享一些我在學習grid和flex的時候,常會參考的文章及教學影片:

深入解析 CSS Flexbox
圖解:CSS Flex 屬性一點也不難
CSS Grid 屬性介紹
CSS Grid For Everyone
Grid Garden - A game for learning CSS grid

上面 CSS Grid For Everyone 這位講者,Part1和Part2講的內容我覺得還蠻清楚的,幫我釐清很多問題,讓我覺得使用grid和flex這兩個屬性不用再那麼害怕,然後講解過程中也會提到一些實務經驗,我覺得很受用,所以推薦給大家。

另外Grid Garden是透過闖關遊戲的方式來熟悉grid的語法,還蠻有趣的,也推薦給大家。

不過在使用這兩個屬性的時候還是需要考慮一下瀏覽器支援度,目前grid還不到90%,所以在使用的時候還是要特別留意。

grid-browser-support

flex-browser-support

在簡單的調整排版之後,我們的成果如下:
tictactoe-grid-layout

大致上整個layout的佈局已經被我們安排定位了,簡單分享一下我的作法,包覆元件的div tag我把它設為滿版成為背景,

.App {
	background: #ffd85c;
	width: 100%;
	min-height: 100vh;
	display: flex;
	justify-content: center;
}

並且我將它宣告成display: flex,讓他成為flex的外部容器,如此一來,在外部容器就能夠使用justify-content來使內部的元件水平置中。

tictactoe-add-classname

StyledTicTacToe

在設定棋盤大小及獲勝條件大小的參數設定區塊,我用一個div使他成為grid的外部容器,並且在外部容器設定grid-template使內部元件能夠以2x2的方式排列。

接著裡面的棋盤格子區塊我也想要用grid來處理,首先,我們需要根據我們 Day03 設計的兩個參數,gameScale以及blocks來將棋盤畫出來。

透過map方法的迭代,我們可以產生九個div tag(因為我們預設是3x3的棋盤)。接著,為了使用grid來產生3x3的棋盤,我將gameScale參數當成props傳入這個styled-component的元件中,將包住這九個div的外部容器設為display: grid,並且根據gameScale來決定grid-template的columns以及rows,另外,grid還有一個很方便的屬性,就是我們不用再透過margin或是padding的方式來設定方格的上下間距,而是能夠過grid-gap來設定方格間的距離。

tictactoe-block-map

tictactoe-block-map-layout

隨棋盤大小彈性調整的間格距離

最後,由於考量到我們是伸縮自如的棋盤,在棋盤區域大小是固定的狀況下,gameScale變大的時候,相對每一個block就會變小,但是如果在此時方格的間距是定值的話,方格的大小和間距的寬度很會不成比例,所以這邊間距我們會讓gameScale與間距成反比,因此當gameScale越大,block會越小,同時間距也會跟著變小。

grid-template

透過grid排列完棋盤之後,在對每一個block做一點樣式調整,就會變成下圖模樣。如果在這時候我們手動修改gameScale的預設值的話,我們也可以順利的把它變成4x4或是5x5的棋盤。

grid-template-lauout

到這邊我們就有一個基本的雛形了!下一篇我們會開始透過事件處理,讓我們可以順利的在棋盤上下棋!


上一篇
Day03 - Tic Tac Toe篇:檔案結構與資料結構規劃
下一篇
Day05 - Tic Tac Toe篇:事件處理
系列文
以經典小遊戲為主題之ReactJS應用練習30

尚未有邦友留言

立即登入留言