You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
9.4 KiB
Vue

1 year ago
<template>
<view class="tm-timeline">
<block v-if="model=='center'">
<block v-for="(item,index) in listData" :key="index">
<view v-if="(index+1)%2" class="tm-timeline-item " >
<view :style="{
width: bwi(item)+'px',
height: bwi(item)+'px'
}" :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">
<tm-icons style="line-height: 0;" dense v-if="item.icon" color="white" :size="item.iconSize||24" :name="item.icon"></tm-icons>
</view>
<view class=" tm-timeline-item-content relative">
<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">
{{item.time}}
</view>
<!-- <tm-divider :vertical="true" :width="4" :height="100"></tm-divider> -->
<view :class="[`border-${item.borderColor?item.borderColor:borderColor}-l-1`,black_tmeme?'bk':'']" class="tm-timeline-item-right pl-36 ">
<view v-if="item.title" class="mb-12 text-align-left">
<text class="text-weight-b text-size-n" :class="[`text-${(item.color?item.color:color_tmeme)}`]">{{item.title}}</text>
</view>
<view class="text-align-left pb-24">
<text class="text-size-s text-grey-darken-1">
{{item.content}}
</text>
</view>
</view>
</view>
</view>
<view v-if="(index+1)%2==0" class="tm-timeline-item ">
<view :style="{
width: bwi(item)+'px',
height: bwi(item)+'px'
}" :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">
<tm-icons style="line-height: 0;" dense v-if="item.icon" color="white" :size="item.iconSize||24" :name="item.icon"></tm-icons>
</view>
<view class=" tm-timeline-item-content relative">
<view :class="[index!==listData.length-1?(`border-${item.borderColor?item.borderColor:borderColor}-r-1`):'',black_tmeme?'bk':'']" class="tm-timeline-item-left pr-36 ">
<view v-if="item.title" class="mb-12 text-align-right">
<text class="text-weight-b text-size-n" :class="[`text-${(item.color?item.color:color_tmeme)}`]">{{item.title}}</text>
</view>
<view class="text-align-right pb-24">
<text class="text-size-s text-grey-darken-1">
{{item.content}}
</text>
</view>
</view>
<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 ">
{{item.time}}
</view>
</view>
</view>
</block>
</block>
<block v-if="model=='left'">
<block v-for="(item,index) in listData" :key="index">
<view class="tm-timeline-item tm-timeline-item--leftDir">
<view style="width: 160upx;">
<view :style="{
width: bwi(item)+'px',
height: bwi(item)+'px'
}" :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">
<tm-icons style="line-height: 0;" dense v-if="item.icon" color="white" :size="item.iconSize||24" :name="item.icon"></tm-icons>
</view>
<view :style="{
marginTop:'-'+botop(item)+'px'
}" :class="[index!==listData.length-1?'tm-timeline-item-boder':'',`${item.borderColor?item.borderColor:borderColor}`,black_tmeme?'bk':'']"></view>
</view>
<view class=" tm-timeline-item-content relative">
<view class="tm-timeline-item-left ">
<slot name="content" :data="item">
<view v-if="item.time" :class="['text-'+(item.color?item.color:color_tmeme)]" class="mb-0 tm-timeline-item-right text-size-s ">
{{item.time}}
</view>
<view v-if="item.title" class="mb-12 text-align-left">
<text :class="['text-'+(item.color?item.color:color_tmeme)]" class="text-weight-b text-size-n ">{{item.title}}</text>
</view>
<view class="text-align-left pb-24 mb-32">
<text class="text-size-s text-grey-darken-1">
{{item.content}}
</text>
</view>
</slot>
</view>
</view>
</view>
</block>
</block>
<block v-if="model=='right'">
<block v-for="(item,index) in listData" :key="index">
<view class="tm-timeline-item tm-timeline-item--leftDir endright">
<view class=" tm-timeline-item-content relative">
<view class="tm-timeline-item-left ">
<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">
{{item.time}}
</view>
<view v-if="item.title" class="mb-12 text-align-right">
<text :class="[`text-${(item.color?item.color:color_tmeme)}`]" class="text-weight-b text-size-n ">{{item.title}}</text>
</view>
<view class="text-align-right pb-24 mb-32">
<text class="text-size-s text-grey-darken-1">
{{item.content}}
</text>
</view>
</view>
</view>
<view style="width: 140upx;">
<view :style="{
width: bwi(item)+'px',
height: bwi(item)+'px'
}" :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">
<tm-icons style="line-height: 0;" dense v-if="item.icon" color="white" :size="item.iconSize||24" :name="item.icon"></tm-icons>
</view>
<view :style="{
marginTop:'-'+botop(item)+'px'
}" :class="[index!==listData.length-1?'tm-timeline-item-boder':'',`${item.borderColor?item.borderColor:borderColor}`,black_tmeme?'bk':'']"></view>
</view>
</view>
</block>
</block>
</view>
</template>
<script>
/**
* timeline 时间轴
* @property {Boolean} reverse = [] 默认false ,是否反转数据
* @property {String} border-color = [] 默认grey-lighten-2 ,默认线的颜色
* @property {String} color = [] 默认primary ,认主题和节点颜色如果
* @property {Number} size = [] 默认32 ,默认的节点大小单位upx
* @property {String} model = [left|center|right] 默认center ,时间轴的方向
* @property {Array} list = [] 默认[] ,数据{
title:'',
content:'我是内容我是内容我是内容',
time:"2020年7月",
color:"blue",
icon:'icon-position-fill',
iconSize:36,
borderColor:'blue'
},
*/
import tmIcons from "@/tm-vuetify/components/tm-icons/tm-icons.vue"
export default {
components:{tmIcons},
name: 'tm-timeline',
props:{
list:{
type:Array,
default:()=>{
return [];
}
},
// 是否反转内容
reverse:{
type:Boolean,
default:false
},
// 默认线的颜色,
borderColor:{
type:String,
default:'grey-lighten-2'
},
// 默认主题和节点颜色如果
color:{
type:String,
default:'primary'
},
size:{
type:Number,
default:36
},
black:{
type:Boolean|String,
default:null
},
model:{
type:String,
default:'center' // left|center|right
},
// 跟随主题色的改变而改变。
fllowTheme:{
type:Boolean|String,
default:true
}
},
data() {
return {
listData:[],
};
},
watch:{
list:{
deep:true,
handler(){
this.jsList = this.list;
}
}
},
computed:{
black_tmeme: function() {
if (this.black !== null) return this.black;
return this.$tm.vx.state().tmVuetify.black;
},
color_tmeme:function(){
if(this.$tm.vx.state().tmVuetify.color!==null&&this.$tm.vx.state().tmVuetify.color && this.fllowTheme){
return this.$tm.vx.state().tmVuetify.color;
}
return this.color;
},
jsList:{
get:function(){
return this.listData;
},
set:function(val){
if(this.reverse){
this.listData = this.list.reverse();
}else{
this.listData = this.list;
}
}
}
},
mounted() {
this.jsList = this.list;
},
methods: {
botop(d){
return uni.upx2px(d.size+8||32)
},
bwi(item){
if(!item||!item['size']){
return uni.upx2px(this.size||24)
}else if(item['size']){
return uni.upx2px(item['size']||24)
}
return uni.upx2px(24)
}
}
};
</script>
<style lang="less" scoped>
.tm-timeline {
.tm-timeline-item {
.tm-timeline-item-left,
.tm-timeline-item-right {
width: 200upx;
flex-shrink: 0;
// transform: translateY(-34upx);
}
.tm-timeline-item-content{
display: flex;
justify-content: center;
align-items: flex-start;
align-content: flex-start;
}
.tm-timeline-jidian {
margin: auto;
}
&.tm-timeline-item--leftDir{
display: flex;
flex-flow: row;
&.endright{
justify-content: flex-end;
}
.tm-timeline-item-left,
.tm-timeline-item-right {
width:auto;
max-width: 400upx;
}
.tm-timeline-item-boder{
height: 100%;
width: 1px;margin: auto;
}
.tm-timeline-jidian {
position: relative;
margin: auto;
z-index: 2;
}
.tm-timeline-item-content{
display: flex;
justify-content: flex-start;
align-items: flex-start;
align-content: flex-start;
}
}
}
}
</style>