`
bee1314
  • 浏览: 166255 次
  • 性别: Icon_minigender_1
  • 来自: 安徽
社区版块
存档分类
最新评论

从省市区多重级联想到的,react和jquery的差别

阅读更多
在我们的前端项目里经常会用到级联的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把重点放在可预测性和数据单向同步上,它对控制复杂度很有效。
 
 
 

分享到:
评论
1 楼 cike8899 2015-08-26  
学习了!!

相关推荐

    react项目使用了 Ant Design等需要三级联动的省市区资源库

    let cityData = { "RECORDS": [ { "value": 110000, "label": "北京", "children": [{ "value": 110100, "label": "北京", "children": [{ "value": 110101, ...Ant Design组件三级联动资源库必备

    jQuery+H5手机省市区三级联动城市选择代码.zip

    不错的前端JS特效、页面功能的代码,很适合练习前端的各种特效和功能,也可直接拿来适当调整后使用,用于练手、学习,也是很不错的

    jQuery省市区三级联动

    总的来说,"jQuery省市区三级联动"是一个结合了DOM操作、事件处理、Ajax通信、数据处理和用户交互等多个前端开发关键知识点的实例,对于学习和掌握JavaScript和jQuery的使用具有很高的实践价值。

    echart3 地图数据省市区三级级联demo

    **ECharts 3 地图数据省市区三级级联演示** ECharts 是一款由百度开源的,基于 JavaScript 的数据可视化库,它提供了丰富的图表类型,适用于各种数据分析和展示场景。在"echart3 地图数据省市区三级级联demo"中,...

    jquery和react的js文件

    在JavaScript的世界里,jQuery和React是两个非常重要的库和框架,它们各自服务于不同的目的并有着独特的功能。jQuery简化了DOM操作、事件处理、Ajax交互等任务,而React则是Facebook推出的一个用于构建用户界面的库...

    免费下载全国省市区及其编码React、Vue、小程序通用.js

    全国省市区及其编码React、Vue、小程序通用【免费下载】

    java 省市区三级联动

    在IT领域,"省市区三级联动"是一种常见的前端交互功能,尤其在地址选择、订单填写等场景中广泛应用。这个功能的实现通常涉及到后端数据的获取以及前端展示的逻辑处理,涉及的技术包括Java和JavaScript。这里我们将...

    H5手机省市区三级联动+省市区Excel数据拿来了马上就能用.zip

    在IT领域,尤其是在Web开发中,"H5手机省市区三级联动"是一个常见的功能需求,主要用于用户填写地址或选择服务范围时提供便捷的选择方式。这个压缩包文件提供了实现这一功能所需的资源,包括前端代码和数据。 首先...

    手机移动端3d滑动省市区三级联动

    通过以上分析,我们可以了解到“手机移动端3D滑动省市区三级联动”是如何实现的,以及其中涉及的关键技术和优化策略。在实际开发中,需要结合具体业务需求和用户体验进行调整,以达到最佳效果。

    jQuery--省市区联动插件

    总的来说,jQuery省市区联动插件是提高移动应用用户体验的重要工具,它结合了jQuery的便利性和动态数据的高效处理,使得地址选择变得简单而直观。通过理解其工作原理和实现方式,开发者可以快速地在自己的项目中部署...

    jQuery手机省市区三级联动城市选择代码.zip

    《jQuery手机省市区三级联动城市选择代码》是一个实用的JavaScript技术实现,主要应用于移动设备上的交互设计,使得用户在选择地址时能方便地从省级、市级到区级进行逐级选择。这个压缩包包含了实现这一功能的核心...

    .Net+JQuery+SQL 无刷新 省市区 三级联动

    本项目".Net+JQuery+SQL 无刷新 省市区 三级联动"就是利用这种技术实现的一种常见功能:在用户选择省份时,城市和区县会自动下拉更新,而这一切都在后台数据库的支持下无缝完成。 首先,.Net框架是微软开发的一种...

    基于react省市区联动 map echarts dome

    【标题】"基于React的省市区联动Map ECharts示例" 在Web开发中,实现省市区联动的效果常常用于地址选择,提高用户输入的便捷性。本项目是基于React框架,结合ECharts库以及地理信息数据,创建的一个省市区联动的...

    province-city-area-cn:react-native版省市区三级联动组件

    react-native-province-city-area这是一个ReactNative版的省市区三级联动地址选择组件,在开发RN地址簿的时候用到地址选择,本来觉得这应该是一个很常用的功能,应该不用重复造轮子。但是几番搜索都没找到想要的,眼...

    jquery实现省市县三级联动

    在网页开发中,"jQuery 实现省市县三级联动"是一个常见的功能需求,尤其在构建具有地理定位信息的网站或应用时。这个功能允许用户在选择省份后,市和县(或区)的下拉列表会自动更新,显示出与之相关的选项,提供了...

    input框省市区三级联动选择

    "input框省市区三级联动选择"是一种常见的用户输入方式,特别是在移动端应用中,它能够优化用户在选择地理位置时的体验。这种设计允许用户通过一个单一的输入框来完成省份、城市和区县的连续选择,减少了操作步骤,...

    省市区三级联动Demo

    在IT行业中,"省市区三级联动Demo"是一个常见的前端交互功能,主要应用于用户在填写地址信息时选择省份、城市和区县的过程。这个Demo通常基于JavaScript或者更具体的前端框架如Vue、React或Angular来实现,它能提供...

    国家省市区三级联动.rar

    在IT行业中,"国家省市区三级联动"是一个常见的地理信息系统(GIS)或前端表单设计中的功能。这个功能主要用于让用户在填写地址时,能够通过下拉菜单的方式依次选择国家、省份(或州)、城市(或区县),形成一个...

    React+jQuery+Node示例源码。

    React、jQuery 和 Node.js 是三个在 Web 开发领域广泛应用的技术栈。这个压缩包中的源码提供了结合这三者的示例,旨在帮助开发者了解如何在实际项目中整合这些技术。 React 是一个由 Facebook 开发的 JavaScript 库...

    省市区三级联动.rar

    这个“省市区三级联动.rar”压缩包文件提供了一种使用JavaScript实现这一功能的方法,使得用户在输入地址时能方便地从预设的省、市、区列表中逐级选择。 首先,我们要理解什么是三级联动。在网页设计中,三级联动指...

Global site tag (gtag.js) - Google Analytics