iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 17
1
Modern Web

寫React的那些事系列 第 17

React Day17 - 在React中使用class

再來我們要美化版面,之前有提過在React中使用style的方式,今天要介紹使用class的方式。分成兩個部分,第一個部分是webpack如何打包CSS檔,第二個部分是在React中指定class name的方式。

Webpack打包CSS檔


之前在Day10,我們有介紹一個plugin extract-text-webpack-plugin ,它會將我們程式中有require("main.css")的CSS(或是使用ES6 import的CSS),都統一搬到一個CSS中。

使用方式

先安裝相關plugins:

npm install css-loader style-loader extract-text-webpack-plugin --save-dev

再到webpack中設定,style和css的loader,和使用plugins:

var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
  module: {
    loaders: [
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
      }
    ]
  },
  plugins: [
  	// 這邊設定bundle CSS後的檔名
    new ExtractTextPlugin("styles.css")
  ]
}

建立一個css資料夾,放入我們編寫的main.css,使用require或import,把css載入:

require("../css/main.css");
// or
import '../css/main.css';

當我們執行 npm run prod 的時候,就會發現build的資料夾中,已經建立一個style.css檔案。而當我們執行 npm run dev 的時候,因為使用index.html,所以我們需要加上css style到html上。

<link rel="stylesheet" href="styles.css">

這樣一來,就可以發現已經成功使用webpack整合css囉!

React中使用classnames


classnames是一個方便javascript管理class name的package,可以有條件的設定class name,配合React剛剛好!

如果我們要設定多個class name給一個元件,通常我們會這樣寫:

render() {
  return (<div className="class1 class2 class3"></div>);
}

可是如果要根據元件state或是props來改變這些class狀態,就會顯得很複雜,你可能這樣需要寫:

render() {
  let classStr = "class1";
  if (this.props.isCompleted) {
    classStr += "class2";
  } else {
    classStr += "class3";
  }
  return (<div className={classStr}></div>);
}

為了避免這樣複雜的寫法,我們可以使用classnames來管理class,當然,首先也是要先install package:

npm install classnames --save

基本的用法,如下

import classNames from 'classnames';
classNames('foo', 'bar'); // => 'foo bar'

classNames是一個function,可以傳入string或是object,如果傳入 'foo' ,表示是 {foo: true} 的縮寫。當key的value是falsy(相當於false),表示是不顯示的class,有時候配合判別式可以決定某個state或props情況下不顯示class。

以下是官方說明的範例,看完應該就會秒懂:

classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'

// 傳入多組string或object
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'

// 只要是falsy value,都會被忽略不顯示
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'

// 當傳入陣列時,每一個值都會扁平化
var arr = ['b', { c: true, d: false }];
classNames('a', arr); // => 'a b c'

而配合ES6的Template literals,可以動態組合key的名稱:

let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true });  // => 'btn-primary'

React實際使用案例

改寫上面提到複雜的寫法,就會是這樣:

import classNames from 'classnames';

// ...

render() {
  const classStr = classNames({
    'class1': true,
    'class2': this.props.isCompleted,
    'class3': !this.props.isCompleted
  });
  return (<div className={classStr}></div>);
}

這樣管理class就變得很簡單明瞭,這邊也把之前todos的範例,加上styles,在css資料夾中新增一個style.css,並加上相關的className,這邊列出最主要有用到classnames的部分,也把TodoItem.js裡面原本使用的style都改成classnames。

render() {
  const { todo, idx, deleteTask, completeTask } = this.props;
  const taskClass = classNames({
    task: true,
    'task-completed': todo.isCompleted
  });
  if (this.state.isEditing) {
    return (
      <tr>
        <td><input type="text" data-idx={idx} defaultValue={todo.task} ref="editInput" className="edit" /></td>
        <td>
          <button onClick={this._onSaveClick}>Save</button>
          <button onClick={this._onCancelClick}>Cancel</button>
        </td>
      </tr>
    );
  }

  return (
    <tr>
      <td>
        <span
          className={taskClass}
          onClick={() => completeTask(idx)}
        >
          {todo.task}
        </span>
      </td>
      <td>
        <button onClick={this._onEditClick}>Edit</button>
        <button onClick={() => deleteTask(idx)}>Delete</button>
      </td>
    </tr>
  );
}

加上好看樣式的部分也完成囉!今天的檔案放在Git上

參考


classnames


上一篇
React Day16 - TODOS Demo(4)
下一篇
React Day18 - Redux 三大原則
系列文
寫React的那些事31

1 則留言

0
jasper
iT邦新手 3 級 ‧ 2017-02-02 17:34:28

當我們執行 npm run prod 的時候,就會發現build的資料夾中,已經建立一個style.css檔案。而當我們執行 npm run dev 的時候,因為使用inex.html,所以我們需要加上css style到html上。

inex.html 應該是 index.html

chiouchu iT邦新手 5 級 ‧ 2020-03-04 14:27:28 檢舉

已修正~感謝你!

我要留言

立即登入留言