在我们平常的企业级应用程序里面,表格形式的数据的展现和搜索是非常常见的。一般的做法都是在列表的上面,加几个搜索条件,然后最下面放一个搜索按钮,然后通过调用后台的Ajax进行过滤,然后调用JQuery等其他框架,进行 DOM书的更新,当然这个也是一个好的实现方法,但是就是有一点不太优雅。而且不是所见即所得,比如,必须输入了所有的输入条件,才能进行结构的搜索,而且把数据传输到后端,在传回来,性能上不是特别的好。 那么有没有更好的方法,刚好笔者这段时间在学习React,看到了Stoyan Stefanov写的一本书,里面提到了一种个人感觉比较优雅的方式,而且结合React框架本身的性能优势,我想用户体验应该是挺不错的。
Stoyan的设计的例子如下:
@静态效果:
@动态效果
其具体代码如下:
<!DOCTYPE html> <html> <head> <title>Table</title> <Meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="03.00.table.css"> </head> <body> <div id="app"> <!-- my app renders here --> </div> <script src="react/build/react.js"></script> <script src="react/build/react-dom.js"></script> <script> var Excel = React.createClass({ displayName: 'Excel',propTypes: { headers: React.PropTypes.arrayOf( React.PropTypes.string ),initialData: React.PropTypes.arrayOf( React.PropTypes.arrayOf( React.PropTypes.string ) ),},getInitialState: function() { return { data: this.props.initialData,sortby: null,descending: false,edit: null,// [row index,cell index],search: false,}; },_sort: function(e) { var column = e.target.cellIndex; var data = this.state.data.slice(); var descending = this.state.sortby === column && !this.state.descending; data.sort(function(a,b) { return descending ? (a[column] < b[column] ? 1 : -1) : (a[column] > b[column] ? 1 : -1); }); this.setState({ data: data,sortby: column,descending: descending,}); },_showEditor: function(e) { this.setState({edit: { row: parseInt(e.target.dataset.row,10),cell: e.target.cellIndex,}}); },_save: function(e) { e.preventDefault(); var input = e.target.firstChild; var data = this.state.data.slice(); data[this.state.edit.row][this.state.edit.cell] = input.value; this.setState({ edit: null,data: data,_preSearchData: null,_toggleSearch: function() { if (this.state.search) { this.setState({ data: this._preSearchData,}); this._preSearchData = null; } else { this._preSearchData = this.state.data; this.setState({ search: true,}); } },_search: function(e) { var needle = e.target.value.toLowerCase(); if (!needle) { this.setState({data: this._preSearchData}); return; } var idx = e.target.dataset.idx; var searchdata = this._preSearchData.filter(function(row) { return row[idx].toString().toLowerCase().indexOf(needle) > -1; }); this.setState({data: searchdata}); },render: function() { return ( React.DOM.div(null,this._renderToolbar(),this._renderTable() ) ); },_renderToolbar: function() { return React.DOM.button( { onClick: this._toggleSearch,className: 'toolbar','search' ); },_renderSearch: function() { if (!this.state.search) { return null; } return ( React.DOM.tr({onChange: this._search},this.props.headers.map(function(_ignore,idx) { return React.DOM.td({key: idx},React.DOM.input({ type: 'text','data-idx': idx,}) ); }) ) ); },_renderTable: function() { return ( React.DOM.table(null,React.DOM.thead({onClick: this._sort},React.DOM.tr(null,this.props.headers.map(function(title,idx) { if (this.state.sortby === idx) { title += this.state.descending ? ' \u2191' : ' \u2193' } return React.DOM.th({key: idx},title); },this) ) ),React.DOM.tbody({onDoubleClick: this._showEditor},this._renderSearch(),this.state.data.map(function(row,rowidx) { return ( React.DOM.tr({key: rowidx},row.map(function(cell,idx) { var content = cell; var edit = this.state.edit; if (edit && edit.row === rowidx && edit.cell === idx) { content = React.DOM.form({onSubmit: this._save},React.DOM.input({ type: 'text',defaultValue: cell,}) ); } return React.DOM.td({ key: idx,'data-row': rowidx,content); },this) ) ); },this) ) ) ); } }); var headers = [ "Book","Author","Language","Published","Sales" ]; var data = [ ["The Lord of the Rings","J. R. R. Tolkien","English","1954-1955","150 million"],["Le Petit Prince (The Little Prince)","Antoine de Saint-Exupéry","French","1943","140 million"],["Harry Potter and the Philosopher's Stone","J. K. Rowling","1997","107 million"],["And Then There Were None","Agatha Christie","1939","100 million"],["Dream of the Red Chamber","Cao Xueqin","Chinese","1754-1791",["The Hobbit","1937",["She: A History of Adventure","H. Rider Haggard","1887",]; var Ex = ReactDOM.render( React.createElement(Excel,{ headers: headers,initialData: data,}),document.getElementById("app") ); </script> </body> </html>代码参考:https://github.com/stoyan/react