2020年12月31日 星期四

React 練習 - 使用 css, scss, img loader, image 壓縮

自己寫的 React, Webpack 練習,

練習了以下 webpack loader:


sass-loader : 

用來處理編譯 sass 檔案。


css-loader : 

用來處理 css 檔案。


style-loader : 

用來將 css 寫進網頁中 (不用在網頁中另寫 <link rel="stylesheet" href="xxx.css" />)。


image-webpack-loader : 

用來處理圖片檔案,有圖片壓縮等功能。


url-loader :

用來將圖片的 url 寫進網頁中,內部使用了 file-loader,所以可使用 file-loader 的選項參數,

有能把圖片的 url 轉成 base64 url 的等功能。


mini-css-extract-plugin : 

用來把處理好的 css 輸出成最後版本 css 檔案的功能,

網頁要使用 css 需自行加入 css style include, Ex:

<link rel="stylesheet" href="xxx.css" />)


實作了一個簡易的 tab 選單當範例來練習:

1. 有三個選單 tab,分別對應三個內容 (暫稱 content),內容中有各自的文字及各放置了不同的圖片。

2. 當滑鼠滑入 tab 中時  (mouseenter) ,下方會切換到對應的 Content。

檔案結構如下圖所示:


重要的程式碼如下 (以下根目錄以從 package.json 檔所在位置,也就是 WebContent 資料夾算起):

/index.html :
<!DOCTYPE html>
<html>
    <head>
        
    </head>
    <body>
        <div id="root"></div>
        <script src="dist/js/index_bundle.js"></script>
    </body>
</html>
/dev/js/index.jsx :
import React from "react"
import ReactDOM from "react-dom"
import {Main} from "./components/Main.jsx"

import "@projectDirPath/dev/css/style.scss"

ReactDOM.render(<Main/>, document.getElementById("root"));
/dev/js/components/Main.jsx :
import React from "react"
import {Tab} from "./Tab.jsx"
import {Content} from "./Content.jsx"
import dogImgSrc from "@projectDirPath/dev/img/dog.jpg"
import catImgSrc from "@projectDirPath/dev/img/cat.jpg"
import bananaCatImgSrc from "@projectDirPath/dev/img/bananaCat.jpg"

function Main(){
    const [itemList, setItemList] = React.useState([
                                                        {
                                                            title: "title1",
                                                            desc: "desc1",
                                                            img: dogImgSrc,
                                                            isActive: true
                                                        },
                                                        {
                                                            title: "title2",
                                                            desc: "desc2",
                                                            img: catImgSrc,
                                                            isActive: false
                                                        },
                                                        {
                                                            title: "title3",
                                                            desc: "desc3",
                                                            img: bananaCatImgSrc,
                                                            isActive: false
                                                        }
                                                    ]);

    function setItemActive(index){
        var updatedItemList = itemList.map((item, i) => {
            item.isActive = (i == index);
            return item;
        });

        setItemList(updatedItemList);
    }

    return (
        <React.Fragment>
            <div className="tab">
                {
                    itemList.map((item, index) => {
                        return <Tab item={item} key={index} index={index} setItemActive={setItemActive}/>;
                    })
                }
            </div>
            <div className="content">
                {
                    itemList.map((item, index) => {
                        return <Content item={item} key={index}/>;
                    })
                }
            </div>
        </React.Fragment>
    )
}

export {Main}
/dev/js/components/Content.jsx :
import React from "react"

function Content({item}){
    return (
        <div className={item.isActive ? "active" : ""}>{item.desc}<img src={item.img}/></div>
    );
}

export {Content}
/dev/js/components/Tab.jsx :
import React from "react"

function Tab({item, index, setItemActive}){

    function handleMouseEnter(){
        setItemActive(index);
    }

    return (
        <div className={item.isActive ? "active" : ""} onMouseEnter={handleMouseEnter}>{item.title}</div>
    );
}

export {Tab}
/dev/css/style.scss :
.tab {
    div {
        display: inline-block;
        width: 30%;
        height: 100px;
        background-color: green;
        background-color: yellow;
        border-bottom: 3px solid black;
    }

    div.active {
        background-color: yellow;
        border-left: 3px solid black;
        border-right: 3px solid black;
        border-top: 3px solid black;
        border-bottom: 3px solid yellow;
    }
}
  
.content {
    background-color: yellow;
    border-left: 3px solid black;
    border-right: 3px solid black;
    border-bottom: 3px solid black;

    div {
        display: none;
        padding: 3px;
    }

    div.active {
        display: block;
    }

    img {
        width : 30%;
    }
 }


webpack.config.js:

  var path = require('path');
//const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
 entry : "./dev/js/index.jsx",
 output : {
  path : path.resolve(__dirname, "dist"),
  filename : "js/index_bundle.js",
  publicPath : "dist/"
 },
 resolve: {
    alias: {
        '@projectDirPath': __dirname
    }
},
 watch : false,
 devtool : 'source-map',
 mode : "development", //"production",
 module : {
  rules : [ {
   test : /\.jsx?$/,
   use : {
    loader : 'babel-loader',
    options : {
     presets : [ '@babel/preset-react', '@babel/preset-env' ]
    }
   }
  },
  {
    test: /\.(png|jpg|gif|jpe?g|svg)$/,
    use: [
      {
        loader: 'url-loader',
        options: {
          limit: 50 * 1024,
          outputPath: "img"
        }        
      },
      "image-webpack-loader"      
    ]
  },/*
  {
      test : /\.css$/,
      use : ["style-loader", "css-loader"]
  },*/
  {
    test: /\.s[ac]ss$/,
    use: [        
         "style-loader", //MiniCssExtractPlugin.loader,
         "css-loader", "sass-loader"
        ]
  }]
 }
 //, plugins: [new MiniCssExtractPlugin()]
}
  

package.json

  {
  "name": "reacttest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack",
    "runServer": "lite-server"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.7.5",
    "@babel/preset-env": "^7.7.5",
    "@babel/preset-react": "^7.7.4",
    "babel-loader": "^8.0.6",
    "css-loader": "^5.0.1",
    "file-loader": "^6.2.0",
    "image-webpack-loader": "^7.0.1",
    "lite-server": "^2.6.1",
    "mini-css-extract-plugin": "^1.3.3",
    "node-sass": "^5.0.0",
    "sass-loader": "^10.1.0",
    "style-loader": "^2.0.0",
    "url-loader": "^4.1.1",
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.10"
  },
  "dependencies": {
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-redux": "^7.2.2",
    "redux": "^4.0.5"
  }
}

  

原始碼分享下載:

ReactTest2.7z


參考:

  1. Webpack 4 筆記 (3)
  2. 新手向 Webpack 完全攻略 (7) – 編譯圖片?略懂略懂
  3. Webpack 前端打包工具 - 使用 image-webpack-loader 壓縮圖片
  4. Webpack 前端打包工具 - 使用 sass-loader 編譯 Sass/SCSS 預處理器
  5. Webpack 前端打包工具 - 使用 mini-css-extract-plugin 把 CSS 抽離出來
  6. NPM – Webpack – 使用 import 的絕對路徑方法

沒有留言 :

張貼留言