文章目录
前言
前端可以做到读写数据、切换视图、用户交互,这意味着,网页其实是一个应用程序,而不是信息的纯展示。这种单张网页的应用程序称为 SPA(single-page-application)。
2010年后,前端工程师从开发页面(切模板),逐渐变成了开发“前端应用”(跑在浏览器里面的应用程序)。目前,最流行的前端框架 Vue、Angular、React 等等,都属于 SPA 开发框架。
react脚手架建立工程
1、安装
npm install create-react-app -g
2、创建
create-react-app react-demo (react-demo项目名)
3、初始化
cd react-demo
npm install or cnpm install or yarn install
4、运行
yarn start
创建一个helloWorld Demo
引入模块
//第一步 导入react
import React,{Component} from 'react';
import '../assets/css/index.css'
import logo from '../assets/images/logo.svg';
import '../assets/css/App.css';
/**
* 绑定原生属性注意:
* class 要换成className
* for 要换成htmlFor
* style 要用{}包裹成对象
*/
//第二步,编写组件类并继承React.Component
class Home extends Component{
constructor(){
super();
//定义数据
this.state={
msg:'你好,世界!'
}
}
//第三步,重写render()方法,用于渲染页面
render(){
return (
<div>
<h1>{this.state.msg}</h1>
<img src={logo} width='500px'></img>
</div>
);
}
}
//第四步,导出该类
export default Home;
然后启动工程即可完成一个简单的demo
yarn start
react是面向组件的,通过JSX语法来操作虚拟dom节点,如果state的数据发生了变化则会触发对应的dom的刷新。JSX语法就是,可以在js文件中插入html片段,是React自创的一种语法。JSX语法会被Babel等转码工具进行转码,得到正常的js代码再执行。所有标签必须闭合
注意在本地引用img等资源时,需要通过{xx}对象形式引用。如果是网络图片,直接用url引用即可。
JSX语法就是,可以在js文件中插入html片段,是React自创的一种语法。JSX语法会被Babel等转码工具进行转码,得到正常的js代码再执行。所有标签必须闭合
react 通过state来定义和绑定数据,但这种绑定并不是MVVM那种双向数据绑定,在JSX中要使用时通过 this.state.xxx
来使用
知识点:
1. 目录结构分析
用脚手架创建的工程的目录是有些不完整的,需要补全(为了方便归档)
component文件主要放组件,model放数据模型,App.js是默认的根组件,index.js是入口文件,相当于main,yarn.lock是项目生成的临时文件,package.json是依赖管理文件(类似maven的pom文件),nodel_modules是存放依赖包的文件夹
2. 创建组件
第一步 导入react
第二步,编写组件类并继承React.Component
第三步,重写render()方法,用于渲染页面
第四步,导出该类
3. JSX注意事项
如果要在模板中嵌套多个HTML标签,需要使用一个父元素对其进行包裹
<div>
<h1>{this.state.msg}</h1>
<img src={logo} width='500px'></img>
</div>
4.绑定数据或对象
js中定义对象用{},其实就是restful风格的东东。
类似于
{
title:"xxx",
content:"xxxx"
}
数据的定义用[ ],一对方括号即可。
在react中绑定对象只需要在state中定义即可
this.state={
msg:'你好,世界!'
}
事件及数据绑定Demo
import React from 'react'
class Demo1 extends React.Component{
constructor(props){
super(props);
this.state={
msg:"demo1组件",
text:"",
keydown:"",
}
}
run=(e)=>{
alert(e.target.getAttribute('id')) //获取当前执行事件的dom节点
e.target.style.background='red';
}
inputChange=(e)=>{
//获取表单的值
//console.log(e.target.value);
this.setState({
text: e.target.value
})
}
inputChange1=()=>{
let value = this.refs.input.value;
this.setState({
text: value
})
}
getInputValue=()=>{
alert(this.state.text)
}
inputOnKeydown = (e)=>{
console.log(e.keyCode);
this.setState({
keydown:e.keyCode
})
}
inputChange2 = (e)=>{
this.setState({
text:e.target.value
})
}
changeTextMode = (e)=>{
this.setState({
text:"改变后的model值,可以看到下面这个输入框的数据已经改变,而上面两个输入框未发生变化"
})
}
render(){
return (
<div>
<hr></hr>
<h2>事件对象演示</h2>
{this.state.msg}
{/* 事件对象 */}
<button id='buttonId' onClick={this.run}>事件对象</button>
<hr></hr>
<h2>表单事件演示</h2>
<p>{this.state.text}</p>
<input type="text" onChange={this.inputChange}/>
<button onClick={this.getInputValue}>获取表单值</button>
<hr></hr>
<h2>ref获取dom节点,获得表单值</h2>
<p>{this.state.text}</p>
<input ref='input' type="text" onChange={this.inputChange1}/>
<button onClick={this.getInputValue}>获取表单值</button>
<hr></hr>
<h2>键盘事件</h2>
<p>{this.state.keydown}</p>
<input type="text" onKeyDown={this.inputOnKeydown}/>
<hr></hr>
<h2>react实现双向数据绑定</h2>
<p>model改变影响view(通过value属性),view改变影响model</p>
<p>model值:{this.state.text}</p>
<input type='text' value={this.state.text} onChange={this.inputChange2}></input>
<button onClick={this.changeTextMode}>改变model的值</button>
</div>
)
}
}
export default Demo1 ;
知识点:
事件绑定:
- 绑定事件需要在对应的事件响应中获得正确的this对象
例如:为Button 绑定了一个事件
<button id='buttonId' onClick={this.run}>事件对象</button>
如果你用箭头函数写响应方法,则this指向的就是react的当前组件
run=(e)=>{
alert(e.target.getAttribute('id')) //获取当前执行事件的dom节点
e.target.style.background='red';
}
如果你用的是普通写法写的函数响应
funtion run(e){
alert(e.target.getAttribute('id')) //获取当前执行事件的dom节点
e.target.style.background='red';
}
需要使用下面这种写法传递对象指向
<button id='buttonId' onClick={this.run.bind(this)}>事件对象</button>
数据绑定(View->Model)
<p>{this.state.text}</p>
<input type="text" onChange={this.inputChange}/>
inputChange=(e)=>{
//获取表单的值,设置model的数据
//console.log(e.target.value);
this.setState({
text: e.target.value
})
}
数据绑定(Model->View)
<button onClick={this.getInputValue}>获取表单值</button>
getInputValue=()=>{
alert(this.state.text) //获取model中的数据
}
双向数据绑定(M->V&V->M 俗称MVVM)
<h2>react实现双向数据绑定</h2>
<p>model改变影响view(通过value属性),view改变影响model</p>
<p>model值:{this.state.text}</p>
<input type='text' value={this.state.text} onChange={this.inputChange2}></input>
<button onClick={this.changeTextMode}>改变model的值</button>
value 通过属性绑定model 完成 m->v的绑定
通过监听onChange完成v->m的绑定 ,和上面那个View->Model的绑定是一样的。
TodoList小练习
该练习的旨在熟悉双向数据绑定和react的基础用法,另外扩展了localStorage缓冲处理方案,实现刷新不会丢失数据状态。
import React, {Component}from 'react';
import Storage from '../model/storage'
class Demo3 extends Component {
constructor(props) {
super(props);
this.state = {
todo:'',
todolist:[],
};
}
//生命周期函数,页面加载触发
componentDidMount=()=>{
let list = Storage.get('todolist');
if(list){
console.log("get:"+list)
this.setState({
todolist:list
})
}
}
addTodoText=(e)=>{
this.setState({
todo: e.target.value
})
}
onAddBtnClick=()=>{
let todolist = this.state.todolist;
todolist.push({
todo:this.state.todo,
checked:false
})
this.setState({
todolist:todolist,
todo:""
})
//缓存数据
Storage.set("todolist",todolist);
}
onPressEnter=(e)=>{
if(e.keyCode==13){
this.onAddBtnClick();
}
}
ondelBtnClick=(index)=>{
let todolist = this.state.todolist;
todolist.splice(index,1);
this.setState({
todolist:todolist
})
//缓存数据
Storage.set("todolist",todolist);
}
checkChange = (index)=>{
let todolist = this.state.todolist;
todolist[index].checked=!todolist[index].checked;
this.setState({
todolist:todolist
})
//缓存数据
Storage.set("todolist",todolist);
}
render() {
return (
<div>
<h2>todoList 演示</h2>
<header><input type="text" value={this.state.todo} onChange={this.addTodoText} onKeyDown={this.onPressEnter}/> <button onClick={this.onAddBtnClick}>增加</button></header>
<hr></hr>
<h4>未完成事项</h4>
<ul>
{
this.state.todolist.map((value,index)=>{
if(!value.checked){
return (
<div key={index}>
<input type='checkbox' checked={value.checked} onChange={this.checkChange.bind(this,index) }/>-----{value.todo} <button onClick={this.ondelBtnClick.bind(this,index)}>删除</button>
</div>
)
}
})
}
</ul>
<hr></hr>
<h4>已完成事项</h4>
<ul>
{
this.state.todolist.map((value,index)=>{
if(value.checked){
return (
<div key={index} className='complete'>
<input type='checkbox' checked={value.checked} onChange={this.checkChange.bind(this,index) }/>-----{value.todo} <button onClick={this.ondelBtnClick.bind(this,index)}>删除</button>
</div>
)
}
})
}
</ul>
</div>
);
}
}
export default Demo3;
远程请求数据Demo
通过axios向服务端请求数据,我这里没有通过配置代理解决跨域问题,而是在后端配置了取消CROS请求来解决跨域问题
import React from 'react'
import axios from 'axios'
import request from '../model/server'
import jsonp from 'fetch-jsonp'
class Demo4 extends React.Component {
constructor(props) {
super(props);
this.state = {
list:[],
};
}
getData = ()=>{
let api = 'http://localhost:18080/house/resources/findAll'
axios.get(api)
.then((response)=>{
console.log(response)
this.setState({
list:response.data
})
})
.catch((error)=>{
console.log(error)
})
// let data =await request.get(api)
// console.log(data)
}
render() {
return (
<div>
<h2>axios获取服务器数据,未处理跨域,取消cros</h2>
<button onClick={this.getData}>获取服务器数据</button>
<p>url:<a href='http://localhost:18080/house/resources/findAll'>http://localhost:18080/house/resources/findAll</a></p>
<ul>
{
this.state.list.map((value,index)=>{
return (
<li key={index}>{value.created}</li>
)
})
}
</ul>
<h2>jsonp获取服务器数据,跨域请求</h2>
<p>怎么看,看你的地址加入callback=xxx之后是否能访问就知道是否支持jsonp了</p>
</div>
);
}
}
export default Demo4;
知识点:
1. 跨域问题
所谓跨域问题就是 协议,域名,端口三者有其一不一致则出现跨域,一般情况下跨域是不被浏览器支持的。
2. axios
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
使用
npm install --save axios
React-router 4.x基本配置及动态路由使用
安装
cnpm install react-router-dom --save
引入
import {BrowserRouter as Router,Route,Link} from 'react-router-dom'
基本使用:
<Router>
<div>
<header className='header'>
<Link to="/">首页</Link><br/>
<Link to="/news">新闻</Link>
</header>
</div>
<hr/>
<div>
<Route exact path="/" component={Home} />
<Route path='/news' component={News}/>
<Route path='/content/:aid' component={Content}/>
</div>
</Router>
动态路由的使用
定义路由
<Route path='/content/:aid' component={Content}/>
使用路由
{
this.state.list1.map((value,key)=>{
return (
//ES6模板字符串写法
<Link to={`/content/${value.aid}?content=${value.content}`} key={key}>
<li>{value.title}</li>
</Link>
)
})
}
在子组件中获得动态路由的传参
aid:this.props.match.params.aid,
在prps.match.params中获取传参即可
利用get实现动态路由
无需定义路由格式,直接使用,在路由后面像get方法一样传参
类似"?name=zhong"这种
使用路由
<Link to={`/content/${value.aid}?content=${value.content}`} key={key}><li>{value.title}</li></Link>
其中
?content=${value.content} 就是使用了get传参
在子组件中获得动态路由的传参
componentDidMount(){
//通过npm带的url模块解析get参数 cnpm install url --save 安装即可
console.log(url.parse(this.props.location.search,true))
let news = {
aid:this.props.match.params.aid, //通过动态路由传值
content:url.parse(this.props.location.search,true).query.content, //通过get传值
}
this.setState({
news:news
})
}