当前位置: 首页 > 知识库问答 >
问题:

javascript - 实现时间轴内容,使用el-slider?

端木令
2024-07-19

想根据element-ui组件里的slider滑块实现时间轴,效果如下
1721276149068.png目前已使用单独组建将次时间轴进行样式显示,现在的问题是,不知道el-slider 滑动时怎么让对应标签在正上方显示。以及怎么时间根据不同间隔(5分钟、6分钟、10分钟、30分钟、 1小时)提示标签对应拖动后增加目前我实现的vue组件内容如下
image.png

<template>
<div class="slider">
    <div class="minipanel">
        <div class="refresh"><el-checkbox v-model="checked">自动刷新</el-checkbox></div>
        <div class="timeleap"><label for="">间隔:</label>
            <select v-model="timeStep" class="timer-select">
                <option v-for="(item,index) in timeOptions" :key="item.value"
                    :label="item.label"
                    :value="item.value"/>
            </select>
        </div>
        <div class="datetime">
            <el-date-picker 
                v-model="timeCur"
                type="date"
                placeholder="选择日期">``
            </el-date-picker>
        </div>
        <div class="play">
            <div class="panelgap" :class="{'noClick':checked}" title="刷新"></div>
            <div class="leftbtn" :class="{'noClick':checked}" title="往前"></div>
            <div v-show="playing" class="playbtn" :class="{'noClick':checked}" title="播放"></div>
            <div v-show="!playing" class="pausebtn" :class="{'noClick':checked}" title="暂停"></div>
            <div class="rightbtn" :class="{'noClick':checked}" title="往后"></div>
        </div>
    </div>
    <div class="slider-timer">
        <!-- <el-slider v-model="nowCur"></el-slider> -->
        <div class="custom-tooltip" v-if="tooltipVisible" >  
            <span class="custom-tooltip-tip">{{ tooltipText }} </span> 
        </div>
        <el-slider ref="slider" :show-tooltip="false" v-model="nowCur" :max="maxTime" @change="handleSliderChange" :step="5"></el-slider> 
        <div class="time-marks">
            <span class="slider-pip" v-for="(item,index) in timeMarks">
                <span class="slider-label">
                    <span class="slider-longline"></span>
                    <div class="_sider_time" style="position: inherit;margin-left:4px;position: inherit;top: 26px;width: 40px;font-weight: normal;">{{ item.hour.replace(/0(\d)/g, '$1') }}</div>
                </span>
            </span>
        </div>
    </div>
</div>
</template>

<script>
import * as moment from 'moment';

export default{
    data(){
        return{
            checked:false,
            timeOptions:[{value: '10',label: '10min'},{value: '30',label: '30min'},{value: '60',label: '1h'}],
            timeStep:10,timeCur:null,nowCur:null,
            playing:true,
            minTime:0,//new Date(new Date().getTime() - 24 * 3600 * 1000 - 3600 * 1000).getTime(), 
            // 当前时间前1小时的过去24小时  
            maxTime:100,//new Date(new Date().getTime() + 10 * 3600 * 1000).getTime(),
            // 当前时间未来10小时  
            timeMarks: [],  
            tooltipVisible: true,  
            tooltipText: '',  
            tooltipStyle: {},  
        }
    },
    prop:{},
    mounted(){this.initTime()},
    methods:{
        initTime(){
            // 获取当前时间
            this.timeCur = moment().format('YYYY-MM-DD');
            this.nowCur =  moment().hour();
            // this.minTime = moment(this.timeCur).subtract(25, 'hours').hour()
            // this.maxTime = moment(this.timeCur).add(12, 'hours').hour()
            // 时间轴时次 
            this.getTimeCur()
            // 时间轴显示toolip
        },
        getTimeCur(){
            const now = moment(this.timeCur); 
            const year = now.year();
            const month = now.format('MM');
            const time = now.valueOf();
            const hourInMs = 60 * 60 * 1000;
            const scaleCountPast = 25;
            const scaleCountFuture = 0; // 36 48
            const scaleWidth = 70;
            const tipsMark = [];const Mark = []

            for (let i = -scaleCountPast; i <= scaleCountFuture; i++) {
                const scaleTime = moment(time + i * hourInMs);
                const day = scaleTime.format('DD');
                const hour = scaleTime.format('HH');
                const minute = scaleTime.format('mm');
                Mark.push({index:i,hour:hour})
            }
            this.timeMarks = Mark
        },
        formatTime(timeStamp) {  
            const date = new Date(timeStamp);  
            return `${date.getDate()}日${date.getHours().toString().padStart(2, '0')}时${date.getMinutes().toString().padStart(2, '0')}分`;  
        },  
        handleSliderChange(value) {  
            // 当 slider 值改变时,更新 tooltip  
            this.updateTooltip(value);  
        },  
        updateTooltip(value) {  
            this.tooltipText = '';  
            this.tooltipVisible = true;  
            const sliderRect = this.$refs.slider.$el.getBoundingClientRect();  
            const sliderMax = this.maxTime;
            const percent = (value / sliderMax) * 100;  
            const left = `${(percent / 100) * 20 - 10}px`; 
            this.tooltipStyle = {  
                left: `${left}%`, // 假设 tooltip 宽度为 100px  
            }; 
        },  
    },
    computed:{

    },
    watch:{},
}
</script>

<style lang="scss" scoped>
$bg:#fff;
.slider{
    margin-left: -350px;
    left: 50%;
    position: absolute;
    z-index: 1;
    width: 700px;
    height: 56px;
    bottom: 32px;
    opacity: 0.8;
    box-sizing: border-box;
    
    .minipanel{
        float: left;
        margin-left: -35px;
        margin-top: -42px;
        color: #000;
        .refresh{
            margin-bottom: 2px;
            width: 100%;
            height: 22px;
            display: flex;justify-content: center;
            -webkit-box-align: center;align-items: center;
            border-radius: 20px;
            border:1px solid #06608a;
            background: $bg;
        }
        .timeleap{
            display: -webkit-box;display: -ms-flexbox;display: flex;
            -webkit-box-pack: center;-ms-flex-pack: center;
            justify-content: center;-webkit-box-align: center;-ms-flex-align: center;
            align-items: center;
            border-radius: 20px;
            border: 1px solid #06608a;
            background: #fff;
            height: 22px;
            line-height: 22px;
            -webkit-box-sizing: border-box;box-sizing: border-box;
            padding: 5px;
            ::v-deep .timer-select{
                width: 60px;
                border: none;
                color: #06608a;
                text-transform: none;
                option{line-height: 20px;height: 20px;}
            }
        }
        .datetime{display: inline-block;line-height: normal;
           ::v-deep .el-date-editor.el-input, .el-date-editor.el-input__inner {
                margin-top: 2px;
                border: 1px solid #06608a;
                display: block;
                background: #fff;
                height: 22px;
                width: 120px;
                border-radius: 12px;
                color: #06608a;
                text-align: center;
                line-height: 22px;
            } 
            ::v-deep .el-input__inner{
                height: 22px;
                line-height: 22px;
                border-radius: 22px;
                font-size: 12px;
                color: #06608a;
                padding-right: 10px;
            }
            ::v-deep .el-input__prefix{top:-8px;}
        }
        .play{
            display: flex;
            justify-content: space-around;
            .panelgap{width: 30px;
            height: 30px;background: url(../assets/home/time_refresh.png);margin-top: 5px;}
            .leftbtn{width: 30px;
            height: 30px;background: url(../assets/home/move_btn.png) center no-repeat;transform: rotateZ(180deg);overflow: hidden;margin-top: 2px;}
            .playbtn{width: 30px;
            height: 30px;background: url(../assets/home/move_play.png) center no-repeat;overflow: hidden;margin-top: 5px;}
            .pausebtn{width: 30px;
            height: 30px;background: url(../assets/home/pause_btn.png) center no-repeat;overflow: hidden;margin-top: 5px;}
            .rightbtn{width: 30px;
            height: 30px;background: url(../assets/home/move_btn.png) center no-repeat;overflow: hidden;margin-top: 5px;}
            // 
            .panelgap.noClick{background: url(../assets/home/time_refresh_stop.png);}
            .leftbtn.noClick{background: url(../assets/home/stop_btn.png) center no-repeat;transform:rotateZ(0deg);cursor: no-drop;pointer-events: none;margin-top: 5px;}
            .playbtn.noClick{background: url(../assets/home/stop_play.png) center no-repeat;cursor: no-drop;pointer-events: none;}
            .rightbtn.noClick{background:url(../assets/home/stop_btn.png) center no-repeat ;transform: rotateZ(180deg);cursor: no-drop;pointer-events: none;margin-top: 1px;}
        }
    }
    &-timer{
        ::v-deep .el-slider{
            margin-left: 120px;
            margin-top:-26px;
            margin-right: 15px;
            height: 8px;
            .el-slider__runway{
                height: 8px;border-radius: 5px;
                border: 1px solid #007ca0!important;
                background: rgba(75,92,108,0.5)!important; //background-color: #4b5c6c80;
            } 
            .el-slider__bar{
                height: 8px;
                background-color: #3090f0;
            } 
            .el-slider__button{
                width: 10px;
                height: 10px;
                z-index: 2;
                border: 3px solid #fff;
                background: -moz-linear-gradient(top, #a7d8ff, #69b7f7);
                background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#a7d8ff), to(#69b7f7));
                background: #3090f0;
                border-radius: 50%;
                -webkit-transform: translate(36%, 0px);
                transform: translate(36%, 0px);
            }  
        } 
    }
    .custom-tooltip{
        position: absolute;
        margin-left: 132px;
        margin-top: 10px;
        margin-right: 15px;
        &-tip{
            position: absolute;
            visibility: hidden;
            top: -40px;
            display: block;
            width: 34px;
            margin-left: -18px;
            left: 50%;
            height: 20px;
            line-height: 20px;
            background: #fff;
            border-radius: 3px;
            border: 1px solid #888;
            text-align: center;
            font-size: 12px;
            opacity: 0;
            color: #333;
            -webkit-transition-duration: .2s,.2s,0;
            transition-duration: .2s,.2s,0;
            -webkit-transition-property: opacity,top,visibility;
            transition-property: opacity,top,visibility;
            -webkit-transition-delay: 0,0,.2s;
            transition-delay: 0,0,.2s;
            visibility: visible;
            opacity: 1;
            top: -25px;
            margin-left: -40px;
            width: 80px;color: #000;background: #fff;
            &::before {
                content: " ";
                width: 0;
                height: 0;
                border: 5px solid hsla(0,0%,100%,0);
                border-top-color: #888;
                position: absolute;
                bottom: -11px;
                left: 50%;
                margin-left: -5px;
            }
            &::after {
                content: " ";
                width: 0;
                height: 0;
                border: 5px solid hsla(0,0%,100%,0);
                border-top-color: #fff;
                position: absolute;
                bottom: -10px;
                left: 50%;
                margin-left: -5px;
            }
        }
    }
    .time-marks{
        display: flex;
        margin: auto;
        margin-top: 30px;
        margin-left: 120px;
        display: none;
        .slider-pip{
            width: 2em;
            height: 1em;
            line-height: 1em;
            position: absolute;
            font-size: .8em;
            color: #999;
            overflow: visible;
            text-align: center;
            top: 20px;
            left: 20px;
            margin-left: -1em;
            cursor: pointer;
            -webkit-touch-callout: none;
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
            .slider-label{

            }
        }
    }
}

</style>

1.拖动滑块时能在对应正上方标签显示当前x日x时x分(根据间隔进行分、时叠加) 2.滑块条为对应整下方为时次显示(左侧选中时间值的过去24小时逐小时内容) 3.点击播放若花开位置已在100%不执行,反之往前走动(每个1s请求)

共有2个答案

淳于泓
2024-07-19

效果

image.png

思路

手搓,只能且必须手搓一个Tool,这个组件只支持鼠标经过隐藏与显示,初始化常态显示压根就不支持。方法就是css伪类。赋值的时候要给content传字符串内容。

代码


      <template>
        <div style="width: 800px; margin: 30px">
          <el-slider
            v-model="time"
            :min="0"
            :max="24"
            :show-tooltip="false"
            @change="handleTimeChange"
          ></el-slider>
        </div>
      </template>
      
      <script>
      import moment from "moment";

      export default {
        data() {
          return {
            time: 0, // 初始化时显示tooltip
          };
        },

        mounted() {
          let hours = moment().format("HH");
          this.showTime(hours);
        },

        methods: {
          showTime(v) {
            const that = this;
            that.time = Number(v); //赋值小时注意这里必须为Number型

            //tool显示文本
            let sliderBar = document.getElementsByClassName("el-slider__bar");
            let sliderButton = document.getElementsByClassName(
              "el-slider__button-wrapper"
            );
            let showTime = moment().format("YYYY-M-D");
            sliderButton[0].setAttribute(
              "data-attr",
              showTime + "\n" + that.time + ":00"
            );

            // 值为0的时候滑块位于最右端
            if (that.time == 0) {
              sliderBar[0].style.width = "0%";
              sliderButton[0].style.left = "0%";
            }
          },

          handleTimeChange(newTime) {
            console.log("�� ~ handleTimeChange ~ newTime:", newTime)
            this.showTime(newTime);
          },
        },
      };
      </script>

      <style lang="scss" scoped>
      ::v-deep .el-slider__button-wrapper::before {
        content: attr(data-attr); // 给伪类添加内容,值为上述传递的值
        position: absolute;
        width: 110px;
        height: 25px;
        border-radius: 5px;
        border: 1px solid #ddd;
        top: -25px;
        left: -40px;
        background: #fff;
        font-size: 12px;
        line-height: 25px;
        text-align: center;
        color: #000;
      }
      </style>
诸葛品
2024-07-19

简单的方案:最大最小值使用时间戳,下面的marks根据开始结束时间进行等量分割,然后格式化,上面拖拽时的内容使用format-tooltip格式化显示就好了,

 类似资料:
  • 本文向大家介绍Android实现列表时间轴,包括了Android实现列表时间轴的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Android列表时间轴展示的具体代码,供大家参考,具体内容如下 实现的效果图如下: 实现的方式是利用recycleview的ItemDecoration这个抽象类,就是我们经常用来画分割线的的这个类, 具体如下 使用比较简单: 以上就是本文的全部内容,希望对

  • 本文向大家介绍DevExpress之ChartControl实现时间轴实例,包括了DevExpress之ChartControl实现时间轴实例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了DevExpress采用ChartControl实现时间轴的方法,分享给大家供大家参考。具体实现方法如下: 关键代码如下: 运行效果如下图所示: 希望本文所述对大家的C#程序设计有所帮助

  • 本文向大家介绍Vue实现可移动水平时间轴,包括了Vue实现可移动水平时间轴的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Vue实现可移动水平时间轴的具体代码,供大家参考,具体内容如下 里程碑时间轴具体实现 效果图 编辑里程碑效果图 编辑里程碑 stonedetail.vue 关于vue.js组件的教程,请大家点击专题vue.js组件学习教程进行学习。 以上就是本文的全部内容,希望对

  • 本文向大家介绍Android自定义时间轴的实现过程,包括了Android自定义时间轴的实现过程的使用技巧和注意事项,需要的朋友参考一下 本文讲述Android自定义时间轴的实现过程,供大家参考,具体内容如下 相关视频链接: Android自定义控件系列 http://edu.csdn.net/course/detail/3719/65396 Android视频全系列 http://edu.csdn

  • 本文向大家介绍Android实现快递物流时间轴效果,包括了Android实现快递物流时间轴效果的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Android实现快递物流时间轴效果展示的具体代码,供大家参考,具体内容如下 首先,这篇参考了别人的代码。根据自己的项目需求简单改造了一下,效果图如下 xml:代码 接下来是Activity,准备数据就好了 Adapter: 每一个item的布

  • 使用Chrome DevTools Timeline(时间轴)面板录制和分析应用程序运行时的所有活动。这是开始检查和感知应用程序性能问题的最佳位置。 TL;DR 进行时间轴录制来分析在网页加载或用户互动后发生的每个事件。 在Overview(概览)窗格中查看FPS,CPU和网络请求。 单击 Flame Chart (火焰)图表中的事件可查看其详细信息。 放大录制的一部分,使分析更容易。 Timel