[2]React 深入淺出-----React的一個高階表格實現功能
阿新 • • 發佈:2019-02-03
在我們平常的企業級應用程式裡面,表格形式的資料的展現和搜尋是非常常見的。一般的做法都是在列表的上面,加幾個搜尋條件,然後最下面放一個搜尋按鈕,然後通過呼叫後臺的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, search: false, }); 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", "English", "1997", "107 million"], ["And Then There Were None", "Agatha Christie", "English", "1939", "100 million"], ["Dream of the Red Chamber", "Cao Xueqin", "Chinese", "1754-1791", "100 million"], ["The Hobbit", "J. R. R. Tolkien", "English", "1937", "100 million"], ["She: A History of Adventure", "H. Rider Haggard", "English", "1887", "100 million"], ]; var Ex = ReactDOM.render( React.createElement(Excel, { headers: headers, initialData: data, }), document.getElementById("app") ); </script> </body> </html>
程式碼參考:https://github.com/stoyan/react