This series is divided into four parts:
  • Site construction tetralogy of back-end interface (SpringBoot+ online)
  • Python Data Crawler (Selenium)
  • Site construction tetralogy before the display (React+ online)
  • Mobile Terminal part of tetralogy of website construction (Android+ online)

Zero, preface,

This series is to summarize the knowledge at hand and pay tribute to my 2018

The key point of this paper is to build a simple website using React data from the first two articles. The technical points summarized in this paper are: React component encapsulation, React implementation of simple lazy loading, network requests in React, search function in React form form and interface connection, use of route React-router-DOM, file upload in React


Let’s review the server interface (with IP:192.168.43.60, port8089As an example)
Query interface: GET request

—- Query all:

http://192.168.43.60:8089/api/android/note – 12 query migration, query 12 (that is, article 12 to a page of page 2) : http://192.168.43.60:8089/api/android/note/12/12 – by region query (A data for Android, SB for SpringBoot data, Re the React data) as http://192.168.43.60:8089/api/android/note/area/A http://192.168.43.60:8089/api/android/note/area/A/12/12 – according to the part name query http://192.168.43.60:8089/api/android/note/name/ http://192.168.43.60:8089/api/android/note/name/ materials / 2/2 – according to the type name query (see first type definition table) http://192.168.43.60:8089/api/android/note/name/ABCS http://192.168.43.60:8089/api/android/note/name/ABCS/2/2 – according to the id name check http://192.168.43.60:8089/api/android/note/12

An interface was added or deleted

Add – POST request: http://192.168.43.60:8089/api/android/note

Add – PUT request: DELETE – DELETE the request: http://192.168.43.60:8089/api/android/note http://192.168.43.60:8089/api/android/note/1


First, the production of the home page

1. Web page effect (notebook) : Online, accessible:www.toly1994.com

The mobile end uses the media inquiry simple adaptation

2. The schematic

In this case, the data is written in indexData.js, but it is also possible to have the server provide the data for dynamic modification

As long as the format is the same as the JSON object in indexData.js


3. Route usage

Since the home page is relatively simple, the layout style will not be posted. Here is how to use the Router

3.1: to install
npm i react-router-dom
Copy the code
3.2: Create a router.js router to manage routes

In fact, it is not very complicated. In one sentence, it is:

http://http://192.168.43.60/Android page can access the Android component

import {BrowserRouter as Router, Route, Switch} from 'react-router-dom'
import React from 'react';
import Index from "./pagers/index/Index";
import Android from "./pagers/Android";
import SpringBoot from "./pagers/SpringBoot";
import ReactJS from "./pagers/ReactJS";
import Note from "./pagers/Note";

export default () => (
    <Router>
        <Switch>
            <Route path={'/index'} component={Index}/>
            <Route path={'/Android'} component={Android}/>
            <Route path={'/SpringBoot'} component={SpringBoot}/>
            <Route path={'/ReactJS'} component={ReactJS}/>
            <Route path={'/Note'} component={Note}/>
            <Route path={'/'} component={Index}/>
        </Switch>
    </Router>
)
Copy the code
3.3:
ReactDOM.render(router(), document.getElementById('root'));
Copy the code
3.4: jump:
The href of the a tag and the to of the Link component are fine. If you go to the Android page, just write '/Android'Copy the code

Two, single package:


1. Component status:

The core is itemInfo, where the field name is consistent with the interface data

This. state = {top: "100%", itemInfo: {type: "data read/write ", name:" 1-si -- Android SQLite Base Usage ", jianshuUrl: "https://www.jianshu.com/p/58076ca06a33", imgUrl: "CreateTime: http://192.168.43.60:8089/imgs/android/f593dab6a21907dec2dfed6ffc39b7e4.png", "2018-08-26", the info: [1] If you're familiar with MySQL, it's like learning how to eat cantaloupe. [2] If you are not familiar with MySQL, you can read my post: Spring... }}Copy the code

2. Component properties and behaviors
This.props. IsNew: whether to add the word "new" this.props. CSS: Expose style modification interface (mainly to modify width and height) // Component behavior: Mouse entry is mask layer + introduction text entry + image amplificationCopy the code

3. Analyze the layout hierarchy


4. Label writing

Use the variation of top to make the text move in while levitating

<div className={"ItemBox"} style={{width: "300px", height: "200px"}}>
    <div className={"box-img-bg"}
         style={{backgroundImage: `url(${this.state.itemInfo.imgUrl})`}}>
    </div>
    <div className="mask-with-text"
         onMouseEnter={() => {
             let itemInfo = this.state.itemInfo;
             this.setState({top: 0, itemInfo})
         }}
         onMouseLeave={() => {
             let itemInfo = this.state.itemInfo;
             itemInfo.text = "";
             this.setState({top: "100%", itemInfo})
         }}>
        <div className="tag">
            <a href="">{this.state.itemInfo.type}</a>
        </div>
        <div className={"text"} style={{
            paddingTop: this.state.top
        }}>
            <a href={this.state.itemInfo.jianshuUrl} target={"_blank"}>
                {this.state.itemInfo.info}
            </a>
        </div>
    </div>
    <div className={"box-info"}>
        <div className={ "new"}>
        </div>
        <div className={"text-info"}>
            <a href={this.state.itemInfo.jianshuUrl} target={"_blank"}>
                {this.state.itemInfo.name}
            </a>
        </div>
    </div>
</div>
Copy the code

5. SCSS style writing
@mixin flexCenter() {display: flex; justify-content: center; align-items: center; } @mixin match-parent() {width: 100%; height: 100%; } @mixin text-single() {text-weight: bold; text-align: center; display: inline-block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } @mixin handleA() {a {color: # FFF; &:hover { color: #4B86FF; text-decoration: underline; } } } .ItemBox { margin-top: 16px; border-radius: 10px; position: relative; overflow: hidden; box-shadow: rgba(214, 214, 214, .8) 1px 1px 2px 2px; &:hover {.mask-with-text {transition: background-color.5s Cubic -bezier(0, 0.51, 1, 1); background-color: rgba(0, 0, 0, .5); }.box-img-bg {transition: transform.5s cubic-bezier(0, 0.51, 1, 1); The transform: scale (1.2); } } .box-img-bg { border-radius: 10px; position: relative; background-size: 100%; background-repeat: no-repeat; @include match-parent; } .mask-with-text { .tag { background-image: url(".. /static/imgs/tag.svg"); font-size: 10px; text-align: center; width: 65px; height: 65px; position: absolute; background-size: 100% 100%; right: -2px; top: -20px; @include flexCenter; @include handleA; } border-radius: 10px 0 0 10px; position: absolute; left: 0; top: 0; @include match-parent; @include flexCenter; .text { transition: padding-top .6s; padding-left: 20px; padding-right: 20px; @include handleA; } } .box-info { position: absolute; bottom: 0; width: 100%; height: 25%; background-color: rgba(0, 0, 0, .5); @include flexCenter; .new { background-image: url(".. /static/imgs/new.svg"); align-self: flex-start; width: 30px; height: 30px; position: absolute; left: 0; background-size: 30px 30px; } .text-info { @include handleA; width: 80%; @include text-single() } } }Copy the code

6. Static interface componentization (attribute docking) :
 <div className={"ItemBox"} style={this.props.css}>
Copy the code
componentDidMount() {
    this.setState({
        itemInfo: this.props.itemInfo
    })
}
Copy the code

3. Obtain data and populate the interface


1. Data acquisition (take Android interface as an example)
1.1: Adds a dependency

The request is sent using Axios

npm i axios
Copy the code
1.2: Simple encapsulation of obtaining data:DataFetcher.js

Encapsulation is to better match the operation of the interface, so that reuse

const axios = require('axios');
const BASE_URL = 'http://192.168.43.60:8089';
const API = '/api/android/note/';

export default class DataFetcher {
    static findAll(callback, style = '', offset = 0, num = 10000) {
        let s = BASE_URL + API + style + "/" + offset + "/" + num;
        console.log(s);
        axios.get(s).then(rp => {
            callback(rp.data.data)
        });
    }

    static findAndroid(callback, offset = 0, num = 10000) {
        DataFetcher.findAll(callback, 'area/A', offset, num)
    }

}
Copy the code
1.3: Usage:

DataFetcher.get(data => {
    console.log(data);
}, 'area/A');
Copy the code

2.Pager page implementation

Once you have the data, you have everything

2.1.Pager status and Attributes:
This. state = {data: []} //Pager state attribute this.props. Img Background image this.props. Type Type this.propsCopy the code
2.2. Data acquisition and update status
componentDidMount() {
    DataFetcher.get(data => {
        this.setState({data})
    }, this.props.type);
}
Copy the code
2.3. Generate views based on data
renderBody() { return ( this.state.data.map((i, index) => { return ( <ItemBox key={index} itemInfo={i} isNew={index < 3} css={{width: "30%", height: "100%"}}> </ItemBox>); }}))Copy the code

2.4. Use

Just change: Pager can load different types of data

class Android extends Component { render() { return ( <div> <Pager pager={{ img: Logic.loadImg("android.svg"), title: Sub_title: "A complete node and summary for Android.", type: "area/A"}}/> < div>); }}Copy the code

3. Lazy loading implementation
3.1 problem:

The problem: all entries are loaded on request, but all entries are loaded on traversal

Solution: Query the scope of the interface, listen for scrolling events, and load more at the end


3.2: Scrolling monitoring:
This. state = {dataCount: 9,// default to load 9 data: []}Copy the code
componentDidMount() { let self = this; window.onscroll = () => { let scrollHeight = document.body.scrollHeight; let top = document.documentElement.scrollTop || document.body.scrollTop; if (scrollHeight - (top + document.body.clientHeight) < 80) { self.state.dataCount += 6; Datafetcher.get ((data) => {this.setstate ({data})}, this.props. Type, 0, this.state.datacount); }}; DataFetcher.get(data => { this.setState({data}) }, this.props.type, 0, this.state.dataCount); }Copy the code


Four, the realization of search function:

After a long time, I finally managed to fix it. During this time, I made a low-level mistake. Mark:

Remember when they search on entry: componentWillReceiveProps (nextProps) to update the state


1. Find the package of the component

Very simple, style above oneself how good-looking how to come

Review the part name query interface: http://192.168.43.60:8089/api/android/note/name/

export default class Searcher extends Component {
    constructor() {
        super();

        this.state = {
            text: ""
        }
    }

    render() {
        return (
            <div className={"pager-search"}>
                <input className="input-search" defaultValue={this.props.searcher.text}
                       onInput={(e) => {
                           this.setState({
                               text: e.target.value
                           });
                       }}>
                </input>
                <img src={Logic.loadImg('search3.svg')} alt=""
                     onClick={() => {
                         this.props.searcher.doOnClick(this.state.text)
                     }}/>
            </div>
        )
    }
}

Copy the code

Styles 2.
.pager-search { position: absolute; right: 0; top: 0; padding: 10px; display: flex; justify-content: space-around; input { padding: 6px; box-shadow: #EAEAEA 1px 1px 30px 1px; width: 60%; color: #cccccc; border-bottom: transparent; border-width: 1px; Background - color: rgba (195243231, 5); border-radius: 10px; &:focus { color: black; } } img { width: 50px; &:hover { transition: transform .5s; The transform: scale (1.2); fill: blue; }}}Copy the code

3. Extraction of the request method

Here we define a variable containing type

let type = ''; componentDidMount() { type = this.props.pager.type; // Assign a value to type //.... } datafetcher.get (data => {this.setstate ({data})}, type, 0, this.state.datacount); }Copy the code

4. Use of the search box:
<Searcher Searcher ={{text: "What's the name?" , doOnClick: (value) => { type = "name/" + value; this.getData(); }}} / >Copy the code

5. The Most important:ItemBox.js
componentWillReceiveProps(nextProps) {
    this.setState({
        itemInfo: nextProps.itemInfo
    });
}
Copy the code

In fact, the search function itself is not difficult, with the background interface with the line


5. Add Operation:

1. Use AXIos to send the POST request and encapsulate the insert method

static insert(obj) {
    let s = BASE_URL + API;
    let params = new URLSearchParams();
    params.append("type", obj.type);
    params.append("name", obj.name);
    params.append("imgUrl", obj.name);
    params.append("localPath", obj.localPath);
    params.append("jianshuUrl", obj.jianshuUrl);
    params.append("juejinUrl", obj.juejinUrl);
    params.append("createTime", obj.createTime);
    params.append("info", obj.info);
    params.append("area", obj.area);
    axios.post(s, params).then(function (response) {
        alert(response.data.data);
    }).catch(function (error) {
        console.log(error);
    });
}
Copy the code

2. Test the use of insert data
DataFetcher.insert({
    type: "C",
    name: "hell0",
    localPath: "hell0",
    jianshuUrl: "hell0",
    juejinUrl: "hell0",
    createTime: "2018-12-13",
    info: "hell0",
    area: "A"
});
Copy the code

3. Encapsulate the file using the AXIos upload method
static upload(name,file) {
    let s = BASE_URL + "/api/android/upload";
    let fd = new FormData();
    fd.append(name, file);
    let config = {
        headers: {
            'Content-Type': 'multipart/form-data'
        }
    };
    axios.post(s, fd, config).then(res => {
        console.log(res)
    }).catch(res => {
        console.log(res)
    })
}
Copy the code

4. Use of the upload method
<form id={"add-form"} onSubmit={this.handlesubmit.bind (this)} Method ={"post"} Name ={"add"} <label> Upload image :<input Type = "file" name = {} "file" / > < / label > < input type = "submit" value = "submit" / > < / form >Copy the code
HandleSubmit (event) {let input = document.forms['add'].file; DataFetcher.upload("file", input.files[0]); event.preventDefault(); }Copy the code


The launch of React project

1. Package. Json configuration homepage
 "homepage": "http://toly1994.com"
Copy the code
Pack 2.
Build and copy the generated build file to the serverCopy the code
3. Run: Ensure that nodes and serve are running on the server

If no serve: NPM I serve

serve -p 80 -s
Copy the code


> < p style = "max-width: 100%; clear: both; min-height: 1em; The React component receives props just like custom properties in Android custom controls, and React has a lot of flexibility. The React CSS layout is just like the Android layout. It also makes React fit the mood of Javaer, so React is very comfortable to writeCopy the code

Finally finished work, front-end I was playing soy sauce, improper place, please forgive me.

Next stop, Android mobile, stay tuned.


Postscript: Jie wen standard

1. Growth record and Errata of this paper
Program source code The date of note
V0.1 2018-12-13 [React+ online] [React+ online](www.jianshu.com/p/b0b4776cc…
2. More about me
Pen name QQ WeChat hobby
Zhang Feng Jie te Li 1981462002 zdl1994328 language
My lot My Jane books I’m the nuggets Personal website
3. The statement

1—- This article is originally written by Zhang Fengjie, please note if reproduced

2—- welcome the majority of programming enthusiasts to communicate with each other 3—- personal ability is limited, if there is something wrong welcome to criticize and testify, must be humble to correct 4—- see here, I thank you here for your love and support