简易版纵向时间轴组件

效果一

在这里插入图片描述

实现一个这样的功能其实不难,下面直接贴代码。但是案例中的气泡边框的三角形会有一个可能被忽视的问题。我们实现三角形的带边框的效果其实就是由两个三角形组成,紫色的三角形和白色的三角形叠加实现。如何实现一个三角形(下面示例把绿色当做白色)
在这里插入图片描述
把背景去掉,两个三角形重叠,紫色部分就是我们需要的气泡角。
在这里插入图片描述

因为我们要保证紫色部分的宽度(也就是下图黄色箭头的距离)是和我们气泡边框的宽度一致为2的话,我们就要求等腰直角三角形的斜边长度就是我们绿色三角形偏移的距离:2px / cos(45deg)

在这里插入图片描述
大部分人可能直接设置偏移2px,下面我来展示一下一个是通过计算得出来的偏移值(图1),一个是直接设置2px偏移(图2)
在这里插入图片描述
在这里插入图片描述

代码

<template>
  <ul class="timeline-wrapper">
    <li class="timeline-wrapper-item" v-for="item in operationList" :key="item.id">
      <div class="out-circle">
        <div class="in-circle"></div>
      </div>
      <div class="timeline-content">
        <div class="timeline-content_box">
          <div class="box-title">{{ item.name }}</div>
          <div class="box-desc">{{ item.remark }}</div>
          <div class="box-date">{{ item.createTime }}</div>
        </div>
      </div>
    </li>
  </ul>
</template>

<script lang="ts">
  import { defineComponent } from 'vue';

  export default defineComponent({
    name: 'OperationRecords',
    components: {},
    props: {
      operationList: {
        type: Array,
        default() {
          return [];
        },
      },
    },
    setup(props) {
      return {};
    },
  });
</script>

<style scoped lang="less">
  .timeline-wrapper {
    list-style: none;
    margin: 0;
    margin-top: 20px;
    padding: 0;

    &-item {
      position: relative;
      margin-left: 16px;
      border-left: 2px solid #ededed;
      &:last-child {
        border-left: 2px solid transparent !important;
      }
      &:first-child {
        border-left: 2px solid #bfb9d8 !important;
      }
      &:not(:first-child) {
        .out-circle {
          background: rgba(153, 153, 153, 0.1) !important;
          box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1) !important;
          .in-circle {
            background: rgba(153, 153, 153, 1) !important;
            box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1) !important;
          }
        }

        .timeline-content {
          &_box {
            border: 2px solid #ededed !important;
            &:before {
              border-color: transparent #ededed transparent transparent !important;
            }
          }
        }
      }

      .out-circle {
        position: absolute;
        top: -8px;
        left: -9px;
        width: 16px;
        height: 16px;
        background: rgba(113, 101, 163, 0.1);
        box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1);
        /*opacity: 0.1;*/
        border-radius: 50%;
        display: flex;
        align-items: center;

        .in-circle {
          width: 8px;
          height: 8px;
          margin: 0 auto;
          background: rgba(113, 101, 163, 1);
          border-radius: 50%;
          box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1);
        }
      }

      .timeline-content {
        position: relative;
        top: -20px;
        padding: 0 0 20px 20px;
        &_box {
          position: relative;
          border: 2px solid #bfb9d8;
          border-radius: 8px;
          padding: 10px;
          &:before {
            /*伪元素必须添加content*/
            content: '';
            width: 0;
            height: 0;
            overflow: hidden;
            display: block;
            border-width: 10px;
            border-color: transparent #bfb9d8 transparent transparent;
            position: absolute;
            top: 10px;
            left: -20px;
            z-index: 1;
          }
          &:after {
            content: '';
            width: 0;
            height: 0;
            overflow: hidden;
            display: block;
            border-width: 10px;
            border-color: transparent #fff transparent transparent;
            position: absolute;
            top: 10px;
            left: calc(-20px + 2px / cos(45deg));
            z-index: 2;
          }

          .box-title {
            font-size: 14px;
            word-break: break-all;
            margin-bottom: 10px;
            color: #333;
            font-weight: 500;
          }

          .box-date {
            font-size: 14px;
            color: #999999;
          }
          .box-desc {
            font-size: 16px;
            color: #999999;
          }
        }
      }
    }
  }
</style>

</style>

效果二

在这里插入图片描述

代码

<template>
  <ul class="timeline-wrapper">
    <li class="timeline-wrapper-item" v-for="item in operationList" :key="item.id">
      <div class="timeline-date">{{ item.createTime }}</div>
      <div class="out-circle">
        <div class="in-circle"></div>
      </div>
      <div class="timeline-content">
        <div class="timeline-content_box">
          <div class="box-title">{{ item.name }}</div>
          <div class="box-desc">{{ item.remark }}</div>
        </div>
      </div>
    </li>
  </ul>
</template>

<script lang="ts">
  import { defineComponent } from 'vue';

  export default defineComponent({
    name: 'OperationRecords',
    components: {},
    props: {
      operationList: {
        type: Array,
        default() {
          return [];
        },
      },
    },
    setup(props) {
      return {};
    },
  });
</script>

<style scoped lang="less">
  .timeline-wrapper {
    list-style: none;
    margin: 0;
    margin-top: 20px;
    padding: 0;

    &-item {
      position: relative;
      margin-left: 16px;
      left: 100px;
      border-left: 2px solid #ededed;
      &:last-child {
        border-left: 2px solid transparent !important;
      }
      &:first-child {
        border-left: 2px solid #bfb9d8 !important;
      }
      &:not(:first-child) {
        .out-circle {
          background: rgba(153, 153, 153, 0.1) !important;
          box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1) !important;
          .in-circle {
            background: rgba(153, 153, 153, 1) !important;
            box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1) !important;
          }
        }

        .timeline-content {
          &_box {
            border: 2px solid #ededed !important;
            &:before {
              border-color: transparent #ededed transparent transparent !important;
            }
          }
        }
      }

      .out-circle {
        position: absolute;
        top: -8px;
        left: -9px;
        width: 16px;
        height: 16px;
        background: rgba(113, 101, 163, 0.1);
        box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1);
        /*opacity: 0.1;*/
        border-radius: 50%;
        display: flex;
        align-items: center;

        .in-circle {
          width: 8px;
          height: 8px;
          margin: 0 auto;
          background: rgba(113, 101, 163, 1);
          border-radius: 50%;
          box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1);
        }
      }

      .timeline-date {
        width: 100px;
        height: 50px;
        //background: lightpink;
        position: absolute;
        top: -8px;
        left: -119px;
        font-size: 14px;
        color: #999999;
        text-align: right;
      }

      .timeline-content {
        position: relative;
        top: -20px;
        padding: 0 0 20px 20px;
        width: calc(100% - 100px);
        &_box {
          position: relative;
          border: 2px solid #bfb9d8;
          border-radius: 8px;
          padding: 10px;
          &:before {
            /*伪元素必须添加content*/
            content: '';
            width: 0;
            height: 0;
            overflow: hidden;
            display: block;
            border-width: 10px;
            border-color: transparent #bfb9d8 transparent transparent;
            position: absolute;
            top: 10px;
            left: -20px;
            z-index: 1;
          }
          &:after {
            content: '';
            width: 0;
            height: 0;
            overflow: hidden;
            display: block;
            border-width: 10px;
            border-color: transparent #fff transparent transparent;
            position: absolute;
            top: 10px;
            left: calc(-20px + 2px / cos(45deg));
            z-index: 2;
          }

          .box-title {
            font-size: 14px;
            word-break: break-all;
            margin-bottom: 10px;
            color: #333;
            font-weight: 500;
          }
          
          .box-desc {
            font-size: 16px;
            color: #999999;
          }
        }
      }
    }
  }
</style>

组件使用

<template>
  <div>
     <OperationRecords :operationList="operationList" />
  </div>
</template>

<script lang="ts">
  import { defineComponent, ref } from 'vue';
  import OperationRecords from './OperationRecords.vue';
  export default defineComponent({
    components: {
      OperationRecords,
    },
    setup() {
      const operationList = ref([
        {
          id: 1,
          name: '芍药',
          createTime: '2023-05-16 12:20:13',
          remark: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1',
        },
        {
          id: 2,
          name: '茉莉',
          createTime: '2023-05-14 14:56:25',
          remark: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX2',
        },
        {
          id: 3,
          name: '芦苇',
          createTime: '2023-05-10 08:23:45',
          remark:
            'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX3',
        },
        {
          id: 4,
          name: '牡丹',
          createTime: '2023-05-03 19:02:37',
          remark: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX4',
        },
      ]);

      return {
        operationList,
      };
    },
  });
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HTML纵向时间轴的代码可以参考以下示例: ```html <!DOCTYPE html> <html> <head> <title>纵向时光轴</title> <style> /* 样式 */ .jazz-timeline-wrapper { padding: 20px; background-color: #f5f5f5; } .jazz-timeline { position: relative; } .timeline__item { position: relative; margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #ccc; } .timeline__item-bg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: #f5f5f5; } .timeline__item-content { margin-left: 100px; padding-left: 20px; } /* 样式结束 */ </style> </head> <body> <div class="jazz-timeline-wrapper"> <div class="jazz-timeline"> <div class="timeline__item"> <div class="timeline__item-bg"></div> <div class="timeline__item-content"> <h3>时间点标题1</h3> <p>时间点1的内容</p> </div> </div> <div class="timeline__item"> <div class="timeline__item-bg"></div> <div class="timeline__item-content"> <h3>时间点标题2</h3> <p>时间点2的内容</p> </div> </div> <!-- 其他时间点 --> </div> </div> </body> </html> ``` 在上述代码中,可以使用`.jazz-timeline-wrapper`包裹整个时间轴,`.jazz-timeline`作为时间轴的容器。每个时间点使用`.timeline__item`来定义,并在其中添加`.timeline__item-bg`和`.timeline__item-content`来设置背景和内容。根据需要可以添加更多时间点,并在`.timeline__item-content`中自定义标题和内容。可以根据需求进行样式修改,例如改变颜色、添加单边时间轴等。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值