React戰記之玩轉Flex佈局(上篇–容器屬性)

張風捷特烈發表於2019-03-04

零、前言

最近一直在總結Android,前端這塊感覺忘得也差不多了
Flex佈局以前也聽過,但沒有詳細學習過,趁機會用React玩轉一下,
遇到一個新的知識怎麼學,一大堆的引數讓人發懵,我最喜歡的一句話:能應對變化的只有變化本身
用自己的能力讓學習的物件非靜態,就像與你交流的是一個活的人而非人偶
本文並非React基礎教程,也非Flex佈局講解教程,只是做一個Flex佈局演示器
原始碼見文尾捷文規範

不廢話了,留圖鎮樓:
效果圖

一、搭建React專案:

1.建立+scss配置

個人比較喜歡scss,最新的create-react-app的webpack已經對scss進行了配置
只需新增node-sass就行了

npm i create-react-app
npm i node-sass -D
複製程式碼

2.搭建靜態頁面
靜態頁面.png

2.1:.Flex矩形div(預設長寬1000*300px)
.Flex {
  border: red 2px solid;
  margin-top: 20px;
  margin-left: 20px;
  width: 1000px;
  height: 300px;
  background-color: rgba(71,71,71,.6);
  display: flex;
  .title {
    border-radius: 10px;
    font-size: 30px;
    text-align: center;
  }
}
複製程式碼
Flex.png

2.2–資料準備:
export class AttrData {
    static getAttrData() {

        let justifyContent = {
            index: 0,
            data: ["normal", "flex-start", "flex-end", "center", "space-between", "space-around"]
        };
        let flexDirection = {
            index: 0,
            data: ["row", "row-reverse", "column", "column-reverse"]
        };
        let flexWrap = {
            index: 0,
            data: ["nowrap", "wrap", "wrap-reverse"]
        };
        let alignItems = {
            index: 0,
            data: ["normal", "stretch", "flex-start", "flex-end", "center", "baseline"]
        };
        let alignContent = {
            index: 0,
            data: ["normal", "stretch", "flex-start", "flex-end", "center", "space-between", "space-around"]
        };

        return {justifyContent, flexDirection, flexWrap, alignItems, alignContent};
    }

    /**
     * 設定屬性
     * @param attr
     * @returns {*}
     */
    static getAttrLooped(attr) {
        return attr.data[attr.index % attr.data.length];
    }

    /**
     * 獲取屬性
     * @param attr
     * @returns {*}
     */
    static getAttr(attr) {
        return attr.data[attr.index];
    }
}
複製程式碼
2.3–資料填充
//獲取資料和函式
const attrData = Data.getAttrData();
const getAttrLooped = Data.getAttrLooped;
const getAttr = Data.getAttr;

let justifyContent = attrData.justifyContent;
let flexDirection = attrData.flexDirection;
let flexWrap = attrData.flexWrap;
let alignItems = attrData.alignItems;
let alignContent = attrData.alignContent;

//對div進行資料填充
<div className="Flex" style={{
    width: this.state.ctrl[1].data + "px",
    height: this.state.ctrl[2].data + "px",
    flexDirection: getAttrLooped(flexDirection),
    flexWrap: getAttrLooped(flexWrap),
    justifyContent: getAttrLooped(justifyContent),
    alignItems: getAttrLooped(alignItems),
    alignContent: getAttrLooped(alignContent)
}}>
    {this.formItem()}
</div>
複製程式碼
2.5–生成若干的條目
加條目.png

輔助函式:隨機顏色:Logic.randomRGB

/**
 * 隨機顏色
 * @param a 透明度--預設為1
 * @returns {string}
 */
static randomRGB(a = 1) {
    return `rgba(${this.rangeInt(0, 255)},${this.rangeInt(0, 255)},${this.rangeInt(0, 255)},${a})`
}
複製程式碼

根據陣列動態生成隨機顏色的條目:Flex.formItem

formItem() {
    let color = [];
    for (let i = 0; i < this.state.ctrl[0].data; i++) {
        color.push(Logic.randomRGB(.8))
    }
    return (
        color.map((item, index) => {
            return (
                <div className={"title"} style={{backgroundColor: item}} key={index}>
                    Toly{index}
                </div>
            );
        })
    )
}
複製程式碼

3.底部欄的元件:ListInfo.js
底部+點選回撥.png
<ListInfo data={this.state.flexObj}
          onItemClick={this.onItemClick.bind(this)}/>
複製程式碼

3.1:資料的獲取:flexObj
/**
 * 底部監聽--屬性變化
 */
notifyAttrChanged() {
    this.setState({
        flexObj: {
            "flex-direction": getAttr(flexDirection),//元素排列方向
            "flex-wrap": getAttr(flexWrap),//換行
            "justify-content": getAttr(justifyContent),//水平對齊方式
            "align-items": getAttr(alignItems),//垂直對齊方式
            "align-content": getAttr(alignContent),//多行垂直對齊方式,
        }
    });
}
複製程式碼

3.2:資料的顯示:ListInfo.js
import React, {Component} from `react`;
import `./ListInfo.scss`

class ListInfo extends Component {
    render() {
        return (
            <div className="ListInfo" >
                {this.formList(this.props.data)}
            </div>
        )
    }

    formList(data) {//物件轉化陣列
        let datas = [];
        for (let key in data) {
            datas.push({
                    name: key,
                    data: data[key]
                }
            );
        }

        return (
            <div id="list-container">
                {datas.map((item, index) => {
                    return (//此處點選回撥onItemClick,捕獲索引
                        <div key={index} className="card" onClick={() => {
                            this.props.onItemClick && this.props.onItemClick(index);
                        }}>
                            {item.name}:<br/>
                            {item.data}<br/>
                        </div>
                    )
                })}
            </div>
        )
    }
}
複製程式碼

3.3:樣式:ListInfo.scss
#list-container {
  display: flex;

  .card{
    background-color: #26A5F8;
    cursor: pointer;
    margin-top: 20px;
    margin-left: 30px;
    padding: 10px;
    font-weight: bold;
    font-size: 24px;
    border-radius: 10px;
    box-shadow: #61dafb 2px 2px 10px 2px;
  }
}
複製程式碼

4.右欄的控制介面:
右側控制.png
4.1:state資料:Flex.js
this.state = {
    flexObj: ``,
    ctrl: [
        {
            data: 10,
            info: "條目數量",
            fun: (input) => {
                this.notifyInputChanged(0, input)
            }
        },
        {
            data: 1000,
            info: "容器寬度",
            fun: (input) => {
                this.notifyInputChanged(1, input)
            }
        },
        {
            data: 300,
            info: "容器高度",
            fun: (input) => {
                this.notifyInputChanged(2, input)
            }
        },
        {
            data: "auto",
            info: "條目寬度",
            fun: (input) => {
                this.notifyInputChanged(3, input)
            }
        },
        {
            data: "auto",
            info: "條目高度",
            fun: (input) => {
                this.notifyInputChanged(4, input)
            }
        }
    ]
}
複製程式碼

4.2:接收資料,渲染介面+回撥CtrlBox.js
import React, {Component} from `react`;
import `./CtrlBox.scss`

class CtrlBox extends Component {

    render() {
        return (
            <div className="right-ctrl">
                {this.createItem(this.props.ctrl)}
            </div>
        )
    }

    createItem(ctrl) {
        return (
            ctrl.map((item, index) => {
                return (
                    <div className={"container"} key={index}>
                        <label>{this.props.ctrl[index].info}:</label>
                        <input
                            onChange={
                                (v) => {
                                    this.bindCallback(index, v);
                                }}
                            defaultValue={this.props.ctrl[index].data}/>
                        <label>px</label>
                    </div>
                );
            })
        )
    }

    /**
     * 繫結回撥事件
     * @param index
     * @param v
     */
    bindCallback(index, v) {
        switch (index) {
            case 0:
                this.props.onCountChanged(v.target.value);
                break;
            case 1:
                this.props.onBoxWidthChanged(v.target.value);
                break;
            case 2:
                this.props.onBoxHeightChanged(v.target.value);
                break;
            case 3:
                this.props.onItemWidthChanged(v.target.value);
                break;
            case 4:
                this.props.onItemHeightChanged(v.target.value);
                break;
            default:
                break;
        }
    }
}

export default CtrlBox;
複製程式碼

4.3、回撥函式與使用:Flex.js
<CtrlBox
    ctrl={this.state.ctrl}
    onCountChanged={this.state.ctrl[0].fun}
    onBoxWidthChanged={this.state.ctrl[1].fun}
    onBoxHeightChanged={this.state.ctrl[2].fun}
    onItemWidthChanged={this.state.ctrl[3].fun}
    onItemHeightChanged={this.state.ctrl[4].fun}/>
複製程式碼
靜態介面.png

這樣靜態頁面和回撥都實現了,下面只要對回撥具體邏輯進行編寫就行了


三、回撥的具體邏輯


1.點選下方條目時,動態改變資料
/**
 * 點選下方條目
 * @param index
 */
onItemClick(index) {
    switch (index) {
        case 0:
            flexDirection.index++;
            break;
        case 1:
            flexWrap.index++;
            break;
        case 2:
            justifyContent.index++;
            break;
        case 3:
            alignItems.index++;
            break;
        case 4:
            alignContent.index++;
            break;
        default:
            break;
    }
    this.notifyChanged();
}
複製程式碼

2:輸入資料變動監聽
/**
 * 輸入監聽--資料變化
 * @param index
 * @param input
 */
notifyInputChanged(index, input) {
    let ctrl = this.state.ctrl;
    ctrl[index].data = input;
    this.setState({
        ctrl
    });
}
複製程式碼

看似功能挺複雜,其實也就這點程式碼,重點在於資料的把握與物件的封裝
我並非一開始就能把資料統籌成這樣,也是遇到了,看能合併,就合併一下,零散的屬性看著煩心
這也全靠Android(或java)讓我對物件認識深刻,所以什麼事就是有聯絡的,思想有了,一切好辦


後記:捷文規範

1.本文成長記錄及勘誤表
專案原始碼 日期 備註
V0.1–github 2018-12-9 React戰記之玩轉Flex佈局(上篇–容器屬性)
2.更多關於我
筆名 QQ 微信 愛好
張風捷特烈 1981462002 zdl1994328 語言
我的github 我的簡書 我的掘金 個人網站
3.宣告

1—-本文由張風捷特烈原創,轉載請註明
2—-歡迎廣大程式設計愛好者共同交流
3—-個人能力有限,如有不正之處歡迎大家批評指證,必定虛心改正
4—-看到這裡,我在此感謝你的喜歡與支援


icon_wx_200.png

相關文章