Slog99_使用React框架進行前端開發10

ArthurSlog

  • ArthurSlog

  • SLog-99

  • Year·1

  • Guangzhou·China

  • October 20th 2018

關注微信公衆號“ArthurSlog”

吾言甚易知 甚易行 天下莫能知 莫能行


開發環境MacOS(Mojave 10.14 (18A391))

信息源

開始編碼

  • 本次來實現前端和後端的接口設計

  • 這裏使用原生的Fetch函數

  • 先在前端頁面添加一個函數 綁定頁面組件的點擊事件 用於向後端發起請求並傳遞數據

  • 這裏添加在商城首頁的‘公告’組件上 綁定該組件的點擊事件

client/

import React, { Component } from 'react'

import Carouselarea from './carouselarea/carouselarea'

// 引入配置文件
import Config from '../../../../config.json'

const bulletinBoardStyle = { alignItems: 'center', display: 'flex', flexDirection: 'raw', width: '100%', height: 64, fontSize: 40, textAlign: 'center', borderStyle: 'none' }
const productListStyle = { width: '100%', fontSize: 40, textAlign: 'center' }
const dividingLineStyle = { backgroundColor: '#000000', height: 1, width: '100%' }
const recommendStyle = { alignItems: 'center', display: 'flex', flexDirection: 'column', backgroundColor: '#FFFFFF', width: '100%' }
const navigationBarStyle = { display: 'flex', alignItems: 'stretch', backgroundColor: '#FFFFFF' }
const navigationBarItemStyle = { alignItems: 'center', display: 'flex', flexDirection: 'column', backgroundColor: '#d8f0f3', color: '#000000', width: '25%', marginLeft: '10px', marginRight: '10px', textAlign: 'center', fontSize: '30' }
const navigationBarItemStyleLeft = { alignItems: 'center', display: 'flex', flexDirection: 'column', backgroundColor: '#d8f0f3', color: '#000000', width: '25%', marginLeft: '20px', marginRight: '10px', textAlign: 'center', fontSize: '30' }
const navigationBarItemStyleLRight = { alignItems: 'center', display: 'flex', flexDirection: 'column', backgroundColor: '#d8f0f3', color: '#000000', width: '25%', marginLeft: '10px', marginRight: '20px', textAlign: 'center', fontSize: '30' }
const categoryStyle = { display: 'flex', alignItems: 'stretch', backgroundColor: '#FFFFFF' }
const categoryItemStyle = { alignItems: 'center', display: 'flex', flexDirection: 'column', backgroundColor: '#d8f0f3', color: '#000000', width: '33.3%', marginLeft: '10px', marginRight: '10px', textAlign: 'center', fontSize: '30' }
const categoryItemStyleLeft = { alignItems: 'center', display: 'flex', flexDirection: 'column', backgroundColor: '#d8f0f3', color: '#000000', width: '33.3%', marginLeft: '20px', marginRight: '10px', textAlign: 'center', fontSize: '30' }
const categoryItemStyleLRight = { alignItems: 'center', display: 'flex', flexDirection: 'column', backgroundColor: '#d8f0f3', color: '#000000', width: '33.3%', marginLeft: '10px', marginRight: '20px', textAlign: 'center', fontSize: '30' }
const categoryImgItemStyleLeft = { width: '220px', height: '220px', textAlign: 'center', lineHeight: '220px', backgroundColor: '#FFFFFF' }
const productStyle = { display: 'flex', alignItems: 'stretch', backgroundColor: '#FFFFFF' }
// const productItemStyle = { alignItems: 'center', display: 'flex', flexDirection: 'column', backgroundColor: '#d8f0f3', color: '#000000', width: '33.3%', marginLeft: '10px', marginRight: '10px', textAlign: 'center', fontSize: '30' }
const productItemStyleLeft = { alignItems: 'center', display: 'flex', flexDirection: 'column', backgroundColor: '#d8f0f3', color: '#000000', width: '50%', marginLeft: '20px', marginRight: '10px', textAlign: 'center', fontSize: '30' }
const productItemStyleRight = { alignItems: 'center', display: 'flex', flexDirection: 'column', backgroundColor: '#d8f0f3', color: '#000000', width: '50%', marginLeft: '10px', marginRight: '20px', textAlign: 'center', fontSize: '30' }
const productImgItemStyle = { width: '400px', height: '400px', textAlign: 'center', lineHeight: '400px', backgroundColor: '#FFFFFF' }

const productItemInfoTextStyle = { width: '400px', marginLeft: '0px', textAlign: 'left' }
const productItemInfoPriceStyle = { width: '400px', marginLeft: '0px', textAlign: 'left' }
const productItemInfoStyle = { alignItems: 'center', display: 'flex', flexDirection: 'column', backgroundColor: '#d8f0f3', width: '400px' }
const productItemInfoTextareaStyle = { width: '400px', textAlign: 'left', margin: '0px' }

const bulletinBoardIconStyle = { width: '56px', height: '56px', fontSize: '12px', textAlign: 'center', lineHeight: '56px', marginLeft: '20px' }
const recommendIconStyle = { width: '256px', height: '256px', textAlign: 'center', lineHeight: '256px', borderStyle: 'solid' }


const navigationBarIconItemStyle = { width: '200px', height: '200px', textAlign: 'center', lineHeight: '200px', backgroundColor: '#FFFFFF', borderStyle: 'solid' }

// BodyContainet區域的樣式
// const bodyContainerBarStyle = { position: "relative", marginTop: 0, marginBottom: 128, height: '100%', width: '100%' }

// BodyContainer區域渲染的內容
class BodyContainer extends Component {

    render() {
        return <div>
            <Carouselarea />
            <div>
                <div style={dividingLineStyle}></div>
                <div style={bulletinBoardStyle} onClick={this.toucha}>
                    <div style={bulletinBoardIconStyle} >圖片</div>
                    <div className='bulletinBoard'>bulletinBoard(公告欄)</div>
                </div>
                <div style={dividingLineStyle}></div>
            </div>
            <div className='navigationBar' style={navigationBarStyle}>
                <div style={navigationBarItemStyleLeft}>
                    <div style={navigationBarIconItemStyle}>圖片</div>
                    <div>所有商品</div>
                </div>
                <div style={navigationBarItemStyle}>
                    <div style={navigationBarIconItemStyle}>圖片</div>
                    <div>拼團</div>
                </div>
                <div style={navigationBarItemStyle}>
                    <div style={navigationBarIconItemStyle}>圖片</div>
                    <div>限時促銷</div>
                </div>
                <div style={navigationBarItemStyleLRight}>
                    <div style={navigationBarIconItemStyle}>圖片</div>
                    <div>秒殺</div>
                </div>
            </div>
            <div style={dividingLineStyle}></div>
            <div className='recommend' style={recommendStyle}>
                <div style={recommendIconStyle}>圖片</div>
                <div>熱銷推薦</div>
            </div>
            <div style={dividingLineStyle}></div>
            <div className='category'>
                <div style={categoryStyle}>
                    <div style={categoryItemStyleLeft}>
                        <div style={categoryImgItemStyleLeft}>圖片</div>
                        <div>類目1</div>
                    </div>
                    <div style={categoryItemStyle}>
                        <div style={categoryImgItemStyleLeft}>圖片</div>
                        <div>類目2</div>
                    </div>
                    <div style={categoryItemStyleLRight}>
                        <div style={categoryImgItemStyleLeft}>圖片</div>
                        <div>類目3</div>
                    </div>
                </div>
                <div style={categoryStyle}>
                    <div style={categoryItemStyleLeft}>
                        <div style={categoryImgItemStyleLeft}>圖片</div>
                        <div>類目4</div>
                    </div>
                    <div style={categoryItemStyle}>
                        <div style={categoryImgItemStyleLeft}>圖片</div>
                        <div>類目5</div>
                    </div>
                    <div style={categoryItemStyleLRight}>
                        <div style={categoryImgItemStyleLeft}>圖片</div>
                        <div>類目6</div>
                    </div>
                </div>
            </div>
            <div style={dividingLineStyle}></div>
            <div className='productList' style={productListStyle}>
                <div style={productStyle}>
                    <div style={productItemStyleLeft}>
                        <div style={productImgItemStyle}>圖片</div>
                        <div style={productItemInfoStyle}>
                            <div style={productItemInfoTextStyle}>
                                商品介紹
                        </div>
                            <div style={productItemInfoPriceStyle}>
                                <span style={productItemInfoTextareaStyle}>¥</span>
                                <span style={productItemInfoTextareaStyle}>8888</span>
                            </div>
                        </div>
                    </div>
                    <div style={productItemStyleRight}>
                        <div style={productImgItemStyle}>圖片</div>
                        <div style={productItemInfoStyle}>
                            <div style={productItemInfoTextStyle}>
                                商品介紹
                        </div>
                            <div style={productItemInfoPriceStyle}>
                                <span style={productItemInfoTextareaStyle}>¥</span>
                                <span style={productItemInfoTextareaStyle}>8888</span>
                            </div>
                        </div>
                    </div>
                </div>
                <div style={productStyle}>
                    <div style={productItemStyleLeft}>
                        <div style={productImgItemStyle}>圖片</div>
                        <div style={productItemInfoStyle}>
                            <div style={productItemInfoTextStyle}>
                                商品介紹
                        </div>
                            <div style={productItemInfoPriceStyle}>
                                <span style={productItemInfoTextareaStyle}>¥</span>
                                <span style={productItemInfoTextareaStyle}>8888</span>
                            </div>
                        </div>
                    </div>
                    <div style={productItemStyleRight}>
                        <div style={productImgItemStyle}>圖片</div>
                        <div style={productItemInfoStyle}>
                            <div style={productItemInfoTextStyle}>
                                商品介紹
                        </div>
                            <div style={productItemInfoPriceStyle}>
                                <span style={productItemInfoTextareaStyle}>¥</span>
                                <span style={productItemInfoTextareaStyle}>8888</span>
                            </div>
                        </div>
                    </div>
                </div>
                <div style={productStyle}>
                    <div style={productItemStyleLeft}>
                        <div style={productImgItemStyle}>圖片</div>
                        <div style={productItemInfoStyle}>
                            <div style={productItemInfoTextStyle}>
                                商品介紹
                        </div>
                            <div style={productItemInfoPriceStyle}>
                                <span style={productItemInfoTextareaStyle}>¥</span>
                                <span style={productItemInfoTextareaStyle}>8888</span>
                            </div>
                        </div>
                    </div>
                    <div style={productItemStyleRight}>
                        <div style={productImgItemStyle}>圖片</div>
                        <div style={productItemInfoStyle}>
                            <div style={productItemInfoTextStyle}>
                                商品介紹
                        </div>
                            <div style={productItemInfoPriceStyle}>
                                <span style={productItemInfoTextareaStyle}>¥</span>
                                <span style={productItemInfoTextareaStyle}>8888</span>
                            </div>
                        </div>
                    </div>
                </div>
                <div style={productStyle}>
                    <div style={productItemStyleLeft}>
                        <div style={productImgItemStyle}>圖片</div>
                        <div style={productItemInfoStyle}>
                            <div style={productItemInfoTextStyle}>
                                商品介紹
                        </div>
                            <div style={productItemInfoPriceStyle}>
                                <span style={productItemInfoTextareaStyle}>¥</span>
                                <span style={productItemInfoTextareaStyle}>8888</span>
                            </div>
                        </div>
                    </div>
                    <div style={productItemStyleRight}>
                        <div style={productImgItemStyle}>圖片</div>
                        <div style={productItemInfoStyle}>
                            <div style={productItemInfoTextStyle}>
                                商品介紹
                        </div>
                            <div style={productItemInfoPriceStyle}>
                                <span style={productItemInfoTextareaStyle}>¥</span>
                                <span style={productItemInfoTextareaStyle}>8888</span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div style={{ marginBottom: '256px' }}></div>
        </div>
    }


    toucha() {
        const myObj = { func: 0, object: "test" }
        fetch(Config.baseUrl + 'api/client', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(myObj),
        })
            .then(response => {
                console.log('Add data to message successfuly')
                const resmsg = response.json()
                console.log('Response1: ', resmsg)
                console.log('Response2: ', response)
                return resmsg
            })
            .catch(err => {
                alert("Error in sending data to server: " + err.message)
            })
    }
}

export default BodyContainer
  • 額 代碼有點長 沒經過整理和優化

  • 但是 可以看到其中的關鍵部分在於

...
// 引入配置文件
import Config from '../../../../config.json'
...

...
<div style={bulletinBoardStyle} onClick={this.toucha}>
    <div style={bulletinBoardIconStyle} >圖片</div>
    <div className='bulletinBoard'>bulletinBoard(公告欄)</div>
</div>
...

...
toucha() {
    const myObj = { func: 0, object: "test" }
    fetch(Config.baseUrl + 'api/client', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(myObj),
    })
        .then(response => {
            console.log('Add data to message successfuly')
            const resmsg = response.json()
            console.log('Response1: ', resmsg)
            console.log('Response2: ', response)
            return resmsg
        })
        .catch(err => {
            alert("Error in sending data to server: " + err.message)
        })
}
...
  • 這裏把後端的地址 定義在了外部文件config.json裏面

  • 然後在‘商城首頁’的‘公告欄’組件上綁定點擊事件

  • 事件關聯了toucha函數 該函數向服務端發起請求

  • 發起的請求包含了兩個數據 一個是‘func: 0’ 一個是 ‘object: “test”’

  • func代表了功能函數的代碼 後端通過前端傳過來的func的值來判斷 前端當前想幹什麼想執行哪個函數

  • 而object就是 前端傳給後端的數據內容了 這些數據傳給後端之後 由後端進行相應的處理 處理完了之後再怎麼弄就看開發的時候怎麼來設計了

  • 下面是後端的代碼

// 這個函數 接收客戶端傳過來的數據 
// 判斷數據裏面是否含有 bootomTabBar的值
// 根據四個bootomTabBar的值 來返回每個基礎界面的數據
// 上面表述的不好理解 下面舉個栗子
// 比如 這個函數 接收到一個數據data data裏面包含有數據‘count’ 和 ‘tabBar’
// 並且‘count’等於1 ‘tabBar’也等於1
// 這代表了 客戶端想要得到的 bootomTabBar數量是一個 想要得到的bootomTabBar是第一個(商城首頁)
// 所以 通過這個函數
// 可以客戶端可以請求到 第一個界面的數據、第二個界面的數據、第三個界面的數據、第四個界面的數據
// {
//     count: int, // 這個就是代表了本次要修改的bootomTabBar的數量
//     tabBar: []  // 這個就是代表了本次要修改的bootomTabBar
// }
//
// 這裏其實還有另一種方式 就是全部的方法統一一個函數
// 具體是這麼做的 例如 app.all('/api/POST', ...
// 那麼 怎麼判斷客戶端請求的是哪個功能呢?
// 是這樣子的 是通過判斷客戶端傳過來的數據data裏面的特定的字段來判斷的
// 可以這麼看 就是根據客戶端傳過來的data裏的‘func’的值 進行路由的
// 路由什麼呢? 路由到指定的功能函數
// 例如 客戶端傳過來的數據data裏的‘func’==01
// 那麼就路由到函數 func1 這個func1函數返回第一個界面的數據
// 如果 ‘func’==02
// 那麼就路由到函數 func2 這個func2函數返回第二個界面的數據
// 以此類推
// 那麼 想要這麼做呢 就需要在後端進行嚴格的檢查判斷 需要一套工業級的機制
// 這麼看來 有點像在寫底層協議了 哈哈
// 包頭+包體 的模式
//
// 客戶端傳過來的數據結構
// {
//     func: int, // 這個就相當於包頭
//     object: [] // 這個就相當於包體
// }
app.all('/api/client', (req, res) => {
    console.log(req.body)
    // 接到來自客戶端的數據
    /*
    const newDatas = req.body
    // 對接受到的數據進行檢測判斷 這裏是第一種方式
    if ((newDatas.count != 0) && (newDatas.count < 5)) {
        console.log('Accept: ', newDatas)
        // newIssue.id = issues.length + 1
        newIssue.created = new Date()

        if (!newIssue.status)
            newIssue.status = 'New'

        // issues.push(newIssue)

        const err = Issue.validIssueStatus(newIssue)
        if (err) {
            res.status(422).json({ message: `Invalid request: ${err}` })
            return
        }

        if (!newIssue) {
            console.log('newIssue is null')
        }
        else if (newIssue) {
            db.collection('issues').insertOne(newIssue)
                .then(result => {
                    return db.collection('issues').find({ _id: result.insertedId }).limit(1).next()
                })
                .then(newIssue => {
                    if (newIssue) {
                        res.header("Access-Control-Allow-Origin", "*")
                        res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type")
                        res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS")
                        res.header("X-Powered-By", ' 3.2.1')
                        res.header("Content-Type", "application/json;charset=utf-8")
                        res.json(newIssue)
                    } else {
                        console.log('newIssue is null')
                        return
                    }
                })
                .catch(err => {
                    console.log(err)
                    res.header("Access-Control-Allow-Origin", "*")
                    res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type")
                    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS")
                    res.header("X-Powered-By", ' 3.2.1')
                    res.header("Content-Type", "application/json;charset=utf-8")
                    res.status(500).json({ message: `Internal Server Error: ${err}` })
                    console.log('newIssue is error')
                })
        }
    }
    else {
        // 如果接收到的數據不符合預期
        res.header("Access-Control-Allow-Origin", "*")
        res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type")
        res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS")
        res.header("X-Powered-By", ' 3.2.1')
        res.header("Content-Type", "application/json;charset=utf-8")
        res.json(newIssue)
        console.log('Client request is err!')
        return
    }

    console.log('POST: have a req from client')
    */

    // 現在採用第二種方式
    // 首先接收到來自客戶端的數據 並保存在 recDatas對象裏
    const recDatas = req.body
    // 接着 我們約定好的數據結構 就是 包頭+包體
    // 也就是 func + object 這樣的數據結構
    // 所以 首先判斷func的值 然後根據不同的值 執行不同的函數
    switch (recDatas.func) {
        case 0:
            console.log('接收到了func等於0的數據')
            res.header("Access-Control-Allow-Origin", "*")
            res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type")
            res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS")
            res.header("X-Powered-By", ' 3.2.1')
            res.header("Content-Type", "application/json;charset=utf-8")
            // 這裏 我們把object傳給函數進行處理 同時還需要把res也傳給函數 可以對客戶端做出反饋
            const results = Func1.func1(recDatas.object)
            res.json(results)
            console.log(results)
            break;
        case 1:
            Func1(recDatas.object, res);
            break;
        case 2:
            Func1(recDatas.object, res);
            break;
        case 3:
            Func1(recDatas.object, res);
            break;
        case 4:
            Func1(recDatas.object, res);
            break;
        case 5:
            Func1(recDatas.object, res);
            break;
        case 6:
            Func1(recDatas.object, res);
        default:
            res.header("Access-Control-Allow-Origin", "*")
            res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type")
            res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS")
            res.header("X-Powered-By", ' 3.2.1')
            res.header("Content-Type", "application/json;charset=utf-8")
            res.json('error');
    }
})
  • switch裏的寫法有一些語法的問題 不影響結果就不理了

  • 關鍵可以看一下注釋的內容

  • 註釋的內容 解釋了一個業務上的邏輯設計

  • 最後經過測試 前後端成功實現了數據交互 接下來進行具體的業務設計 比較繁瑣

  • 這裏把最關鍵的思想已經呈現出來了 一次不講太多 避輕就重比較合適

  • 工程文件已經上傳至Github:https://github.com/BlessedChild/ArthurSlogStore

  • 至此,確定了前後端的數據交互的業務邏輯的設計。


  • 歡迎關注我的微信公衆號 ArthurSlog

關注微信公衆號“ArthurSlog”

  • 如果你喜歡我的文章 歡迎點贊 留言

  • 謝謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章