目录
React项目:... 1
win下开发环境的搭建:... 1
简介:... 5
例,测试程序:... 7
例,组件状态:... 9
例,复杂例子:... 11
react-mobx-starter-master.zip #解压此文件到指定位置,该位置即为项目根目录
$ npm install #或$npm i,会按照package.json的配置,安装依赖模块,生成node_modules目录(安装所有依赖的模块)
……
added 1212 packages in 135.079s
配置文件说明:
package.json文件:
npm init后产生的文件,记录项目信息,项目依赖;
需要修改name、version、description、repository、author、license,改好后可开始开发;
{
"name": "react-mobx-starter",
"version": "1.0.0",
"description": "react mobx starter",
"main": "index.js",
"scripts": { #项目管理,start指定启动webpack的dev server,build使用webpack构建打包
"test": "test",
"start": "webpack-dev-server --config webpack.config.dev.js --hot --inline",
"build": "webpack -p --config webpack.config.prod.js"
},
"repository": {}, #版本管理,如有用type和url定义,"type": "git","url":"……"
"author": "magedu",
"license": "MIT",
"devDependencies": { #开发时依赖
"babel-core": "^6.24.1", #babel转译,因为开发用了很多ES6语法,从6.X开始babel拆分成很多插件,需要什么引入什么,babel-core为核心
"babel-jest": "^19.0.0",
"babel-loader": "^6.4.1", #webpack的loader,webpack是基于loader的
"babel-plugin-transform-decorators-legacy": "^1.3.4", #转换装饰器用
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.4.0", #babel-preset-X,预设的转换插件
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"css-loader": "^0.28.0", #css相关,包括css-loader、less、less-loader、style-loader
"html-webpack-plugin": "^2.28.0",
"jest": "^19.0.2",
"less": "^2.7.2",
"less-loader": "^4.0.3",
"react-hot-loader": "^3.0.0-beta.6", #热加载插件,在改动保存后,直接在页面上就能反馈,不需要手动刷新
"source-map": "^0.5.6", #文件打包,js会合并或压缩,没法调试,用它来看js源文件是什么,source-map-loader也需要webpack的loader
"source-map-loader": "^0.2.1",
"style-loader": "^0.16.1",
"uglify-js": "^2.8.22",
"webpack": "^2.4.1", #打包工具
"webpack-dev-server": "^2.4.2" #启动一个开发的server
},
"dependencies": { #运行时依赖
"antd": "^2.9.1", #基于react实现,蚂蚁金服开源的react的UI库,做中后台管理非常方便
"axios": "^0.16.1", #异步请求支持
"babel-polyfill": "^6.23.0", #解决浏览器api不支持的问题,可抹平差异化
"babel-runtime": "^6.23.0",
"mobx": "^3.1.9", #状态管理库,透明化
"mobx-react": "^4.1.8",
"mobx-react-devtools": "^4.2.11",
"prop-types": "^15.5.8",
"react": "^15.5.4", #react开发的主框架,reaact-dom支持DOM,react-router支持路由,react-router-dom,DOM绑定路由;react和mobx是强强联合
"react-dom": "^15.5.4",
"react-router": "^4.1.1",
"react-router-dom": "^4.1.1"
}
}
.babelrc文件:
babel转译的配置文件,按官网给的配置:
{
"presets": [
"react",
"env",
"stage-0"
],
"plugins": ["transform-decorators-legacy", "transform-runtime"]
}
webpack.config.dev.js文件:
这是一个符合commonjs的模块,webpack配置;
const path = require('path');
const webpack = require('webpack');
module.exports = { #导出
devtool: 'source-map', #导出devtools是source-map
entry: { #描述入口,entry如果是一个字符串,定义就是入口文件;如果是一个数组,里面包含入口文件,另一个参数可用来配置一个服务器;这里配置的是热加载插件,可自动刷新
'app': [
'react-hot-loader/patch',
'./src/index'
]
},
output: { #输出,输出目录是__dirname+'dist',文件名是bundle.js
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/assets/'
},
resolve: { #指定解析什么文件类型,此处设置对js文件解析
extensions: ['.js']
},
module: { #模块
rules: [ #对.js结尾但不在node_modules目录的文件使用热加载loader和转译babel-loader
{
test: /\.js$/,
exclude: /node_modules/, #打包排除目录,重要,一定要有,否则编译就把这个目录下所有文件拿出来,超大无比
use: [
{ loader: 'react-hot-loader/webpack' },
{ loader: 'babel-loader' }
]
},
{
test: /\.less$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{ loader: "less-loader" }
]
}
]
},
plugins: [ #webpack的插件
new webpack.optimize.OccurrenceOrderPlugin(true),
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('development')}})
],
devServer: { #开发用server,启动端口3000,支持热加载;proxy,指定访问/api开头的路径都代理到http://127.0.0.1:8080
compress: true,
port: 3000,
publicPath: '/assets/',
hot: true,
inline: true,
historyApiFallback: true,
stats: {
chunks: false
},
proxy: {
'/api': {
target: 'http://127.0.0.1:8080',
changeOrigin: true
}
}
}
};
jsconfig.json文件:
vscode的本地配置文件,覆盖当前配置;
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"experimentalDecorators": true
}
}
$ npm start #启动项目,在项目根目录下
http://127.0.0.1:3000/ #启动成功,访问
“查看网页源代码” #下载到用户本地执行
F12,Network,都是动态生成的;
VS中打开react-mobx-starter-master/index.html,修改<h2>段,保存,重新打开网页,网页内容会有变化;
VS中查看reac-mobx-starter-master/src/index.js;
React是facebook开发并开源(2013年开源)的前端框架;
11年他们团队在市面上没找到合适的MVC框架,就自己写了一个js框架,用在大名鼎鼎的Instagram图片分享社区网络;
React解决的是前端MVC框架中的View视图层的问题;
Virtual DOM:
document object model,文档对象模型;
将网页内所有内容映射到一棵树型结构的层级对象模型上,browser提供对DOM的支持,用户可用脚本调用DOM API来动态的修改DOM结点,从而达到修改网页的目的,这种修改在browser中完成,browser会根据DOM的改变重绘改变的DOM结点部分;
修改DOM重新渲染代价太高,前端框架为了提高效率,尽量减少DOM的重绘,提出了virtual dom,所有的修改都是在当前virtual dom上完成的,通过比较算法,找出browser DOM之间的差异,使用这个差异操作DOM,browser只需要渲染这部分变化就行;
React实现了DOM diff算法,可高效比对virtual DOM和DOM的差异(类似事务,一块提交);
virtual DOM实质是内存中的数据结构;
支持JSX语法:
JSX,是一种javascript和xml混写的语法,是javascript的扩展;不用函数调用,就可知道结构;
JSX语法是XML,要求所有元素必须闭合,如<br />不能写成<br>;
JSX规范:
首字母小写就是html标记,首字母大写就是组件;
要求严格的html标记,要求所有标签必须闭合,如<br />,/前留一空格;
单行省略小括号,多行使用小括号;
元素有嵌套建议多行,注意缩进;
jsx表达式,使用{}括起来,如果大括号内使用了引号,会当作字符串处理,如<div>{'2>1?true:false'}</div>,里面的表达式就为字符串了;
React.render(
<div>
<div>
<div>content</div>
</div>
</div>,
document.getElementById('example')
);
state组件状态:
每一个React组件都有一个状态变量(各是各的),它是一个javascript对象,可为它定义属性来保存值,如果状态变化了,会触发UI的重新渲染;
state是组件自己内部使用的,是组件私有的属性;
组件是封装的最小单位;
jsx内只允许表达式,三目运算符即为表达式(换为if...else即为语句);
getElementById,通常用id找,也有用name找;
render()内,一般认为state是变化过的,建议不要再对state作变化;
setTimeout()和setInterval()是异步处理的,是在render()之后改的;
state对象中,属性的值可以是字符串、对象、数组等,只要这个值发生了变化就可以;
组件间的通信用props;
src/index.js
import React from 'react'; //导入React模块,主框架
import ReactDom from 'react-dom'; //导入ReactDom模块
class Root extends React.Component { //方1,推荐用jsx语法,组件类定义,从React.Component类上继承,这个类生成JSXElement对象,即react元素;叫react组件,或react元素,或jsx元素
render() { //渲染函数,返回组件中渲染的内容,只能返回唯一一个顶级元素,重要
return <div>hello magedu</div> //必须返回一个顶级元素,若为<div>aa</div><hr>则报错,JSX语法是XML,要求所有元素必须闭合
}
}
// class Root extends React.Component { //方2
// render() {
// return React.createElement('div', null, 'welcome to magedu.');
// }
// }
ReactDom.render(<Root />, document.getElementById('root')); //第一个参数<Root />是JSXElement对象,第二个参数document.getElementById('root')是DOM的Element元素,将React元素添加到Dom的Element元素中并渲染,此处root要与index.html的<div id="root"></div>对应
// ReactDom.render(React.createElement(Root), document.getElementById('root')); //方2,还可使用React.createElement创建react元素,第一参数是React组件或一个HTML的标签名称(如div、span)
src/index.js保存后,会自动编译,并重新装载刷新browser端界面;
增加一个子元素:
import React from 'react';
import ReactDom from 'react-dom';
class SubEle extends React.Component {
render() {
return <div>sub content</div>;
// return <div>{1 + 2}</div>; //V
// return <div>{1<2?'true':'false'}</div>; //V
// return <div>{'1<2?true:false'}</div>; //X,表格式显示为字符串
// return <div>{1<2?true:false}</div>; //X,true和false去掉引号,browser将不会显示
}
}
class Root extends React.Component {
render() {
return (
<div> //首字母小写是html标记
<h3>welcome magedu.com</h3>
<br />
<SubEle /> //首字母大写是组件
</div>
);
}
}
ReactDom.render(<Root />, document.getElementById('root'));
http://127.0.0.1:3000/api/index.js
504 Gateway Timeout
注:可用于做代理事情;
import React from 'react';
import ReactDom from 'react-dom';
class SubEle extends React.Component {
render() {
return <div>sub content</div>;
}
}
class Root extends React.Component {
state = { //内部私有,此类之外是不允许访问的,这种方式不好
p1:'magedu',
p2:'.com'
};
dealsth() {
this.setState({p1:'www.magedu'});
}
render() {
// this.state.p1 = 'www.magedu'; //V,可以更新
// this.setState({p1:'www.magedu'}); //X,不可以对还在更新中的state使用setState,browser的Console上有警告Warning
setTimeout(() => this.setState({p1:'magedu',p2:'.net'}),5000); //V,可用延时函数操作,5s后页面自动刷新;this.setState({p1:'magedu'})并不会把state对象的所有属性覆盖掉,只是改了对应p1属性的值
// this.dealsth(); //X,通过方法操作也不可以
return (
<div>
<h3>welcome to {this.state.p1}{this.state.p2}</h3>
<br />
<SubEle />
</div>
);
}
}
ReactDom.render(<Root />, document.getElementById('root'));
this.setState({p1:'www.magedu'}); //X,表现如下
Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.
每5s会重绘;
传统的html编程方式:
{/* <html>
<head>
<script type="text/javascript">
function getEventTrigger(event) {
x = event.target;
alert("trigger's element id is: " + x.id);
}
</script>
</head>
<body>
<div id="t1" onmousedown="getEventTrigger(event)">
click me,it will be trigger a event,and alert window
</div>
</body>
</html> */}
注:
head与http的响应头没关系,head是响应头中body部分的头,head中的<script>是不显示的;可在此head中加title(即browser中标签部分),另title上一行可加<meta>元信息(给SE或爬虫看的);
div的id是t1,鼠标按下事件(onmousedown,另还有onmouseup和onmouseclick)捆绑了一个函数,只要鼠标按下就会触发调用getEventTrigger函数,浏览器会送给它一个参数event(event是浏览器送进来的对象),event是事件对象,当事件触发时,event包含触发这个事件的对象;
用react实现:
import React from "react";
import ReactDom from 'react-dom';
class Toggle extends React.Component {
state = {
flag: true
};
handleClick(event) {
console.log(event);
console.log(event.target);
console.log(event.target.id);
console.log(event.target === this);
console.log(this);
console.log(this.state);
let x = event.target;
alert("触发的元素的id是:" + x.id);
this.setState({flag:!this.state.flag});
}
render() {
let text = this.state.flag?'true':'flase';
return (<div id='t1' onClick={this.handleClick.bind(this)}> //onClick小驼峰,一般用这个就够了,另onMouseUp和onMouseDown要结合;this.handleClick.bind(this)此处是返回函数,在之前的对象模型中解决this指针问题用到的bind最后要函数调用
点击这句话,会触发一个事件,并弹出一个警示框<br />
flag = {text}
</div>);
}
}
class Root extends React.Component {
render() {
return (<div>
my first test<hr /> //此处的<h3>已不完全是html了,可用css控制或js控制
<Toggle />
</div>);
}
}
ReactDom.render(<Root />, document.getElementById('root'));
注:
传统方式是分开写(混着写,html+css+js都要会),现合到一个class里了;与显示相关的放到render里了;
鼠标操作都是通过事件来捕捉的,仅是在指定的div上点,在其它地方点和这个div上的事件没关系;
项目根下的index.html即模板文件,一个网页即解决所有问题(换底图除外),即SPA,single page web application只有一张web页面的应用,在<div>里嵌入不同的内容;
Toggle类,有自己的state属性;
当render完成后,网页上有一个div标签,div标签对象捆绑了一个click事件的处理函数,div标签内有文本内容;如果点击左键,就触发了onClick关联的handleClick函数,在这个函数里对状态值改变,状态值state的改变将引发render重绘;
如果组件自己的state变了,只会触发自己的render方法重绘;
{this.handleClick.bind(this)},表达式内不能加引号,要绑定this,否则当触发捆绑的函数时,this是函数执行的上下文决定的,this已经不是触发事件的对象了;
console.log(event.target.id),取回产生事件的对象的id,但是这不是我们封装的组件对象,所以console.log(event.target===this)为false,所以这里一定要用this,而这个this是通过绑定来的;
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。