在我们的前端项目里经常会用到级联的select,比如省市区这样。通常这种级联大多是动态的。比如先加载了省,点击省加载市,点击市加载区。然后数据通常ajax返回。如果没有数据则说明到了叶子节点。
针 对这种场景,如果我们使用jquery来实现,要考虑很多的问题,数据部分,以及大量的dom操作。比如这个页面上显示了某个区,这时候我切换省,要把市 重新初始化数据,然后区域的部分要从页面中删除。这个判断是非常烦躁的。所以之前碰到这个问题时,就直接使用递归删除省下面的所有子,然后再重新生成市。 所以jquery的思路是以dom为中心,所以的操作都在围绕着dom的变化来操作。也就是jquery的核心思想是dom可变。写jQuery写长了一 个最真实的感受就是,仿佛天天都在写状态机,直到罗列了页面可能出现的所有情况。
这个问题在我学习React的时候思考很久,按照jQuery的思路我完全找不到北。因为React的style中很少有DOM的操作,而且很少直接去操作dom(几乎没有)。那怎么才能实现上面的需求呢?经过苦苦的思考React的函数式的哲学,终于想明白了。
React强烈支持组件式开发,将页面的区域抽象为组件。如,最简单的一个组件
var React = require(‘react’);
var HelloComponent = React.createClass({
render: function() {
return <div>Hello {this.props.name}<div>;
}
});
React.renderComponent(<HelloComponent name=“react!"/>, document.body);
这样我们根据我们的业务需要建立一个组件HelloCompoent,然后通过属性参数实现动态的展现效果。然后将这个组件挂载在document.body之上。
函数式-不可变。
函数式的风格的前端,首先一开始就和jQuery的思路迥异,函数式一上来就认为DOM不可变。那这里就让人很迷糊,纳尼?dom不可变?是的不可变。
DOM 不可变意味着什么?意味着当你的状态或者属性发生变化时,DOM部分就该不加任何思索,re-render,是的,完全的重绘,不会像jQuery一样在 你上一次的基础上重绘成新的状态,这个工作量太大了。极端的例子,上一次dom展示的是一个cat,现在的数据渲染的是一个dog,我*,这个重绘的工作 量就大发了。所以re-render真是最自然最简单地办法。但是亲爱的聪明的你突然想明白了我在忽悠?每次重新re-render会带来页面大量的 repaint-reflow。如果操作复杂会把页面性能拖到非常low的一个水平。哎。是的呢。那我们看看React的实现和哲学吧。
React的每个组件包含状态和属性,且状态和属性和dom隔离。dom的部分就是动态模板。
1. React认为页面dom不可变,所以当状态和属性发生变化时会re-render dom。
2. React的会根据新的状态和属性生成新的VirtualDOM Tree然后和旧的VirtualDOM Tree做对比(类似于版本控制的机制)。
3. 通过对比计算出最小的更新代价,然后将这些更新的方法进入队列。
4. 批量更新。
所以通过React实现了超高速的re-render,每秒可以60fps,这是变态的游戏级的水准。
且React强调single data flow,大大的减少了前端的复杂度。
且通过不断的组合组件实现更复杂的组件,这点很爽。
关于VirtualDOM再举个带状态栗子:计时器。
var React = require(‘react’);
var Timer = React.createClass({
getInitialState: function() {
return {secondElapsed: 0};
},
tick: function() {
this.setState({
secondElapsed: this.state.secondElapsed + 1
});
},
componentDidMount: function() {
this.interval = setInterval(this.tick, 1000);
},
componentWillUnmount: function() {
clearInterval(this.interval);
},
render: function() {
return <div>Time elapsed: {this.state.secondElapsed}</div>;
}
});
React.render(<Timer/>, document.body);
当secondElapsed变化时,React会计算出最小更新代价。
好 了,绕了这么大一圈,还没有回到故事的原点。那怎么玩出React的Style的感觉的级联Select呢?这个时候我们考虑问题不在以我们的DOM为中 心了,我们应该以我们的领域为中心,就是被Angular发扬光大的MDV(Model-Driven-View),模型驱动视图。
好的,省市区是我们的模型
我们的领域的描述:
items: [
//省
{label: ‘省’, data: [{id: 1, name: ‘安徽’}, {id: 2, name: '江苏'}]},
//市
{label: ’市’, data: [{id: 11, name: '蚌埠'}]},
//区
{label: ‘区’, data: [{id: 111, name: '怀远'}]}
];
choose: [1, 11, 111];
So 明白了嘛?
比如items就是我们的省市区领域数据,
1. 第一次加载ajax得到省信息,然后push到items
这时候React发现数据的状态发生了变化,赶紧计算diff,然后re-render,省就被virtualdom渲染出来了。
2. 当点击某个省,ajax获取市信息,然后push到items,且记录选中省的id
React又发现了变化,根据计算diff,发现省的信息没有变嘛,so就重绘了一个市select出来。So 这就是React比较库的地方。
3. 点击区。。。。你懂了。
4. 这时候我点击省了,如果没有选中任何省,只是选中"了请选择“, 我就将市和区的信息全clean掉,React又发现数据变化了,发现省的数据没有变化,不重新渲染,发生市和区数据没有了,re-render之后页面的市和区的select直接被clean掉。
通过上述步骤,我们清晰的看到原本我们是对DOM费事的操作转化为对我们领域的操作。DOM会被re-render,想一想都开心呢。
附上代码:
/**@jsx React.DOM*/
var React = window.React = require('react');
var provData = {
label: '省',
data: [
{id:1, name: '安徽'},
{id:2, name: '江苏'}
]
};
var cityData = [{
label: '市',
pid: 1,
data: [
{id: 10, name: '蚌埠'},
{id: 11, name: '巢湖'},
{id: 12, name: '太湖'}
]
}];
var CascadeSelect = React.createClass({
getInitialState: function() {
return {
items: [],
choose: []
}
},
componentWillMount: function() {
//AJAX call
this.setState({
items: this.state.items.concat([provData])
});
},
_handleChange: function(e) {
e.preventDefault();
var value = e.target.value.split("\:");
var selectIndex = value[0];
var selectValue = value[1];
var newData;
var index = selectIndex;
var nextItems = this.state.items;
var nextChoose = this.state.choose;
if (selectValue != '') {
index++;
nextChoose[selectIndex] = selectValue;
//ajax call
newData = cityData.filter(function(item) {
return item.pid == selectValue;
});
}
nextChoose = nextChoose.slice(0, index);
nextItems = nextItems.slice(0, selectIndex+1);
if (newData!=null && newData.length > 0) {
nextItems.push(newData[0]);
}
this.setState({
items: nextItems,
choose: nextChoose
});
},
_handleClick: function(e) {
e.preventDefault();
alert(this.state.choose.join("=>"));
},
render: function() {
return (
<div>
{this.state.items.map(function(item, i) {
return (
<div key={i}>
<label>{item.label}</label>
<select data-order={i} onChange={this._handleChange}>
<option value={i + ":"}> ==请选择== </option>
{item.data.map(function(data) {
return (<option key={data.id} value={i + ":" + data.id}>{data.name}</option>);
})}
</select>
</div>
);
}, this)}
<button onClick={this._handleClick}>查看选择项</button>
</div>
);
}
});
React.renderComponent(<CascadeSelect/>, document.body);
时间紧,任务重,代码就先草率的写到这了。通过代码和我们预期的一样,大部分的操作在model而不是dom。
我们再进一步抽象数据源,设置url属性,这样下次你在任何的地方想使用这种级联的select都只需要简单地
<CascadeSelect firstLevelUrl=“/provData” secondLevelUrl=‘' />
最后,不是因为我们用了React或者Angular就比jQuery高大上,从来不是这样的。我们的目标不是高大上,而是更好的解决我们的问题。提供更好的服务。我们要学习的是隐藏在React或者Angular背后的设计思想,对问题的抽象架构的方法。
最后和兄弟们共勉:
Dijkstra曰:编程的艺术就是处理复杂性的艺术。设法把代码写的精简从来就不是什么境界。代码架构内部的秩序能有效适应需求变化和化解业务的复杂度易于扩展和维护才是要追求的境界。
React把重点放在可预测性和数据单向同步上,它对控制复杂度很有效。
转载:http://www.cnblogs.com/yunfeifei/category/569007.html
- EF Core 遇到“可能会导致循环或多重级联路径”
在ef core中你可能会设计这样一个实体: public class Customer : Entity,IMustHaveTenant, IHasCreationTime { public Cus ...
- 可能会导致循环或多重级联路径。请指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。
错误提示:可能会导致循环或多重级联路径.请指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束. 原因:自表连接(同一张表 ...
- Vue省市区三级联选择器V-Distpicker的使用
Vue省市区三级联选择器V-Distpicker的使用 最近用的Vue+Element UI时,有些地方需要用到省市区三联选择器,网上安装并尝试了多种类似的插件,但都因为无法正常实现或是没有眼缘而弃用 ...
- [C#]使用 C# 代码实现拓扑排序 dotNet Core WEB程序使用 Nginx反向代理 C#里面获得应用程序的当前路径 关于Nginx设置端口号,在Asp.net 获取不到的,解决办法 .Net程序员 初学Ubuntu ,配置Nignix 夜深了,写了个JQuery的省市区三级级联效果
[C#]使用 C# 代码实现拓扑排序 目录 0.参考资料 1.介绍 2.原理 3.实现 4.深度优先搜索实现 回到顶部 0.参考资料 尊重他人的劳动成果,贴上参考的资料地址,本文仅作学习记录之用. ...
- C# json反序列化 对象中嵌套数组 (转载) 可能会导致循环或多重级联路径。请指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。
C# json反序列化 对象中嵌套数组 (转载) 看图: 这里可以看到是二层嵌套!!使用C#如何实现?? 思路:使用list集合实现 → 建立类 → list集合 → 微软的 Newtonso ...
- react与jQuery对比,有空的时候再翻译一下
参考资料:http://reactfordesigners.com/labs/reactjs-introduction-for-people-who-know-just-enough-jquery-t ...
- 夜深了,写了个JQuery的省市区三级级联效果
刚刚练手的JQuery,希望大神们指正 主要实现以下功能: 1.三级菜单级联加载数据 2.可以在不操作脚本的情况下,给元素加属性实现级联功能 3.自定义动态显示数据 咨询问题: 对于一般比较固定不变的 ...
- 关于EF中出现FOREIGNKEY约束可能会导致循环或多重级联路径的问题
ef中,我们创建外键的时候需要注意,否则会出现标题所示问题. 例:有项目表,项目收藏表,用户表 项目表有如下字段:ProjectId,InputPersonId等 项目收藏表有如下字段:Project ...
- 省市区三级联选select2.js
<div class="mui-input-row row_then" id='showCityPicker3'> <input id='cityResult3' ...
随机推荐
- How do you render tooltip on disabled HTML Button
This idea's based on the following (x)html: <form><fieldset><buttondisabledtitle=&quo ...
- IOS 使用webview 显示 doc/docx/xls/pdf等
在一款项目里添加阅读各种文档功能 那么对在线的文档或者是下载后的文档 进行阅读,比如 doc/docx/xls/pdf等文件 有两种方法总结如下: 1. - (void)viewDidLoad { [ ...
- iOS系统下 的手机屏幕尺寸 分辨率 及系统版本 总结
今天 我对iOS系统下 的手机屏幕尺寸 分辨率 及系统版本做了一次系统总结 供大家参考. 首先 是系统: 随着iOS 系统不断升级,现在已经到iOS7.0了, 并且TA有了很多新变化,最震撼的 ...
- [Java] HashMap遍历的两种方式
Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml第一种: Map map = new HashMap( ...
- property在括号中应该怎样写
property 属性的定义,类似于get set assign: 简单的赋值,不更改索引计数 使用assign是针对基础的数据类型,比如NSinterger,CGFloat和c数据类型(int fl ...
- CMP指令(转)
刚刚看到了cmp指令,一开始有点晕.后来上网找了些资料,终于看明白了,为了方便初学者,我就简单写下我的思路吧.高手绕过,谢谢! cmp(compare)指令进行比较两个操作数的大小 例:cmp opr ...
- revel + swagger 文档也能互动啦
beego 从 1.3 后开始支持自动化API文档,不过,目测比较复杂,一直期望 revel 能有官方支持. revel 确实已经有了官方支持的计划,有可能将在 0.14 版本支持,现在才 0.11. ...
- css优先机制
样式的优先级 (外部样式)External style sheet <(内部样式)Internal style sheet <(内联样式)Inline style (内部样式就是css写在 ...
- 根据不同的浏览器对不同元素进行css调整
<!if firefox> .element { top:4px; } <![endif]> <!if chrome> .element { top:6px; } ...
- Part 98 Anonymous methods in c#
What is an anonymous method? Anonymous method is a method without a name. Introduced in C# 2.0,they ...