JQuery+HTML5+CSS3制作时间轴插件,支持响应式布局

一、效果图预览

                            (图一)

          (图二)

附注说明:

图一是浏览器宽度像素大于560px下的展示效果,图二是在浏览器宽度像素小于560px下的展现效果。使用的是CSS3的Media Query(媒体查询)实现的效果。

另外页面中圆形、圆角和三角同样使用了CSS3的特殊样式。这些基础的样式和效果在本文中不会赘述,不了解的童鞋可以上网搜索学习一下,很简单。

页面上每个时间节点的展示内容提供了三种展示样式,多张图片的展示风格、单张图片的展示风格和无图片的展示风格。这些可以根据自己的需求自己更改。

二、分析页面布局思路

  页面的布局其实主要就是将外层的容器使用相对定位,容器内的元素使用绝对定位即可。具体的分析请看下图

依照图片上的分析就可以达到时间轴插件的布局展示效果。

布局好了之后,我们就可以添加我们需要展现的内容了。为了页面不那么单调,可以使用JQuery的animate函数添加一些效果,比如可以让左侧的节点从页面左侧滑入页面,右侧节点从页面右侧滑入页面。代码简单,稍后贴出。

三、加入滚动触发事件机制,动态加载时间节点

在时间节点较多的情况下,一般情况下比如一个公司的发展历程和重大记事都不太可能只有三、五条信息吧,随着时间的推移,值得记录的大事件就会越多。如果一次就要让全部的信息展示在页面上可能会影响页面的展示效率,用户的体验也不会很好。

所以,可以利用触发滚动事件机制,每次加载固定的条数。这跟实现分页效果是一样的。只不过我们的触发条件是滚动触发。

注意事项:

1. 首次加载固定条数时,假设每次加载5条记录,如果首次加载5条后,没有出现滚动条,应该再次调用查询方法,继续加载,直到出现滚动条(否则首次加载5条后,没有出现滚动条,以后就无法触发滚动事件了,自然也就无法继续查询之后的记录了)。

2. 触发滚动事件,不能够只要滚动就触发,否则程序一直在触发加载记录方法,页面可能会无法由于频繁发送请求无法响应。解决方法,可以在滚动条滚动到页面底部的时候再触发加载记录方法。

具体的判定请看代码

CSS代码

.timeline-container{
    width:100%;
    /*height:auto;*/
}
.timeline{
    width:100%;
    margin:auto;
    position:relative;
    height: auto;
    padding:30px 0px 0px 0px;
}
.timeline > .timeline-block{
    width:50%;
}
.timeline-block > .popover{
    max-width: 70%;
}
.timeline > .timeline-block-odd{
    float:left;
}
.timeline > .timeline-block-even{
    float:right;
}
.timeline-block-odd>.timeline-content{
    display: block;
    position:relative;
    float:right;
    margin-right:50px;
}
.timeline-block-even>.timeline-content{
    display: block;
    float:left;
    position:relative;
    margin-left:50px;
}

.timeline-content > .arrow{
    top:20px !important;
    background: #f7f7f7;
}
.timeline-content > .popover-content{
    max-height: 240px;
    overflow-y: auto;
    color: #696969;
    font-size: 11px;
}

.timeline-content>.popover-footer{
    padding:8px 14px;
    margin:0px;
    font-size: 11px;
    border-top: 1px dotted #b9b9b9;
    color: #4b4b4b;
    background:#F2F2F2;
}
.timeline img{
    border:1px solid #dddddd;
    padding:2px;
}
.timeline-img{
    width:50px;
    height:50px;
    -webkit-border-radius: 25px;
    -moz-border-radius: 25px;
    -o-border-radius: 25px;
    border-radius: 25px;
    border:3px solid #A3E3E8;
    margin:auto;
    background: #ffffff;
    position:absolute;
    z-index: 9;
    left:50%;
    margin-left:-25px;
    background: url(../../indexImg/greeneye.jpg);
    background-size: cover;
}

.timeline-line{
    width:4px;
    height:100%;
    background: #aef0f5;
    position:absolute;
    z-index:8;
    left:50%;
    border-left:1px solid #aef0f5;
    border-right:1px solid #ffffff;
    margin-left: -2px;
    margin-top:-30px;
}

.timeline-block-odd>.popover.left>.arrow:after {
    right: 2px;
    border-left-color: #F7F7F7;
}
.timeline-block-even>.popover.right>.arrow:after {
    left: 2px;
    border-right-color: #F7F7F7;
}



/** mediaquery查询样式 **/
@media screen and (max- 560px){

    .timeline{
        width:100%;
        position:relative;
        height: auto;
        padding:30px 0px 0px 0px;
    }
    .timeline > .timeline-block{
        width:100%;
    }
    .timeline > .timeline-block-odd{
        float:right;
    }
    .timeline-block-odd>.timeline-content{
        display: block;
        position:relative;
        float:left;
        margin-left:75px;
    }
    .timeline-block-even>.timeline-content{
        display: block;
        position:relative;
        float:left;
        margin-left:75px;
    }

    .timeline-block-odd>.popover>.arrow, .timeline-block-odd>.popover>.arrow:after {
        position: absolute;
        display: block;
        width: 0;
        height: 0;
        border-color: transparent;
        border-style: solid;
    }
    .timeline-block-odd>.popover.left>.arrow {
        left: -21px;
        bottom: -10px;
        content: " ";
        border-left-width: 0;
        border-right-color: #999;
        border-width: 10px;
    }

    .timeline-block-odd>.popover.left>.arrow:after {
        left:1px;
        right: 1px;
        bottom: -10px;
        content: " ";
        border-left-width: 0;
        border-right-color: #fff;
    }
    .timeline-block-odd>.popover>.arrow:after {
        content: "";
        border-width: 10px;
    }

    .timeline-img{
        width:50px;
        height:50px;
        margin:auto;
        background: #ffffff;
        -webkit-border-radius: 25px;
        -moz-border-radius: 25px;
        -o-border-radius: 25px;
        border-radius: 25px;
        border:3px solid #8e8e8e;
        position:absolute;
        z-index: 9;
        left:0;
        margin-left:0px;
    }

    .timeline-line{
        width:4px;
        height:100%;
        background: #d0d0d0;
        border-left:1px solid #ececec;
        border-right:1px solid #ececec;
        position:absolute;
        z-index:8;
        left:0;
        margin-left: 24px;
        margin-top:-30px;
    }


}

JQuery代码

$(function(){
    var _timeline_row_ = $("<div></div>").addClass("row");
    $(".timeline-container").append(_timeline_row_);
    var loadData=function(){
        $.getJSON("timeline.json", function (data) {
            $.each(data, function (i, tl) {
                var _timeline_ = $("<div></div>").addClass("timeline");
                _timeline_row_.append(_timeline_);

                var _time_block_ = $("<div></div>").addClass("timeline-block");
                var _time_content_ = $("<div></div>").addClass("popover timeline-content");
                _time_block_.append(_time_content_);
                /**
                 * 设置显示内容
                 */

                var _popover_title_ = $("<h3></h3>").addClass("popover-title").text(tl["diagTime"]);
                var _popover_footer_ = $("<div></div>").addClass("popover-footer").text(tl["result"]);
                var _popover_content_ = $("<div></div>").addClass("popover-content");
                _time_content_.append($("<div></div>").addClass("arrow"))
                    .append(_popover_title_)
                    .append(_popover_content_)
                    .append(_popover_footer_);
                /**
                 * 主页展示内容布局
                 */

                if (tl["images"].length > 1 && tl["images"] != "" && tl["images"] != null && tl["images"] != "undefined") {
                    var _img_container_ = $("<div></div>").css("margin-bottom", "10px");
                    var _table_container_ = $("<table></table>").addClass("table table-bordered table-condensed");
                    for (var m = 0; m < tl["images"].length; m++) {
                        _img_container_.append($("<img/>").attr("src", tl["images"][m]).css({"width":"60px","height":"60px","margin-right":"10px"}));
                    }
                    _popover_content_.append(_img_container_);
                    _table_container_.append($("<tr></tr>")
                            .append($("<td nowrap></td>").text("眼象特征"))
                            .append($("<td></td>").text(tl["feature"]))
                    );

                    _table_container_.append($("<tr></tr>")
                            .append($("<td nowrap></td>").text("匹配结果"))
                            .append($("<td></td>").text(tl["matchList"]))
                    );

                    _table_container_.append($("<tr></tr>")
                            .append($("<td nowrap></td>").text("结论说明"))
                            .append($("<td></td>").text(tl["desc"]))
                    );

                    _popover_content_.append(_img_container_).append(_table_container_);

                } else if (tl["images"].length == 1 && tl["images"] != "" && tl["images"] != null && tl["images"] != "undefined") {
                    var _img_container_ = $("<div></div>")
                        .addClass("pull-left")
                        .append($("<img/>").attr("src",tl["images"][0]).css({"margin": "5px 10px","width": "100px", "height": "100px"}));
                    var _text_container_ = $("<p></p>").css({"margin-left": "10px", "margin-top": "5px", "font-size": "12px"})
                        .append("眼象特征: " + tl["feature"]).append("<br/>")
                        .append("匹配结果: " + tl["matchList"]).append("<br/>")
                        .append("结论说明: " + tl["desc"]).append("<br/>");
                    _popover_content_.append(_img_container_).append(_text_container_);
                } else if (tl["images"].length < 1 || tl["images"] == "" || tl["images"] == null || tl["images"] == "undefined") {
                    var _text_container_ = $("<p></p>").css({"margin-left": "10px", "margin-top": "5px", "font-size": "12px"})
                        .append("眼象特征: " + tl["feature"]).append("<br/>")
                        .append("匹配结果: " + tl["matchList"]).append("<br/>")
                        .append("结论说明: " + tl["desc"]).append("<br/>");
                    _popover_content_.append(_img_container_).append(_text_container_);
                }

                $(_timeline_).append(_time_block_)
                    .append($("<div></div>").addClass("timeline-img"))
                    .append($("<div></div>").addClass("timeline-line"))
                    .append($("<div></div>").addClass("clearfix"));
                if ($(_timeline_).prev().find(".timeline-block").hasClass("timeline-block-odd")) {
                    $(_timeline_).find(".timeline-block").addClass("timeline-block-even");
                    $(_timeline_).find(".timeline-block-even>.timeline-content").addClass("right").css({"left": "150px"});
                } else {
                    $(_timeline_).find(".timeline-block").addClass("timeline-block-odd");
                    $(_timeline_).find(".timeline-block-odd>.timeline-content").addClass("left").css({"left": "-150px"});
                }
                $(_timeline_).find(".timeline-block>.timeline-content").animate({
                    left: "0px"
                }, 1000);
            });
            if($(window).height()>=document.documentElement.scrollHeight){
                //没有出现滚动条,继续加载下一页
                loadData();
            }

        });


    }

    var tcScroll=function(){
        $(window).on('scroll', function () {
            var scrollTop = $(this).scrollTop();
            var scrollHeight = $(document).height();
            var windowHeight = $(this).height();
            if (scrollTop + windowHeight == scrollHeight) {
                //此处是滚动条到底部时候触发的事件,在这里写要加载的数据,或者是拉动滚动条的操作
                loadData();
            }
        })
    }
    loadData();
    tcScroll();

});

总结一下:

1. 本文偏重在时间轴的布局设置分析,主要是通过外层容器的相对定位和内层元素的绝对定位实现布局效果。

2. 触发滚动事件机制,达到类似分页的加载效果。在触发滚动事件是要保证逻辑的严谨性。

  比较久之前写的Demo了,Jquery插件写的不是很好,和CSS样式混杂在一起,也没有将其单独提取出来。不过作为分享学习使用还是可以的。正式开发的时候,不要像我这么写JS。呵~。

  最后,依旧是感谢阅读。

  附加html片段和json文件格式。具体的图片等路径请自行调整

  html片段:

<div class="timeline-container"></div>

  json格式文件:

[
    {
    "id":1,
    "userNo":"user0001",
    "diagTime":"2015/07/14 11:00",
    "diagDoc":"李医生",
    "feature":"通过图像识别获得的眼象特征",
    "matchList":"知识库自动获取的病证信息",
    "result":"根据病证信息获得的综合分析结果",
    "desc":"\n\t对综合结论进\n\t\t\t  行的详细描述,其中可能包括眼象说明、病证分析、相关疾病说明、诊疗方法等。",
    "images":[
        "01.jpg",
        "02.jpg",
        "03.jpg"
    ],
    "ctime":"2014-07-13",
    "utime":""
    },
    {
        "id":2,
        "userNo":"user0001",
        "diagTime":"2015/07/14 16:00",
        "diagDoc":"王医生",
        "feature":"通过图像识别获得的眼象特征",
        "matchList":"",
        "result":"根据病证信息获得的综合分析结果",
        "desc":"对综合结论进行的详细描述,其中可能包括眼象说明、病证分析、相关疾病说明、诊疗方法等。",
        "images":[
            "01.jpg"
        ],
        "ctime":"2014-07-13",
        "utime":""
    },
    {
        "id":3,
        "userNo":"user0001",
        "diagTime":"2015/07/15 14:00",
        "diagDoc":"王医生",
        "feature":"通过图像识别获得的眼象特征",
        "matchList":"",
        "result":"根据病证信息获得的综合分析结果",
        "desc":"对综合结论进行的详细描述,其中可能包括眼象说明、病证分析、相关疾病说明、诊疗方法等。",
        "images":"",
        "ctime":"2014-07-13",
        "utime":""
    },{
    "id":4,
    "userNo":"user0001",
    "diagTime":"2015/07/15 14:00",
    "diagDoc":"王医生",
    "feature":"通过图像识别asdfasf获得的眼象特征",
    "matchList":"",
    "result":"根据病证信息获得的综合分析结果",
    "desc":"对综合结论进行的详细描述,其中可能包括眼象说明、病证分析、相关疾病说明、诊疗方法等。",
    "images":"",
    "ctime":"2014-07-13",
    "utime":""
}
]
原文地址:https://www.cnblogs.com/chunyangji/p/5753374.html