Vue.js implements timeline function

Vue.js implements timeline function

This article shares the specific code of Vue.js to implement the timeline function for your reference. The specific content is as follows

GitHub

Timeline component package

Main.js

<template>
  <div class="timeline-main">
    <div class="timeline-axis">
      <div class="axis-item"
        v-for="(time, index) in dateTimes"
        :key="index">
        <div class="axis-item-tick"
          :class="{ 'axis-item-tick-active': index === highlightIndex }"
          @mouseenter="hoverIndex = index"
          @mouseleave="hoverIndex = -1"
          @click="tickClick(time, index)">
        </div>
        <div class="axis-item-label"
          v-if="dateTimeIndexes.indexOf(index) >= 0">
          {{ time }}</div>
        <div class="axis-item-tip"
          v-if="index === highlightIndex || index === hoverIndex">
          {{ time }}</div>
      </div>
    </div>
    <div class="timeline-control">
      <i class="menu-icon icon-left"
        :class="{'menu-icon-disabled': playing}"
        @click="backward"></i>
      <i class="menu-icon"
        :class="{'icon-play': !playing, 'icon-pause': playing}"
        @click="togglePlay"
        @mouseleave="hoverIndex = -1"></i>
      <i class="menu-icon icon-right"
        :class="{'menu-icon-disabled': playing}"
        @click="forward"></i>
      <i class="menu-icon icon-up"
        :class="{'menu-icon-disabled': playing}"
        @click="speedSlow"></i>
      <i
        class="menu-icon speed">{{ options.speed }}</i>
      <i class="menu-icon icon-down"
        :class="{'menu-icon-disabled': playing}"
        @click="speedQuick"></i>
    </div>
  </div>
</template>
<script>
import { dateFormat } from '../util/formatdate.js' // Date format export default {
  data() {
    return {
      intervalTimer: null, // timer dateTimeIndexes: [], // date list playing: false, // play activeIndex: 0, // current time position hoverIndex: 0 // time position when the mouse moves in }
  },
  props: {
    options:
      type: Object,
      default() {
        return {}
      }
    },
    dateTimes: {
      type: Array,
      default() {
        return []
      }
    },
    interval: {
      type: Number,
      default() {
        return 100
      }
    }
  },
  computed: {
    highlightIndex() {
      return (
        (this.activeIndex === -1 && this.dateTimes.length - 1) ||
        this.activeIndex
      )
    }
  },
  watch:
    options:
      handler() {
        this.renderTimeline()
      },
      deep: true
    },
    playing() {
      if (this.playing) {
        this.intervalTimer = setInterval(() => {
          this.activeIndex = (this.activeIndex + 1) % this.dateTimes.length
        }, this.options.speed * 1000)
      } else {
        if (this.intervalTimer) {
          clearInterval(this.intervalTimer)
          this.intervalTimer = null
        }
      }
    },
    activeIndex() {
      const time = this.dateTimes[this.activeIndex].split(' ')[0]
      this.$emit('getDateFun', time)
    }
  },
  mounted() {
    this.renderTimeline()
    let that = this
    window.onresize = function () {
      that.renderTimeline()
    }
  },
  filters:
    formatDatetime(dateTime) {
      dateTime = dateFormat(dateTime, 'MM.dd')
      return dateTime
    }
  },
  methods: {
    /**
     * @name: Initialize timeline*/
    renderTimeline() {
      // Timeline width const timelineWidth = this.$el.offsetWidth - 40
      //Number of dates const dateTimesSize = this.dateTimes.length
      // If all the time is displayed, the ideal width of the timeline const dateTimesWidth = dateTimesSize * this.interval
      // If the width of the timeline is less than the ideal width if (timelineWidth >= dateTimesWidth) {
        this.dateTimeIndexes = this.dateTimes.map((dateTime, index) => {
          return index
        })
        return
      }
      // How many date ticks can the current timeline width accommodate at most const maxTicks = Math.floor(timelineWidth / this.interval)
      // Number of interval ticks const gapTicks = Math.floor(dateTimesSize / maxTicks)
      // Record the date index to be displayed this.dateTimeIndexes = []
      for (let t = 0; t <= maxTicks; t++) {
        this.dateTimeIndexes.push(t * gapTicks)
      }
      const len ​​= this.dateTimeIndexes.length
      // The last item needs special handling if (len > 0) {
        const lastIndex = this.dateTimeIndexes[len - 1]
        if (lastIndex + gapTicks > dateTimesSize - 1) {
          this.dateTimeIndexes[len - 1] = dateTimesSize - 1
        } else {
          this.dateTimeIndexes.push(dateTimesSize - 1)
        }
      }
    },

    /**
     * @name: click scale * @param {time}
     * @param {index}
     */
    tickClick(time, index) {
      if (this.playing) {
        return
      }
      this.activeIndex = index
    },

    /**
     * @name: Play and Pause */
    togglePlay() {
      this.playing = !this.playing
    },

    /**
     * @name: time goes back one day*/
    backward() {
      if (this.playing) {
        return
      }
      this.activeIndex = this.activeIndex - 1
      if (this.activeIndex === -1) {
        this.activeIndex = this.dateTimes.length - 1
      }
    },

    /**
     * @name: Time advances one day*/
    forward() {
      if (this.playing) {
        return
      }
      this.activeIndex = (this.activeIndex + 1) % this.dateTimes.length
    },

    /**
     * @name: slow down */
    speedSlow() {
      if (this.playing || this.options.speed >= this.options.speedMax) {
        return
      }
      this.options.speed = this.options.speed + 1
    },

    /**
     * @name: Speed ​​up */
    speedQuick() {
      if (this.playing || this.options.speed <= 1) {
        return
      }
      this.options.speed = this.options.speed - 1
    }
  }
}
</script>
<style scoped lang="scss">
.timeline-main {
  padding: 10px;
  box-sizing: border-box;
  .timeline-axis {
    position: relative;
    display: flex;
    justify-content: space-around;
    padding: 8px 0;
    &::before {
      content: '';
      width: 100%;
      height: 10px;
      position: absolute;
      left: 0;
      bottom: 8px;
      display: inline-block;
      background: rgba(0, 0, 0, 0.5);
    }
    .axis-item {
      position: relative;
      display: flex;
      flex-direction: column;
      align-items: center;
      .axis-item-tick {
        display: inline-block;
        width: 4px;
        height: 20px;
        background: rgba(0, 0, 0, 0.5);
        transition: background 0.3s;
        cursor: pointer;
        &:hover {
          background: #000;
        }
      }
      .axis-item-tick-active {
        background: #000;
      }
      .axis-item-label {
        position: absolute;
        bottom: -30px;
        white-space: nowrap;
      }
      .axis-item-tip {
        position: absolute;
        top: -25px;
        padding: 2px 6px;
        border-radius: 2px;
        background: rgba(0, 0, 0, 0.5);
        white-space: nowrap;
        color: #fff;
      }
    }
  }
  .timeline-control {
    margin-top: 40px;
    text-align: center;
    i {
      cursor: pointer;
      display: inline-block;
      font-style: normal;
    }
    .menu-icon {
      font-size: 20px;
      width: 20px;
      height: 20px;
      background-size: cover;
      background-repeat: no-repeat;
      &.icon-left {
        background-image: url('../assets/icon-left.png');
      }

      &.icon-right {
        background-image: url('../assets/icon-right.png');
      }

      &.icon-play {
        background-image: url('../assets/icon-play.png');
      }

      &.icon-pause {
        background-image: url('../assets/icon-pause.png');
      }
      &.icon-up {
        background-image: url('../assets/icon-up.png');
      }

      &.icon-down {
        background-image: url('../assets/icon-down.png');
      }
      &.menu-icon-disabled {
        cursor: no-drop;
        opacity: 0.5;
      }
    }
  }
}
</style>

Using Components

App.vue

<template>
  <div>
    <h2
      style="margin:0;text-align:center;">
      {{this.date}}
    </h2>
    <Main :options="options"
      :dateTimes="dateTimes"
      @getDateFun="getDateFun"
      :interval="interval"></Main>
  </div>
</template>

<script>
import { dateFormat } from './util/formatdate.js'
import Main from './components/Main'
export default {
  name: 'app',
  data() {
    return {
      date: '',
      options:
        speed: 1, // speed speedMax: 10 // maximum speed},
      interval: 20, // The interval between days dateTimes: [
        '03-04',
        '03-05',
        '03-06',
        '03-07',
        '03-08',
        '03-09',
        '03-10',
        '03-11',
        '03-12',
        '03-13'
      ]
    }
  },
  components:
    Main
  },
  mounted() {
    // Get the dates of the last 10 days let list = []
    for (let i = 0; i < 10; i++) {
      list.unshift(
        dateFormat(
          new Date(
            new Date().setDate(new Date().getDate() - i)
          ).toLocaleDateString(),
          'MM-dd'
        )
      )
    }
    this.date = list[0]
    this.dateTimes = list
  },
  methods: {
    // Receive the value passed by the parent component getDateFun(time) {
      console.log(time)
      this.date = time
    },
  }
}
</script>

The above is the full content of this article. I hope it will be helpful for everyone’s study. I also hope that everyone will support 123WORDPRESS.COM.

You may also be interested in:
  • Vue implements horizontal timeline
  • Vue implements timeline function
  • Vue sample code for implementing two-column horizontal timeline
  • VUE implements timeline playback component
  • How to draw the timeline with vue+canvas
  • Vue+swiper realizes timeline effect
  • Vue realizes the logistics timeline effect
  • Vue timeline vue-light-timeline usage instructions
  • Vue implements movable horizontal timeline
  • Vue implements timeline effect

<<:  Linux system command notes

>>:  Detailed explanation of the use of custom parameters in MySQL

Recommend

Where is the project location deployed by IntelliJ IDEA using Tomcat?

After IntelliJ IDEA deploys a Javaweb project usi...

The difference between useEffect and useLayoutEffect in React

Table of contents Prerequisites useEffect commitB...

Example of how to achieve ceiling effect using WeChat applet

Table of contents 1. Implementation 2. Problems 3...

How to connect a Linux virtual machine to WiFi

In life, the Internet is everywhere. We can play ...

Introduction to the usage of common XHTML tags

There are many tags in XHTML, but only a few are ...

Vue implements login type switching

This article example shares the specific code of ...

VMWare virtual machine 15.X LAN network configuration tutorial diagram

Recently, I have been working on several virtual ...

Unicode signature BOM (Byte Order Mark) issue for UTF-8 files

I recently encountered a strange thing when debug...

Detailed explanation on how to install MySQL database on Alibaba Cloud Server

Preface Since I needed to install Zookeeper durin...

A brief discussion on DDL and DML in MySQL

Table of contents Preface 1. DDL 1.1 Database Ope...

In-depth understanding of Vue's data responsiveness

Table of contents 1. ES syntax getter and setter ...

Three Vue slots to solve parent-child component communication

Table of contents Preface Environment Preparation...