【前端】使用jQuery实现地铁线路地图动态加载站点

简介: 通过上篇文章,我们已经把地铁线路静态布局设计好了,接下来就是让静态转为动态化和交互今天,有个小伙伴咨询我说,已经有很多成熟的前端框架可以使用,我直接学习他们的用法,完全不用怎么自己写布局,干嘛还要花这么多时间从原始方式去布局呢我的回答是,其实他说的是有道理的,时间是宝贵的,但是长期已往,如果不能了解和理解最原视的架构,可能技术在迭代更新过程中会很费劲,亦或者更加依赖某一项框架对技术的追求还是那句话:掌握原理,不断练习,才能更好跟上前言技术
作者:小5聊基础
简介:一只喜欢全栈方向的程序员,欢迎咨询,尽绵薄之力答疑解惑
编程原则:Write Less Do More

image.png

主要知识点列表

编号 语言或插件 知识点 说明
1 js template type的属性值,用于标志为html标签模板
2 js $('
')
操作虚拟化DOM
3 html $(dom).html() 获取dom对象的html标签,不包括自己本身
4 jQuery $(dom).css() 获取或设置dom对象的css样式,可以设置单个和多个,font-size有横线分隔的改为第二个首字母大写,css("fontSize","16px")
5 jQuery $(dom).addClass() 添加class样式名称
6 js trim 去掉字符串前后空格,字符串中间的空格不会去掉
7 jQuery $(dom).mouseenter 鼠标移动进入到指定dom元素里触发的方法
8 jQuery $(dom).mousecleave 鼠标移动离开到指定dom元素里触发的方法
9 jQuery $(dom).parent() 获取父级元素对象,这个方法比较有意思,可以不断迭代往上获取父级元素对象,感兴趣的有小伙伴也可以思想这个是怎么实现的,可以浏览他们的jQuery代码
10 jQuery $(dom).outerWidth() 获取dom对象的宽度,包括内边距
11 jQuery $(dom).outerHeight() 获取dom对象的高度,包括内边距
12 jQuery $(dom).append() 向dom元素追加内容,追加在后面
13 jQuery $(dom).offset() 获取dom对象元素相对于文档的top和left值,offset().top/left

1、动态化模板布局

script标签,有这样一个属性,template模板
可能大家没怎么用过,现在前端有非常多成熟的框架,用过vue的小伙伴应该不陌生
模板可以包含循环体的代码块,如下

  • 部分代码
<!--模板-->
<script id="site" type="text/template">
    <div class="item" style="left: 0px;top: 0px;">
        <div class="line"></div>
        <div class="text" style="width:100px;right: -8px;text-align:right;">
            <span></span>
        </div>
        <div class="circular" style="left: 24px;top: 0px;"></div>
    </div>
</script>
<!--换乘图标模板-->

1.1 动态参数分析

1)单元块,top和left <br/>
2)线条的旋转角度是 <br/>
3)线条的颜色,不同颜色代表不同的线路 <br/>
4)站点名称 <br/>
5)换成图标 <br/>
6)是否是最后一个站点,线条长度和圆圈大小一致 <br/>
通过上面的分析,我们可以得出如下json格式

  • 部分代码
{
    text: '嘉禾望岗',
    position: {
        left: 500,
        top: 0
    },
    class: {
        rorate: 'line-transform-45',
        line: 'line-2'
    },
    is_rorate_line: 1
}

1.2 逻辑实现

1)通过for循环多个站点值,并使用站点模板追加到目标div里 <br/>
2)$(template),先通过jQuery虚拟化操作dom进行赋值 <br/>
这里的template不能出现前后空格,所以需要使用trim()去掉前后空格
3)通过虚拟dom即可给文本值、旋转样式、换乘图标、单元块等值进行判断和赋值

  • 效果

image.png

  • 部分代码
var html = '';
for (var i = 0; i < line_arr.length; i++) {
    var data = line_arr[i];
    var temp = site_template;
    var dom = $(temp);
    $(".text", dom).html(data.text);
    dom.css({ "left": data.position.left, "top": data.position.top });
    $(".line", dom).addClass(data.class.rorate);
    $(".line", dom).addClass(data.class.line);
    if (data.is_exchange_line) {
        $(".circular", dom).html(exchange_template);
    }
    html += dom.prop('outerHTML');
}

$(".metro-map").html(html);

2、站点弹窗显示信息

image.png

2.1 实现逻辑

1)鼠标移动到站点,显示站点开始和结束的运营时间,同样可通过模板方式动态追加
2)鼠标移开站点,则隐藏,弹窗信息移除
3)json格式增加,站点运营时间等信息,起点站只有一个方向,中间站可能会有多个方向
4)弹窗位置计算方式,默认透明度为0,先获取赋值后,弹窗的整体高宽度,从而计算得出合适的位置left和top值,display:none,在隐藏的情况是无法获取高宽度
5)由于position元素会继承position父级的宽度,所以弹窗需要设置为fixed固定样式,才能不被限定宽度,此时就需要获取父级的相对html的top值

{
    text: '黄边',
    position: {
        left: 450,
        top: 50
    },
    class: {
        rorate: 'line-transform-45',
        line: 'line-2'
    },
    is_exchange_line: 0,
    direction: [
        '嘉禾望岗方向 始:06:23 末:00:16',
        '广州南站方向 始:06:03 末:23:36'
    ]
}
<!--弹窗信息模板-->
<script id="info" type="text/template">
    <div class="info" style="position:fixed;left: 0px;top: 0px;box-shadow:0 0 13px #ccc;padding:6px 8px;border-radius:10px;font-size: 13px;background:#fff;opacity:0;"></div>
</script>

3、完整代码

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>标题</title>
    <script src="jquery-2.0.0.min.js"></script>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            font-size: 100%;
        }

        .item {
            position: absolute;
            left: 0px;
            top: 0px;
        }

        .line {
            width: 10px;
            height: 80px;
        }

        .line-end {
            height: 10px;
        }

        .line-transform-45 {
            right: -8px;
            transform: rotate(45deg);
            -ms-transform: rotate(45deg); /* Internet Explorer */
            -moz-transform: rotate(45deg); /* Firefox */
            -webkit-transform: rotate(45deg); /* Safari 和 Chrome */
            -o-transform: rotate(45deg); /* Opera */
        }

        .line-2 {
            background: #0066cc;
        }

        .text {
            position: absolute;
            right: 18px;
            top: 0px;
        }

        .circular {
            position: absolute;
            left: -5px;
            top: -5px;
            background: #fff;
            border: 4px solid #0066CC;
            width: 12px;
            height: 12px;
            border-radius: 14px;
            cursor: pointer;
        }

            .circular:hover {
                border: 4px solid #4398ed;
            }

            .circular .icon {
                width: 1.4rem;
                height: 1.4rem;
                vertical-align: middle;
                fill: #333;
                overflow: hidden;
                position: absolute;
                top: -5px;
                left: -5px;
                background: #fff;
                border-radius: 1.5rem;
            }

            .circular:hover .icon {
                fill: #4398ed !important;
            }

        .circular-position {
            left: 24px;
            top: 0px;
        }

        .light {
            background: #aae298 !important;
            border: 4px solid #44ce3f !important;
        }

            .light .icon {
                display: none;
            }
    </style>
</head>
<body>
    <div style="position:fixed;top:10px;right:10px;">
        <div style="text-align:center;">
            <svg class="icon" style="width: 2rem;height: 2rem;vertical-align: middle;fill: #333;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2152"><path d="M255.329 231.83C212.739 142.273 153.359 65.132 77.148 0.386L267.84 0a686.133 686.133 0 0 1 149.188 218.117 685.707 685.707 0 0 1 56.011 267.446v538.418H321.49V525.925c0-103.384-22.06-201.422-66.18-294.096zM550.955 1024V485.583a685.688 685.688 0 0 1 55.991-267.466C642.466 135.883 692.183 63.177 756.154 0l190.693 0.387C870.616 65.133 811.235 142.274 768.665 231.83a677.418 677.418 0 0 0-66.16 294.077V1024h-151.55z" fill="#BE1120" p-id="2153"></path></svg>
            <br />
            <span>广州地铁</span>
        </div>
        <div style="text-align:center;">
            <span style="color:#0066cc;">二号线</span>
        </div>
    </div>
    <div class="metro-map" style="position:relative;margin-top:50px;margin-left:100px;height:1800px;">

    </div>
</body>
</html>

<!--站点模板-->
<script id="site" type="text/template">
    <div class="item" style="left: 0px;top: 0px;">
        <div class="line"></div>
        <div class="text" style="width:100px;text-align:right;">
            <span></span>
        </div>
        <div class="circular"></div>
    </div>
</script>
<!--换成图标模板-->
<script id="exchange" type="text/template">
    <svg class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7696"><path d="M514.56 962.56C267.776 962.56 66.56 761.344 66.56 514.56S267.776 66.56 514.56 66.56 962.56 267.776 962.56 514.56 761.344 962.56 514.56 962.56z m0-834.56C301.568 128 128 301.568 128 514.56S301.568 901.12 514.56 901.12s386.56-173.568 386.56-386.56S727.552 128 514.56 128z" p-id="7697"></path><path d="M737.28 482.816H291.84c-15.36 0-28.16-12.8-28.16-28.16s12.8-28.16 28.16-28.16h445.44c15.36 0 28.16 12.8 28.16 28.16s-12.8 28.16-28.16 28.16z" p-id="7698"></path><path d="M615.936 293.376l141.312 141.312c10.752 10.752 10.752 28.672 0 39.936-10.752 10.752-28.672 10.752-39.936 0l-141.312-141.312c-10.752-10.752-10.752-28.672 0-39.936 11.264-10.752 29.184-10.752 39.936 0zM311.808 555.008L453.12 696.32c10.752 10.752 10.752 28.672 0 39.936-10.752 10.752-28.672 10.752-39.936 0l-141.312-141.312c-10.752-10.752-10.752-28.672 0-39.936s28.672-11.264 39.936 0z" p-id="7699"></path><path d="M737.28 603.136H291.84c-15.36 0-28.16-12.8-28.16-28.16s12.8-28.16 28.16-28.16h445.44c15.36 0 28.16 12.8 28.16 28.16s-12.8 28.16-28.16 28.16z" p-id="7700"></path></svg>
</script>
<!--弹窗信息模板-->
<script id="info" type="text/template">
    <div class="info" style="position:fixed;left: 0px;top: 0px;box-shadow:0 0 13px #ccc;padding:6px 8px;border-radius:10px;font-size: 13px;opacity:0;background:#fff;"></div>
</script>
<!--交互js-->
<script type="text/javascript">
    $(function () {

        // 模板
        var site_template = $("#site").html().trim(); //获取站点模板并去掉前后空格
        var exchange_template = $("#exchange").html().trim(); //获取换乘模板并去掉前后空格
        var info_template = $("#info").html().trim(); //获取弹窗信息模板

        // 数组 - 根据站点间的时间差可知距离长度
        var line_arr = [
            {
                text: '嘉禾望岗',
                position: {
                    left: 500,
                    top: 0
                },
                class: {
                    rorate: 'line-transform-45',
                    line: 'line-2',
                    position: 'circular-position'
                },
                is_exchange_line: 1,
                direction: ['广州南站方向 始:06:00 末:23:35']
            },
            {
                text: '黄边',
                position: {
                    left: 450,
                    top: 50
                },
                class: {
                    rorate: 'line-transform-45',
                    line: 'line-2',
                    position: 'circular-position'
                },
                is_exchange_line: 0,
                direction: [
                    '嘉禾望岗方向 始:06:23 末:00:16',
                    '广州南站方向 始:06:03 末:23:36'
                ]
            },
            {
                text: '江夏',
                position: {
                    left: 400,
                    top: 100
                },
                class: {
                    rorate: 'line-transform-45',
                    line: 'line-2',
                    position: 'circular-position'
                },
                is_exchange_line: 0,
                direction: [
                    '嘉禾望岗方向 始:06:21 末:00:14',
                    '广州南站方向 始:06:05 末:23:38'
                ]
            },
            {
                text: '萧岗',
                position: {
                    left: 350,
                    top: 150
                },
                class: {
                    rorate: 'line-transform-45',
                    line: 'line-2',
                    position: 'circular-position'
                },
                is_exchange_line: 0,
                direction: [
                    '嘉禾望岗方向 始:06:18 末:00:13',
                    '广州南站方向 始:06:07 末:23:41'
                ]
            },
            {
                text: '白云文化广场',
                position: {
                    left: 300,
                    top: 200
                },
                class: {
                    rorate: 'line-transform-45',
                    line: 'line-2',
                    position: 'circular-position'
                },
                is_exchange_line: 0,
                direction: [
                    '',
                    ''
                ]
            },
            {
                text: '白云公园',
                position: {
                    left: 250,
                    top: 250
                },
                class: {
                    rorate: 'line-transform-45',
                    line: 'line-2',
                    position: 'circular-position'
                },
                is_exchange_line: 0,
                direction: [
                    '嘉禾望岗方向 始:06:14 末:00:09',
                    '广州南站方向 始:06:11 末:23:45'
                ]
            },
            {
                text: '飞翔公园',
                position: {
                    left: 224,
                    top: 314
                },
                class: {
                    rorate: '',
                    line: 'line-2',
                    position: ''
                },
                is_exchange_line: 0,
                direction: [
                    '嘉禾望岗方向 始:06:12 末:00:07',
                    '广州南站方向 始:06:13 末:23:47'
                ]
            },
            {
                text: '三元里',
                position: {
                    left: 224,
                    top: 384
                },
                class: {
                    rorate: '',
                    line: 'line-2',
                    position: ''
                },
                is_exchange_line: 0,
                direction: [
                    '嘉禾望岗方向 始:06:10 末:00:05',
                    '广州南站方向 始:06:10 末:23:49'
                ]
            },
            {
                text: '广州火车站',
                position: {
                    left: 224,
                    top: 464
                },
                class: {
                    rorate: '',
                    line: 'line-2',
                    position: ''
                },
                is_exchange_line: 1,
                direction: [
                    '',
                    ''
                ]
            }
        ]

        // 循环加载站点
        var html = '';
        for (var i = 0; i < line_arr.length; i++) {
            var data = line_arr[i];
            var temp = site_template;
            var dom = $(temp);
            $(".text", dom).html(data.text);
            dom.css({ "left": data.position.left, "top": data.position.top });
            $(".line", dom).addClass(data.class.rorate);
            $(".line", dom).addClass(data.class.line);
            $(".circular", dom).addClass(data.class.position);
            if (data.is_exchange_line) {
                $(".circular", dom).html(exchange_template);
            }
            html += dom.prop('outerHTML');
        }

        $(".metro-map").html(html);

        // 绑定站点事件
        $(".circular").mouseenter(function () {
            var parent = $(this).parent();
            var top_parent = parent.offset().top;
            var left_parent = parent.offset().left;
            var i = parent.index();
            var data = line_arr[i];
            var dom = $(info_template);
            dom.html(data.direction.join('<br />'));
            $(this).append(dom);
            var info = $('.info', $(this));
            var width = info.outerWidth();
            var height = info.outerHeight();
            info.css({ "left": (left_parent - (width / 2)), "top": top_parent - height - 6, "opacity": "1" });
        }).mouseleave(function () {
            $('.info', $(this)).remove();
        });
    })
</script>
相关文章
|
JavaScript 前端开发
前端基础 - JQuery自定义校验器
前端基础 - JQuery自定义校验器
65 0
|
27天前
|
JSON 缓存 前端开发
个人练习前端技术使用Bootstrap、JQuery、thymeleaf
个人练习前端技术使用Bootstrap、JQuery、thymeleaf
22 2
|
19天前
|
JavaScript 前端开发 API
【前端基础篇】JavaScript之jQuery介绍
【前端基础篇】JavaScript之jQuery介绍
43 0
|
5月前
|
前端开发 JavaScript UED
第五章(原理篇) 微前端技术之模块联邦与动态加载
第五章(原理篇) 微前端技术之模块联邦与动态加载
259 0
|
2月前
|
JavaScript 前端开发 程序员
后端程序员的前端必备-jQuery核心学习笔记
后端程序员的前端必备-jQuery核心学习笔记
52 13
|
3月前
|
JavaScript 前端开发 API
前端框架与库 - jQuery基础与DOM操作
【7月更文挑战第18天】jQuery 是一个简化JavaScript任务的库,以其“write less, do more”理念著称。核心功能包括DOM操作、事件处理和Ajax。DOM操作如选择元素(`$(&quot;p&quot;)`、`$(&quot;#myDiv&quot;)`、`$(&quot;.myClass&quot;)`)、创建及添加元素、修改属性和内容。事件处理如绑定(`click`)和触发(`trigger`)。常见问题涉及`$`符号冲突(使用`jQuery`代替)、异步加载管理和选择器性能优化。了解并规避这些问题能提升jQuery使用效率。
28 0
|
4月前
|
JavaScript 前端开发
杨校老师课堂之Web前端JS类库_JQuery案例[效果图与代码齐全]
杨校老师课堂之Web前端JS类库_JQuery案例[效果图与代码齐全]
34 0
|
5月前
|
JavaScript 前端开发 算法
JQuery 基本使用,2024BAT大厂Web前端社招面试题
JQuery 基本使用,2024BAT大厂Web前端社招面试题
JQuery 基本使用,2024BAT大厂Web前端社招面试题
|
5月前
|
JavaScript 前端开发 索引
【Web 前端】jQuery 里的 each() 是什么函数?你是如何使用它的?
【5月更文挑战第2天】【Web 前端】jQuery 里的 each() 是什么函数?你是如何使用它的?
|
5月前
|
JavaScript 前端开发
【Web 前端】jQuery 库中的 $() 是什么?
【5月更文挑战第1天】【Web 前端】jQuery 库中的 $() 是什么?