本系列爲了總結一下手上的知識,致敬個人2018
本篇的重點在於:用前兩篇的數據使用React搭建一個簡單網站
本篇總結的技術點:
React的組件封裝
、React實現簡單的懶加載
、React中的網絡請求
、搜索功能
React中form表單與接口的對接
、路由react-router-dom的使用
、React中文件上傳
css
192.168.43.60
,端口8089
爲例)----查詢全部:
http://192.168.43.60:8089/api/android/note
----查詢偏移12條,查詢12條(即12條爲一頁的第2頁):
http://192.168.43.60:8089/api/android/note/12/12
----按區域查詢(A爲Android數據,SB爲SpringBoot數據,Re爲React數據)
http://192.168.43.60:8089/api/android/note/area/A
http://192.168.43.60:8089/api/android/note/area/A/12/12
----按部分名稱查詢
http://192.168.43.60:8089/api/android/note/name/材料
http://192.168.43.60:8089/api/android/note/name/材料/2/2
----按類型名稱查詢(類型定義表見第一篇)
http://192.168.43.60:8089/api/android/note/name/ABCS
http://192.168.43.60:8089/api/android/note/name/ABCS/2/2
----按id名稱查
http://192.168.43.60:8089/api/android/note/12
前端
添-POST請求:
http://192.168.43.60:8089/api/android/note
添-PUT請求:http://192.168.43.60:8089/api/android/note
刪-DELETE請求:http://192.168.43.60:8089/api/android/note/1
node
手機端用媒體查詢簡單適配了一下react
這裏的數據寫死在了
IndexData.js
裏,固然也可讓服務端提供數據,方便動態修改
只要格式和IndexData.js
裏的json對象保持一致就好了android
因爲主頁比較簡單,佈局樣式就不貼了,這裏講一下router的使用ios
npm i react-router-dom
複製代碼
其實也不是很是複雜,一句畫來講就是:
http://http://192.168.43.60/Android
能夠訪問到Android
組件頁面git
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>
)
複製代碼
ReactDOM.render(router(), document.getElementById('root'));
複製代碼
a標籤的href和Link組件的to均可以,若是跳到Android頁,寫上`/Android`就好了
複製代碼
核心是itemInfo,字段名稱與接口數據保持一致github
this.state = {
top: "100%",
itemInfo: {
type: "數據讀寫",
name: "1-SI--安卓SQLite基礎使用指南",
jianshuUrl: "https://www.jianshu.com/p/58076ca06a33",
imgUrl: "http://192.168.43.60:8089/imgs/android/f593dab6a21907dec2dfed6ffc39b7e4.png",
createTime: "2018-08-26",
info: "零、前言 [1]熟悉MySQL的學這個就像會西瓜的人去學吃哈密瓜同樣簡單。[2]若是對MySQL不太熟悉的童鞋,能夠看一下個人這篇:Spring..."
}
}
複製代碼
//組件屬性
this.props.itemInfo:上層組件傳遞來的數據
this.props.isNew :是否加"新"字
this.props.css: 暴露樣式修改接口(主要爲了修改寬高)
//組件行爲:
鼠標進入是遮罩層+介紹文字進入+圖片放大
複製代碼
使用top的變化來讓懸浮時文字移入npm
<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>
複製代碼
//使用flex佈局並內容居中
@mixin flexCenter() {
display: flex;
justify-content: center;
align-items: center;
}
//寬高同父控件
@mixin match-parent() {
width: 100%;
height: 100%;
}
//文字單行加省略號
@mixin text-single() {
font-weight: bold;
text-align: center;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
//a標籤的統一處理
@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);
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()
}
}
}
複製代碼
<div className={"ItemBox"} style={this.props.css}>
複製代碼
componentDidMount() {
this.setState({
itemInfo: this.props.itemInfo
})
}
複製代碼
這裏使用axios發送請求編程
npm i axios
複製代碼
DataFetcher.js
封裝一下是爲了更符合接口的操做,以便複用
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)
}
}
複製代碼
DataFetcher.get(data => {
console.log(data);
}, 'area/A');
複製代碼
數據獲取了,就已經萬事具有
//Pager的狀態
this.state = {
data: []
}
//Pager的狀態屬性
this.props.img 背景圖
this.props.type 類型
this.props.sub_title 副標題
this.props.title標題
複製代碼
componentDidMount() {
DataFetcher.get(data => {
this.setState({data})
}, this.props.type);
}
複製代碼
renderBody() {
return (
this.state.data.map((i, index) => {
return (
<ItemBox key={index} itemInfo={i}
isNew={index < 3}
css={{width: "30%", height: "100%"}}>
</ItemBox>);
}
)
)
}
複製代碼
只要改變:
pager
就能加載不一樣類型的數據
class Android extends Component {
render() {
return (
<div>
<Pager
pager={{
img: Logic.loadImg("android.svg"),
title: "Android 技術棧",
sub_title: "A complete node and summary for Android.",
type: "area/A"
}}/>
</div>
);
}
}
複製代碼
問題所在:請求時是因此數據,遍歷時全部條目都會加載
解決方案:查詢範圍的接口,監聽滾動事件,快到底部時加載更多
this.state = {
dataCount: 9,//默認加載9條
data: []
}
複製代碼
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;//每次多加載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);
}
複製代碼
折騰了好一會,總算擺弄處理了,期間犯了一個低級失誤,mark一下: 搜索時記得在條目的:
componentWillReceiveProps(nextProps)
裏更新state
很簡單,樣式上面的本身怎麼好看怎麼來吧
回顧一下按部分名稱查詢接口: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>
)
}
}
複製代碼
.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(195,243,231,.5);
border-radius: 10px;
&:focus {
color: black;
}
}
img {
width: 50px;
&:hover {
transition: transform .5s;
transform: scale(1.2);
fill: blue;
}
}
}
複製代碼
這裏定義了一個變量盛放type
let type = '';
componentDidMount() {
type = this.props.pager.type;//爲type賦值
//....
}
getData() {//抽取獲取數據函數
DataFetcher.get(data => {
this.setState({data})
}, type, 0, this.state.dataCount);
}
複製代碼
<Searcher
searcher={{
text: "張風捷特烈是誰?",
doOnClick: (value) => {
type = "name/" + value;
this.getData();
}
}
}/>
複製代碼
ItemBox.js
componentWillReceiveProps(nextProps) {
this.setState({
itemInfo: nextProps.itemInfo
});
}
複製代碼
其實搜索功能自己不難,有後臺接口配合就好了
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);
});
}
複製代碼
DataFetcher.insert({
type: "C",
name: "hell0",
localPath: "hell0",
jianshuUrl: "hell0",
juejinUrl: "hell0",
createTime: "2018-12-13",
info: "hell0",
area: "A"
});
複製代碼
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)
})
}
複製代碼
<form id={"add-form"} onSubmit={this.handleSubmit.bind(this)} method={"post"} name={"add"}
<label>上傳圖片:<input type="file" name={"file"}/>
</label>
<input type="submit" value="提交"/>
</form>
複製代碼
//執行上傳
handleSubmit(event) {
let input = document.forms['add'].file;
DataFetcher.upload("file", input.files[0]);
event.preventDefault();
}
複製代碼
"homepage": "http://toly1994.com"
複製代碼
build一下,將生成的build文件加拷貝到服務器
複製代碼
沒有serve的話:npm i serve
serve -p 80 -s
複製代碼
>那個jQuery隨意操縱dom的時代已經一去不復返了,React的思想很是符合Android
我常常把React自定義組件和Android自定義控件去比較:
React組件接收的props就像Android自定義控件中的自定義屬性,而且React靈活不少
css的佈局就像Android中的佈局,相比而言,css強大不少
ES6的語法加持,更讓React寫起來符合Javaer的心情,因此React寫起來很舒心
複製代碼
終於打完收工,前端我是打醬油的,不當之處,還請海涵。
下一站,安卓移動端(命屬),敬請期待。
項目源碼 | 日期 | 備註 |
---|---|---|
V0.1 | 2018-12-13 | [建站四部曲以前端顯示篇(React+上線)](www.jianshu.com/p/b0b4776cc… |
筆名 | 微信 | 愛好 | |
---|---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 | 語言 |
個人github | 個人簡書 | 個人掘金 | 我的網站 |
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大編程愛好者共同交流
3----我的能力有限,若有不正之處歡迎你們批評指證,一定虛心改正
4----看到這裏,我在此感謝你的喜歡與支持