Vue3时间轴(Timeline)

70 篇文章 4 订阅
68 篇文章 3 订阅

Vue2时间轴(Timeline)

可自定义设置以下属性:

  • 时间轴内容数组(timelineData),必传,类型:Array<{desc: string, color?: string}>,默认 []

  • 时间轴区域总宽度(width),类型:number|string,单位px,默认 '100%'

  • 时间线样式(lineStyle),类型: 'solid'|'dashed'|'dotted',默认 'solid'

  • 通过设置 mode 可以改变时间轴和内容的相对位置(mode),类型:'left'|'center'|'right',默认 'left

  • 当 mode 为 center 时,内容交替展现,内容从左边(left)开始或者右边(right)开始展现(position),类型:'left'|'right',默认:'left'

时间轴内容数组(TimelineData):

  • desc:文字描述,必传,支持 string | slot

  • color:圆圈颜色,可选四种预置颜色:blue | green | red | gray 或者 使用颜色值,支持 string

效果如下图:在线预览

①创建时间轴组件Timeline.vue:

<script setup lang="ts">
import { ref, computed, watchEffect } from 'vue'
enum ColorStyle { // 颜色主题对象
  blue = '#1677ff',
  green = '#52c41a',
  red = '#ff4d4f',
  gray = '#00000040'
}
interface Data {
  desc: string // 文字描述 string | slot
  color?: string // 圆圈颜色,可选四种预置颜色:blue | green | red | gray 或者 使用颜色值,默认值 blue
}
interface Props {
  timelineData: Data[] // 时间轴内容数组
  width?: number|string // 时间轴区域总宽度,单位px
  lineStyle?: 'solid'|'dashed'|'dotted' // 时间线样式
  mode?: 'left'|'center'|'right' // 通过设置 mode 可以改变时间轴和内容的相对位置
  position?: 'left'|'right' // 当 mode 为 center 时,内容交替展现,内容从左边(left)开始或者右边(right)开始展现
}
const props = withDefaults(defineProps<Props>(), {
  timelineData: () => [],
  width: '100%',
  lineStyle: 'solid',
  mode: 'left',
  position: 'left'
})
const desc = ref()
const dotsHeight = ref<string[]>([])
const totalWidth = computed(() => {
  if (typeof props.width === 'number') {
    return props.width + 'px'
  } else {
    return props.width
  }
})
const len = computed(() => {
  return props.timelineData.length
})
function getDotsHeight () {
  for (let n = 0; n < len.value; n++) {
    dotsHeight.value[n] = getComputedStyle(desc.value[n].firstElementChild || desc.value[n], null).getPropertyValue('line-height')
  }
}
watchEffect(() => {
  getDotsHeight()
}, { flush: 'post' })
watchEffect(() => {
  if (props.mode === 'center') {
    for (let n = 0; n < len.value; n++) {
      if ((n + 1) % 2) { // odd
        if (props.position === 'left') {
          desc.value[n].classList.add('alternate-left-desc')
        } else {
          desc.value[n].classList.add('alternate-right-desc')
        }
      } else { // even
        if (props.position === 'left') {
          desc.value[n].classList.add('alternate-right-desc')
        } else {
          desc.value[n].classList.add('alternate-left-desc')
        }
      }
    }
  }
}, { flush: 'post' })
</script>
<template>
  <div class="m-timeline-area" :style="`width: ${totalWidth};`">
    <div class="m-timeline">
      <div
        :class="['m-timeline-item', {'last': index === timelineData.length - 1}]"
        v-for="(data, index) in timelineData" :key="index">
        <span :class="`u-tail ${mode}-tail`" :style="`border-left-style: ${lineStyle};`"></span>
        <div :class="`m-dot ${mode}-dot`" :style="`height: ${dotsHeight[index]}`">
          <slot name="dot" :index="index">
            <span class="u-dot" v-if="data.color === 'red'" :style="{borderColor: ColorStyle.red}"></span>
            <span class="u-dot" v-else-if="data.color === 'gray'" :style="{borderColor: ColorStyle.gray}"></span>
            <span class="u-dot" v-else-if="data.color === 'green'" :style="{borderColor: ColorStyle.green}"></span>
            <span class="u-dot" v-else-if="data.color === 'blue'" :style="{borderColor: ColorStyle.blue}"></span>
            <span class="u-dot" v-else :style="{borderColor: data.color || ColorStyle.blue}"></span>
          </slot>
        </div>
        <div ref="desc" :class="`u-desc ${mode}-desc`">
          <slot name="desc" :index="index">{{ data.desc || '--' }}</slot>
        </div>
      </div>
    </div>
  </div>
</template>
<style lang="less" scoped>
.m-timeline-area {
  .m-timeline {
    .m-timeline-item {
      position: relative;
      padding-bottom: 30px;
      .u-tail {
        position: absolute;
        top: 12px;
        width: 0;
        height: 100%;
        border-left-width: 2px;
        border-left-color: #e8e8e8;
      }
      .left-tail {
        left: 5px;
      }
      .center-tail {
        left: 0;
        right: 0;
        margin: 0 auto;
      }
      .right-tail {
        right: 5px;
      }
      .m-dot {
        position: absolute;
        display: flex;
        align-items: center;
        .u-dot {
          display: inline-block;
          width: 12px;
          height: 12px;
          border-width: 2px;
          border-style: solid;
          border-radius: 50%;
          background: #FFF;
        }
      }
      .left-dot {
        left: 6px;
        transform: translateX(-50%);
      }
      .center-dot {
        left: 50%;
        transform: translateX(-50%);
      }
      .right-dot {
        right: 6px;
        transform: translateX(50%);
      }
      .u-desc {
        font-size: 14px;
        line-height: 1.5714285714285714;
        word-break: break-all;
      }
      .left-desc {
        margin-left: 25px;
      }
      .center-desc {
        width: calc(50% - 12px);
      }
      .alternate-left-desc {
        text-align: end;
      }
      .alternate-right-desc {
        margin-left: calc(50% + 12px);
      }
      .right-desc {
        margin-right: 25px;
        text-align: end;
      }
    }
    .last {
      .u-tail {
        display: none;
      }
    }
  }
}
</style>

②在要使用的页面引入:

<script setup lang="ts">
import Timeline from './Timeline.vue'
import { ref } from 'vue'

const timelineData = ref([
  {
    desc: 'Create a services site 2023-05-24',
    color: 'green'
  },
  {
    desc: 'Solve initial network problems 1 Solve initial network problems 2 2023-05-24',
    color: 'red'
  },
  {
    desc: 'Technical testing 2023-05-24',
    color: 'blue'
  },
  {
    desc: 'Network problems being solved 2023-05-24'
  },
  {
    desc: 'Network problems being solved 2',
    color: 'gray'
  }
])
</script>
<template>
  <div>
    <h1>Timeline 时间轴</h1>
    <h2 class="mt30 mb10">基本使用</h2>
    <Timeline :timeline-data="timelineData" />
    <h2 class="mb10">自定义样式</h2>
    <Timeline :timeline-data="timelineData">
      <template #dot="{ index }">
        <span class="big-dot" v-if="index===2"></span>
        <svg focusable="false" v-if="index===3" class="u-icon" data-icon="clock-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path><path d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"></path></svg>
      </template>
      <template #desc="{ index }">
        <p class="desc" v-if="index===2">Create a services site</p>
      </template>
    </Timeline>
    <h2 class="mb10">使用虚线</h2>
    <Timeline :timeline-data="timelineData" line-style="dashed" />
    <h2 class="mb10">右侧时间轴点</h2>
    <Timeline :timeline-data="timelineData" mode="right" :width="500" />
    <h2 class="mb10">中间时间轴点</h2>
    <h3 class="mb10">内容从左边开始交替展现</h3>
    <Timeline :timeline-data="timelineData" mode="center" :width="500">
      <template #dot="{ index }">
        <span class="big-dot" v-if="index===2"></span>
      </template>
    </Timeline>
    <h3 class="mb10">内容从右边开始交替展现</h3>
    <Timeline :timeline-data="timelineData" mode="center" position="right" :width="500">
      <template #dot="{ index }">
        <span class="big-dot" v-if="index===2"></span>
      </template>
    </Timeline>
  </div>
</template>
<style lang="less" scoped>
.big-dot {
  display: inline-block;
  width: 18px;
  height: 18px;
  border: 4px solid #1677ff;
  border-radius: 50%;
  background: #FFF;
}
.u-icon {
  fill: #1668dc;
  background: #fff;
  border-radius: 50%;
}
.desc {
  font-size: 16px;
  font-weight: 500;
}
</style>
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Vue3 Timeline 时间线实现会拐弯的时间轴相对于普通的时间线来说更加有趣和独特。在实现这种时间轴时,我们可以使用 Vue3 的组件化开发方式来创建一个可重复使用的时间线组件。 首先,我们需要创建一个 TimeNode(时间节点)组件,用来表示每个时间点。我们可以为每个节点设置一个时间和一个事件描述。时间节点可以通过计算属性或者接收传递的属性来设定其位置。 接下来,在时间线组件中,我们需要创建一个数组来存储时间节点。我们可以使用 v-for 指令来遍历这个数组,并将每个时间节点渲染到视图中。 然后,我们可以使用 CSS 来为时间节点添加样式,使其能够正确地显示出拐弯的效果。我们可以为时间节点设置不同的样式类,然后在 CSS 中定义这些样式类的样式规则,来实现时间轴的拐弯效果。 最后,我们可以根据时间节点的数量和位置,计算出时间轴的长度和位置,然后通过 CSS 来设置时间轴的样式,使其正确地显示出拐弯的时间轴效果。 通过以上的步骤,我们就可以实现一个拐弯的时间轴组件。这个组件可以根据需要接收传递的属性,可以根据时间节点的数量和位置来自动计算出时间轴的样式,使其能够正确地显示出拐弯的效果。 总之,Vue3 Timeline 时间线实现会拐弯的时间轴,通过使用 Vue3 的组件化开发方式,结合计算属性、遍历数组、添加样式和计算位置等技巧,可以比较容易地实现出一个有趣和独特的时间轴组件。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值