├── .gitignore ├── README.md ├── react16.2 ├── example.gif ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json └── src │ ├── createServiceWorker.js │ ├── data.js │ ├── index.js │ ├── index.scss │ └── package.json └── react16.3 ├── example.gif ├── package.json ├── public ├── favicon.ico ├── index.html └── manifest.json └── src ├── createServiceWorker.js ├── data.js ├── index.js ├── index.scss └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # antd-editTable 2 | 使用antd实现表格增、删、编辑,分别基于react16.2和react16.3实现两种方式 3 | 4 | ## 背景 5 | React在版本16.3-alpha里引入了新的Context API,antd3.10.0基于react16.3-alpha,利用React.createContext()特性实现表格编辑。 6 | 7 | ## 方式一:基于react16.2, antd8.4实现表格增、删、编辑,未实现校验功能 8 | ### 示例 9 | ![example](https://github.com/Youzi-wr/antd-editTable/blob/master/react16.2/example.gif) 10 | 11 | ### Demo 12 | [https://codesandbox.io/s/v85jlv541y](https://codesandbox.io/s/v85jlv541y) 13 | 14 | 15 | ## 方式二:基于react16.3, antd3.10实现表格增、删、编辑,已实现校验功能 16 | ### 示例 17 | ![example](https://github.com/Youzi-wr/antd-editTable/blob/master/react16.3/example.gif) 18 | 19 | ### Demo 20 | [https://codesandbox.io/s/73zvp3vljx](https://codesandbox.io/s/73zvp3vljx) 21 | -------------------------------------------------------------------------------- /react16.2/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youzi-wr/antd-editTable/b0db17313f451d1920a37f7c9234c58e077c9759/react16.2/example.gif -------------------------------------------------------------------------------- /react16.2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "react-dom": "latest", 4 | "react": "latest", 5 | "antd": "latest" 6 | }, 7 | "name": "v85jlv541y", 8 | "description": null, 9 | "version": "0.0.0", 10 | "devDependencies": { 11 | "react-scripts": "1.0.0" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | } 19 | } -------------------------------------------------------------------------------- /react16.2/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youzi-wr/antd-editTable/b0db17313f451d1920a37f7c9234c58e077c9759/react16.2/public/favicon.ico -------------------------------------------------------------------------------- /react16.2/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 26 |
27 | 30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /react16.2/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react16.2/src/createServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | export default function register() { 12 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 13 | window.addEventListener('load', () => { 14 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 15 | navigator.serviceWorker 16 | .register(swUrl) 17 | .then(registration => { 18 | // eslint-disable-next-line no-param-reassign 19 | registration.onupdatefound = () => { 20 | const installingWorker = registration.installing; 21 | installingWorker.onstatechange = () => { 22 | if (installingWorker.state === 'installed') { 23 | if (navigator.serviceWorker.controller) { 24 | // At this point, the old content will have been purged and 25 | // the fresh content will have been added to the cache. 26 | // It's the perfect time to display a "New content is 27 | // available; please refresh." message in your web app. 28 | console.log('New content is available; please refresh.'); // eslint-disable-line no-console 29 | } else { 30 | // At this point, everything has been precached. 31 | // It's the perfect time to display a 32 | // "Content is cached for offline use." message. 33 | console.log('Content is cached for offline use.'); // eslint-disable-line no-console 34 | } 35 | } 36 | }; 37 | }; 38 | }) 39 | .catch(error => { 40 | console.error('Error during service worker registration:', error); 41 | }); 42 | }); 43 | } 44 | } 45 | 46 | export function unregister() { 47 | if ('serviceWorker' in navigator) { 48 | navigator.serviceWorker.ready.then(registration => { 49 | registration.unregister(); 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /react16.2/src/data.js: -------------------------------------------------------------------------------- 1 | export default { 2 | getList: [ 3 | { 4 | name: "大庆水果城", 5 | price: "20", 6 | fruitTypes: ["apple"], 7 | tenantCode: "001", 8 | evaluate: false, 9 | id: 2905258602579968 10 | }, 11 | { 12 | name: "同顺水果铺", 13 | price: "40", 14 | fruitTypes: ["apple", "orange"], 15 | tenantCode: "001", 16 | evaluate: false, 17 | id: 2904806276614144 18 | } 19 | ] 20 | }; 21 | -------------------------------------------------------------------------------- /react16.2/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import style from "./index.scss"; 4 | import "antd/dist/antd.css"; 5 | import data from "./data.js"; 6 | import { 7 | Table, 8 | Checkbox, 9 | Input, 10 | Divider, 11 | Select, 12 | Button, 13 | notification, 14 | Form 15 | } from "antd"; 16 | 17 | const sty = style; 18 | const Option = Select.Option; 19 | const CheckboxGroup = Checkbox.Group; 20 | const fruitList = [ 21 | { 22 | value: "apple", 23 | label: "苹果" 24 | }, 25 | { 26 | value: "banana", 27 | label: "香蕉" 28 | }, 29 | { 30 | value: "orange", 31 | label: "橘子" 32 | } 33 | ]; 34 | 35 | class Client extends React.Component { 36 | constructor(props) { 37 | super(props); 38 | 39 | this.state = { 40 | isRowOpen: false, //当前是否处于编辑状态(有且只有一行可编辑) 41 | locale: { 42 | emptyText: "暂无数据" 43 | }, 44 | data: [], 45 | //正在编辑数据的缓存以便取消动作 46 | editCacheData: [] 47 | }; 48 | 49 | this.columns = [ 50 | { 51 | title: "名称", 52 | key: "name", // todo 校验 53 | dataIndex: "name", 54 | render: (name, record) => { 55 | return record.type !== "view" ? ( 56 | this.nameChange(e, record)} 59 | /> 60 | ) : ( 61 | name 62 | ); 63 | } 64 | }, 65 | { 66 | title: "评价一下", 67 | width: 120, 68 | key: "evaluate", 69 | dataIndex: "evaluate", 70 | render: (evaluate, record) => { 71 | return record.type !== "view" ? ( 72 | 80 | ) : evaluate ? ( 81 | "不好吃" 82 | ) : ( 83 | "好吃" 84 | ); 85 | } 86 | }, 87 | { 88 | title: "水果", 89 | width: "25%", 90 | key: "fruitTypes", 91 | dataIndex: "fruitTypes", 92 | render: (fruitTypes, record) => { 93 | return ( 94 | this.fruitTypesChange(e, record)} 96 | disabled={record.type !== "view" ? false : true} 97 | options={fruitList} 98 | defaultValue={fruitTypes} 99 | /> 100 | ); 101 | } 102 | }, 103 | { 104 | title: "价格", 105 | width: "38%", 106 | key: "price", // todo 校验 107 | render: record => { 108 | return record.type !== "view" ? ( 109 | this.priceChange(e, record)} 112 | /> 113 | ) : ( 114 | record.price 115 | ); 116 | } 117 | }, 118 | { 119 | title: "操作", 120 | render: record => ( 121 | 122 | {record.type === "new" && ( 123 | 124 | this.addSubmit(record)}> 125 | 完成 126 | 127 | 128 | this.removeAdd(record)}> 129 | 取消 130 | 131 | 132 | )} 133 | {record.type === "edit" && ( 134 | 135 | this.editSubmit(record)}> 136 | 完成 137 | 138 | 139 | this.giveUpUpdata(record)}> 140 | 取消 141 | 142 | 143 | this.delete(record)}> 144 | 删除 145 | 146 | 147 | )} 148 | {record.type === "view" && ( 149 | 150 | this.edit(record)}> 151 | 编辑 152 | 153 | 154 | this.delete(record)}> 155 | 删除 156 | 157 | 158 | )} 159 | 160 | ), 161 | width: 150 162 | } 163 | ]; 164 | } 165 | componentDidMount() { 166 | this.initRowType(data.getList); 167 | } 168 | initRowType(data) { 169 | for (let item of data) { 170 | item["type"] = "view"; 171 | } 172 | this.updateDataSource(data); 173 | } 174 | // ---------------------- cell change start------------------ 175 | nameChange(e, record) { 176 | this.updateEditCacheData(record, { name: e.target.value }); 177 | } 178 | evaluateChange(e, record) { 179 | this.updateEditCacheData(record, { evaluate: e == "1" ? true : false }); 180 | } 181 | fruitTypesChange(e, record) { 182 | this.updateEditCacheData(record, { fruitTypes: e }); 183 | } 184 | priceChange(e, record) { 185 | this.updateEditCacheData(record, { price: e.target.value }); 186 | } 187 | // ---------------------- cell change end------------------ 188 | updateEditCacheData(record, obj) { 189 | let { editCacheData } = this.state; 190 | let cacheData = 191 | record.id === editCacheData.id 192 | ? { ...editCacheData, ...obj } 193 | : { ...record, ...obj }; 194 | this.setState({ editCacheData: cacheData }); 195 | } 196 | updateDataSource(newData, isAddDisabled) { 197 | let isRowOpen = 198 | typeof isAddDisabled == "boolean" 199 | ? isAddDisabled 200 | : newData.some(item => item.type === "new" || item.type === "edit"); 201 | this.setState({ 202 | isRowOpen, 203 | data: newData 204 | }); 205 | } 206 | addRow = () => { 207 | let { data } = this.state; 208 | let newRecord = { 209 | fruitTypes: ["apple", "banana", "orange"], 210 | name: "", 211 | evaluate: true, 212 | price: "", 213 | type: "new", 214 | id: "" 215 | }; 216 | 217 | data.push(newRecord); 218 | this.updateDataSource(data); 219 | }; 220 | addSubmit(record) { 221 | let { data, editCacheData } = this.state; 222 | // console.log(editCacheData); 223 | setTimeout(res => { 224 | editCacheData.type = "view"; 225 | data.pop(); 226 | data.push(editCacheData); 227 | this.updateDataSource(data); 228 | notification["success"]({ message: "添加成功!" }); 229 | }, 500); 230 | } 231 | removeAdd(record) { 232 | let { data } = this.state; 233 | data.pop(); 234 | this.updateDataSource(data); 235 | } 236 | editSubmit(record) { 237 | let { data, editCacheData } = this.state; 238 | 239 | setTimeout(res => { 240 | //将cacheData更新到dataSource 241 | let newData = data.map(item => { 242 | if (item.id === editCacheData.id) { 243 | item = Object.assign({}, editCacheData); 244 | item.type = "view"; 245 | } 246 | return item; 247 | }); 248 | this.updateDataSource(newData); 249 | notification["success"]({ message: "修改成功!" }); 250 | }, 500); 251 | } 252 | giveUpUpdata(record) { 253 | let { data } = this.state; 254 | let editRow = data.find(item => item.id === record.id); 255 | editRow.type = "view"; 256 | this.updateDataSource(data); 257 | } 258 | delete(record) { 259 | let { data } = this.state; 260 | console.log(record); 261 | setTimeout(res => { 262 | let index = data.findIndex(item => item.id === record.id); 263 | data.splice(index, 1); 264 | this.updateDataSource(data); 265 | notification["success"]({ message: "删除成功!" }); 266 | }); 267 | } 268 | edit(record) { 269 | let { data } = this.state; 270 | let newData = data.filter(item => { 271 | if (item.id === record.id) { 272 | item.type = "edit"; 273 | return item; 274 | } else if (item.type !== "new") { 275 | item.type = "view"; 276 | return item; 277 | } 278 | }); 279 | this.updateDataSource(newData, true); 280 | } 281 | render() { 282 | const { data, locale, isRowOpen } = this.state; 283 | 284 | return ( 285 |
286 |
287 | 294 | record.id} 298 | size={"middle"} 299 | columns={this.columns} 300 | dataSource={data} 301 | pagination={false} 302 | /> 303 | 304 | 305 | ); 306 | } 307 | } 308 | 309 | ReactDOM.render(, document.getElementById("container")); 310 | -------------------------------------------------------------------------------- /react16.2/src/index.scss: -------------------------------------------------------------------------------- 1 | .client { 2 | padding: 16px; 3 | .client-wrap { 4 | padding: 20px; 5 | background-color: #fff; 6 | } 7 | .colmns-ip { 8 | display: flex; 9 | justify-content: space-between; 10 | align-items: center; 11 | } 12 | :global { 13 | .ant-table-thead > tr > th, 14 | .ant-table-tbody > tr > td { 15 | padding: 15px 9px; 16 | } 17 | .editable-row .ant-form-explain { 18 | position: absolute; 19 | font-size: 12px; 20 | margin-top: -4px; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /react16.2/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "react-dom": "latest", 4 | "react": "latest", 5 | "antd": "latest" 6 | } 7 | } -------------------------------------------------------------------------------- /react16.3/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youzi-wr/antd-editTable/b0db17313f451d1920a37f7c9234c58e077c9759/react16.3/example.gif -------------------------------------------------------------------------------- /react16.3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "react-dom": "^16.3.2", 4 | "react": "^16.3.2", 5 | "antd": "^3.10.0" 6 | }, 7 | "name": "73zvp3vljx", 8 | "description": null, 9 | "version": "0.0.17", 10 | "devDependencies": { 11 | "react-scripts": "1.0.0" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | } 19 | } -------------------------------------------------------------------------------- /react16.3/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youzi-wr/antd-editTable/b0db17313f451d1920a37f7c9234c58e077c9759/react16.3/public/favicon.ico -------------------------------------------------------------------------------- /react16.3/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 26 |
27 | 30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /react16.3/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react16.3/src/createServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | export default function register() { 12 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 13 | window.addEventListener('load', () => { 14 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 15 | navigator.serviceWorker 16 | .register(swUrl) 17 | .then(registration => { 18 | // eslint-disable-next-line no-param-reassign 19 | registration.onupdatefound = () => { 20 | const installingWorker = registration.installing; 21 | installingWorker.onstatechange = () => { 22 | if (installingWorker.state === 'installed') { 23 | if (navigator.serviceWorker.controller) { 24 | // At this point, the old content will have been purged and 25 | // the fresh content will have been added to the cache. 26 | // It's the perfect time to display a "New content is 27 | // available; please refresh." message in your web app. 28 | console.log('New content is available; please refresh.'); // eslint-disable-line no-console 29 | } else { 30 | // At this point, everything has been precached. 31 | // It's the perfect time to display a 32 | // "Content is cached for offline use." message. 33 | console.log('Content is cached for offline use.'); // eslint-disable-line no-console 34 | } 35 | } 36 | }; 37 | }; 38 | }) 39 | .catch(error => { 40 | console.error('Error during service worker registration:', error); 41 | }); 42 | }); 43 | } 44 | } 45 | 46 | export function unregister() { 47 | if ('serviceWorker' in navigator) { 48 | navigator.serviceWorker.ready.then(registration => { 49 | registration.unregister(); 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /react16.3/src/data.js: -------------------------------------------------------------------------------- 1 | export default { 2 | getList: [ 3 | { 4 | name: "大庆水果城", 5 | price: "20", 6 | fruitTypes: ["apple"], 7 | tenantCode: "001", 8 | evaluate: false, 9 | id: 2905258602579968 10 | }, 11 | { 12 | name: "同顺水果铺", 13 | price: "40", 14 | fruitTypes: ["apple", "orange"], 15 | tenantCode: "001", 16 | evaluate: false, 17 | id: 2904806276614144 18 | } 19 | ] 20 | }; 21 | -------------------------------------------------------------------------------- /react16.3/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import style from "./index.scss"; 4 | import "antd/dist/antd.css"; 5 | import data from "./data.js"; 6 | import { 7 | Table, 8 | Checkbox, 9 | Input, 10 | Divider, 11 | Select, 12 | Button, 13 | notification, 14 | Form 15 | } from "antd"; 16 | 17 | const sty = style; 18 | const CheckboxGroup = Checkbox.Group; 19 | const FormItem = Form.Item; 20 | const EditableContext = React.createContext(); 21 | const fruitList = [ 22 | { 23 | value: "apple", 24 | label: "苹果" 25 | }, 26 | { 27 | value: "banana", 28 | label: "香蕉" 29 | }, 30 | { 31 | value: "orange", 32 | label: "橘子" 33 | } 34 | ]; 35 | 36 | const EditableRow = ({ form, index, ...props }) => ( 37 | 38 |
39 | 40 | ); 41 | 42 | const EditableFormRow = Form.create()(EditableRow); 43 | 44 | class EditableCell extends React.Component { 45 | constructor(props) { 46 | super(props); 47 | } 48 | render() { 49 | const { renderDom, record, ...restProps } = this.props; 50 | 51 | return ( 52 | 60 | ); 61 | } 62 | } 63 | 64 | class Client extends React.Component { 65 | constructor(props) { 66 | super(props); 67 | 68 | this.state = { 69 | isRowOpen: false, //当前是否处于编辑状态(有且只有一行可编辑) 70 | locale: { 71 | emptyText: "暂无数据" 72 | }, 73 | data: [] 74 | }; 75 | 76 | this.columns = [ 77 | { 78 | title: "名称", 79 | key: "name", 80 | renderDom: (form, record) => { 81 | return record.type !== "view" ? ( 82 | 83 | {form.getFieldDecorator("name", { 84 | rules: [ 85 | { 86 | required: true, 87 | message: "名称不能为空!" 88 | } 89 | ], 90 | initialValue: record.name 91 | })()} 92 | 93 | ) : ( 94 | record.name 95 | ); 96 | } 97 | }, 98 | { 99 | title: "评价一下", 100 | width: 120, 101 | key: "evaluate", 102 | renderDom: (form, record) => { 103 | return record.type !== "view" ? ( 104 | 105 | {form.getFieldDecorator("evaluate", { 106 | rules: [], 107 | initialValue: record.evaluate ? "1" : "0" 108 | })( 109 | 113 | )} 114 | 115 | ) : record.evaluate ? ( 116 | "不好吃" 117 | ) : ( 118 | "好吃" 119 | ); 120 | } 121 | }, 122 | { 123 | title: "水果", 124 | width: "25%", 125 | key: "fruitTypes", 126 | renderDom: (form, record) => { 127 | return ( 128 | 129 | {form.getFieldDecorator("fruitTypes", { 130 | rules: [], 131 | initialValue: record.fruitTypes 132 | })( 133 | 137 | )} 138 | 139 | ); 140 | } 141 | }, 142 | { 143 | title: "价格", 144 | width: "38%", 145 | key: "price", 146 | renderDom: (form, record) => { 147 | return record.type !== "view" ? ( 148 | 149 | {form.getFieldDecorator("price", { 150 | rules: [ 151 | { 152 | required: true, 153 | message: "价格不能为空!" 154 | } 155 | ], 156 | initialValue: record.price 157 | })()} 158 | 159 | ) : ( 160 | record.price 161 | ); 162 | } 163 | }, 164 | { 165 | title: "操作", 166 | renderDom: (form, record) => ( 167 | 168 | {record.type === "new" && ( 169 | 170 | this.addSubmit(form, record)} 173 | > 174 | 完成 175 | 176 | 177 | this.removeAdd(record)}> 178 | 取消 179 | 180 | 181 | )} 182 | {record.type === "edit" && ( 183 | 184 | this.editSubmit(form, record)} 187 | > 188 | 完成 189 | 190 | 191 | this.giveUpUpdata(record)}> 192 | 取消 193 | 194 | 195 | this.delete(record)}> 196 | 删除 197 | 198 | 199 | )} 200 | {record.type === "view" && ( 201 | 202 | this.edit(record)}> 203 | 编辑 204 | 205 | 206 | this.delete(record)}> 207 | 删除 208 | 209 | 210 | )} 211 | 212 | ), 213 | width: 150 214 | } 215 | ]; 216 | } 217 | componentDidMount() { 218 | this.initRowType(data.getList); 219 | } 220 | initRowType(data) { 221 | for (let item of data) { 222 | item["type"] = "view"; 223 | } 224 | this.updateDataSource(data); 225 | } 226 | updateDataSource(newData, isAddDisabled) { 227 | let isRowOpen = 228 | typeof isAddDisabled == "boolean" 229 | ? isAddDisabled 230 | : newData.some(item => item.type === "new" || item.type === "edit"); 231 | this.setState({ 232 | isRowOpen, 233 | data: newData 234 | }); 235 | } 236 | addRow = () => { 237 | let { data } = this.state; 238 | let newRecord = { 239 | fruitTypes: ["apple", "banana", "orange"], 240 | name: "", 241 | evaluate: true, 242 | price: "", 243 | type: "new", 244 | id: "" 245 | }; 246 | 247 | data.push(newRecord); 248 | this.updateDataSource(data); 249 | }; 250 | addSubmit(form, record) { 251 | let { data } = this.state; 252 | 253 | form.validateFields((error, values) => { 254 | if (error) { 255 | return; 256 | } 257 | values.evaluate = values.evaluate == "1" ? true : false; 258 | let updateData = { ...record, ...values }; 259 | 260 | setTimeout(res => { 261 | updateData.type = "view"; 262 | data.pop(); 263 | data.push(updateData); 264 | this.updateDataSource(data); 265 | notification["success"]({ message: "添加成功!" }); 266 | }, 500); 267 | }); 268 | } 269 | editSubmit(form, record) { 270 | let { data } = this.state; 271 | 272 | form.validateFields((error, values) => { 273 | if (error) { 274 | return; 275 | } 276 | values.evaluate = values.evaluate == "1" ? true : false; 277 | let updateData = { ...record, ...values }; 278 | 279 | // console.log(updateData); 280 | setTimeout(res => { 281 | //将updateData更新到dataSource 282 | let newData = data.map(item => { 283 | if (item.id === updateData.id) { 284 | item = Object.assign({}, updateData); 285 | item.type = "view"; 286 | } 287 | return item; 288 | }); 289 | this.updateDataSource(newData); 290 | notification["success"]({ message: "修改成功!" }); 291 | }); 292 | }); 293 | } 294 | removeAdd(record) { 295 | let { data } = this.state; 296 | data.pop(); 297 | this.updateDataSource(data); 298 | } 299 | giveUpUpdata(record) { 300 | let { data } = this.state; 301 | let editRow = data.find(item => item.id === record.id); 302 | editRow.type = "view"; 303 | this.updateDataSource(data); 304 | } 305 | delete(record) { 306 | let { data } = this.state; 307 | // console.log(record); 308 | setTimeout(res => { 309 | let index = data.findIndex(item => item.id === record.id); 310 | data.splice(index, 1); 311 | this.updateDataSource(data); 312 | notification["success"]({ message: "删除成功!" }); 313 | }); 314 | } 315 | edit(record) { 316 | let { data } = this.state; 317 | let newData = data.filter(item => { 318 | if (item.id === record.id) { 319 | item.type = "edit"; 320 | return item; 321 | } else if (item.type !== "new") { 322 | item.type = "view"; 323 | return item; 324 | } 325 | }); 326 | this.updateDataSource(newData, true); 327 | } 328 | render() { 329 | const { data, locale, isRowOpen } = this.state; 330 | const components = { 331 | body: { 332 | row: EditableFormRow, 333 | cell: EditableCell 334 | } 335 | }; 336 | const columns = this.columns.map(col => { 337 | return { 338 | ...col, 339 | onCell: record => ({ 340 | ...col, 341 | record 342 | }) 343 | }; 344 | }); 345 | 346 | return ( 347 |
348 |
349 | 356 |
(this.cell = node)} {...restProps}> 53 | 54 | {form => { 55 | this.form = form; 56 | return renderDom(form, record); 57 | }} 58 | 59 |
record.id} 361 | columns={columns} 362 | dataSource={data} 363 | pagination={false} 364 | rowClassName="editable-row" 365 | /> 366 | 367 | 368 | ); 369 | } 370 | } 371 | 372 | ReactDOM.render(, document.getElementById("container")); 373 | -------------------------------------------------------------------------------- /react16.3/src/index.scss: -------------------------------------------------------------------------------- 1 | .client { 2 | padding: 16px; 3 | .client-wrap { 4 | padding: 20px; 5 | background-color: #fff; 6 | } 7 | .colmns-ip { 8 | display: flex; 9 | justify-content: space-between; 10 | align-items: center; 11 | } 12 | .ant-table-thead > tr > th, 13 | .ant-table-tbody > tr > td { 14 | padding: 15px 9px; 15 | } 16 | .editable-row .ant-form-explain { 17 | position: absolute; 18 | font-size: 12px; 19 | margin-top: -4px; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /react16.3/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "react-dom": "^16.3.2", 4 | "react": "^16.3.2", 5 | "antd": "^3.10.0" 6 | } 7 | } --------------------------------------------------------------------------------