利用react开发一个简单的博客系统,
首先我们简单的了解一下react的简单实用
博客的功能
信息发布系统
- 登录管理
- 博客发布
- 后台管理
- 权限管理
什么是前端开发?
将页面显示和业务逻辑独立,使用组件开发,解决传统页面代码混合html显示及js业务代码的弊端
常见的框架:
- react(facebook,react-native)
- vue
- AngularJS
nodejs的出现使JS代码的开发脱离了浏览器并且提供了统一的构建环境及包管理工具
实验流程
基本项目结构
- 使用vscode打开相应文件夹(file->open)
- 打开terminal->new terminal 执行 npm init -y,生成package json
- 创建dist 及 src目录
- 在src目录下创建index.html和index.js
什么是SPA?(单页面应用程序)
初始化环境
- npm i react --save
- npm i react-dom --save
- npm i webpack -g 安装到全局作用域
- npm i webpack-cli -g 安装到全局作用域
- npm i webpack-dev-server --save-dev
- npm i webpack --save-dev
- npm i webpack-cli --save-dev
- 在项目根目录创建webpack.config.js(webpack的配置文件)
开始开发
-
在index.html添加相应代码
第一个react程序
</html>
-
在index.js添加相应代码:
console.log(“ok”) -
执行webpack进行打包编译
-
执行webpack-dev-server,启动测试服务器
(
如果出现webpack-dev-server无法找到使用
npm i webpack-dev-server -g
进行全局安装
)
注意事项:webpack 4.x以后,默认查找scr/index.js作为打包入口
-
如何在开发中热部署程序(修改后立即生效)
- npm i html-webpack-plugin --save-dev
- 在webpack.config.js中添加下述代码选择开发模式
module.exports = {
mode:'development',
}
备注:CommonJS、RequireJS是JS下的两个包管理规范
-
初始化html-webpack-plugin,添加如下代码到webpack.config.js最开始部分
let path = require('path') //创建htmlPlugin对象 let HtmlWebpackPlugin = require('html-webpack-plugin') let htmlPlugin = new HtmlWebpackPlugin({ template:path.join(__dirname,'./src/index.html'),//指明模版位置 filename:'index.html'//访问的文件名 })
5.在module.exports中加载插件
```
module.exports = {
mode:'development',
plugins:[
htmlPlugin
]
}
```
基本的react页面生成,在index.js里添加如下代码
import React from 'react'
import ReactDom from 'react-dom'
let myli = React.createElement('li',null,'这是一个React标题')//创建一个li元素
let mydiv = React.createElement('div',null,myli) //创建一个div,包含li
ReactDom.render(mydiv,document.getElementById('app'))
react在内存中生成一棵虚拟DOM树基于diff算法对DOM树的增删改查进行监控
使项目支持JSX语法
-
安装基本的babel依赖
npm i babel-core babel-loader babel-plugin-transform-runtime babel-preset-env babel-preset-react babel-preset-stage-0 --save-dev
-
在项目根目录创建babel配置文件.babelrc,并且添加如下内容:
{ "presets":["env","stage-0","react"], "plugins":["transform-runtime"] }
3.在webpack.config.js中添加module模块,用来处理jsx的语法文件
module:{
rules:[
{test:/\.js|jsx$/, use:'babel-loader',exclude:/node_modules/},
],
}
4.在index.js里面添加一个function定义的组件,其中return中直接写html代码写法就是JSX语法,该语法会被babel-load自动解释成eact.createElement的形式。react组件可以像内置html标签一样使用例如
function MyList(props) {
return <div>
<li>李白</li>
<li>白居易</li>
<li>杜甫</li>
<li>柳宗元</li>
</div>
}
ReactDom.render(<MyList></MyList>,document.getElementById('app'))
-
如何向组件传递参数
jsx语法中如果要使用js,必须使用大括号括起来
- {props.libai}
使用{…对象}展开运算符进行参数传递:
//如何传递参数
function MyList(props) {return <div> <li>{props.libai}</li> <li>{props.dufu}</li> <li>{props.baijuyi}</li> </div> } let poems = {libai:'李白',dufu:'杜甫',baijuyi:'柳宗元'} ReactDom.render(<MyList {...poems}></MyList>,document.getElementById('app'))
展开运算符{…对象}相当于:
创建独立的组件
-
在src中创建components文件夹
-
在components中创建MyList.jsx
-
在MyList.jsx中添加如下代码:
import React from 'react' function MyList(props) { return <div> <li>{props.libai}</li> <li>{props.dufu}</li> <li>{props.baijuyi}</li> </div> } export default MyList;
4.在index.js中引入组件:
import MyList from './components/MyList.jsx' //使用方法和上例一样
5.如何自动引入组件扩展名及使用’@'别名,在webpack.config.js中添加如下配置:
resolve:{ extensions: ['.js', '.jsx', '.json'], alias: { '@': path.join(__dirname,'./src') } }
创建基于类的组件
-
在components下创建MyListClass.jsx文件
-
添加如下代码:
import React from 'react' class MyListClass extends React.Component{ constructor(){ super() } render(){ return <div> <li>{this.props.libai}</li> <li>{this.props.dufu}</li> <li>{this.props.baijuyi}</li> </div> }
}
export default MyListClass;
-
在index.js中引入类组件
import MyListClass from '@/components/MyListClass' let poems = {libai:'李白',dufu:'杜甫',baijuyi:'柳宗元'}
ReactDom.render(<MyListClass {…poems}>,document.getElementById(‘app’))
怎么创建评论列表
-
创建CmtList组件
import React from ‘react’
import CmtItem from ‘@/components/CmtItem’class CmtList extends React.Component{
constructor(){ super() //由于class组件可以设置state属性,所以是有状态组件 //function是无状态组件 this.state = { commentList:[ {id:1,name:'张三',title:'沙发',content:'抢沙发'}, {id:2,name:'李四',title:'板凳',content:'抢板凳'}, {id:3,name:'王五',title:'茶几',content:'抢茶几'}, ] } } render(){ return <div> <h2>评论内容</h2> <br/> {this.state.commentList.map(item=> <div key={item.id}> <CmtItem {...item}/> </div> )} </div> }
}
export default CmtList
2.创建CmtItem组件
import React from 'react'
class CmtItem extends React.Component{
constructor(){
super()
}
render(){
return <div>
<h3>{this.props.title}</h3>
<p>内容:{this.props.content}</p>
<p>发帖人:{this.props.name}</p>
</div>
}
}
export default CmtItem;
3.在index.js中使用CmtList组件
import CmtList from '@/components/CmtList'
ReactDom.render(<CmtList></CmtList>,document.getElementById('app'))
使用React组件访问后端restful接口
- 创建SearchContent.jsx组件并安装jquery
安装jquery
npm i jquery --save
创建组件
import React from 'react'
import $ from 'jquery'
import CmtItem from '@/components/CmtItem'
class SearchContent extends React.Component{
constructor(){
super()
this.state = {lists:[
{id:1,name:'python',title:'求助',content:'python崩溃了'}
]}
}
get_data = () => {
let t = this
$.ajax(
{
url:"http://localhost:5000/api/tasks",
dataType:"json",
success:function(results){
t.setState( {
lists:results.Comments
})
}
}
)
}
render(){
return <div>
<h2 style={{textAlign:'center'}}>网络评论列表</h2>
<button onClick={this.get_data}>请求网络数据</button>
<br/>
{this.state.lists.map(
item=><div key={item.id}>
<CmtItem {...item}/>
</div>
)}
</div>
}
}
export default SearchContent;
2.创建Flask服务器
from flask import jsonify,Flask
from flask_cors import cross_origin
app = Flask(__name__)
commentList = [
{
"id":1,
"name":"jack",
"title":"react",
"content":"react真简单"
},
{
"id":2,
"name":"lily",
"title":"python",
"content":"python真简单"
}
]
@app.route("/api/tasks",methods=['GET'])
@cross_origin()
def get_task():
return jsonify({"Comments":commentList})
if __name__ == '__main__':
app.run(debug=True)
3.使用SearchContent.jsx,在index.js中添加代码
import SearchContent from '@/components/SearchContent'
ReactDom.render(<SearchContent></SearchContent>,document.getElementById('app'))
4.关于跨域问题
-
jsonp解决跨域问题的本质
使用引用外部js脚本不受跨域问题影响的特点设计的一种调用方法 -
比较通用解决跨域问题的方法
在响应头中设置Access-Control-Allow-Origin属性,例如python flask中可以按照如下实现``` @app.after_request
def af_request(resp):
resp = make_response(resp)
resp.headers[‘Access-Control-Allow-Origin’] = ‘*’
resp.headers[‘Access-Control-Allow-Methods’] = ‘GET,POST’
resp.headers[‘Access-Control-Allow-Headers’] = ‘x-requested-with,content-type’
return resp -
Flask中的其他解决方式
使用flask-cors库,其中cross_origin指定函数允许跨域:
@cross_origin()
def get_tasks():
return jsonify({‘tasks’: tasks})或者使用CORS全局解决
if name == ‘main’:
app.run(debug=True)
CORS(app) -
跨域带来的问题
过多的跨域请求会给服务器带来安全性问题
-
更好的解决方案
使用nginx代理转发
React实现博客
运行方式
- 解压缩React-Express-Blog-Demo-master
- cd React-Express-Blog-Demo-master
- cnpm i (备注:如果系统没有cnpm执行:npm i cnpm -g 进行安装)
- 进入mongodb安装目录的bin目录,执行 ./mongod --dbpath ./ (./可以替换为自己的数据库路径,改步骤为启动mongodb)
- 进入mongodb安装目录的bin目录,执行 ./mongorestore --db blog @blogdata所在目录 注意:将 @blogdata所在目录替换为自己本机blogdata目录,该步骤为恢复数据库文件
- 重新进入React-Express-Blog-Demo-master,执行:npm start
关键组件
1.react-redux 在组件之间共享状态
2.react-route 组件的路由工具
3.antd 一个组件库
4.mongoose ORM工具类似于Flask-SQLAlchemy
5.cookies react处理cookies的工具
查看代码的主要流程
1.app/index.js是入口文件,Provider组件是react-redux提供状态共享的提供者
2.containers/index.js 是下一层组件,提供了主要的路由方式
3.containers/front/Front.js 是主页面
4.主页面中的组件是轮播图,是标签页组件,是详情页列表组件,是登陆组件