tm-timeline.vue 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. <template>
  2. <view class="tm-timeline">
  3. <block v-if="model=='center'">
  4. <block v-for="(item,index) in listData" :key="index">
  5. <view v-if="(index+1)%2" class="tm-timeline-item " >
  6. <view :style="{
  7. width: bwi(item)+'px',
  8. height: bwi(item)+'px'
  9. }" :class="[item['icon']?'pa-4':'',item.color?item.color:color_tmeme,`shadow-${item.color?item.color:color_tmeme}-4`,black_tmeme?'bk':'']" class=" flex-center rounded tm-timeline-jidian border-white-a-2">
  10. <tm-icons style="line-height: 0;" dense v-if="item.icon" color="white" :size="item.iconSize||24" :name="item.icon"></tm-icons>
  11. </view>
  12. <view class=" tm-timeline-item-content relative">
  13. <view :class="[`text-${(item.color?item.color:color_tmeme)}`]" v-if="item.time" class="tm-timeline-item-right pr-36 text-weight-b text-size-n text-align-right">
  14. {{item.time}}
  15. </view>
  16. <!-- <tm-divider :vertical="true" :width="4" :height="100"></tm-divider> -->
  17. <view :class="[`border-${item.borderColor?item.borderColor:borderColor}-l-1`,black_tmeme?'bk':'']" class="tm-timeline-item-right pl-36 ">
  18. <view v-if="item.title" class="mb-12 text-align-left">
  19. <text class="text-weight-b text-size-n" :class="[`text-${(item.color?item.color:color_tmeme)}`]">{{item.title}}</text>
  20. </view>
  21. <view class="text-align-left pb-24">
  22. <text class="text-size-s text-grey-darken-1">
  23. {{item.content}}
  24. </text>
  25. </view>
  26. </view>
  27. </view>
  28. </view>
  29. <view v-if="(index+1)%2==0" class="tm-timeline-item ">
  30. <view :style="{
  31. width: bwi(item)+'px',
  32. height: bwi(item)+'px'
  33. }" :class="[item['icon']?'pa-4':'',item.color?item.color:color_tmeme,`shadow-${item.color?item.color:color_tmeme}-4`,black_tmeme?'bk':'']" class="flex-center rounded tm-timeline-jidian border-white-a-2">
  34. <tm-icons style="line-height: 0;" dense v-if="item.icon" color="white" :size="item.iconSize||24" :name="item.icon"></tm-icons>
  35. </view>
  36. <view class=" tm-timeline-item-content relative">
  37. <view :class="[index!==listData.length-1?(`border-${item.borderColor?item.borderColor:borderColor}-r-1`):'',black_tmeme?'bk':'']" class="tm-timeline-item-left pr-36 ">
  38. <view v-if="item.title" class="mb-12 text-align-right">
  39. <text class="text-weight-b text-size-n" :class="[`text-${(item.color?item.color:color_tmeme)}`]">{{item.title}}</text>
  40. </view>
  41. <view class="text-align-right pb-24">
  42. <text class="text-size-s text-grey-darken-1">
  43. {{item.content}}
  44. </text>
  45. </view>
  46. </view>
  47. <view v-if="item.time" :class="[`text-${(item.color?item.color:color_tmeme)}`]" class="tm-timeline-item-right pl-36 text-weight-b text-size-n ">
  48. {{item.time}}
  49. </view>
  50. </view>
  51. </view>
  52. </block>
  53. </block>
  54. <block v-if="model=='left'">
  55. <block v-for="(item,index) in listData" :key="index">
  56. <view class="tm-timeline-item tm-timeline-item--leftDir">
  57. <view style="width: 160upx;">
  58. <view :style="{
  59. width: bwi(item)+'px',
  60. height: bwi(item)+'px'
  61. }" :class="[item['icon']?'pa-4':'',item.color?item.color:color_tmeme,`shadow-${item.color?item.color:color_tmeme}-4`,black_tmeme?'bk':'']" class="flex-center rounded tm-timeline-jidian border-white-a-2">
  62. <tm-icons style="line-height: 0;" dense v-if="item.icon" color="white" :size="item.iconSize||24" :name="item.icon"></tm-icons>
  63. </view>
  64. <view :style="{
  65. marginTop:'-'+botop(item)+'px'
  66. }" :class="[index!==listData.length-1?'tm-timeline-item-boder':'',`${item.borderColor?item.borderColor:borderColor}`,black_tmeme?'bk':'']"></view>
  67. </view>
  68. <view class=" tm-timeline-item-content relative">
  69. <view class="tm-timeline-item-left ">
  70. <slot name="content" :data="item">
  71. <view v-if="item.time" :class="['text-'+(item.color?item.color:color_tmeme)]" class="mb-0 tm-timeline-item-right text-size-s ">
  72. {{item.time}}
  73. </view>
  74. <view v-if="item.title" class="mb-12 text-align-left">
  75. <text :class="['text-'+(item.color?item.color:color_tmeme)]" class="text-weight-b text-size-n ">{{item.title}}</text>
  76. </view>
  77. <view class="text-align-left pb-24 mb-32">
  78. <text class="text-size-s text-grey-darken-1">
  79. {{item.content}}
  80. </text>
  81. </view>
  82. </slot>
  83. </view>
  84. </view>
  85. </view>
  86. </block>
  87. </block>
  88. <block v-if="model=='right'">
  89. <block v-for="(item,index) in listData" :key="index">
  90. <view class="tm-timeline-item tm-timeline-item--leftDir endright">
  91. <view class=" tm-timeline-item-content relative">
  92. <view class="tm-timeline-item-left ">
  93. <view v-if="item.time" :class="[`text-${(item.color?item.color:color_tmeme)}`]" class="mb-0 tm-timeline-item-right text-size-s text-align-right">
  94. {{item.time}}
  95. </view>
  96. <view v-if="item.title" class="mb-12 text-align-right">
  97. <text :class="[`text-${(item.color?item.color:color_tmeme)}`]" class="text-weight-b text-size-n ">{{item.title}}</text>
  98. </view>
  99. <view class="text-align-right pb-24 mb-32">
  100. <text class="text-size-s text-grey-darken-1">
  101. {{item.content}}
  102. </text>
  103. </view>
  104. </view>
  105. </view>
  106. <view style="width: 140upx;">
  107. <view :style="{
  108. width: bwi(item)+'px',
  109. height: bwi(item)+'px'
  110. }" :class="[item['icon']?'pa-4':'',item.color?item.color:color_tmeme,`shadow-${item.color?item.color:color_tmeme}-4`,black_tmeme?'bk':'']" class="flex-center rounded tm-timeline-jidian border-white-a-2">
  111. <tm-icons style="line-height: 0;" dense v-if="item.icon" color="white" :size="item.iconSize||24" :name="item.icon"></tm-icons>
  112. </view>
  113. <view :style="{
  114. marginTop:'-'+botop(item)+'px'
  115. }" :class="[index!==listData.length-1?'tm-timeline-item-boder':'',`${item.borderColor?item.borderColor:borderColor}`,black_tmeme?'bk':'']"></view>
  116. </view>
  117. </view>
  118. </block>
  119. </block>
  120. </view>
  121. </template>
  122. <script>
  123. /**
  124. * timeline 时间轴
  125. * @property {Boolean} reverse = [] 默认:false ,是否反转数据。
  126. * @property {String} border-color = [] 默认:grey-lighten-2 ,默认线的颜色。
  127. * @property {String} color = [] 默认:primary ,认主题和节点颜色如果。
  128. * @property {Number} size = [] 默认:32 ,默认的节点大小,单位upx
  129. * @property {String} model = [left|center|right] 默认:center ,时间轴的方向。
  130. * @property {Array} list = [] 默认:[] ,数据。{
  131. title:'',
  132. content:'我是内容我是内容我是内容',
  133. time:"2020年7月",
  134. color:"blue",
  135. icon:'icon-position-fill',
  136. iconSize:36,
  137. borderColor:'blue'
  138. },
  139. */
  140. import tmIcons from "@/tm-vuetify/components/tm-icons/tm-icons.vue"
  141. export default {
  142. components:{tmIcons},
  143. name: 'tm-timeline',
  144. props:{
  145. list:{
  146. type:Array,
  147. default:()=>{
  148. return [];
  149. }
  150. },
  151. // 是否反转内容
  152. reverse:{
  153. type:Boolean,
  154. default:false
  155. },
  156. // 默认线的颜色,
  157. borderColor:{
  158. type:String,
  159. default:'grey-lighten-2'
  160. },
  161. // 默认主题和节点颜色如果
  162. color:{
  163. type:String,
  164. default:'primary'
  165. },
  166. size:{
  167. type:Number,
  168. default:36
  169. },
  170. black:{
  171. type:Boolean|String,
  172. default:null
  173. },
  174. model:{
  175. type:String,
  176. default:'center' // left|center|right
  177. },
  178. // 跟随主题色的改变而改变。
  179. fllowTheme:{
  180. type:Boolean|String,
  181. default:true
  182. }
  183. },
  184. data() {
  185. return {
  186. listData:[],
  187. };
  188. },
  189. watch:{
  190. list:{
  191. deep:true,
  192. handler(){
  193. this.jsList = this.list;
  194. }
  195. }
  196. },
  197. computed:{
  198. black_tmeme: function() {
  199. if (this.black !== null) return this.black;
  200. return this.$tm.vx.state().tmVuetify.black;
  201. },
  202. color_tmeme:function(){
  203. if(this.$tm.vx.state().tmVuetify.color!==null&&this.$tm.vx.state().tmVuetify.color && this.fllowTheme){
  204. return this.$tm.vx.state().tmVuetify.color;
  205. }
  206. return this.color;
  207. },
  208. jsList:{
  209. get:function(){
  210. return this.listData;
  211. },
  212. set:function(val){
  213. if(this.reverse){
  214. this.listData = this.list.reverse();
  215. }else{
  216. this.listData = this.list;
  217. }
  218. }
  219. }
  220. },
  221. mounted() {
  222. this.jsList = this.list;
  223. },
  224. methods: {
  225. botop(d){
  226. return uni.upx2px(d.size+8||32)
  227. },
  228. bwi(item){
  229. if(!item||!item['size']){
  230. return uni.upx2px(this.size||24)
  231. }else if(item['size']){
  232. return uni.upx2px(item['size']||24)
  233. }
  234. return uni.upx2px(24)
  235. }
  236. }
  237. };
  238. </script>
  239. <style lang="less" scoped>
  240. .tm-timeline {
  241. .tm-timeline-item {
  242. .tm-timeline-item-left,
  243. .tm-timeline-item-right {
  244. width: 200upx;
  245. flex-shrink: 0;
  246. // transform: translateY(-34upx);
  247. }
  248. .tm-timeline-item-content{
  249. display: flex;
  250. justify-content: center;
  251. align-items: flex-start;
  252. align-content: flex-start;
  253. }
  254. .tm-timeline-jidian {
  255. margin: auto;
  256. }
  257. &.tm-timeline-item--leftDir{
  258. display: flex;
  259. flex-flow: row;
  260. &.endright{
  261. justify-content: flex-end;
  262. }
  263. .tm-timeline-item-left,
  264. .tm-timeline-item-right {
  265. width:auto;
  266. max-width: 400upx;
  267. }
  268. .tm-timeline-item-boder{
  269. height: 100%;
  270. width: 1px;margin: auto;
  271. }
  272. .tm-timeline-jidian {
  273. position: relative;
  274. margin: auto;
  275. z-index: 2;
  276. }
  277. .tm-timeline-item-content{
  278. display: flex;
  279. justify-content: flex-start;
  280. align-items: flex-start;
  281. align-content: flex-start;
  282. }
  283. }
  284. }
  285. }
  286. </style>