1. 程式人生 > >自己寫的一款jq時間軸元件

自己寫的一款jq時間軸元件

效果圖

html

<!-- 時間軸 -->
<div id="timer-shaft"></div>

css

.f__clearfix{
    *zoom: 1;
}
.f__clearfix:after{
    visibility: hidden;
    display: block;
    font-size: 0;
    content: "";
    clear: both;
    height: 0;
}

/* 時間軸 */
.m-timer-shaft{
    width: 910px;
    height: 0;
    background: rgba(0,0,0,0);
    position: absolute;
    left: -84px;
    right: 0;
    bottom: 120px;
    margin: auto;
    z-index: 10;
}
.m-timer-shaft *{
    box-sizing: border-box;
}
.m-timer-shaft .timer-progress{
    height: 50px;
    width: 100%;
    background: rgba(16, 43, 35, 0.8);
    padding: 14px 15px 20px 15px;
    position: relative;
    -webkit-border-radius: 6px;
    border-radius: 6px;
    color: #d2d2d2;
    -webkit-box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.5);
    box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.5);
}
.m-timer-shaft .timer-progress .label{
    width: 60px;
    height: 22px;
    line-height: 22px;
    text-align: center;
    border: 1px solid #d2d2d2;
    -webkit-border-radius: 4px;
    border-radius: 4px;
    font-size: 12px;
    position: absolute;
    left: 11px;
    bottom: 0;
    top: 0;
    margin: auto;
}
/* 進度容器 */
.m-timer-shaft .timer-progress .progress-wrap{
    width: 800px;
    height: 16px;
    margin: 0 0 0 74px;
    position: relative;
}

.m-timer-shaft .progress-wrap .ruling{
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    display: block;
    z-index: 1;
}
.m-timer-shaft .progress-wrap .ruling .r_short,
.m-timer-shaft .progress-wrap .ruling .r_medium,
.m-timer-shaft .progress-wrap .ruling .r_long{
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 0;
    margin: auto;
    border-right: 1px solid #c8c8c8;
    cursor: pointer;
}
.m-timer-shaft .progress-wrap .ruling .r_short{
    height: 5px;
    top: -4px;
    border-color: #a5a5a5;
}
.m-timer-shaft .progress-wrap .ruling .r_medium{
    height: 12px;
    top: -4px;
}
.m-timer-shaft .progress-wrap .ruling .r_long{
    height: 18px;
    top: -3px;
}
.m-timer-shaft .progress-wrap .ruling-mark{
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    display: block;
    cursor: pointer;
    z-index: 2;
}
.m-timer-shaft .progress-wrap .line{
    height: 0;
    position: absolute;
    left: 0;
    right: 0;
    top: -2px;
    bottom: 0;
    margin: auto;
    border-bottom: 1px solid #c8c8c8;
    cursor: pointer;
}
.m-timer-shaft .progress-wrap .line::before,
.m-timer-shaft .progress-wrap .line::after{
    content: "";
    display: block;
    width: 0;
    height: 18px;
    border-color: #c8c8c8;
    border-left: 1px solid;
    position: absolute;
    left: 0;
    top: -10px;
}
.m-timer-shaft .progress-wrap .line::after{
    left: 100%;
}
/* 縮圖指標 */
.m-timer-shaft .progress-wrap .thumb-handle{
    width: 2px;
    height: 20px;
    position: absolute;
    top: -14px;
    left: 0;
    background: #e45;
    -webkit-transition: all .05s cubic-bezier(0.71, 0.38, 0.33, 0.74);
    transition: all .05s cubic-bezier(0.71, 0.38, 0.33, 0.74);
    -webkit-transform: translateX(0) scaleX(0.5);
    transform: translateX(0) scaleX(0.5);
    z-index: 1;
    display: none;
}
/* 縮圖容器 */
.m-timer-shaft .progress-wrap .thumb-wrap{
    width: 180px;
    height: 125px;
    position: absolute;
    top: -140px;
    left: 0;
    margin-left: -90px;
    -webkit-transition: all .05s cubic-bezier(0.71, 0.38, 0.33, 0.74);
    transition: all .05s cubic-bezier(0.71, 0.38, 0.33, 0.74);
    -webkit-transform: translateX(0);
    transform: translateX(0);
    background: rgba(16, 43, 35, 0.8);
    -webkit-border-radius: 1px;
    border-radius: 1px;
    display: none;
}
.m-timer-shaft .progress-wrap .thumb-wrap::after{
    content: '暫無圖片';
    display: block;
    width: 174px;
    height: 100px;
    line-height: 100px;
    text-align: center;
    background: rgba(16, 23, 39, 0.3);
    color: #aaa;
    font-size: 12px;
    letter-spacing: 2px;
    text-indent: 2px;
    position: absolute;
    top: 3px;
    left: 0;
    right: 0;
    margin: auto;
    z-index: 1;
}
.m-timer-shaft .progress-wrap .thumb-wrap img{
    width: 174px;
    height: 100px;
    position: absolute;
    top: 3px;
    left: 0;
    right: 0;
    margin: auto;
    z-index: 2;
}
.m-timer-shaft .progress-wrap .thumb-wrap p{
    height: 22px;
    line-height: 22px;
    position: absolute;
    top: 103px;
    padding: 0 10px;
    left: 0;
    right: 0;
    margin: auto;
    text-align: center;
}
/* 刻度名稱 */
.m-timer-shaft .progress-wrap .ruling-labels{
    width: 100%;
    height: 100%;
    position: absolute;
    top: 16px;
}
.m-timer-shaft .progress-wrap .ruling-labels .la_txt{
    width: 60px;
    height: 20px;
    line-height: 20px;
    text-align: center;
    font-size: 12px;
    position: absolute;
    left: 0;
    top: 0;
    -webkit-transform-origin: center top;
    transform-origin: center top;
    -webkit-transform: translate(-50%,0) scale(.85);
    transform: translate(-50%,0) scale(.85);
}
/* 指標 */
.m-timer-shaft .progress-wrap .hand{
    width: 13px;
    height: 38px;
    position: absolute;
    top: -8px;
    left: 0;
    -webkit-transform: translate(-47.5%,0);
    transform: translate(-47.5%,0);
    background: url(../img/icon-finger_02.png) center center no-repeat;
}
/* 控制區 */
.m-timer-shaft .contral{
    color: #f2f2f2;
    height: 40px;
    width: 188px;
    border-radius: 20px;
    margin: 0 auto;
    background: rgba(16, 43, 35, 0.8);
    margin-top: 20px;
    padding: 0 0 0 15px;
    -webkit-box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.5);
    box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.5);
}
.m-timer-shaft .contral .item{
    width: 74px;
    height: 40px;
    float: left;
    padding: 8px 0;
    margin-right: 10px; 
}
.m-timer-shaft .contral .txt{
    line-height: 24px;
    font-size: 12px;
    letter-spacing: 1px;
    text-indent: 1px;
    display: block;
    float: left;
    -webkit-transform: translate(-2px , 2px);
    transform: translate(-2px , 2px);
}
.m-timer-shaft .contral .icon{
    width: 24px;
    height: 24px;
    display: block;
    float: left;
    margin-right: 13px;
    background: url("../img/icon-fly.png") 0 0 no-repeat;
    cursor: pointer;
}
.m-timer-shaft .contral .icon.start{
    background-position: 0 -24px;
}
.m-timer-shaft .contral .icon.start.active{
    background-position: 0 -48px;
}
.m-timer-shaft .contral .icon.stop{
    background-position: 0 -72px;
}
/* 結束時的處理 */
.m-timer-shaft.is_end{
    bottom: 70px;
}
.m-timer-shaft.is_end .timer-progress{
    display: none;
}
.m-timer-shaft.is_end .contral{
    width: 100px;
}
.m-timer-shaft.is_end .contral .stop-item{
    display: none;
}

jq指令碼

/**
 * @description: 時間軸
 * @author: 則丸
 **/

;(function($, window, document,undefined) {

    // 定義TimerShaft的建構函式
    var TimerShaft = function (ele, opt) {
        this.$element = ele,
        this.defaults = {
            'labels': [],         // 刻度名稱列表
            'rulingInterval': 5,  // 刻度間隔
            'runningTime': 5,     // 執行一段需要的時間
            'thumbBaseURL': '',   // 縮圖相對路徑
            'thumbImages': [],    // 縮圖資源
            'start': null,        // 開始的回撥
            'stop': null,         // 停止的回撥
            'passByLine': null,   // 通過刻度線的回撥
            'clickRuling': null,  // 點選刻度尺的回撥
            'isOpenClick': false  // 是否啟用刻度容器點選事件
        },
        this.options = $.extend({}, this.defaults, opt)
        // 其他引數
        this.label_len = this.options.labels.length
        this.rule_sum = this.options.rulingInterval * (this.label_len - 1)
        // 時間軸指標的位置
        this.handLeft = 0
        // 當前處於第幾個指標
        this.currIndex = 0
        // 指標運動的定時器
        this.handMoveTimer = null
    }
    
    // 定義TimerShaft的方法
    TimerShaft.prototype = {
        // 渲染方法
        init: function () {
            var scope = this
            // 時間軸
            var timer_progress = `
                <div class="timer-progress">
                    <div class="label">時間視點</div>
                    <div class="progress-wrap">
                        <div class="ruling"></div>
                        <div class="ruling-mark"></div>
                        <div class="line"></div>
                            <div class="thumb-handle"></div>
                            <div class="thumb-wrap">
                                <img/>
                                <p></p>
                            </div>
                        <div class="ruling-labels"></div>
                        <div class="hand"></div>
                    </div>
                </div>
            `
            // 控制區域
            var timer_contral = `
                <div class="contral f__clearfix">
                    <div class="item">
                        <i class="icon start"></i>
                        <span class="txt">開始</span>
                    </div>
                    <div class="item stop-item">
                        <i class="icon stop"></i>
                        <span class="txt">結束</span>
                    </div>
                </div>
            `
            // 主要的html繪製
            this.$element.addClass('m-timer-shaft is_end').append(timer_progress + timer_contral)
            // 時間軸樣式 調整
            this.setTimerShaftStyle();
            // 刻度渲染
            this.ruleRender()

            var rulingHandle = function (ev) {
                // 是否啟用
                if (!scope.options.isOpenClick) return
                ev || (ev = window.event)
                var dom_width = scope.$element.find('.progress-wrap').width()
                var w_block = dom_width / scope.rule_sum
                var ruling_offsetLeft = $(this).offset().left
                var ev_left = ev.clientX
                scope.handLeft = ev_left - ruling_offsetLeft
                scope.currIndex = parseInt(scope.handLeft / w_block)
                scope.options.clickRuling && scope.clickRuling(scope.options.currIndex)
                // 重啟 | 啟動
                scope.restart()
                $(this).siblings(".hand").css('left', scope.handLeft + 'px');
            }
            // 縮圖 刻度容器觸控事件
            var thumbHandleHover = function (ev) {
                ev || (ev = window.event)
                var dom_width = scope.$element.find('.progress-wrap').width()
                var w_block = dom_width / scope.rule_sum
                var ruling_offsetLeft = $(this).offset().left
                var ev_left = ev.clientX
                var offset_left = ev_left - ruling_offsetLeft
                var the_index = Math.floor(offset_left / (w_block * scope.options.rulingInterval))
                var thumb_handle = scope.$element.find(".thumb-handle")
                var thumb_wrap = scope.$element.find(".thumb-wrap")
                thumb_handle.css({
                    'WebkitTransform': `translateX(${offset_left}px) scaleX(0.5)`,
                    'transform': `translateX(${offset_left}px) scaleX(0.5)`
                }).show()
                var attr_index = thumb_wrap.find('img').attr('data-index')
                if(attr_index&&attr_index!=the_index) {
                    // 當圖片存在時
                    if (scope.options.thumbImages[the_index]) {
                        thumb_wrap.find('img').attr('src' ,scope.options.thumbBaseURL + scope.options.thumbImages[the_index]).show()
                    } else {
                        thumb_wrap.find('img').hide()
                    }
                }
                thumb_wrap.find('img').attr('data-index', the_index)
                thumb_wrap.find('p').html(scope.options.labels[the_index])
                thumb_wrap.css({
                    'WebkitTransform': `translateX(${offset_left}px)`,
                    'transform': `translateX(${offset_left}px)`
                }).show()
            }
            // 縮圖 刻度容器 離開觸控事件
            var thumbHandleLeave = function (ev) {
                var thumb_handle = scope.$element.find(".thumb-handle")
                var thumb_wrap = scope.$element.find(".thumb-wrap")
                ev || (ev = window.event)
                thumb_handle.hide()
                thumb_wrap.hide()
            }
            this.$element.find(".ruling-mark").click(rulingHandle)
            this.$element.find(".ruling-mark").mousemove(thumbHandleHover)
            this.$element.find(".ruling-mark").mouseleave(thumbHandleLeave)
            return this
        },
        // 渲染時間軸刻度
        ruleRender: function () {
            if (!this.options.labels) return this.$element
            var $timer_progress = this.$element.find('.timer-progress')
            var dom_width = $timer_progress.find('.progress-wrap').width()
            var w_block = dom_width / this.rule_sum
            var append_dom = ''
            var long_len = 0
            var labels_dom = `<div class="la_txt" style="left: 0px;">${this.options.labels[0]}</div>`
            for (var i = 0; i< this.rule_sum - 1 ;i++) {
                if ((i + 1) % this.options.rulingInterval === 0) {
                    if (long_len % 2 === 0) {
                        append_dom += `<div class='r_medium' point-num='${i+1}' style="left: ${(i+1)*w_block}px;"></div>`
                    } else {
                        append_dom += `<div class='r_long' point-num='${i+1}' style="left: ${(i+1)*w_block}px;"></div>`
                    }
                    labels_dom += `<div class="la_txt" style="left: ${(i+1)*w_block}px;">${this.options.labels[long_len+1]}</div>`
                    long_len += 1
                } else {
                    append_dom += `<div class='r_short' point-num='${i+1}' style="left: ${(i+1)*w_block}px;"></div>`
                }
            }
            labels_dom += `<div class="la_txt" style="left: ${(this.rule_sum)*w_block}px;">${this.options.labels[this.label_len - 1]}</div>`
            $timer_progress.find(".ruling").html('').append(append_dom)
            $timer_progress.find(".ruling-labels").html('').append(labels_dom)
            return this.$element
        },
        // 時間軸樣式 調整
        setTimerShaftStyle: function () {
            var bgColor = "rgba(16, 43, 35, 0.8)"
            var wrap_width = $(window).width() - 653;
            wrap_width = wrap_width > 1000 ? 1000 : wrap_width
            wrap_width = wrap_width < 380 ? 380 : wrap_width
            this.$element.css({
                'width': wrap_width + 'px'
            });
            
            this.$element.find('.progress-wrap').css('width', (wrap_width - 110) + 'px');
            // 顏色設定
            this.$element.find('.timer-progress').css('backgroundColor', bgColor);
            this.$element.find('.contral').css('backgroundColor', bgColor);
        },
        // 時間軸動畫
        timelineAnimate: function () {
            var dom_width = this.$element.find('.progress-wrap').width()
            var w_block = dom_width / this.rule_sum
            var fps_distance = (dom_width / (this.label_len - 1))  / this.options.runningTime / (1000 / 60)
            this.handLeft += fps_distance
            this.$element.find(".hand").css('left', this.handLeft + 'px');
            var the_index = parseInt(this.handLeft / w_block)
            if (the_index != this.currIndex) {
                this.currIndex = the_index
                this.options.passByLine && this.options.passByLine(this.currIndex)
            }
            if (this.handLeft>=dom_width) {
                this.close()
            }
        },
        // 開始
        begin: function () {
            var scope = this
            this.handMoveTimer = setInterval(function(){
                scope.timelineAnimate()
            }, 1000 / 60);
            this.options.start && this.options.start(this)
        },
        // 終止
        close: function () {
            this.handLeft = 0
            var dom_width = this.$element.find('.progress-wrap').width()
            this.$element.find(".hand").css('left', dom_width + 'px');
            this.currIndex = this.options.rulingInterval * (this.label_len - 1)
            clearInterval(this.handMoveTimer)
            this.options.stop && this.options.stop(this)
        },
        // 暫停
        pause: function () {
            clearInterval(this.handMoveTimer)
        },
        // 重啟
        restart: function () {
            this.pause()
            this.begin()
        },
        // 重置
        reset: function () {
            this.handLeft = 0
            this.$element.find(".hand").css('left', this.handLeft + 'px');
            this.currIndex = 0
            this.$element.find(".contral .start").removeClass('active').siblings('.txt').text('繼續');
            clearInterval(this.handMoveTimer)
        }
    }
    // 在外掛中使用TimerShaft物件
    $.fn.timerShaft = function (options) {
        // 建立Beautifier的實體
        var timerShaft = new TimerShaft(this, options);
        // 呼叫渲染方法
        timerShaft.init()
        var start_btn = timerShaft.$element.find(".contral .start");
        var stop_btn = timerShaft.$element.find(".contral .stop");
        // 啟動時間軸
        start_btn.on("click", function(){
            timerShaft.$element.hasClass('is_end') && timerShaft.$element.removeClass('is_end')
            var is_pause = $(this).hasClass('active')
            if (!is_pause) {
                $(this).addClass('active').siblings('.txt').text('暫停');
                timerShaft.begin()
            } else {
                $(this).removeClass('active').siblings('.txt').text('繼續');
                timerShaft.pause()
            }
        })
        // 終止時間軸
        stop_btn.on("click", function(){
            timerShaft.$element.hasClass('is_end') || timerShaft.$element.addClass('is_end')
            start_btn.removeClass('active').siblings('.txt').text('開始');
            timerShaft.close()
        })
        // 瀏覽器視窗變化時, 時間軸樣式調整
        $(window).resize(function(){
            timerShaft.setTimerShaftStyle();
            // 時間軸重新渲染
            timerShaft.reset();
            timerShaft.ruleRender();
        })
        return timerShaft;
    }

})(jQuery, window, document);