React是Facebook推出的一個前端JavaScript框架,React的設計思想極其獨特,屬於革命性創新,性能出衆,代碼邏輯卻非常簡單。所以,越來越多的人開始關注和使用。
React框架主要用於前端頁面的編寫,非常的高效,而且安全。框架自動處理了前端頁面相關的常見安全漏洞:如跨域攻擊、SQL注入等等。React框架採用組件化思想,進行構建頁面。例如我們可以把一個前端頁面分成幾個組件來組合:導航組件、內容組件(內容列表組件、推薦欄組件等)、底部版權等信息組件等等。這樣大大提高了編寫的清晰度、以及後期的可維護性、組件的複用,達到高內聚、低耦合的設計原則。
React的特點:(引用)
-
1.聲明式設計 −React採用聲明範式,可以輕鬆描述應用。
-
2.高效 −React通過對DOM的模擬,最大限度地減少與DOM的交互。
-
3.靈活 −React可以與已知的庫或框架很好地配合。
-
4.JSX − JSX 是 JavaScript 語法的擴展。React 開發不一定使用 JSX ,但我們建議使用它。
-
5.組件 − 通過 React 構建組件,使得代碼更加容易得到複用,能夠很好的應用在大項目的開發中。
-
6.單向響應的數據流 − React 實現了單向響應的數據流,從而減少了重複代碼,這也是它爲什麼比傳統數據綁定更簡單。
-
7.安全 − React實現的單頁面應用,安全性能高、常見的漏洞都已經自行處理。
那麼接下來我就帶領大家把最近用到的React分享一下,實現從開始搭建環境到編寫出一個簡單的組件化前端頁面。
這裏選擇的開發工具是:Visual Studio Code。
一、首先我們進行React的安裝。
1、最簡單的引用。
我們直接在單頁面應用的html裏引入React庫:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 生產環境中不建議使用 -->
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
然後我們寫一個最簡單的頁面內容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="body"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('body')
);
</script>
</body>
</html>
這樣我們就把我們的動態Html代碼渲染添加到了指定id的DOM結點中了。是不是很簡單?
其實React的核心特點就是,只需要寫一個最簡單的Html頁面框架,內部只需要一個根<div>標籤即可,後續的所有針對頁面的繪製、綁定數據等都是編寫React組件類來實現,然後渲染到這個根<div>標籤上即可。最後編寫完所有邏輯後,就直接用node命令來實現實時運行查看效果和編譯成最後的頁面:npm run start(實時運行查看);npm run build(編譯成最終的靜態頁面)。
2、通過npm安裝。
我們需要安裝和配置Nodejs環境,Nodejs的安裝非常簡單,我們去Nodejs的官網下載對應的安裝包安裝即可。官網:https://nodejs.org/en/
下載安裝後,我們就可以使用npm命令了。
如果覺得國內使用npm下載相關庫慢的話,可以切換使用淘寶的npm庫。
$ npm config set registry https://registry.npm.taobao.org
接下來我們就通過create-react-app命令創建react應用框架。
create-react-app 自動創建的項目是基於 Webpack + ES6 。
$ npm install -g create-react-app
$ create-react-app my-app
$ cd my-app/
$ npm start
運行後,我們在瀏覽器裏訪問http://localhost:3000/,即可看到默認的頁面框架。
如果運行npm run build後,在build目錄生成的頁面遇到找不到相關js和css資源文件的話,可能是路徑用了絕對路徑,我們需要修改爲相對路徑引用。最新版的話是直接在項目的package.json裏添加一個homepage屬性字段即可。
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"homepage": "./",
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"react": "^16.13.0",
"react-dom": "^16.13.0",
"react-scripts": "3.4.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
二、編寫綜合實例單頁面。
這個實例既簡單有複雜,雖然頁面可能不是太美觀,但是涵蓋了很多React和前端的東西。這裏也用到了阿里巴巴的Antd:https://ant.design/。
主要把頁面分成了Header組件、Body組件和Footer組件。Body組件裏後續也可以再繼續細分。
編寫Html頁面:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>index</title>
<link rel="stylesheet" type="text/css" href="../src/index.css">
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<div id="header"></div>
<div id="tip"></div>
<div id="web"></div>
<div id="antd" style="padding: 24px"></div>
<div id="cal"></div>
<div id="body"></div>
<div id="footer"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</script>
<!-- <script type="text/babel" src="../src/index.js"></script> -->
</body>
</html>
header.js組件
import React from 'react';
import './header.css'
import ReactDOM from 'react-dom';
class Header extends React.Component {
constructor() {
super();
this.state = { index: 0 };
}
subMenuClick(e) {
e.preventDefault();
alert('subMenu點擊');
}
menuClick(index, e) {
var body = null;
switch (index) {
case 0:
body = <div>頁面一,切換頁面+{index}</div>;
break
case 1:
body = <div>頁面二,切換頁面+{index}</div>;
break
default:
break;
}
ReactDOM.render(
body,
document.getElementById('body')
);
}
render() {
return (<div className='headerContent'>
{/* <div className='header'> */}
<ul className='menu clearfix'>
<li className='menuItem' onClick={this.menuClick.bind(this, 0)}>標題1</li>
<li className='menuItem'>標題2<img className='more' src='https://raw.githubusercontent.com/google/material-design-icons/master/hardware/2x_web/ic_keyboard_arrow_down_black_48dp.png' alt='更多' />
<div id='subMenu' className='subMenu'>
<ul>
<li><a href='#' onClick={this.subMenuClick}>菜單1</a></li>
<li><a href='#'>菜單2</a></li>
</ul>
</div>
</li>
<li className='menuItem' onClick={this.menuClick.bind(this, 1)}>標題3</li>
<li className='menuItemRight'>標題4</li>
<li className='menuItemRight'>標題5</li>
</ul>
{/* </div> */}
</div>);
};
}
export {
Header
}
header.css
html,
body {
width: 100%;
height: 3000px;
/* text-align: center; */
}
.headerContent {
position: fixed;
top: 0px;
width: 100%;
height: 70px;
background: rgb(67, 163, 244);
}
.header {
max-width: 980px;
height: 70px;
position: fixed;
margin: 0 auto;
left: 0;
right: 0;
background: rgb(27, 146, 243);
/*flex 佈局*/
display: flex;
/*實現垂直居中*/
align-items: center;
}
.menu {
list-style: none;
background: rgb(27, 146, 243);
max-width: 980px;
margin: 0 auto;
left: 0;
padding-left: 0;
right: 0;
width: 100%;
height: 70px;
}
.menuItem {
list-style: none;
padding: 0 10px;
height: 70px;
line-height: 70px;
float: left;
align-items: center;
cursor: pointer;
}
.menuItem:hover {
color: white;
}
.subMenu {
display: none;
}
.subMenu ul {
list-style: none;
margin: 0 auto;
left: 0;
padding-left: 0;
right: 0;
}
.subMenu li {
list-style: none;
text-align: center;
}
.subMenu li a {
color: white;
}
.menuItem:hover .subMenu {
background-color: rgb(27, 146, 243);
padding: 5px;
color: white;
list-style: none;
display: block;
}
.menuItemRight {
padding: 0 10px;
float: right;
list-style: none;
height: 70px;
line-height: 70px;
cursor: pointer;
}
.menuItemRight:hover {
color: white;
}
.clearfix::after {
content: '';
display: block;
clear: both;
}
.more {
height: 30px;
margin: 0 auto;
}
footter.js
import React from 'react';
import './footer.css'
class Footer extends React.Component {
render() {
return (<div className='footer'>
<div className='info'>Information</div>
<div className='copyRight'>copyRight</div>
</div>);
};
}
export {
Footer
}
footer.css
.footer {
margin: 0 auto;
text-align: center;
}
.info{
color: black;
}
body.js
import React from 'react';
import { Slider, Tabs } from 'antd';
import './body.css'
class Body extends React.Component {
state = {
disabled: false,
};
onAfterChange(value) {
alert(value);
}
componentDidMount() {
// alert('渲染組件');
console.log('渲染組件');
}
componentWillUnmount() {
// alert('關閉界面');
console.log('關閉界面');
}
render() {
const { disabled } = this.state;
return (<div className='bodyComponent'>
<p>Body Component</p>
<div className='slider'>
<Slider defaultValue={30} disabled={disabled} max={100} min={0} onAfterChange={this.onAfterChange} />
</div>
<div className='textArea'>
<textarea className='textArea' rows='10' wrap='soft' placeholder='輸入文本...'></textarea>
</div>
<progress value='60' max='100'></progress>
<div className='photo'>
<img className='avatar'></img>
<a>名稱</a>
</div>
<div className='left'></div>
<div className='right'></div>
<div className='main'></div>
<div className='layout'>
<div className='layout_left'></div>
<div className='layout_main'></div>
<div className='layout_right'></div>
</div>
<div className='animation'></div>
</div>);
}
}
export {
Body
}
body.css
.bodyComponent {
text-align: center;
}
.textArea {
width: 960px;
height: 500px;
}
.slider {
width: 20%;
padding: 20px;
background-color: peru;
}
.photo {
width: 100px;
height: 100px;
text-align: center;
}
.avatar {
width: 100px;
height: 100px;
background-color: royalblue;
border-radius: 50%;
}
.photo a {
margin-top: -20px;
padding-top: -20px;
clip-path: circle(50%);
}
.left {
width: 200px;
height: 100px;
background: #a0b3d6;
float: left;
}
.right {
width: 200px;
height: 100px;
background: #a0b3d6;
float: right;
}
.main {
height: 100px;
margin: 0 210px;
background: #ffe6b8;
}
.layout {
display: -webkit-flex;
/* Safari */
display: flex;
justify-content: space-between;
align-items: center;
}
.layout_left {
background-color: royalblue;
height: 100px;
width: 30%;
}
.layout_right {
background-color: royalblue;
height: 100px;
width: 30%;
}
.layout_main {
background-color: sandybrown;
height: 100px;
width: 30%;
}
.animation {
width: 100px;
height: 100px;
background-color: silver;
transition: .3s;
}
.animation:hover {
width: 100px;
height: 100px;
background-color: slateblue;
transform: rotate(45deg);
}
有很多改寫和參考的地方,新手可以參考學習。