fat_server.png
这个架构的特点:
一些改进:
fat_client.png
这个架构的特点:
前端负责的逻辑这么复杂了,为了便于管理,自然要进行必要的分层。
web_mvc.png
典型代表:backbone之类的前端框架
web_mvp.png
这个在Android开发中用得比较多。
web_mvvm.png
MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。这种双向绑定功能一般借助于ReactJS、VueJS、AngularJS之类的UI框架。
React (有时叫 React.js 或 ReactJS) 是一个为数据提供渲染为 HTML 的视图的开源 JavaScript 库。React 视图通常采用包含以自定义 HTML 标记规定的其他组件的组件渲染。React 为程序员提供了一种子组件不能直接影响外层组件 (“data flows down”) 的模型,数据改变时对 HTML 文档的有效更新,和现代单页应用中组件之间干净的分离。它由 Facebook, Instagram 和一个由个人开发者和企业组成的社群维护,它于 2013 年 5 月在 JSConf US 开源。
在Web开发中,我们总需要将变化的数据实时反应到UI上,这时就需要对DOM进行操作,而复杂或频繁的DOM操作通常是性能瓶颈产生的原因。
React为此引入了虚拟DOM(Virtual DOM)的机制:在浏览器端用Javascript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。而且React能够批处理虚拟DOM的刷新,在一个事件循环(Event Loop)内的两次数据变化会被合并。
尽管每一次都需要构造完整的虚拟DOM树,但是因为虚拟DOM是内存数据,性能是极高的,而对实际DOM进行操作的仅仅是Diff部分,因而能达到提高性能的目的。这样,在保证性能的同时,开发者将不再需要关注某个数据的变化如何更新到一个或多个具体的DOM元素,而只需要关心在任意一个数据状态下,整个界面是如何Render的。
这里有一个更通俗的解释
如果对虚拟DOM的工作方式感兴趣,可以看这里
仅仅只要表达出你的应用程序在任一个时间点应该长的样子,然后当底层的数据变了,React 会自动处理所有用户界面的更新。
数据变化后,React 概念上与点击“刷新”按钮类似,但仅会更新变化的部分。
React 易于构建可复用的组件。事实上,通过 React 你唯一要做的事情就是构建组件。得益于其良好的封装性,组件使代码复用、测试和关注分离(separation of concerns)更加简单。
React并没有依赖其它的技术栈,因此可以在老旧项目中使用ReactJS开发新功能,不需要重写存在的代码。React可以在浏览器端或服务端进行渲染,甚至借助于React Native,可在移动设备中渲染。
ReactDOM.render
是 React 的最基本方法,用于将模板转为HTML语言,并插入指定的DOM节点。用于将模板转为HTML语言,并插入指定的 DOM 节点
<!DOCTYPE html>
<html>
<head>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
</script>
</body>
</html>
HTML语言直接写在JavaScript语言之中,不加任何引号,这就是JSX的语法,它允许HTML与JavaScript的混写。
JSX的规则是:遇到HTML标签(以<
开头),就用HTML规则解析;遇到代码块(以{
开头),就用 JavaScript 规则解析。
这种写法虽然将模板直接写到JavaScript中了,但带来很多灵活,不需要去学特定的标签语法,会JS就成。比如下面的代码:
var names = ['Alice', 'Emily', 'Kate'];
ReactDOM.render(
<div>
{
names.map(function (name) {
return <div>Hello, {name}!</div>
})
}
</div>,
document.getElementById('example')
);
React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。所有组件类都必须有自己的render
方法,用于输出组件。组件的用法与原生的HTML标签完全一致,可以任意加入属性。组件的属性可以在组件类的this.props
对象上获取。
class HelloWorld extends React.Component{
render(){
return <h1>Hello, {this.props.name}</h1>
}
}
class Container extends React.Component{
render(){
return <HelloWorld name="world"></HelloWorld>
}
}
ReactDOM.render(
<Container />,
document.getElementById('root')
);
组件免不了要与用户互动,React将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染UI。
class LikeButton extends React.Component{
constructor(props){
super(props);
this.state = {liked: false};
}
handleClick() {
this.setState({liked: !this.state.liked});
}
render() {
var text = this.state.liked ? 'like' : 'haven\'t liked';
return (
<p onClick={() => this.handleClick()}>
You {text} this. Click to toggle.
</p>
);
}
}
ReactDOM.render(
<LikeButton />,
document.getElementById('example')
);
组件的生命周期分成三个状态:
Mounting:已插入真实 DOM
Updating:正在被重新渲染
Unmounting:已移出真实 DOM
React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数。
componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()
比如说实际编码过程中,我们经常会在componentDidMount
方法加入逻辑:发出AJAX请求,请求后台数据后修改组件状态。
react_sample.png
更多示例代码见 https://facebook.github.io/react
我自己写的一个SSM+ReactJS+Redux工程示例:http://git.oschina.net/jeremy-xu/ssm-scaffold
http://www.ruanyifeng.com/blog/2015/03/react.html
http://wiki.jikexueyuan.com/project/react/
一些后台管理、UI交互特别复杂、频繁操作DOM的页面
ReactDOM.findDOMNode(componentInstance)
或ReactDOM.findDOMNode(this.refs.compRef)
SyntheticEvent
,它不是原生的DOM事件,支持的属性与方法见这里this
回归JavaScript的本意。这样当指定事件回调方法时,this
很有可能指定的是触发事件的组件。可以用ES6里的箭头函数来解决这个问题。比如一个实际的例子:
test.jsp
<c:set var="ctx" value="${pageContext.request.contextPath}"/>
<body>
<div id="root"></div>
<!-- 喜欢使用lodash里一些工具方法,高效且实用 -->
<script type="text/javascript" src="${ctx}/libs/lodash.min.js"></script>
<!-- React的库文件 -->
<script type="text/javascript" src="${ctx}/libs/react.min.js"></script>
<script type="text/javascript" src="${ctx}/libs/react-dom.min.js"></script>
<!-- 阿里出品,强大的React组件库 -->
<script type="text/javascript" src="${ctx}/libs/antd.min.js"></script>
<!-- 时间日期工具库 -->
<script type="text/javascript" src="${ctx}/libs/moment.min.js"></script>
<!-- Promise风格发送AJAX请求,避免javascript callback hell http://callbackhell.com/ -->
<script type="text/javascript" src="${ctx}/libs/axios.min.js"></script>
<!-- 使用babel将ES6的代码在浏览器端翻译为ES5代码 -->
<script type="text/javascript" src="${ctx}/libs/babel/browser.min.js"></script>
<!-- 声明一个JS变量保存webapp上下文,以后发送AJAX请求时会用到 -->
<script type="text/javascript">var __CTX_PATH__='${ctx}';</script>
<!-- 引入业务JSX文件 -->
<script type="text/babel" src="${ctx}/scripts/business1.jsx"></script>
</body>
business1.jsx
const React = window.React;
const ReactDOM = window.ReactDOM;
const axios = window.axios;
const antd = window.antd;
const _ = window._;
class Demo1 extends React.Component{
render(){
return <h1>TODO</h1>
}
}
ReactDOM.render(
<Demo1 />,
document.getElementById('root')
);
ES6教程 http://es6.ruanyifeng.com/
Gulp教程 http://www.gulpjs.com.cn/docs/
Webpack教程 http://zhaoda.net/webpack-handbook/module-system.html
Browserify文档 https://github.com/substack/node-browserify#usage
Babeljs使用教程 https://babeljs.io/docs/setup/#installation
lodash文档 http://lodashjs.com/docs/
js callback hell
利器Promise教程 http://es6.ruanyifeng.com/#docs/promise
Axios教程 https://www.kancloud.cn/yunye/axios/234845
React-Router教程 https://react-guide.github.io/react-router-cn/
Antd文档 https://ant.design/docs/react/introduce-cn
Redux教程 http://cn.redux.js.org/docs/basics/index.html
VueJS文档 https://cn.vuejs.org/v2/guide/
Vuex文档 https://vuex.vuejs.org/zh-cn/
element组件文档 http://element.eleme.io/#/zh-CN/component/installation