検索
ホームページウェブフロントエンドhtmlチュートリアルDOM 操作から Vue&React のフロントエンドのコンポーネント化を確認し、React の demo_html/css_WEB-ITnose を補足します。

まえがき

上の続き: フロントエンドのコンポーネント化における「コンポーネント」についての私の理解をお話しし、Vue と React のデモを書きます

前回のブログを書き終えた後、何人かの友人がこう言いました。最初の内容は少し深かったので、混乱しているように見えました。2番目に、Vue&reactのソースコード分析を直接記述する方が良いと思いました。ここで理解すること。

まず第一に、ソースコード分析を書くのは本質的に難しいため、一般的にはコードではなく実装のアイデアを理解する必要があります

第二に、開発者にはそれぞれ独自のスタイルがあるため、一人の人のコードを徹底的に理解することは、その時点での作成者と同じ問題の解決策を常に探し、常にリファクタリングしていなければ、ユーザーの意図を理解することは容易ではありません。

私たちが最後に行ったのは、実際の実務経験に基づいて、コードの堅牢性と優雅さが追いつくことができなかったものの、他の作者と同じように、同じ問題を解決することを考えた計画でした。前回は遅すぎて急いで終了しました。実際、デモのプロセス中に、ビジネスコードはほぼ同じですが、細部が異なるため、製品の品質を決定するのは依然として開発者であるという事実を発見しました。ビジネス コードの機能を強化するために、フレームワークは単なる補助にすぎません。

この種のコードは大規模なアプリケーション向けであるため、React や Vue のようなコンポーネント化されたフレームワークを使用しても、実際にはコードをうまく整理することはできません。 、それは人の建築能力をさらにテストするので、誰もが内面の育成の向上にもっと注意を払う必要があります。

今日の本題に移りましょう。ここで、理解を助けるためにいくつかの情報を提供します。

github

コード アドレス: https://github.com/yexiaochai/module/

デモ アドレス: http:/ /yexiaochai.github .io/module/me/index.html

記事内のいくつかのコードについて混乱している場合は、次の記事を比較して読むことができます:

[インタビュー] JavaScript の継承についてもう一度話します

[モバイルフロントエンド開発実践】ゼロから知っておきたいこと(統計、リクエスト、MVC、モジュール化)より H5開発指南

【コンポーネントベース開発】フロントエンド上級編:保守性とアップグレード性の高いコードの書き方

プレビュー

Vue の使用に関する考え

最初のデモは Vue 用であり、React も同様であるはずです。 前のコードを比較すると、重要な違いが見つかりました:

DOM操作真的完全没有了!!!

はい、これはまったく DOM 操作がありません。素晴らしいのは、2 つの場所があると思うからです。 DOM 操作を取り除くのは難しいです:

① コンポーネントをどのコンテナに配置する必要があるか? 次のような位置決め要素が必要です:

1 this.sortModule = new SortModule({2     view: this,3     selector: '.js_sort_wrapper',4     sortEntity: this.sortEntity5 });

コンテナにどちらを配置するかを明確に指示します。コンポーネントが属します

② このようなリストについては、さらに混乱しています このタイプのイベントをどのように処理するか、次のような必要なパラメータがイベントに基づいて取得されるためです:

1 listItemClick: function (e) {2     var el = $(e.currentTarget);3     //根据el做一些事情4 }

これに関して、Vue の作者は、イベントがハンドラーはインライン化して表示ステートメントを作成する必要があります:

你可能注意到这种事件监听的方式违背了传统理念 “separation of concern”。不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护困难。实际上,使用 v-on 有几个好处:扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何自己清理它们。
<button v-on:click="say('hello!', $event)">Submit</button>
1 methods: {2   say: function (msg, event) {3     // 现在我们可以访问原生事件对象4     event.preventDefault()5   }6 }

一般的に使用される操作 (radioList など) がもう 1 つあります。現在のオプションをクリックして項目を選択します。一般的なアプローチは次のとおりです。

1 setIndex: function (i) {2     this.index = i;3     this.$('li').removeClass(this.curClass);4     this.$('li[data-index="' + i + '"]').addClass(this.curClass);5 }

これは相対的なものです。シンプルですが、問題が発生します。つまり、データと dom 表現のプロセスが変更されています。正しいプロセスはインデックス変更です。dom は、Vue:

1 setIndex: function (i) {2     this.index = i;3     //这部分逻辑Vue会自动实现4     //this.$('li').removeClass(this.curClass);5     //this.$('li[data-index="' + i + '"]').addClass(this.curClass);6 }

Before などのデータに基づいて更新されます。パフォーマンスを向上させるためには、単純な選択機能としてデータに基づいてリスト全体を直接再レンダリングしますが、Vue&React は部分的なレンダリングを実現しています。これはコア アルゴリズムの部分になると思います。これを理解する必要があります。時間があるときに後で深くしてください。

上記の部分的な解釈に基づいて、次の 2 つの条件が満たされる限り DOM 操作を削除できるという結論に達します:

① コンポーネントが配置されているコンテナを知る

② に基づいてページをレンダリングするデータ

追記: ここにあるのは、コンポーネントのネストやコンポーネント通信などの過度に複雑な問題を考慮していない、非常に単純な 1 つのリングです

したがって、上記の条件が満たされている場合、ビジネス ロジックに DOM 操作を含めなくてもよいでしょうか?次に試してみましょう。

DOM 操作を取り除く方法

これは、実際には、以前の複雑すぎるビジネス ロジックを使用せずに、検証を行うデモ クラスの試みです。ここで、me ディレクトリを一緒にコピーし、元のコードを基礎となる依存関係として使用します。リストと最上位のソート関数については、実装を簡素化し、コードの再利用を維持するために、エンティティ モジュールを直接再利用する必要があります。最初のステップは、データ内のオブジェクトがエンティティ インスタンスである必要があります。ここでは list モジュール module を抽象化するため、メイン コントロールは次のようになります。実際、現時点では DOM 操作はありません。

 1 initEntity: function () { 2     //实例化排序的导航栏的实体 3     this.sortEntity = new SortEntity(); 4     this.sortEntity.subscribe(this.renderList, this); 5 }, 6  7 initModule: function () { 8     //view为注入给组件的根元素 9     //selector为组件将要显示的容器10     //sortEntity为注入给组件的数据实体,做通信用11     //这个module在数据显示后会自动展示12     this.sortModule = new SortModule({13         view: this,14         selector: '.js_sort_wrapper',15         sortEntity: this.sortEntity16     });17     this.listModule = new ListModule({18         view: this,19         selector: '.js_list_wrapper',20         entity: this.sortEntity21     });22 },23 24 propertys: function ($super) {25     $super();26 27     this.initEntity();28     this.initModule();29     this.viewId = 'list';30     this.template = layoutHtml;31     this.events = {};32 }

実際の list コンポーネントの実装を簡単に見てみましょう。 、元のルートの位置を変更することです ビューコード:

  1 define([  2     'ModuleView',  3     'pages/list.data',  4     'text!pages/tpl.list.html'  5   6 ], function (ModuleView,  7              listData,  8              tpl) {  9     return _.inherit(ModuleView, { 10  11         //此处若是要使用model,处实例化时候一定要保证entity的存在,如果不存在便是业务BUG 12         initData: function () { 13  14             this.template = tpl; 15             this.entity.subscribe(this.render, this); 16  17         }, 18  19         _timeSort: function (data, sort) { 20             data = _.sortBy(data, function (item) { 21                 item = item.from_time.split(':'); 22                 item = item[0] + '.' + item[1]; 23                 item = parseFloat(item); 24                 return item; 25             }); 26             if (sort == 'down') data.reverse(); 27             return data; 28         }, 29  30         _sumTimeSort: function (data, sort) { 31             data = _.sortBy(data, function (item) { 32                 return parseInt(item.use_time); 33             }); 34             if (sort == 'down') data.reverse(); 35             return data; 36         }, 37  38         _priceSort: function (data, sort) { 39             data = _.sortBy(data, function (item) { 40                 return item.min_price; 41             }); 42             if (sort == 'down') data.reverse(); 43             return data; 44         }, 45  46         //获取导航栏排序后的数据 47         getSortData: function (data) { 48             var tmp = []; 49             var sort = this.entity.get(); 50  51             for (var k in sort) { 52                 if (sort[k].length > 0) { 53                     tmp = this['_' + k + 'Sort'](data, sort[k]) 54                     return tmp; 55                 } 56             } 57         }, 58  59         //复杂的业务数据处理,为了达到产品的需求,这段代码逻辑与业务相关 60         //这段数据处理的代码过长(超过50行就过长),应该重构掉 61         formatData: function (data) { 62             var item, seat; 63             var typeMap = { 64                 'g': 'g', 65                 'd': 'd', 66                 't': 't', 67                 'c': 'g' 68             }; 69  70             //出发时间对应的分钟数 71             var fromMinute = 0; 72  73             //获取当前班车日期当前的时间戳,这个数据是动态的,这里写死了 74             var d = 1464192000000; 75             var date = new Date(); 76             var now = parseInt(date.getTime() / 1000); 77             date.setTime(d); 78             var year = date.getFullYear(); 79             var month = date.getMonth(); 80             var day = date.getDate(); 81             var toBegin; 82             var seatName, seatIndex, iii; 83  84             //处理坐席问题,仅显示二等座,一等座,特等座 无座 85             //                二等座 一等座 商务座 无座 动卧 特等座 86             var my_seats = {}; 87             var seatSort = ['二等座', '一等座', '硬座', '硬卧', '软卧', '商务座', '无座', '动卧', '特等座', '软座']; 88  89             for (var i = 0, len = data.length; i < len; i++) { 90                 fromMinute = data[i].from_time.split(':'); 91                 fromMinute[0] = fromMinute[0] + ''; 92                 fromMinute[1] = fromMinute[1] + ''; 93                 if ((fromMinute[0].charAt(0) == '0')) fromMinute[0] = fromMinute[0].charAt(1); 94                 if ((fromMinute[1].charAt(0) == '0')) fromMinute[1] = fromMinute[1].charAt(1); 95                 date = new Date(year, month, day, fromMinute[0], fromMinute[1], 0); 96                 fromMinute = parseInt(date.getTime() / 1000) 97                 toBegin = parseInt((fromMinute - now) / 60); 98  99                 data[i].toBegin = toBegin;100 101                 //处理车次类型问题102                 data[i].my_train_number = typeMap[data[i].train_number.charAt(0).toLowerCase()] || 'other';103 104                 seat = data[i].seats;105                 //所有余票106                 data[i].sum_ticket = 0;107                 //最低价108                 data[i].min_price = null;109 110                 for (var j = 0, len1 = seat.length; j < len1; j++) {111                     if (!data[i].min_price || data[i].min_price > seat[j].seat_price) data[i].min_price = parseFloat(seat[j].seat_price);112                     data[i].sum_ticket += parseInt(seat[j].seat_yupiao);113 114                     //坐席问题如果坐席不包括上中下则去掉115                     seatName = seat[j].seat_name;116                     //去掉上中下117                     seatName = seatName.replace(/上|中|下/g, '');118                     if (!my_seats[seatName]) {119                         my_seats[seatName] = parseInt(seat[j].seat_yupiao);120                     } else {121                         my_seats[seatName] = my_seats[seatName] + parseInt(seat[j].seat_yupiao);122                     }123                 }124                 //这里myseat为对象,需要转换为数组125                 //将定制坐席转为排序后的数组126                 data[i].my_seats = [];127                 for (iii = 0; iii < seatSort.length; iii++) {128                     if (typeof my_seats[seatSort[iii]] == 'number') data[i].my_seats.push({129                         name: seatSort[iii],130                         yupiao: my_seats[seatSort[iii]]131                     });132                 }133 134                 my_seats = {};135             }136 137             return data;138         },139 140         //完成所有的筛选条件,逻辑比较重141         getViewModel: function () {142             var data = this.formatData(listData);143             data = this.getSortData(data);144             return {data: data};145         }146 147     });148 149 });View Code

この簡単な変更により、DOM 操作から解放されるように見えますが、実際には、ページのすべてのステータスをデータによって制御できます。ここには「タグ付き」がありませんが、あまり良くないと思われるので、タグ付きコードに変換できるかどうか試してみましょう。

我们这里的业务代码(module与entity)没有什么需要改动的,这里主要在底层做改造,这里在我看来是提供了一种“语法糖”的东西,这里的具体概念后续阅读Vue源码再深入了解,这里先照着做,这里看结果想实现,也是我们常用的一种设计方案,首先我们的index编程了这个样子:

1 <article class="cm-page page-list" id="main">2     <div class="js_sort_wrapper sort-bar-wrapper">3         <mySortBar :entity="sortEntity"></mySortBar>4     </div>5     <myList :entity="listEntity" :sort="sort"></myList>6 </article>
 1 (function () { 2     require.config({ 3         paths: { 4             'text': 'libs/require.text', 5  6             'AbstractView': 'js/view', 7             'AbstractEntity': 'js/entity', 8             'ModuleView': 'js/module' 9         }10     });11 12     require(['pages/list.label'], function (List) {13         var list = new List();14         list.show();15     });16 })();

PS:里面的js钩子基本无用了

这里标签化带来的好处是,根View中有一段实例代码可以不用与选择器映射了,比如这个:

1 this.sortModule = new SortModule({2     //view: this,3     //selector: '.js_sort_wrapper',4     //sortEntity: this.sortEntity5 });

因为处于组件中,其中所处位置已经定了,view实例或者entity实例全部是跟View显示注入的,这里根View中参考Vue的使用,新增一个$components与$entities属性,然后增加一$watch对象。

大家写底层框架时,私有属性或者方法使用_method的方式,如果是要释放的可以是$method这种,一定要“特殊化”防止被实例或者继承覆盖
 1 define([ 2     'AbstractView', 'pages/en.sort', 'pages/mod.sort', 'pages/mod.list' 3 ], function (AbstractView, SortEntity, SortModule, ListModule) { 4     return _.inherit(AbstractView, { 5         propertys: function ($super) { 6             $super(); 7             this.$entities = { 8                 sortEntity: SortEntity 9             };10             this.$components = {11                 mySortBar: SortModule,12                 listModule: ListModule13             };14             this.$watch = {15 16             };17             this.viewId = 'list';18             this.template = layoutHtml;19             this.events = {};20         }21     });22 });

他这种做法,需要组件在显示后框架底层将刚刚的业务代码实现,使用组件生成的html代码将原来标签的占位符给替换掉。

这里在组件也需要明示根View需要注入什么给自己:

PS:事实上这个可以不写,写了对后续属性的计算有好处

//记录需要根View注入的属性props:[sortEntity],

PS:底层什么时候执行替换这个是有一定时机的,我们这里暂时放到根View展示后,这里更好的实现,后续我们在Vue与React中去找寻

因为我们这里是demo类实现,为降低难度,我们为每一个组件动态增加一个div包裹层,于是,我们在跟View中,在View展示后,我们另外多加一段逻辑:

1 //实例化实体,后面要用2 this._initEntity();3 //新增标签逻辑4 this._initComponent();

然后将实体与组件的实例化放到框架底层,这里实体的实例化比较简单(如果有特殊数据需求再说,这里只考虑最简单情况):

1 _initEntity: function() {2     var key, entities = this.$entities;3     //这里没有做特殊化,需要注意4     for(key in entities) {5         this[key] = new entities[key]();6     }7 },

而实例化组件的工作复杂许多,因为他需要将页面中的自定义标签替换掉,还需要完成很多属性注入操作:

1 _initComponent: function() {2     var key, components = this.$components;3     for(key in components) {4         //这里实例化的过程有点复杂,首先将页面的标签做一个替换5         var s = ''6     }7 },
 1 _initComponent: function() { 2     var key, components = this.$components; 3     var el, attributes, attr, param, clazz, i, len, tmp, id, name; 4  5     //这里实例化的过程有点复杂,首先将页面的标签做一个替换 6     for(key in components) { 7         param = {}; 8         clazz = components[key]; 9         //由原型链上获取根元素要注入给子组件的属性(这个实现好像不太好)10         attributes = clazz.prototype.props;11 12         //首先获取标签dom元素,因为html是不区分大小写的,这里将标签小写13         el = this.$(key.toLowerCase());14         if(!el[0]) continue;15 16         if(attributes) {17             for (i = 0, len = attributes.length; i < len; i++) {18                 attr = attributes[i];19                 name = el.attr(':' + attr);20                 param[attr] = this[name] || name;21             }22         }23 24         //创建一个空div去替换原来的标签25         id = _.uniqueId('componenent-id-');26         tmp = $('<div component-name="' + key + '" id="' + id + '"></div>');27         tmp.insertBefore(el);28         el.remove();29         param.selector = '#' + id;30         param.view = this;31         this[key] = new components[key](param);32     }33 34 },

于是这个标签便能正常展示了:

1 <article class="cm-page page-list" id="main">2     <div class="js_sort_wrapper sort-bar-wrapper">3         <mySortBar :entity="sortEntity" :myname="111"></mySortBar>4     </div>5     <myList :entity="sortEntity" :sort="sort"></myList>6 </article>

后面想要把这段代码去掉也十分轻易,我这里就不进行了:

1 'click .js_sort_item li ': function (e) {2     var el = $(e.currentTarget);3     var sort = el.attr('data-sort');4     this.entity['set' + sort]();5 }

总结

这里首先根据上次Vue的demo产生了一些思考,并且以简单的demo验证了这些思考,楼主在使用过程中发现Vue很多好的点子,后续应该会深入研究,并且以实际项目入手,这里回到今天的正题,我们使用React实现上次遗留的demo。

React的实现

在我最初接触React的时候,React Native还没出现,所以很多人对React的关注不高,当时做移动端直接放弃了angular,以体量来说,React也不在我们的考虑范围内,谁知道野心勃勃的Facebook搞出了React Native,让React彻底的跟着火了一把,事实上只要有能力以JavaScript统一Native UI的公司,这个实现就算换个框架依旧会火,虽然都已经这么火了,但是React的文档却不怎样,我后续也有试水React Native的兴趣,届时再与各位分享。

PS:根据之前的反馈,这次demo稍微做简单点,也只包含顶部导航和列表即可:

  1 <!doctype html>  2 <html>  3 <head>  4     <meta charset="UTF-8">  5     <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui"/>  6     <meta content="yes" name="apple-mobile-web-app-capable"/>  7     <meta content="black" name="apple-mobile-web-app-status-bar-style"/>  8     <meta name="format-detection" content="telephone=no"/>  9     <link href="./static/css/global.css" rel="stylesheet" type="text/css"/> 10     <link href="./pages/list.css" rel="stylesheet" type="text/css"/> 11     <title>组件化</title> 12 </head> 13 <body> 14 <div class="cm-header"> 15     <h1 id="组件化Demo"> 组件化Demo </h1> 16 </div> 17  18 <article class="cm-page page-list" id="main"> 19 </article> 20  21  22 <script src="./libs/react-with-addons.js"></script> 23 <script src="./libs/JSXTransformer.js"></script> 24 <script type="text/javascript" src="./pages/list.data.js"></script> 25 <script type="text/javascript" src="./libs/underscore.js"></script> 26 <script type="text/jsx"> 27  28  29  30 var MySortBar = React.createClass({ 31     getInitialState: function() { 32         return { 33             time: 'up', 34             sumTime: '', 35             price: '' 36         }; 37     }, 38  39     resetData: function () { 40         this.setState({ 41             time: '', 42             sumTime: '', 43             price: '' 44         }); 45     }, 46  47     setTime: function () { 48         this._setData('time'); 49     }, 50  51     setSumTime: function () { 52         this._setData('sumTime'); 53     }, 54  55     setPrice: function () { 56         this._setData('price'); 57     }, 58  59     _setData: function (key) { 60         var param = {}; 61  62         //如果设置当前key存在,则反置,否则清空筛选,设置默认值 63         if (this.state[key] != '') { 64             if (this.state[key] == 'up') param[key] = 'down'; 65             else param[key] = 'up'; 66         } else { 67             this.resetData(); 68             param[key] = 'down'; 69         } 70         this.setState(param); 71     }, 72  73     _getClassName: function(icon) { 74         return 'icon-sort ' + icon; 75     }, 76  77     render: function () { 78         return ( 79             <ul className="bus-tabs sort-bar js_sort_item"> 80                 <li className="tabs-item" onClick={this.setTime}  >出发时间<i className={this._getClassName(this.state.time)}></i></li> 81                 <li className="tabs-item" onClick={this.setSumTime} >耗时<i className={this._getClassName(this.state.sumTime)}></i></li> 82                 <li className="tabs-item"  onClick={this.setPrice} >价格<i className={this._getClassName(this.state.price)}></i></li> 83             </ul> 84         ); 85     } 86  87 }); 88  89 var Seat = React.createClass({ 90     render: function () { 91         var seat = this.props.seat; 92  93         return ( 94             <span >{seat.name}({seat.yupiao }) </span> 95         ); 96     } 97 }); 98  99 var Item = React.createClass({100     render: function () {101 102         var item = this.props.item;103         var mapping = {104             'g': '高速',105             't': '特快',106             'd': '高速动车',107             'c': '城际高铁',108             'z': '直达'109         };110 111         var seats = item.my_seats.map(function(item){112             return <Seat seat={item}/>;113         });114 115 116         return (117             <li className="bus-list-item ">118                 <div className="bus-seat">119                     <span className=" fl">{item.train_number } | {mapping[item.my_train_number] || '其它'} </span>120                     <span className=" fr">{parseInt(item.use_time / 60) + '小时' + item.use_time % 60 + '分'}</span>121                     </div>122                     <div className="detail">123                     <div className="sub-list set-out">124                     <span className="bus-go-off">{item.from_time}</span> <span className="start"><span className="icon-circle s-icon1">125                     </span>{item.from_station }</span> <span className="fr price">¥{item.min_price}起</span>126                 </div>127                 <div className="sub-list">128                         <span className="bus-arrival-time">{item.to_time}</span> <span className="end"><span className="icon-circle s-icon2">129                         </span>{item.to_station}</span> <span className="fr ">{item.sum_ticket}张</span>130                 </div>131                 </div>132                 <div className="bus-seats-info" >133                     {seats}134                 </div>135             </li>136         );137     }138 });139 140 141 var MyList = React.createClass({142 143     formatData: function (data) {144 145         var item, seat;146         var typeMap = {147             'g': 'g',148             'd': 'd',149             't': 't',150             'c': 'g'151         };152 153         //出发时间对应的分钟数154         var fromMinute = 0;155 156         //获取当前班车日期当前的时间戳,这个数据是动态的,这里写死了157         var d = 1464192000000;158         var date = new Date();159         var now = parseInt(date.getTime() / 1000);160         date.setTime(d);161         var year = date.getFullYear();162         var month = date.getMonth();163         var day = date.getDate();164         var toBegin;165         var seatName, seatIndex, iii;166 167         //处理坐席问题,仅显示二等座,一等座,特等座 无座168         //                二等座 一等座 商务座 无座 动卧 特等座169         var my_seats = {};170         var seatSort = ['二等座', '一等座', '硬座', '硬卧', '软卧', '商务座', '无座', '动卧', '特等座', '软座'];171 172         for (var i = 0, len = data.length; i < len; i++) {173             fromMinute = data[i].from_time.split(':');174             fromMinute[0] = fromMinute[0] + '';175             fromMinute[1] = fromMinute[1] + '';176             if ((fromMinute[0].charAt(0) == '0')) fromMinute[0] = fromMinute[0].charAt(1);177             if ((fromMinute[1].charAt(0) == '0')) fromMinute[1] = fromMinute[1].charAt(1);178             date = new Date(year, month, day, fromMinute[0], fromMinute[1], 0);179             fromMinute = parseInt(date.getTime() / 1000)180             toBegin = parseInt((fromMinute - now) / 60);181 182             data[i].toBegin = toBegin;183 184             //处理车次类型问题185             data[i].my_train_number = typeMap[data[i].train_number.charAt(0).toLowerCase()] || 'other';186 187             seat = data[i].seats;188             //所有余票189             data[i].sum_ticket = 0;190             //最低价191             data[i].min_price = null;192 193             for (var j = 0, len1 = seat.length; j < len1; j++) {194                 if (!data[i].min_price || data[i].min_price > seat[j].seat_price) data[i].min_price = parseFloat(seat[j].seat_price);195                 data[i].sum_ticket += parseInt(seat[j].seat_yupiao);196 197                 //坐席问题如果坐席不包括上中下则去掉198                 seatName = seat[j].seat_name;199                 //去掉上中下200                 seatName = seatName.replace(/上|中|下/g, '');201                 if (!my_seats[seatName]) {202                     my_seats[seatName] = parseInt(seat[j].seat_yupiao);203                 } else {204                     my_seats[seatName] = my_seats[seatName] + parseInt(seat[j].seat_yupiao);205                 }206             }207             //这里myseat为对象,需要转换为数组208             //将定制坐席转为排序后的数组209             data[i].my_seats = [];210             for (iii = 0; iii < seatSort.length; iii++) {211                 if (typeof my_seats[seatSort[iii]] == 'number') data[i].my_seats.push({212                     name: seatSort[iii],213                     yupiao: my_seats[seatSort[iii]]214                 });215             }216 217             my_seats = {};218         }219 220         return data;221     },222 223     render: function () {224 225         var main;226         var data = this.formatData(this.props.data);227 228 229         main = data.map(function(item) {230             return <Item item={item}/>;231         });232 233         return (234             <ul className="bus-list js_bus_list ">235                 {main}236             </ul>237         );238     }239 240 });241 242 var data = getListData();243 244 React.render(245     <div>246         <div className="js_sort_wrapper sort-bar-wrapper">247             <MySortBar />248         </div>249         <MyList data={data} />250     </div>,251     document.getElementById('main')252 );253 254 </script>255 256 257 </body>258 </html>View Code

他这个语法据说是让开发变得更简单了,我反正是不喜欢,这里有个不好的地方,之前数据实体全部是在根View上实例化的,然后注入给子View,React这里属性完全独享了,现在我触发了状态的改变,如何通知到list组件重新渲染排序呢?

React 组件通信

这里React子组件之间如何通信暂没有研究出来,所以将需要通信的数据做到了父组件中
  1 <!doctype html>  2 <html>  3 <head>  4     <meta charset="UTF-8">  5     <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui"/>  6     <meta content="yes" name="apple-mobile-web-app-capable"/>  7     <meta content="black" name="apple-mobile-web-app-status-bar-style"/>  8     <meta name="format-detection" content="telephone=no"/>  9     <link href="./static/css/global.css" rel="stylesheet" type="text/css"/> 10     <link href="./pages/list.css" rel="stylesheet" type="text/css"/> 11     <title>组件化</title> 12 </head> 13 <body> 14 <div class="cm-header"> 15     <h1 id="组件化Demo"> 组件化Demo </h1> 16 </div> 17  18 <article class="cm-page page-list" id="main"> 19 </article> 20  21  22 <script src="./libs/react-with-addons.js"></script> 23 <script src="./libs/JSXTransformer.js"></script> 24 <script type="text/javascript" src="./pages/list.data.js"></script> 25 <script type="text/javascript" src="./libs/underscore.js"></script> 26 <script type="text/jsx"> 27  28  29  30 var MySortBar = React.createClass({ 31     _getClassName: function(icon) { 32         return 'icon-sort ' + icon; 33     }, 34  35     render: function () { 36         var state = this.props.state; 37         return ( 38             <ul className="bus-tabs sort-bar js_sort_item"> 39                 <li className="tabs-item" onClick={this.props.setTime}  >出发时间<i className={this._getClassName(state.time)}></i></li> 40                 <li className="tabs-item" onClick={this.props.setSumTime} >耗时<i className={this._getClassName(state.sumTime)}></i></li> 41                 <li className="tabs-item"  onClick={this.props.setPrice} >价格<i className={this._getClassName(state.price)}></i></li> 42             </ul> 43         ); 44     } 45  46 }); 47  48 var Seat = React.createClass({ 49     render: function () { 50         var seat = this.props.seat; 51  52         return ( 53             <span >{seat.name}({seat.yupiao }) </span> 54         ); 55     } 56 }); 57  58 var Item = React.createClass({ 59     render: function () { 60  61         var item = this.props.item; 62         var mapping = { 63             'g': '高速', 64             't': '特快', 65             'd': '高速动车', 66             'c': '城际高铁', 67             'z': '直达' 68         }; 69  70         var seats = item.my_seats.map(function(item){ 71             return <Seat seat={item}/>; 72         }); 73  74  75         return ( 76             <li className="bus-list-item "> 77                 <div className="bus-seat"> 78                     <span className=" fl">{item.train_number } | {mapping[item.my_train_number] || '其它'} </span> 79                     <span className=" fr">{parseInt(item.use_time / 60) + '小时' + item.use_time % 60 + '分'}</span> 80                     </div> 81                     <div className="detail"> 82                     <div className="sub-list set-out"> 83                     <span className="bus-go-off">{item.from_time}</span> <span className="start"><span className="icon-circle s-icon1"> 84                     </span>{item.from_station }</span> <span className="fr price">¥{item.min_price}起</span> 85                 </div> 86                 <div className="sub-list"> 87                         <span className="bus-arrival-time">{item.to_time}</span> <span className="end"><span className="icon-circle s-icon2"> 88                         </span>{item.to_station}</span> <span className="fr ">{item.sum_ticket}张</span> 89                 </div> 90                 </div> 91                 <div className="bus-seats-info" > 92                     {seats} 93                 </div> 94             </li> 95         ); 96     } 97 }); 98  99 var MyList = React.createClass({100 101     formatData: function (data) {102 103         var item, seat;104         var typeMap = {105             'g': 'g',106             'd': 'd',107             't': 't',108             'c': 'g'109         };110 111         //出发时间对应的分钟数112         var fromMinute = 0;113 114         //获取当前班车日期当前的时间戳,这个数据是动态的,这里写死了115         var d = 1464192000000;116         var date = new Date();117         var now = parseInt(date.getTime() / 1000);118         date.setTime(d);119         var year = date.getFullYear();120         var month = date.getMonth();121         var day = date.getDate();122         var toBegin;123         var seatName, seatIndex, iii;124 125         //处理坐席问题,仅显示二等座,一等座,特等座 无座126         //                二等座 一等座 商务座 无座 动卧 特等座127         var my_seats = {};128         var seatSort = ['二等座', '一等座', '硬座', '硬卧', '软卧', '商务座', '无座', '动卧', '特等座', '软座'];129 130         for (var i = 0, len = data.length; i < len; i++) {131             fromMinute = data[i].from_time.split(':');132             fromMinute[0] = fromMinute[0] + '';133             fromMinute[1] = fromMinute[1] + '';134             if ((fromMinute[0].charAt(0) == '0')) fromMinute[0] = fromMinute[0].charAt(1);135             if ((fromMinute[1].charAt(0) == '0')) fromMinute[1] = fromMinute[1].charAt(1);136             date = new Date(year, month, day, fromMinute[0], fromMinute[1], 0);137             fromMinute = parseInt(date.getTime() / 1000)138             toBegin = parseInt((fromMinute - now) / 60);139 140             data[i].toBegin = toBegin;141 142             //处理车次类型问题143             data[i].my_train_number = typeMap[data[i].train_number.charAt(0).toLowerCase()] || 'other';144 145             seat = data[i].seats;146             //所有余票147             data[i].sum_ticket = 0;148             //最低价149             data[i].min_price = null;150 151             for (var j = 0, len1 = seat.length; j < len1; j++) {152                 if (!data[i].min_price || data[i].min_price > seat[j].seat_price) data[i].min_price = parseFloat(seat[j].seat_price);153                 data[i].sum_ticket += parseInt(seat[j].seat_yupiao);154 155                 //坐席问题如果坐席不包括上中下则去掉156                 seatName = seat[j].seat_name;157                 //去掉上中下158                 seatName = seatName.replace(/上|中|下/g, '');159                 if (!my_seats[seatName]) {160                     my_seats[seatName] = parseInt(seat[j].seat_yupiao);161                 } else {162                     my_seats[seatName] = my_seats[seatName] + parseInt(seat[j].seat_yupiao);163                 }164             }165             //这里myseat为对象,需要转换为数组166             //将定制坐席转为排序后的数组167             data[i].my_seats = [];168             for (iii = 0; iii < seatSort.length; iii++) {169                 if (typeof my_seats[seatSort[iii]] == 'number') data[i].my_seats.push({170                     name: seatSort[iii],171                     yupiao: my_seats[seatSort[iii]]172                 });173             }174 175             my_seats = {};176         }177 178         return data;179     },180 181     _timeSort: function (data, sort) {182         data = _.sortBy(data, function (item) {183             item = item.from_time.split(':');184             item = item[0] + '.' + item[1];185             item = parseFloat(item);186             return item;187         });188         if (sort == 'down') data.reverse();189         return data;190     },191 192     _sumTimeSort: function (data, sort) {193         data = _.sortBy(data, function (item) {194             return parseInt(item.use_time);195         });196         if (sort == 'down') data.reverse();197         return data;198     },199 200     _priceSort: function (data, sort) {201         data = _.sortBy(data, function (item) {202             return item.min_price;203         });204         if (sort == 'down') data.reverse();205         return data;206     },207 208     //获取导航栏排序后的数据209     getSortData: function (data) {210         var tmp = [];211         var sort = this.props.state;212 213         for (var k in sort) {214             if (sort[k].length > 0) {215                 tmp = this['_' + k + 'Sort'](data, sort[k])216                 return tmp;217             }218         }219     },220 221     render: function () {222 223         var main;224         var data = this.formatData(this.props.data);225         data = this.getSortData(data);226 227         main = data.map(function(item) {228             return <Item item={item}/>;229         });230 231         return (232             <ul className="bus-list js_bus_list ">233                 {main}234             </ul>235         );236     }237 238 });239 240 var App = React.createClass({241     getInitialState: function() {242         return {243             time: 'up',244             sumTime: '',245             price: ''246         };247     },248 249     resetData: function () {250         this.setState({251             time: '',252             sumTime: '',253             price: ''254         });255     },256 257     setTime: function () {258         this._setData('time');259     },260 261     setSumTime: function () {262         this._setData('sumTime');263     },264 265     setPrice: function () {266         this._setData('price');267     },268 269     _setData: function (key) {270         var param = {};271 272         //如果设置当前key存在,则反置,否则清空筛选,设置默认值273         if (this.state[key] != '') {274             if (this.state[key] == 'up') param[key] = 'down';275             else param[key] = 'up';276         } else {277             this.resetData();278             param[key] = 'down';279         }280         this.setState(param);281     },282 283     formatData: function (data) {284 285         var item, seat;286         var typeMap = {287             'g': 'g',288             'd': 'd',289             't': 't',290             'c': 'g'291         };292 293         //出发时间对应的分钟数294         var fromMinute = 0;295 296         //获取当前班车日期当前的时间戳,这个数据是动态的,这里写死了297         var d = 1464192000000;298         var date = new Date();299         var now = parseInt(date.getTime() / 1000);300         date.setTime(d);301         var year = date.getFullYear();302         var month = date.getMonth();303         var day = date.getDate();304         var toBegin;305         var seatName, seatIndex, iii;306 307         //处理坐席问题,仅显示二等座,一等座,特等座 无座308         //                二等座 一等座 商务座 无座 动卧 特等座309         var my_seats = {};310         var seatSort = ['二等座', '一等座', '硬座', '硬卧', '软卧', '商务座', '无座', '动卧', '特等座', '软座'];311 312         for (var i = 0, len = data.length; i < len; i++) {313             fromMinute = data[i].from_time.split(':');314             fromMinute[0] = fromMinute[0] + '';315             fromMinute[1] = fromMinute[1] + '';316             if ((fromMinute[0].charAt(0) == '0')) fromMinute[0] = fromMinute[0].charAt(1);317             if ((fromMinute[1].charAt(0) == '0')) fromMinute[1] = fromMinute[1].charAt(1);318             date = new Date(year, month, day, fromMinute[0], fromMinute[1], 0);319             fromMinute = parseInt(date.getTime() / 1000)320             toBegin = parseInt((fromMinute - now) / 60);321 322             data[i].toBegin = toBegin;323 324             //处理车次类型问题325             data[i].my_train_number = typeMap[data[i].train_number.charAt(0).toLowerCase()] || 'other';326 327             seat = data[i].seats;328             //所有余票329             data[i].sum_ticket = 0;330             //最低价331             data[i].min_price = null;332 333             for (var j = 0, len1 = seat.length; j < len1; j++) {334                 if (!data[i].min_price || data[i].min_price > seat[j].seat_price) data[i].min_price = parseFloat(seat[j].seat_price);335                 data[i].sum_ticket += parseInt(seat[j].seat_yupiao);336 337                 //坐席问题如果坐席不包括上中下则去掉338                 seatName = seat[j].seat_name;339                 //去掉上中下340                 seatName = seatName.replace(/上|中|下/g, '');341                 if (!my_seats[seatName]) {342                     my_seats[seatName] = parseInt(seat[j].seat_yupiao);343                 } else {344                     my_seats[seatName] = my_seats[seatName] + parseInt(seat[j].seat_yupiao);345                 }346             }347             //这里myseat为对象,需要转换为数组348             //将定制坐席转为排序后的数组349             data[i].my_seats = [];350             for (iii = 0; iii < seatSort.length; iii++) {351                 if (typeof my_seats[seatSort[iii]] == 'number') data[i].my_seats.push({352                     name: seatSort[iii],353                     yupiao: my_seats[seatSort[iii]]354                 });355             }356 357             my_seats = {};358         }359 360         return data;361     },362 363     render: function () {364 365         var main;366         var data = this.formatData(this.props.data);367         main = data.map(function(item) {368             return <Item item={item}/>;369         });370 371         return (372             <div>373                 <div className="js_sort_wrapper sort-bar-wrapper">374                 <MySortBar state={this.state} setTime={this.setTime} setSumTime={this.setSumTime} setPrice={this.setPrice}/>375                 </div>376                 <MyList data={data} state={this.state} />377             </div>378         );379     }380 381 });382 383 var data = getListData();384 385 React.render(386     <App data={data}/>,387     document.getElementById('main')388 );389 390 </script>391 392 393 </body>394 </html>View Code

总结

react的中文文档整理较差,很多资料找不到,jsx语法比较怪异,不是所有人能接受,我去找模板循环时候压根就没找到,所以jsx有个特点,他让你不得不去拆分你的组件,在我写React代码中,感觉React代码控制力度要重一点,但是如果没有良好的架构能力,我可以毫不夸张的说,你依旧写不好业务代码。

至于React与Vue的优劣,这个方面见仁见智吧,好了今天的文章到此为止。

后续我们可能会深入分析下Vue的实现,在React Native上做深入,有兴趣的同学可以持续关注。

文章有任何不足错误,请您提出,因为小钗也是第二次使用React写demo,如果使用不当请多包涵

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
HTML、CSS、およびJavaScriptの未来:Web開発動向HTML、CSS、およびJavaScriptの未来:Web開発動向Apr 19, 2025 am 12:02 AM

HTMLの将来の傾向はセマンティクスとWebコンポーネントであり、CSSの将来の傾向はCSS-in-JSとCSShoudiniであり、JavaScriptの将来の傾向はWebAssemblyとServerLessです。 1。HTMLセマンティクスはアクセシビリティとSEO効果を改善し、Webコンポーネントは開発効率を向上させますが、ブラウザの互換性に注意を払う必要があります。 2。CSS-in-JSは、スタイル管理の柔軟性を高めますが、ファイルサイズを増やす可能性があります。 CSShoudiniは、CSSレンダリングの直接操作を可能にします。 3. Webassemblyブラウザーアプリケーションのパフォーマンスを最適化しますが、急な学習曲線があり、サーバーレスは開発を簡素化しますが、コールドスタートの問題の最適化が必要です。

HTML:構造、CSS:スタイル、JavaScript:動作HTML:構造、CSS:スタイル、JavaScript:動作Apr 18, 2025 am 12:09 AM

Web開発におけるHTML、CSS、およびJavaScriptの役割は次のとおりです。1。HTMLは、Webページ構造を定義し、2。CSSはWebページスタイルを制御し、3。JavaScriptは動的な動作を追加します。一緒に、彼らは最新のウェブサイトのフレームワーク、美学、および相互作用を構築します。

HTMLの未来:ウェブデザインの進化とトレンドHTMLの未来:ウェブデザインの進化とトレンドApr 17, 2025 am 12:12 AM

HTMLの将来は、無限の可能性に満ちています。 1)新機能と標準には、より多くのセマンティックタグとWebComponentsの人気が含まれます。 2)Webデザインのトレンドは、レスポンシブでアクセス可能なデザインに向けて発展し続けます。 3)パフォーマンスの最適化により、応答性の高い画像読み込みと怠zyなロードテクノロジーを通じてユーザーエクスペリエンスが向上します。

HTML対CSS対JavaScript:比較概要HTML対CSS対JavaScript:比較概要Apr 16, 2025 am 12:04 AM

Web開発におけるHTML、CSS、およびJavaScriptの役割は次のとおりです。HTMLはコンテンツ構造を担当し、CSSはスタイルを担当し、JavaScriptは動的な動作を担当します。 1。HTMLは、セマンティクスを確保するためにタグを使用してWebページの構造とコンテンツを定義します。 2。CSSは、セレクターと属性を介してWebページスタイルを制御して、美しく読みやすくします。 3。JavaScriptは、動的でインタラクティブな関数を実現するために、スクリプトを通じてWebページの動作を制御します。

HTML:それはプログラミング言語か何か他のものですか?HTML:それはプログラミング言語か何か他のものですか?Apr 15, 2025 am 12:13 AM

htmlisnotaprogramminglanguage; itisamarkuplanguage.1)htmlStructuresandformatswebcontentusingtags.2)ItworkswithcsssssssssdjavascriptforInteractivity、強化を促進します。

HTML:Webページの構造の構築HTML:Webページの構造の構築Apr 14, 2025 am 12:14 AM

HTMLは、Webページ構造の構築の基礎です。 1。HTMLは、コンテンツ構造とセマンティクス、および使用などを定義します。タグ。 2. SEO効果を改善するために、などのセマンティックマーカーを提供します。 3.タグを介したユーザーの相互作用を実現するには、フォーム検証に注意してください。 4. JavaScriptと組み合わせて、動的効果を実現するなどの高度な要素を使用します。 5.一般的なエラーには、閉じられていないラベルと引用されていない属性値が含まれ、検証ツールが必要です。 6.最適化戦略には、HTTP要求の削減、HTMLの圧縮、セマンティックタグの使用などが含まれます。

テキストからウェブサイトへ:HTMLの力テキストからウェブサイトへ:HTMLの力Apr 13, 2025 am 12:07 AM

HTMLは、Webページを構築するために使用される言語であり、タグと属性を使用してWebページの構造とコンテンツを定義します。 1)htmlは、などのタグを介してドキュメント構造を整理します。 2)ブラウザはHTMLを分析してDOMを構築し、Webページをレンダリングします。 3)マルチメディア関数を強化するなど、HTML5の新機能。 4)一般的なエラーには、閉じられていないラベルと引用されていない属性値が含まれます。 5)最適化の提案には、セマンティックタグの使用とファイルサイズの削減が含まれます。

HTML、CSS、およびJavaScriptの理解:初心者向けガイドHTML、CSS、およびJavaScriptの理解:初心者向けガイドApr 12, 2025 am 12:02 AM

webdevelopmentReliesOnhtml、css、andjavascript:1)htmlStructuresContent、2)cssStylesit、および3)Javascriptaddsinteractivity、形成、

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

mPDF

mPDF

mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境