Commit 2cb8a6d93e7705490f5045e737a292360505a0ce
1 parent
d2e82cd7
commit Table component
commit Table component
Showing
12 changed files
with
334 additions
and
0 deletions
Show diff stats
1 | +<template> | |
2 | + <thead> | |
3 | + <tr> | |
4 | + <th v-for="column in columns">{{{ renderHeader(column, $index) }}}</th> | |
5 | + </tr> | |
6 | + </thead> | |
7 | +</template> | |
8 | +<script> | |
9 | + export default { | |
10 | + props: { | |
11 | + prefixCls: String, | |
12 | + columns: Array | |
13 | + }, | |
14 | + data () { | |
15 | + return { | |
16 | + | |
17 | + } | |
18 | + }, | |
19 | + computed: { | |
20 | + | |
21 | + }, | |
22 | + methods: { | |
23 | + renderHeader (column, $index) { | |
24 | + if ('renderHeader' in this.columns[$index]) { | |
25 | + return this.columns[$index].renderHeader(column, $index); | |
26 | + } else { | |
27 | + return column.title || '#'; | |
28 | + } | |
29 | + } | |
30 | + } | |
31 | + } | |
32 | +</script> | |
0 | 33 | \ No newline at end of file | ... | ... |
1 | +<template> | |
2 | + <div :class="classes"> | |
3 | + <div :class="[prefixCls + '-body']"> | |
4 | + <table> | |
5 | + <colgroup> | |
6 | + <col v-for="column in columns" :width="column.width"> | |
7 | + </colgroup> | |
8 | + <thead | |
9 | + is="table-head" | |
10 | + :prefix-cls="prefixCls + '-thead'" | |
11 | + :columns="columns"></thead> | |
12 | + <tbody :class="[prefixCls + '-tbody']" v-el:render> | |
13 | + <tr :class="[prefixCls + '-row']" v-for="(index, row) in data"> | |
14 | + <td v-for="column in columns">{{{ renderRow(row, column) }}}</td> | |
15 | + </tr> | |
16 | + </tbody> | |
17 | + </table> | |
18 | + </div> | |
19 | + </div> | |
20 | +</template> | |
21 | +<script> | |
22 | + import TableHead from './table-head.vue'; | |
23 | + import { oneOf } from '../../utils/assist'; | |
24 | + const prefixCls = 'ivu-table'; | |
25 | + | |
26 | + export default { | |
27 | + components: { TableHead }, | |
28 | + props: { | |
29 | + data: { | |
30 | + type: Array, | |
31 | + default () { | |
32 | + return [] | |
33 | + } | |
34 | + }, | |
35 | + columns: { | |
36 | + type: Array, | |
37 | + default () { | |
38 | + return [] | |
39 | + } | |
40 | + }, | |
41 | + size: { | |
42 | + validator (value) { | |
43 | + return oneOf(value, ['small', 'large']); | |
44 | + } | |
45 | + }, | |
46 | + stripe: { | |
47 | + type: Boolean, | |
48 | + default: false | |
49 | + }, | |
50 | + border: { | |
51 | + type: Boolean, | |
52 | + default: false | |
53 | + }, | |
54 | + fit: { | |
55 | + type: Boolean, | |
56 | + default: true | |
57 | + }, | |
58 | + showHeader: { | |
59 | + type: Boolean, | |
60 | + default: true | |
61 | + }, | |
62 | + selection: { | |
63 | + validator (value) { | |
64 | + return oneOf(value, ['single', 'multiple', false]); | |
65 | + }, | |
66 | + default: false | |
67 | + }, | |
68 | + showIndex: { | |
69 | + type: Boolean, | |
70 | + default: false | |
71 | + } | |
72 | + }, | |
73 | + data () { | |
74 | + return { | |
75 | + prefixCls: prefixCls, | |
76 | + compiledUids: [] | |
77 | + } | |
78 | + }, | |
79 | + computed: { | |
80 | + classes () { | |
81 | + return [ | |
82 | + `${prefixCls}`, | |
83 | + { | |
84 | + [`${prefixCls}-${this.size}`]: !!this.size | |
85 | + } | |
86 | + ] | |
87 | + } | |
88 | + }, | |
89 | + methods: { | |
90 | + renderRow (row, column) { | |
91 | + return 'render' in column ? '' : row[column.key]; | |
92 | + }, | |
93 | + compileRender (update = false) { | |
94 | + this.$nextTick(() => { | |
95 | + if (update) { | |
96 | + for (let i = 0; i < this.$parent.$children.length; i++) { | |
97 | + const index = this.compiledUids.indexOf(this.$parent.$children[i]._uid); | |
98 | + if (index > -1) { | |
99 | + this.$parent.$children[i].$destroy(); | |
100 | + this.compiledUids.splice(index, 1); | |
101 | + i--; | |
102 | + } | |
103 | + } | |
104 | + } | |
105 | + | |
106 | + const $el = this.$els.render; | |
107 | + for (let i = 0; i < this.columns.length; i++) { | |
108 | + const column = this.columns[i]; | |
109 | + if (column.render) { | |
110 | + for (let j = 0; j < this.data.length; j++) { | |
111 | + // todo 做一个深度缓存,只在需要改render时再重新编译,否则data改变时不用再编译 | |
112 | + const row = this.data[j]; | |
113 | + const template = column.render(row, column, j); | |
114 | + const cell = document.createElement('div'); | |
115 | + cell.innerHTML = template; | |
116 | + const _oldParentChildLen = this.$parent.$children.length; | |
117 | + this.$parent.$compile(cell); | |
118 | + const _newParentChildLen = this.$parent.$children.length; | |
119 | + | |
120 | + if (_oldParentChildLen !== _newParentChildLen) { // if render normal html node, do not tag | |
121 | + this.compiledUids.push(this.$parent.$children[this.$parent.$children.length - 1]._uid); // tag it, and delete when data or columns update | |
122 | + } | |
123 | + $el.children[j].children[i].innerHTML = ''; | |
124 | + $el.children[j].children[i].appendChild(cell); | |
125 | + } | |
126 | + } | |
127 | + } | |
128 | + }); | |
129 | + } | |
130 | + }, | |
131 | + ready () { | |
132 | + this.compileRender(); | |
133 | + }, | |
134 | + watch: { | |
135 | + data: { | |
136 | + handler () { | |
137 | + this.compileRender(true); | |
138 | + }, | |
139 | + deep: true | |
140 | + }, | |
141 | + columns: { | |
142 | + handler () { | |
143 | + this.compileRender(true); | |
144 | + }, | |
145 | + deep: true | |
146 | + } | |
147 | + } | |
148 | + } | |
149 | +</script> | |
0 | 150 | \ No newline at end of file | ... | ... |
src/components/transfer/search.vue
src/index.js
... | ... | @@ -24,6 +24,7 @@ import Slider from './components/slider'; |
24 | 24 | import Spin from './components/spin'; |
25 | 25 | import Steps from './components/steps'; |
26 | 26 | import Switch from './components/switch'; |
27 | +import Table from './components/table'; | |
27 | 28 | import Tag from './components/tag'; |
28 | 29 | import Timeline from './components/timeline'; |
29 | 30 | import Tooltip from './components/tooltip'; |
... | ... | @@ -69,6 +70,7 @@ const iview = { |
69 | 70 | Step: Steps.Step, |
70 | 71 | Steps, |
71 | 72 | Switch, |
73 | + iTable: Table, | |
72 | 74 | Tag, |
73 | 75 | Timeline, |
74 | 76 | TimelineItem: Timeline.Item, | ... | ... |
src/utils/assist.js
... | ... | @@ -75,4 +75,16 @@ export function getStyle (element, styleName) { |
75 | 75 | } catch(e) { |
76 | 76 | return element.style[styleName]; |
77 | 77 | } |
78 | +} | |
79 | + | |
80 | +// firstUpperCase | |
81 | +function firstUpperCase(str) { | |
82 | + return str.toString()[0].toUpperCase() + str.toString().slice(1); | |
83 | +} | |
84 | + | |
85 | +// Warn | |
86 | +export function warnProp(component, prop, correctType, wrongType) { | |
87 | + correctType = firstUpperCase(correctType); | |
88 | + wrongType = firstUpperCase(wrongType); | |
89 | + console.error(`[iView warn]: Invalid prop: type check failed for prop ${prop}. Expected ${correctType}, got ${wrongType}. (found in component: ${component})`); | |
78 | 90 | } |
79 | 91 | \ No newline at end of file | ... | ... |
test/app.vue
test/main.js
... | ... | @@ -102,6 +102,11 @@ router.map({ |
102 | 102 | component: function (resolve) { |
103 | 103 | require(['./routers/transfer.vue'], resolve); |
104 | 104 | } |
105 | + }, | |
106 | + '/table': { | |
107 | + component: function (resolve) { | |
108 | + require(['./routers/table.vue'], resolve); | |
109 | + } | |
105 | 110 | } |
106 | 111 | }); |
107 | 112 | ... | ... |
1 | +<template> | |
2 | + <div> | |
3 | + <i-table :columns="columns" :data="data"></i-table> | |
4 | + </div> | |
5 | +</template> | |
6 | +<script> | |
7 | + export default { | |
8 | + props: { | |
9 | + | |
10 | + }, | |
11 | + data () { | |
12 | + return { | |
13 | + columns: [ | |
14 | + { | |
15 | + title: '姓名', | |
16 | + key: 'name' | |
17 | + }, | |
18 | + { | |
19 | + title: '年龄', | |
20 | + key: 'age', | |
21 | +// render (row) { | |
22 | +// return `<i-button>${row.age}</i-button>` | |
23 | +// } | |
24 | + }, | |
25 | + { | |
26 | + title: '地址', | |
27 | + key: 'address', | |
28 | +// render (row, column, index) { | |
29 | +// if (row.edit) { | |
30 | +// return `<i-input :value.sync="data[${index}].name"></i-input>`; | |
31 | +// } else { | |
32 | +// return `<Tooltip content="${row.address}"><i-button @click="show(${index})">${row.name}</i-button></Tooltip>`; | |
33 | +// } | |
34 | +// } | |
35 | + }, | |
36 | + { | |
37 | + title: '操作', | |
38 | + key: 'action', | |
39 | + render (row, column, index) { | |
40 | + return `<i-button @click="edit(${index})">编辑</i-button>` | |
41 | + } | |
42 | + } | |
43 | + ], | |
44 | + data: [ | |
45 | + { | |
46 | + name: '梁灏', | |
47 | + age: 25, | |
48 | + address: '北京市朝阳区', | |
49 | + edit: false | |
50 | + }, | |
51 | + { | |
52 | + name: '段模', | |
53 | + age: 26, | |
54 | + address: '北京市海淀区', | |
55 | + edit: false | |
56 | + }, | |
57 | + { | |
58 | + name: '刘天娇', | |
59 | + age: 27, | |
60 | + address: '北京市东城区', | |
61 | + edit: true | |
62 | + } | |
63 | + ] | |
64 | + } | |
65 | + }, | |
66 | + computed: { | |
67 | + | |
68 | + }, | |
69 | + methods: { | |
70 | + show (name) { | |
71 | + this.$Message.info(name); | |
72 | + }, | |
73 | + edit (index) { | |
74 | + this.data[index].edit = true; | |
75 | + } | |
76 | + }, | |
77 | + ready () { | |
78 | + setTimeout(() => { | |
79 | + this.data.push({ | |
80 | + name: '刘天娇2', | |
81 | + age: 272, | |
82 | + address: '北京市东城区2', | |
83 | + edit: false | |
84 | + }); | |
85 | + }, 1000); | |
86 | + } | |
87 | + } | |
88 | +</script> | |
0 | 89 | \ No newline at end of file | ... | ... |