mirror of https://github.com/ElemeFE/element
				
				
				
			Timeline: add timeline component (#14248)
* Table: fix params order of row events (#12086) * Timeline: add timeline component (#11736) * Timeline: add timeline component * Timeline: add timeline component * Timeline: add test case * Timeline: fix icon class * Timeline: update docs * Timeline: fix test case * Timeline: remove pending attribute * Timeline: fix docs * Timeline: make reverse default to false * Timline: fix test case * Timeline: update element-ui.d.ts * Timeline: optimize codepull/14297/head
							parent
							
								
									b350749d42
								
							
						
					
					
						commit
						f17533ab11
					
				|  | @ -67,5 +67,7 @@ | |||
|   "header": "./packages/header/index.js", | ||||
|   "aside": "./packages/aside/index.js", | ||||
|   "main": "./packages/main/index.js", | ||||
|   "footer": "./packages/footer/index.js" | ||||
|   "footer": "./packages/footer/index.js", | ||||
|   "timeline": "./packages/timeline/index.js", | ||||
|   "timeline-item": "./packages/timeline-item/index.js" | ||||
| } | ||||
|  |  | |||
|  | @ -2097,9 +2097,9 @@ You can customize row index in `type=index` columns. | |||
| | cell-mouse-leave | triggers when hovering out of a cell | row, column, cell, event | | ||||
| | cell-click | triggers when clicking a cell | row, column, cell, event | | ||||
| | cell-dblclick | triggers when double clicking a cell | row, column, cell, event | | ||||
| | row-click | triggers when clicking a row | row, event, column | | ||||
| | row-contextmenu | triggers when user right clicks on a row | row, event | | ||||
| | row-dblclick | triggers when double clicking a row | row, event | | ||||
| | row-click | triggers when clicking a row | row, column, event | | ||||
| | row-contextmenu | triggers when user right clicks on a row | row, column, event | | ||||
| | row-dblclick | triggers when double clicking a row | row, column, event | | ||||
| | header-click | triggers when clicking a column header | column, event | | ||||
| | header-contextmenu | triggers when user right clicks on a column header | column, event | | ||||
| | sort-change | triggers when Table's sorting changes | { column, prop, order } | | ||||
|  |  | |||
|  | @ -0,0 +1,199 @@ | |||
| <script> | ||||
|   export default { | ||||
|     data() { | ||||
|       return { | ||||
|         reverse: true, | ||||
|         activities: [{ | ||||
|           content: 'Event start', | ||||
|           timestamp: '2018-04-15' | ||||
|         }, { | ||||
|           content: 'Approved', | ||||
|           timestamp: '2018-04-13' | ||||
|         }, { | ||||
|           content: 'Success', | ||||
|           timestamp: '2018-04-11' | ||||
|         }], | ||||
|         activities2: [{ | ||||
|           content: 'Custom icon', | ||||
|           timestamp: '2018-04-12 20:46', | ||||
|           size: 'large', | ||||
|           type: 'primary', | ||||
|           icon: 'el-icon-more' | ||||
|         }, { | ||||
|           content: 'Custom color', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           color: '#0bbd87' | ||||
|         }, { | ||||
|           content: 'Custom size', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           size: 'large' | ||||
|         }, { | ||||
|           content: 'Default node', | ||||
|           timestamp: '2018-04-03 20:46' | ||||
|         }] | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
| <style> | ||||
|   .demo-timeline .source .radio { | ||||
|     margin-bottom: 20px; | ||||
|   } | ||||
|   .demo-timeline .source .radio .el-radio-group { | ||||
|     margin-left: 20px; | ||||
|   } | ||||
| </style> | ||||
| 
 | ||||
| ## Timeline | ||||
| 
 | ||||
| Visually display timeline. | ||||
| 
 | ||||
| ### Basic usage | ||||
| 
 | ||||
| Timeline can be split into multiple activities in ascending or descending. Timestamps are important features that distinguish them from other components. Note the difference with Steps. | ||||
| 
 | ||||
| :::demo | ||||
| ```html | ||||
| <div class="block"> | ||||
|   <div class="radio"> | ||||
|     Order:  | ||||
|     <el-radio-group v-model="reverse"> | ||||
|       <el-radio :label="true">descending</el-radio> | ||||
|       <el-radio :label="false">ascending</el-radio> | ||||
|     </el-radio-group> | ||||
|   </div> | ||||
| 
 | ||||
|   <el-timeline :reverse="reverse"> | ||||
|     <el-timeline-item | ||||
|       v-for="(activity, index) in activities" | ||||
|       :key="index" | ||||
|       :timestamp="activity.timestamp"> | ||||
|       {{activity.content}} | ||||
|     </el-timeline-item> | ||||
|   </el-timeline> | ||||
| </div> | ||||
| 
 | ||||
| <script> | ||||
|   export default { | ||||
|     data() { | ||||
|       return { | ||||
|         reverse: true, | ||||
|         activities: [{ | ||||
|           content: 'Event start', | ||||
|           timestamp: '2018-04-15' | ||||
|         }, { | ||||
|           content: 'Approved', | ||||
|           timestamp: '2018-04-13' | ||||
|         }, { | ||||
|           content: 'Success', | ||||
|           timestamp: '2018-04-11' | ||||
|         }] | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
| ``` | ||||
| ::: | ||||
| 
 | ||||
| ### Custom node | ||||
| 
 | ||||
| Size, color, and icons can be customized in node. | ||||
| 
 | ||||
| :::demo | ||||
| ```html | ||||
| <div class="block"> | ||||
|   <el-timeline> | ||||
|     <el-timeline-item | ||||
|       v-for="(activity, index) in activities2" | ||||
|       :key="index" | ||||
|       :icon="activity.icon" | ||||
|       :type="activity.type" | ||||
|       :color="activity.color" | ||||
|       :size="activity.size" | ||||
|       :timestamp="activity.timestamp"> | ||||
|       {{activity.content}} | ||||
|     </el-timeline-item> | ||||
|   </el-timeline> | ||||
| </div> | ||||
| 
 | ||||
| <script> | ||||
|   export default { | ||||
|     data() { | ||||
|       return { | ||||
|         activities2: [{ | ||||
|           content: 'Custom icon', | ||||
|           timestamp: '2018-04-12 20:46', | ||||
|           size: 'large', | ||||
|           type: 'primary', | ||||
|           icon: 'el-icon-more' | ||||
|         }, { | ||||
|           content: 'Custom color', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           color: '#0bbd87' | ||||
|         }, { | ||||
|           content: 'Custom size', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           size: 'large' | ||||
|         }, { | ||||
|           content: 'Default node', | ||||
|           timestamp: '2018-04-03 20:46' | ||||
|         }] | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
| ``` | ||||
| ::: | ||||
| 
 | ||||
| ### Custom timestamp | ||||
| 
 | ||||
| Timestamp can be placed on top of content when content is too high. | ||||
| 
 | ||||
| :::demo | ||||
| ```html | ||||
| <div class="block"> | ||||
|   <el-timeline> | ||||
|     <el-timeline-item timestamp="2018/4/12" placement="top"> | ||||
|       <el-card> | ||||
|         <h4>Update Github template</h4> | ||||
|         <p>Tom committed 2018/4/12 20:46</p> | ||||
|       </el-card> | ||||
|     </el-timeline-item> | ||||
|     <el-timeline-item timestamp="2018/4/3" placement="top"> | ||||
|       <el-card> | ||||
|         <h4>Update Github template</h4> | ||||
|         <p>Tom committed 2018/4/3 20:46</p> | ||||
|       </el-card> | ||||
|     </el-timeline-item> | ||||
|     <el-timeline-item timestamp="2018/4/2" placement="top"> | ||||
|       <el-card> | ||||
|         <h4>Update Github template</h4> | ||||
|         <p>Tom committed 2018/4/2 20:46</p> | ||||
|       </el-card> | ||||
|     </el-timeline-item> | ||||
|   </el-timeline> | ||||
| </div> | ||||
| ``` | ||||
| ::: | ||||
| 
 | ||||
| ### Timeline Attributes | ||||
| | Attribute      | Description    | Type      | Accepted Values | Default   | | ||||
| |---------- |-------- |---------- |-------------  |-------- | | ||||
| | reverse | whether the node is ascending or descending, default is ascending | boolean | — | false | | ||||
| 
 | ||||
| ### Timeline-item Attributes | ||||
| | Attribute      | Description    | Type      | Accepted Values | Default   | | ||||
| |---------- |-------- |---------- |-------------  |-------- | | ||||
| | timestamp     | timestamp content | string  | - | — | | ||||
| | hide-timestamp  | whether to show timestamp | boolean | — | false | | ||||
| | placement | position of timestamp | string | top / bottom | bottom | | ||||
| | type | node type | string | primary / success / warning / danger / info | - | | ||||
| | color | background color of node | string | hsl / hsv / hex / rgb | - | | ||||
| | size | node size | string | normal / large | normal | | ||||
| | icon | icon class name | string | — | - | | ||||
| 
 | ||||
| ### Timeline-Item Slot | ||||
| | name | Description | | ||||
| |------|--------| | ||||
| | — | Custom content for timeline item | | ||||
| | dot | Custom defined node | | ||||
|  | @ -2099,9 +2099,9 @@ Puede personalizar el índice de la fila con la propiedad `type=index` de las co | |||
| | cell-mouse-leave   | se dispara cuando se desplaza fuera de una celda | row, column, cell, event          | | ||||
| | cell-click         | se dispara cuando se hace clic en una celda | row, column, cell, event          | | ||||
| | cell-dblclick      | se dispara cuando se hace doble clic en una celda | row, column, cell, event          | | ||||
| | row-click          | se dispara cuando se hace clic en una fila | row, event, column                | | ||||
| | row-contextmenu    | se dispara cuando el usuario hace clic derecho en una fila | row, event                        | | ||||
| | row-dblclick       | se dispara cuando se hace doble clic en una fila | row, event                        | | ||||
| | row-click          | se dispara cuando se hace clic en una fila | row, column, event                | | ||||
| | row-contextmenu    | se dispara cuando el usuario hace clic derecho en una fila | row, column, event                        | | ||||
| | row-dblclick       | se dispara cuando se hace doble clic en una fila | row, column, event                        | | ||||
| | header-click       | se dispara cuando se hace click en una cabecera de columna | column, event                     | | ||||
| | header-contextmenu | se dispara cuando el usuario hace clic derecho en una cabecera de columna | column, event                     | | ||||
| | sort-change        | se dispara cuando el ordenamiento de la tabla cambia | { column, prop, order }           | | ||||
|  |  | |||
|  | @ -0,0 +1,199 @@ | |||
| <script> | ||||
|   export default { | ||||
|     data() { | ||||
|       return { | ||||
|         reverse: true, | ||||
|         activities: [{ | ||||
|           content: 'Success', | ||||
|           timestamp: '2018-04-11' | ||||
|         }, { | ||||
|           content: 'Approved', | ||||
|           timestamp: '2018-04-13' | ||||
|         }, { | ||||
|           content: 'Event start', | ||||
|           timestamp: '2018-04-15' | ||||
|         }], | ||||
|         activities2: [{ | ||||
|           content: 'Custom icon', | ||||
|           timestamp: '2018-04-12 20:46', | ||||
|           size: 'large', | ||||
|           type: 'primary', | ||||
|           icon: 'el-icon-more' | ||||
|         }, { | ||||
|           content: 'Custom color', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           color: '#0bbd87' | ||||
|         }, { | ||||
|           content: 'Custom size', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           size: 'large' | ||||
|         }, { | ||||
|           content: 'Default node', | ||||
|           timestamp: '2018-04-03 20:46' | ||||
|         }] | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
| <style> | ||||
|   .demo-timeline .source .radio { | ||||
|     margin-bottom: 20px; | ||||
|   } | ||||
|   .demo-timeline .source .radio .el-radio-group { | ||||
|     margin-left: 20px; | ||||
|   } | ||||
| </style> | ||||
| 
 | ||||
| ## Timeline | ||||
| 
 | ||||
| Visually display timeline. | ||||
| 
 | ||||
| ### Basic usage | ||||
| 
 | ||||
| Timeline can be split into multiple activities in ascending or descending. Timestamps are important features that distinguish them from other components. Note the difference with Steps. | ||||
| 
 | ||||
| :::demo | ||||
| ```html | ||||
| <div class="block"> | ||||
|   <div class="radio"> | ||||
|     Order:  | ||||
|     <el-radio-group v-model="reverse"> | ||||
|       <el-radio :label="true">descending</el-radio> | ||||
|       <el-radio :label="false">ascending</el-radio> | ||||
|     </el-radio-group> | ||||
|   </div> | ||||
| 
 | ||||
|   <el-timeline :reverse="reverse"> | ||||
|     <el-timeline-item | ||||
|       v-for="(activity, index) in activities" | ||||
|       :key="index" | ||||
|       :timestamp="activity.timestamp"> | ||||
|       {{activity.content}} | ||||
|     </el-timeline-item> | ||||
|   </el-timeline> | ||||
| </div> | ||||
| 
 | ||||
| <script> | ||||
|   export default { | ||||
|     data() { | ||||
|       return { | ||||
|         reverse: true, | ||||
|         activities: [{ | ||||
|           content: 'Success', | ||||
|           timestamp: '2018-04-11' | ||||
|         }, { | ||||
|           content: 'Approved', | ||||
|           timestamp: '2018-04-13' | ||||
|         }, { | ||||
|           content: 'Event start', | ||||
|           timestamp: '2018-04-15' | ||||
|         }] | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
| ``` | ||||
| ::: | ||||
| 
 | ||||
| ### Custom node | ||||
| 
 | ||||
| Size, color, and icons can be customized in node. | ||||
| 
 | ||||
| :::demo | ||||
| ```html | ||||
| <div class="block"> | ||||
|   <el-timeline> | ||||
|     <el-timeline-item | ||||
|       v-for="(activity, index) in activities2" | ||||
|       :key="index" | ||||
|       :icon="activity.icon" | ||||
|       :type="activity.type" | ||||
|       :color="activity.color" | ||||
|       :size="activity.size" | ||||
|       :timestamp="activity.timestamp"> | ||||
|       {{activity.content}} | ||||
|     </el-timeline-item> | ||||
|   </el-timeline> | ||||
| </div> | ||||
| 
 | ||||
| <script> | ||||
|   export default { | ||||
|     data() { | ||||
|       return { | ||||
|         activities2: [{ | ||||
|           content: 'Custom icon', | ||||
|           timestamp: '2018-04-12 20:46', | ||||
|           size: 'large', | ||||
|           type: 'primary', | ||||
|           icon: 'el-icon-more' | ||||
|         }, { | ||||
|           content: 'Custom color', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           color: '#0bbd87' | ||||
|         }, { | ||||
|           content: 'Custom size', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           size: 'large' | ||||
|         }, { | ||||
|           content: 'Default node', | ||||
|           timestamp: '2018-04-03 20:46' | ||||
|         }] | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
| ``` | ||||
| ::: | ||||
| 
 | ||||
| ### Custom timestamp | ||||
| 
 | ||||
| Timestamp can be placed on top of content when content is too high. | ||||
| 
 | ||||
| :::demo | ||||
| ```html | ||||
| <div class="block"> | ||||
|   <el-timeline> | ||||
|     <el-timeline-item timestamp="2018/4/12" placement="top"> | ||||
|       <el-card> | ||||
|         <h4>Update Github template</h4> | ||||
|         <p>Tom committed 2018/4/12 20:46</p> | ||||
|       </el-card> | ||||
|     </el-timeline-item> | ||||
|     <el-timeline-item timestamp="2018/4/3" placement="top"> | ||||
|       <el-card> | ||||
|         <h4>Update Github template</h4> | ||||
|         <p>Tom committed 2018/4/3 20:46</p> | ||||
|       </el-card> | ||||
|     </el-timeline-item> | ||||
|     <el-timeline-item timestamp="2018/4/2" placement="top"> | ||||
|       <el-card> | ||||
|         <h4>Update Github template</h4> | ||||
|         <p>Tom committed 2018/4/2 20:46</p> | ||||
|       </el-card> | ||||
|     </el-timeline-item> | ||||
|   </el-timeline> | ||||
| </div> | ||||
| ``` | ||||
| ::: | ||||
| 
 | ||||
| ### Timeline Attributes | ||||
| | Attribute      | Description    | Type      | Accepted Values | Default   | | ||||
| |---------- |-------- |---------- |-------------  |-------- | | ||||
| | reverse | whether the node is ascending or descending, default is ascending | boolean | — | false | | ||||
| 
 | ||||
| ### Timeline-item Attributes | ||||
| | Attribute      | Description    | Type      | Accepted Values | Default   | | ||||
| |---------- |-------- |---------- |-------------  |-------- | | ||||
| | timestamp     | timestamp content | string  | - | — | | ||||
| | hide-timestamp  | whether to show timestamp | boolean | — | false | | ||||
| | placement | position of timestamp | string | top / bottom | bottom | | ||||
| | type | node type | string | primary / success / warning / danger / info | - | | ||||
| | color | background color of node | string | hsl / hsv / hex / rgb | - | | ||||
| | size | node size | string | normal / large | normal | | ||||
| | icon | icon class name | string | — | - | | ||||
| 
 | ||||
| ### Timeline-Item Slot | ||||
| | name | Description | | ||||
| |------|--------| | ||||
| | — | Custom content for timeline item | | ||||
| | dot | Custom defined node | | ||||
|  | @ -2157,9 +2157,9 @@ | |||
| | cell-mouse-leave | 当单元格 hover 退出时会触发该事件 | row, column, cell, event | | ||||
| | cell-click | 当某个单元格被点击时会触发该事件 | row, column, cell, event | | ||||
| | cell-dblclick | 当某个单元格被双击击时会触发该事件 | row, column, cell, event | | ||||
| | row-click | 当某一行被点击时会触发该事件 | row, event, column | | ||||
| | row-contextmenu | 当某一行被鼠标右键点击时会触发该事件 | row, event | | ||||
| | row-dblclick | 当某一行被双击时会触发该事件 | row, event | | ||||
| | row-click | 当某一行被点击时会触发该事件 | row, column, event | | ||||
| | row-contextmenu | 当某一行被鼠标右键点击时会触发该事件 | row, column, event | | ||||
| | row-dblclick | 当某一行被双击时会触发该事件 | row, column, event | | ||||
| | header-click | 当某一列的表头被点击时会触发该事件 | column, event | | ||||
| | header-contextmenu | 当某一列的表头被鼠标右键点击时触发该事件 | column, event | | ||||
| | sort-change | 当表格的排序条件发生变化的时候会触发该事件 | { column, prop, order } | | ||||
|  |  | |||
|  | @ -0,0 +1,199 @@ | |||
| <script> | ||||
|   export default { | ||||
|     data() { | ||||
|       return { | ||||
|         reverse: true, | ||||
|         activities: [{ | ||||
|           content: '活动按期开始', | ||||
|           timestamp: '2018-04-15' | ||||
|         }, { | ||||
|           content: '通过审核', | ||||
|           timestamp: '2018-04-13' | ||||
|         }, { | ||||
|           content: '创建成功', | ||||
|           timestamp: '2018-04-11' | ||||
|         }], | ||||
|         activities2: [{ | ||||
|           content: '支持使用图标', | ||||
|           timestamp: '2018-04-12 20:46', | ||||
|           size: 'large', | ||||
|           type: 'primary', | ||||
|           icon: 'el-icon-more' | ||||
|         }, { | ||||
|           content: '支持自定义颜色', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           color: '#0bbd87' | ||||
|         }, { | ||||
|           content: '支持自定义尺寸', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           size: 'large' | ||||
|         }, { | ||||
|           content: '默认样式的节点', | ||||
|           timestamp: '2018-04-03 20:46' | ||||
|         }] | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
| <style> | ||||
|   .demo-timeline .source .radio { | ||||
|     margin-bottom: 20px; | ||||
|   } | ||||
|   .demo-timeline .source .radio .el-radio-group { | ||||
|     margin-left: 20px; | ||||
|   } | ||||
| </style> | ||||
| 
 | ||||
| ## Timeline 时间线 | ||||
| 
 | ||||
| 可视化地呈现时间流信息。 | ||||
| 
 | ||||
| ### 基础用法 | ||||
| 
 | ||||
| Timeline 可拆分成多个按照时间戳正序或倒序排列的 activity,时间戳是其区分于其他控件的重要特征,使⽤时注意与 Steps 步骤条等区分。 | ||||
| 
 | ||||
| :::demo | ||||
| ```html | ||||
| <div class="block"> | ||||
|   <div class="radio"> | ||||
|     排序: | ||||
|     <el-radio-group v-model="reverse"> | ||||
|       <el-radio :label="true">倒序</el-radio> | ||||
|       <el-radio :label="false">正序</el-radio> | ||||
|     </el-radio-group> | ||||
|   </div> | ||||
| 
 | ||||
|   <el-timeline :reverse="reverse"> | ||||
|     <el-timeline-item | ||||
|       v-for="(activity, index) in activities" | ||||
|       :key="index" | ||||
|       :timestamp="activity.timestamp"> | ||||
|       {{activity.content}} | ||||
|     </el-timeline-item> | ||||
|   </el-timeline> | ||||
| </div> | ||||
| 
 | ||||
| <script> | ||||
|   export default { | ||||
|     data() { | ||||
|       return { | ||||
|         reverse: true, | ||||
|         activities: [{ | ||||
|           content: '活动按期开始', | ||||
|           timestamp: '2018-04-15' | ||||
|         }, { | ||||
|           content: '通过审核', | ||||
|           timestamp: '2018-04-13' | ||||
|         }, { | ||||
|           content: '创建成功', | ||||
|           timestamp: '2018-04-11' | ||||
|         }] | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
| ``` | ||||
| ::: | ||||
| 
 | ||||
| ### ⾃定义节点样式 | ||||
| 
 | ||||
| 可根据实际场景⾃定义节点尺⼨、颜⾊,或直接使⽤图标。 | ||||
| 
 | ||||
| :::demo | ||||
| ```html | ||||
| <div class="block"> | ||||
|   <el-timeline> | ||||
|     <el-timeline-item | ||||
|       v-for="(activity, index) in activities2" | ||||
|       :key="index" | ||||
|       :icon="activity.icon" | ||||
|       :type="activity.type" | ||||
|       :color="activity.color" | ||||
|       :size="activity.size" | ||||
|       :timestamp="activity.timestamp"> | ||||
|       {{activity.content}} | ||||
|     </el-timeline-item> | ||||
|   </el-timeline> | ||||
| </div> | ||||
| 
 | ||||
| <script> | ||||
|   export default { | ||||
|     data() { | ||||
|       return { | ||||
|         activities2: [{ | ||||
|           content: '支持使用图标', | ||||
|           timestamp: '2018-04-12 20:46', | ||||
|           size: 'large', | ||||
|           type: 'primary', | ||||
|           icon: 'el-icon-more' | ||||
|         }, { | ||||
|           content: '支持自定义颜色', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           color: '#0bbd87' | ||||
|         }, { | ||||
|           content: '支持自定义尺寸', | ||||
|           timestamp: '2018-04-03 20:46', | ||||
|           size: 'large' | ||||
|         }, { | ||||
|           content: '默认样式的节点', | ||||
|           timestamp: '2018-04-03 20:46' | ||||
|         }] | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
| ``` | ||||
| ::: | ||||
| 
 | ||||
| ### ⾃定义时间戳 | ||||
| 
 | ||||
| 当内容在垂直⽅向上过⾼时,可将时间戳置于内容之上。 | ||||
| 
 | ||||
| :::demo | ||||
| ```html | ||||
| <div class="block"> | ||||
|   <el-timeline> | ||||
|     <el-timeline-item timestamp="2018/4/12" placement="top"> | ||||
|       <el-card> | ||||
|         <h4>更新 Github 模板</h4> | ||||
|         <p>王小虎 提交于 2018/4/12 20:46</p> | ||||
|       </el-card> | ||||
|     </el-timeline-item> | ||||
|     <el-timeline-item timestamp="2018/4/3" placement="top"> | ||||
|       <el-card> | ||||
|         <h4>更新 Github 模板</h4> | ||||
|         <p>王小虎 提交于 2018/4/3 20:46</p> | ||||
|       </el-card> | ||||
|     </el-timeline-item> | ||||
|     <el-timeline-item timestamp="2018/4/2" placement="top"> | ||||
|       <el-card> | ||||
|         <h4>更新 Github 模板</h4> | ||||
|         <p>王小虎 提交于 2018/4/2 20:46</p> | ||||
|       </el-card> | ||||
|     </el-timeline-item> | ||||
|   </el-timeline> | ||||
| </div> | ||||
| ``` | ||||
| ::: | ||||
| 
 | ||||
| ### Timeline Attributes | ||||
| | 参数      | 说明    | 类型      | 可选值       | 默认值   | | ||||
| |---------- |-------- |---------- |-------------  |-------- | | ||||
| | reverse | 指定节点排序方向,默认为正序 | boolean | — | false | | ||||
| 
 | ||||
| ### Timeline-item Attributes | ||||
| | 参数      | 说明    | 类型      | 可选值       | 默认值   | | ||||
| |---------- |-------- |---------- |-------------  |-------- | | ||||
| | timestamp     | 时间戳 | string  | - | — | | ||||
| | hide-timestamp  | 是否隐藏时间戳 | boolean | — | false | | ||||
| | placement | 时间戳位置 | string | top / bottom | bottom | | ||||
| | type | 节点类型 | string | primary / success / warning / danger / info | - | | ||||
| | color | 节点颜色 | string | hsl / hsv / hex / rgb | - | | ||||
| | size | 节点尺寸 | string | normal / large | normal | | ||||
| | icon | 节点图标 | string | — | - | | ||||
| 
 | ||||
| ### Timeline-Item Slot | ||||
| | name | 说明 | | ||||
| |------|--------| | ||||
| | — | Timeline-Item 的内容 | | ||||
| | dot | 自定义节点 | | ||||
|  | @ -243,6 +243,10 @@ | |||
|             { | ||||
|               "path": "/collapse", | ||||
|               "title": "Collapse 折叠面板" | ||||
|             }, | ||||
|             { | ||||
|               "path": "/timeline", | ||||
|               "title": "Timeline 时间线" | ||||
|             } | ||||
|           ] | ||||
|         } | ||||
|  | @ -493,6 +497,10 @@ | |||
|             { | ||||
|               "path": "/collapse", | ||||
|               "title": "Collapse" | ||||
|             }, | ||||
|             { | ||||
|               "path": "/timeline", | ||||
|               "title": "Timeline" | ||||
|             } | ||||
|           ] | ||||
|         } | ||||
|  | @ -743,6 +751,10 @@ | |||
|             { | ||||
|               "path": "/collapse", | ||||
|               "title": "Collapse" | ||||
|             }, | ||||
|             { | ||||
|               "path": "/timeline", | ||||
|               "title": "Timeline" | ||||
|             } | ||||
|           ] | ||||
|         } | ||||
|  |  | |||
|  | @ -381,7 +381,7 @@ export default { | |||
|           table.$emit(`cell-${name}`, row, column, cell, event); | ||||
|         } | ||||
|       } | ||||
|       table.$emit(`row-${name}`, row, event, column); | ||||
|       table.$emit(`row-${name}`, row, column, event); | ||||
|     }, | ||||
| 
 | ||||
|     handleExpandClick(row, e) { | ||||
|  |  | |||
|  | @ -683,6 +683,12 @@ $--footer-padding: 0 20px !default; | |||
| --------------------------*/ | ||||
| $--main-padding: 20px !default; | ||||
| 
 | ||||
| /* Timeline | ||||
| --------------------------*/ | ||||
| $--timeline-node-size-normal: 12px !default; | ||||
| $--timeline-node-size-large: 14px !default; | ||||
| $--timeline-node-color: $--border-color-light !default; | ||||
| 
 | ||||
| /* Break-point | ||||
| --------------------------*/ | ||||
| $--sm: 768px !default; | ||||
|  |  | |||
|  | @ -65,3 +65,5 @@ | |||
| @import "./aside.scss"; | ||||
| @import "./main.scss"; | ||||
| @import "./footer.scss"; | ||||
| @import "./timeline.scss"; | ||||
| @import "./timeline-item.scss"; | ||||
|  |  | |||
|  | @ -0,0 +1,86 @@ | |||
| @import "mixins/mixins"; | ||||
| @import "common/var"; | ||||
| 
 | ||||
| @include b(timeline-item) { | ||||
|   position: relative; | ||||
|   padding-bottom: 20px; | ||||
| 
 | ||||
|   @include e(wrapper) { | ||||
|     position: relative; | ||||
|     padding-left: 28px; | ||||
|     top: -3px; | ||||
|   } | ||||
| 
 | ||||
|   @include e(tail) { | ||||
|     position: absolute; | ||||
|     left: 4px; | ||||
|     height: 100%; | ||||
|     border-left: 2px solid $--timeline-node-color; | ||||
|   } | ||||
| 
 | ||||
|   @include e(icon) { | ||||
|     color: $--color-white; | ||||
|     font-size: $--font-size-small; | ||||
|   } | ||||
| 
 | ||||
|   @include e(node) { | ||||
|     position: absolute; | ||||
|     background-color: $--timeline-node-color; | ||||
|     border-radius: 50%; | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
| 
 | ||||
|     @include m(normal) { | ||||
|       left: -1px; | ||||
|       width: $--timeline-node-size-normal; | ||||
|       height: $--timeline-node-size-normal; | ||||
|     } | ||||
|     @include m(large) { | ||||
|       left: -2px; | ||||
|       width: $--timeline-node-size-large; | ||||
|       height: $--timeline-node-size-large; | ||||
|     } | ||||
| 
 | ||||
|     @include m(primary) { | ||||
|       background-color: $--color-primary; | ||||
|     } | ||||
|     @include m(success) { | ||||
|       background-color: $--color-success; | ||||
|     } | ||||
|     @include m(warning) { | ||||
|       background-color: $--color-warning; | ||||
|     } | ||||
|     @include m(danger) { | ||||
|       background-color: $--color-danger; | ||||
|     } | ||||
|     @include m(info) { | ||||
|       background-color: $--color-info; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @include e(dot) { | ||||
|     position: absolute; | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|   } | ||||
| 
 | ||||
|   @include e(content) { | ||||
|     color: $--color-text-primary; | ||||
|   } | ||||
| 
 | ||||
|   @include e(timestamp) { | ||||
|     color: $--color-text-secondary; | ||||
|     line-height: 1; | ||||
|     font-size: $--font-size-small; | ||||
| 
 | ||||
|     @include when(top) { | ||||
|       margin-bottom: 8px; | ||||
|       padding-top: 4px; | ||||
|     } | ||||
|     @include when(bottom) { | ||||
|       margin-top: 8px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,14 @@ | |||
| @import "mixins/mixins"; | ||||
| @import "common/var"; | ||||
| 
 | ||||
| @include b(timeline) { | ||||
|   margin: 0; | ||||
|   font-size: $--font-size-base; | ||||
|   list-style: none; | ||||
| 
 | ||||
|   & .el-timeline-item:last-child { | ||||
|     & .el-timeline-item__tail { | ||||
|       display: none; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,8 @@ | |||
| import ElTimelineItem from '../timeline/src/item'; | ||||
| 
 | ||||
| /* istanbul ignore next */ | ||||
| ElTimelineItem.install = function(Vue) { | ||||
|   Vue.component(ElTimelineItem.name, ElTimelineItem); | ||||
| }; | ||||
| 
 | ||||
| export default ElTimelineItem; | ||||
|  | @ -0,0 +1,8 @@ | |||
| import Timeline from './src/main'; | ||||
| 
 | ||||
| /* istanbul ignore next */ | ||||
| Timeline.install = function(Vue) { | ||||
|   Vue.component(Timeline.name, Timeline); | ||||
| }; | ||||
| 
 | ||||
| export default Timeline; | ||||
|  | @ -0,0 +1,73 @@ | |||
| <template> | ||||
|   <li class="el-timeline-item"> | ||||
|     <div class="el-timeline-item__tail"></div> | ||||
| 
 | ||||
|     <div v-if="!$slots.dot" | ||||
|       class="el-timeline-item__node" | ||||
|       :class="[ | ||||
|         `el-timeline-item__node--${size || ''}`, | ||||
|         `el-timeline-item__node--${type || ''}` | ||||
|       ]" | ||||
|       :style="{ | ||||
|         backgroundColor: color | ||||
|       }" | ||||
|     > | ||||
|       <i v-if="icon" | ||||
|         class="el-timeline-item__icon" | ||||
|         :class="icon" | ||||
|       ></i> | ||||
|     </div> | ||||
|     <div v-if="$slots.dot" class="el-timeline-item__dot"> | ||||
|       <slot name="dot"></slot> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="el-timeline-item__wrapper"> | ||||
|       <div v-if="!hideTimestamp && placement === 'top'" | ||||
|         class="el-timeline-item__timestamp is-top"> | ||||
|         {{timestamp}} | ||||
|       </div> | ||||
| 
 | ||||
|       <div class="el-timeline-item__content"> | ||||
|         <slot></slot> | ||||
|       </div> | ||||
| 
 | ||||
|       <div v-if="!hideTimestamp && placement === 'bottom'" | ||||
|         class="el-timeline-item__timestamp is-bottom"> | ||||
|         {{timestamp}} | ||||
|       </div> | ||||
|     </div> | ||||
|   </li> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'ElTimelineItem', | ||||
| 
 | ||||
|     inject: ['timeline'], | ||||
| 
 | ||||
|     props: { | ||||
|       timestamp: String, | ||||
| 
 | ||||
|       hideTimestamp: { | ||||
|         type: Boolean, | ||||
|         default: false | ||||
|       }, | ||||
| 
 | ||||
|       placement: { | ||||
|         type: String, | ||||
|         default: 'bottom' | ||||
|       }, | ||||
| 
 | ||||
|       type: String, | ||||
| 
 | ||||
|       color: String, | ||||
| 
 | ||||
|       size: { | ||||
|         type: String, | ||||
|         default: 'normal' | ||||
|       }, | ||||
| 
 | ||||
|       icon: String | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
|  | @ -0,0 +1,38 @@ | |||
| <template> | ||||
|   <ul class="el-timeline" | ||||
|     :class="{ | ||||
|       'is-reverse': reverse | ||||
|     }"> | ||||
|     <slot></slot> | ||||
|   </ul> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'ElTimeline', | ||||
| 
 | ||||
|     props: { | ||||
|       reverse: { | ||||
|         type: Boolean, | ||||
|         default: false | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     provide() { | ||||
|       return { | ||||
|         timeline: this | ||||
|       }; | ||||
|     }, | ||||
| 
 | ||||
|     watch: { | ||||
|       reverse: { | ||||
|         handler(newVal) { | ||||
|           if (newVal) { | ||||
|             this.$slots.default = [...this.$slots.default].reverse(); | ||||
|           } | ||||
|         }, | ||||
|         immediate: true | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
|  | @ -69,6 +69,8 @@ import Header from '../packages/header/index.js'; | |||
| import Aside from '../packages/aside/index.js'; | ||||
| import Main from '../packages/main/index.js'; | ||||
| import Footer from '../packages/footer/index.js'; | ||||
| import Timeline from '../packages/timeline/index.js'; | ||||
| import TimelineItem from '../packages/timeline-item/index.js'; | ||||
| import locale from 'element-ui/src/locale'; | ||||
| import CollapseTransition from 'element-ui/src/transitions/collapse-transition'; | ||||
| 
 | ||||
|  | @ -138,6 +140,8 @@ const components = [ | |||
|   Aside, | ||||
|   Main, | ||||
|   Footer, | ||||
|   Timeline, | ||||
|   TimelineItem, | ||||
|   CollapseTransition | ||||
| ]; | ||||
| 
 | ||||
|  | @ -245,5 +249,7 @@ export default { | |||
|   Header, | ||||
|   Aside, | ||||
|   Main, | ||||
|   Footer | ||||
|   Footer, | ||||
|   Timeline, | ||||
|   TimelineItem | ||||
| }; | ||||
|  |  | |||
|  | @ -0,0 +1,228 @@ | |||
| import { createVue, destroyVM } from '../util'; | ||||
| 
 | ||||
| describe('Timeline', () => { | ||||
|   let vm; | ||||
|   afterEach(() => { | ||||
|     destroyVM(vm); | ||||
|   }); | ||||
| 
 | ||||
|   it('create', () => { | ||||
|     vm = createVue({ | ||||
|       template: ` | ||||
|         <el-timeline> | ||||
|           <el-timeline-item | ||||
|             v-for="(activity, index) in activities" | ||||
|             :key="index" | ||||
|             :timestamp="activity.timestamp"> | ||||
|             {{activity.content}} | ||||
|           </el-timeline-item> | ||||
|         </el-timeline> | ||||
|       `, | ||||
|       data() { | ||||
|         return { | ||||
|           activities: [{ | ||||
|             content: '创建成功', | ||||
|             timestamp: '2018-04-11' | ||||
|           }, { | ||||
|             content: '通过审核', | ||||
|             timestamp: '2018-04-13' | ||||
|           }, { | ||||
|             content: '活动按期开始', | ||||
|             timestamp: '2018-04-15' | ||||
|           }] | ||||
|         }; | ||||
|       } | ||||
|     }, true); | ||||
|     let contentElms = vm.$el.querySelectorAll('.el-timeline-item__content'); | ||||
|     contentElms.forEach((elm, index) => { | ||||
|       expect(elm.innerText).to.equal(vm.activities[index].content); | ||||
|     }); | ||||
|     let timestampElms = vm.$el.querySelectorAll('.el-timeline-item__timestamp'); | ||||
|     timestampElms.forEach((elm, index) => { | ||||
|       expect(elm.innerText).to.equal(vm.activities[index].timestamp); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   it('reverse', done => { | ||||
|     vm = createVue({ | ||||
|       template: ` | ||||
|         <el-timeline :reverse="reverse"> | ||||
|           <el-timeline-item | ||||
|             v-for="(activity, index) in activities" | ||||
|             :key="index" | ||||
|             :timestamp="activity.timestamp"> | ||||
|             {{activity.content}} | ||||
|           </el-timeline-item> | ||||
|         </el-timeline> | ||||
|       `, | ||||
| 
 | ||||
|       data() { | ||||
|         return { | ||||
|           reverse: true, | ||||
|           activities: [{ | ||||
|             content: '创建成功', | ||||
|             timestamp: '2018-04-11' | ||||
|           }, { | ||||
|             content: '通过审核', | ||||
|             timestamp: '2018-04-13' | ||||
|           }, { | ||||
|             content: '活动按期开始', | ||||
|             timestamp: '2018-04-15' | ||||
|           }] | ||||
|         }; | ||||
|       } | ||||
|     }, true); | ||||
| 
 | ||||
|     const contentElms = vm.$el.querySelectorAll('.el-timeline-item__content'); | ||||
|     contentElms.forEach((elm, index) => { | ||||
|       expect(elm.innerText).to.equal(vm.activities[vm.activities.length - index - 1].content); | ||||
|     }); | ||||
| 
 | ||||
|     vm.reverse = false; | ||||
|     vm.$nextTick(() => { | ||||
|       const contentElms = vm.$el.querySelectorAll('.el-timeline-item__content'); | ||||
|       contentElms.forEach((elm, index) => { | ||||
|         expect(elm.innerText).to.equal(vm.activities[index].content); | ||||
|       }); | ||||
|       done(); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   it('placement', () => { | ||||
|     vm = createVue({ | ||||
|       template: ` | ||||
|         <el-timeline> | ||||
|           <el-timeline-item | ||||
|             v-for="(activity, index) in activities" | ||||
|             :key="index" | ||||
|             :timestamp="activity.timestamp" | ||||
|             :placement="activity.placement"> | ||||
|             {{activity.content}} | ||||
|           </el-timeline-item> | ||||
|         </el-timeline> | ||||
|       `, | ||||
| 
 | ||||
|       data() { | ||||
|         return { | ||||
|           activities: [{ | ||||
|             content: '创建成功', | ||||
|             timestamp: '2018-04-11', | ||||
|             placement: 'top' | ||||
|           }, { | ||||
|             content: '通过审核', | ||||
|             timestamp: '2018-04-13' | ||||
|           }, { | ||||
|             content: '活动按期开始', | ||||
|             timestamp: '2018-04-15' | ||||
|           }] | ||||
|         }; | ||||
|       } | ||||
|     }, true); | ||||
| 
 | ||||
|     const timestampElm = vm.$el.querySelectorAll('.el-timeline-item__timestamp')[0]; | ||||
|     expect(timestampElm.classList.contains('is-top')).to.true; | ||||
|   }); | ||||
| 
 | ||||
|   it('hide-timestamp', () => { | ||||
|     vm = createVue({ | ||||
|       template: ` | ||||
|         <el-timeline> | ||||
|           <el-timeline-item | ||||
|             v-for="(activity, index) in activities" | ||||
|             :key="index" | ||||
|             :timestamp="activity.timestamp" | ||||
|             :hide-timestamp="activity.hideTimestamp"> | ||||
|             {{activity.content}} | ||||
|           </el-timeline-item> | ||||
|         </el-timeline> | ||||
|       `, | ||||
| 
 | ||||
|       data() { | ||||
|         return { | ||||
|           activities: [{ | ||||
|             content: '创建成功', | ||||
|             timestamp: '2018-04-11', | ||||
|             hideTimestamp: true | ||||
|           }, { | ||||
|             content: '通过审核', | ||||
|             timestamp: '2018-04-13' | ||||
|           }, { | ||||
|             content: '活动按期开始', | ||||
|             timestamp: '2018-04-15' | ||||
|           }] | ||||
|         }; | ||||
|       } | ||||
|     }, true); | ||||
| 
 | ||||
|     const timestampElms = vm.$el.querySelectorAll('.el-timeline-item__timestamp'); | ||||
|     expect(timestampElms.length).to.equal(2); | ||||
|   }); | ||||
| 
 | ||||
|   it('color', () => { | ||||
|     vm = createVue({ | ||||
|       template: ` | ||||
|         <el-timeline> | ||||
|           <el-timeline-item | ||||
|             timestamp="2018-04-11" | ||||
|             color="#f00"> | ||||
|             创建成功 | ||||
|           </el-timeline-item> | ||||
|         </el-timeline> | ||||
|       ` | ||||
|     }, true); | ||||
| 
 | ||||
|     const nodeElm = vm.$el.querySelector('.el-timeline-item__node'); | ||||
|     expect(nodeElm.style.backgroundColor).to.equal('rgb(255, 0, 0)'); | ||||
|   }); | ||||
| 
 | ||||
|   it('type', () => { | ||||
|     vm = createVue({ | ||||
|       template: ` | ||||
|         <el-timeline> | ||||
|           <el-timeline-item | ||||
|             timestamp="2018-04-11" | ||||
|             type="primary"> | ||||
|             创建成功 | ||||
|           </el-timeline-item> | ||||
|         </el-timeline> | ||||
|       ` | ||||
|     }, true); | ||||
| 
 | ||||
|     const nodeElm = vm.$el.querySelector('.el-timeline-item__node'); | ||||
|     expect(nodeElm.classList.contains('el-timeline-item__node--primary')).to.true; | ||||
|   }); | ||||
| 
 | ||||
|   it('size', () => { | ||||
|     vm = createVue({ | ||||
|       template: ` | ||||
|         <el-timeline> | ||||
|           <el-timeline-item | ||||
|             timestamp="2018-04-11" | ||||
|             type="large"> | ||||
|             创建成功 | ||||
|           </el-timeline-item> | ||||
|         </el-timeline> | ||||
|       ` | ||||
|     }, true); | ||||
| 
 | ||||
|     const nodeElm = vm.$el.querySelector('.el-timeline-item__node'); | ||||
|     expect(nodeElm.classList.contains('el-timeline-item__node--large')).to.true; | ||||
|   }); | ||||
| 
 | ||||
|   it('icon', () => { | ||||
|     vm = createVue({ | ||||
|       template: ` | ||||
|         <el-timeline> | ||||
|           <el-timeline-item | ||||
|             timestamp="2018-04-11" | ||||
|             icon="el-icon-more"> | ||||
|             创建成功 | ||||
|           </el-timeline-item> | ||||
|         </el-timeline> | ||||
|       ` | ||||
|     }, true); | ||||
| 
 | ||||
|     const nodeElm = vm.$el.querySelector('.el-timeline-item__icon'); | ||||
|     expect(nodeElm.classList.contains('el-icon-more')).to.true; | ||||
|   }); | ||||
| }); | ||||
|  | @ -61,6 +61,8 @@ import { ElTableColumn } from './table-column' | |||
| import { ElTag } from './tag' | ||||
| import { ElTabs } from './tabs' | ||||
| import { ElTabPane } from './tab-pane' | ||||
| import { ElTimeline } from './timeline' | ||||
| import { ElTimelineItem } from './timeline-item' | ||||
| import { ElTimePicker } from './time-picker' | ||||
| import { ElTimeSelect } from './time-select' | ||||
| import { ElTooltip } from './tooltip' | ||||
|  | @ -275,6 +277,12 @@ export class TabPane extends ElTabPane {} | |||
| /** Tag Component */ | ||||
| export class Tag extends ElTag {} | ||||
| 
 | ||||
| /** Timeline Component */ | ||||
| export class Timeline extends ElTimeline {} | ||||
| 
 | ||||
| /** Timeline Item Component */ | ||||
| export class TimelineItem extends ElTimelineItem {} | ||||
| 
 | ||||
| /** TimePicker Component */ | ||||
| export class TimePicker extends ElTimePicker {} | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,20 @@ | |||
| import { ElementUIComponent } from './component' | ||||
| 
 | ||||
| export type TimelineItemPlacement = 'top' | 'bottom' | ||||
| export type TimelineItemType = 'primary' | 'success' | 'warning' | 'danger' | 'info' | ||||
| export type TimelineItemSize = 'normal' | 'large' | ||||
| 
 | ||||
| /** TimelineItem Component */ | ||||
| export declare class ElTimelineItem extends ElementUIComponent { | ||||
|   timestamp: string | ||||
| 
 | ||||
|   hideTimestamp: boolean | ||||
| 
 | ||||
|   placement: TimelineItemPlacement | ||||
| 
 | ||||
|   type: TimelineItemType | ||||
| 
 | ||||
|   size: TimelineItemSize | ||||
| 
 | ||||
|   icon: string | ||||
| } | ||||
|  | @ -0,0 +1,6 @@ | |||
| import { ElementUIComponent } from './component' | ||||
| 
 | ||||
| /** Timeline Component */ | ||||
| export declare class ElTimeline extends ElementUIComponent { | ||||
|   reverse: boolean | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	 Zhi Cun
						Zhi Cun