openlayers开发离线地图

时间:2024-03-12 12:47:04

最近公司搞一个离线地图项目。恰好我刚入职,这个任务就落到我头上了。咋搞?!???完全没头绪啊。

硬着头皮也要搞嘛!

经过痛苦的找资料,终于确定用openlayers实现。

1.先下载离线地图吧。通过MaptileDownloader1.95即可。

2.建立地图服务。将下载的地图放到openlayers下即可。

3.现在开始正式的代码部分,准备好了么?

<%@ page isELIgnored="true"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<%@ include file="/common/master.jsp"%>
<html>
<head>
<link rel="stylesheet" href="<%=request.getContextPath()%>/css/style.css" type="text/css" />
<style>

html ,body{
    width: 100%;
    height: 100%;
}
#map {
    width: 100%;
    height: 100%;
    float: left;
}

.olControlPanel div {
    display: block;
    position: absolute;
    top: 0px;
    left: 190px;
    width: 60px;
    height: 23px;
    margin: 5px;
}

.olControlPanel .olControlMouseDefaultsItemActive {
    background-image: url("/openlayers/img/Pan.gif");
}

.olControlPanel .olControlMouseDefaultsItemInactive {
    background-image: url("/openlayers/img/PanSelected.gif");
}

.olControlPanel .olControlZoomBoxItemInactive {
    width: 60px;
    height: 23px;
    position: absolute;
    top: 0px;
    left: 250px;
    background-image: url("/openlayers/img/ZoomInSelected.gif");
}

.olControlPanel .olControlZoomBoxItemActive {
    width: 60px;
    height: 23px;
    position: absolute;
    top: 0px;
    left: 250px;
    background-image: url("/openlayers/img/ZoomIn.gif");
}

.olControlPanel .olControlSelectFeatureItemInactive {
    width: 60px;
    height: 23px;
    position: absolute;
    top: 0px;
    left: 310px;
    background-image: url("/openlayers/img/InfoSelected.gif");
}

.olControlPanel .olControlSelectFeatureItemActive {
    width: 60px;
    height: 23px;
    position: absolute;
    top: 0px;
    left: 310px;
    background-image: url("/openlayers/img/Info.gif");
}

#panel {
    width: 15%;
    height: auto;
    float: left;
}
.olControlEditingToolbar {
    margin-right: 90px;
}
.olControlEditingToolbar .olControlDrawFeaturePointItemActive {
    background-position: -77px -23px;
     
    /* background: #fff url(\'../openlayers/img/marker.png\') no-repeat left top;*/
}

.olControlEditingToolbar .olControlDrawFeaturePointItemInactive {
    background-position: -77px -0px;
}

.olPopup {
    width: 300px ;
    height :   auto;
    font-size: 10px;
}

.olPopupContent {
    height:inherit;
    width:inherit;
}

button {
    font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
    position: absolute;
    font-size: 1.5em;
    text-transform: uppercase;
    padding: 7px 15px;
    width: 30px;
    border-radius: 10px;
    color: #FFF;
    text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.8);
    border-width: 5px;
    border-style: solid;
    border-color: transparent transparent rgba(0, 0, 0, 0.35);
    -moz-border-top-colors: none;
    -moz-border-right-colors: none;
    -moz-border-bottom-colors: none;
    -moz-border-left-colors: none;
    border-image: none;
    cursor: pointer;
    animation: 1s ease 0s alternate none infinite pulse;
    transition: #000 0.4s ease 0s, border 0.2s ease 0s, margin 0.2s ease 0s;
    z-index: 9999;
    filter: alpha(opacity = 70); /*IE滤镜,透明度50%*/
    -moz-opacity: 0.7; /*Firefox私有,透明度50%*/
    opacity: 0.7; /*其他,透明度50%*/
}

#lineMenu {
    top: 50px;
    right: 10px;
    background: none repeat scroll 0% 0% rgba(25, 90, 198, 1);
}

#pointMenu {
    top: 150px;
    right: 10px;
    background: none repeat scroll 0% 0% #A0C3FD;
}

.menuContent {
    font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
    position: absolute;
    font-size: 1.5em;
    text-transform: uppercase;
    padding: 7px 15px;
    width: 200px;
    height: 400px;
    overflow: auto;
    border-radius: 10px;
    color: #FFF;
    text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.2);
    border-width: 5px;
    border-color: transparent transparent rgba(0, 0, 0, 0.35);
    background: none repeat scroll 0% 0% rgba(254, 254, 254, 1);
    background-image:url("<%=request.getContextPath()%>/background/images/biienbg.png");
    -moz-border-top-colors: none;
    -moz-border-right-colors: none;
    -moz-border-bottom-colors: none;
    -moz-border-left-colors: none;
    border-image: none;
    cursor: pointer;
    animation: 1s ease 0s alternate none infinite pulse;
    transition: #000 0.4s ease 0s, border 0.2s ease 0s, margin 0.2s ease 0s;
    z-index: 9999;
    filter: alpha(opacity = 70); /*IE滤镜,透明度50%*/
    -moz-opacity: 0.7; /*Firefox私有,透明度50%*/
    opacity: 0.7; /*其他,透明度50%*/
}

#lines {
    top: 50px;
    right: 40px;
    display: none;
    color:#fff;
}

#lines img{
width:14px;
}


#points {
    top: 50px;
    right: 40px;
    display: none;
}

#fullScreen{
    top: 4px;
    width: 26px;
    height: 28px;
    right: 10px;
    margin-right:3px;
}
.nav{
    position: absolute;
    -moz-border-top-colors: none;
    -moz-border-right-colors: none;
    -moz-border-bottom-colors: none;
    -moz-border-left-colors: none;
    border-image: none;
    cursor: pointer;
    animation: 1s ease 0s alternate none infinite pulse;
    z-index: 9999;
    opacity: 0.7;
    top: 4px;
    width: 76px;
    height: 28px;
    right: 10px;
    margin-right:3px;
}
.nav img{
    width: 26px;
    height: 28px;
}
form p{
    margin-bottom: 10px;
}
form{
    width:300px;
    height:auto;
}
form span{
    font-size:15px;
    font-weight:bold;
    margin-left: 30%;
}

</style>
<script src="<%=request.getContextPath()%>/js/openlayers/OpenLayers.js" type="text/javascript"></script>
<link rel="stylesheet" href="<%=request.getContextPath()%>/css/zTreeStyle/zTreeStyle.css" type="text/css">
<script type="text/javascript" src="<%=request.getContextPath()%>/js/jquery.ztree.core-3.5.js"></script>
<script type="text/javascript" src="<%=request.getContextPath()%>/js/jquery.ztree.excheck-3.5.js"></script>

<script type="text/javascript">
    var arrmarkers = new Array();
    var sf;
    var editingToolbar;
    var pointFeatures= new Array();
    var routeList = new Array();
    var setting = {
            check: {
                enable: true,
                //chkStyle: "checkbox",
                chkboxType: { "Y": "s", "N": "s" }
            },
            data: {
                simpleData: {
                    enable: true
                }
            },callback: {
                //beforeCheck: beforeCheck,
                onCheck: onCheck,
                onClick: zTreeOnClick
            }
        };
    var zNodes=[];
    var panel;
    var draw; 
    var navigater;
    var dragFeature;
    $(document).ready(function() {
                        map = new OpenLayers.Map("map", {
                            maxExtent : new OpenLayers.Bounds(
                                    -20037508.3427892, -20037508.3427892,
                                    20037508.3427892, 20037508.3427892),
                            numZoomLevels : 17,
                            maxResolution : 156543.0339,
                            units : \'m\',
                            projection : "EPSG:900913",
                            displayProjection : new OpenLayers.Projection(
                                    "EPSG:4326")
                        });

                        layer = new OpenLayers.Layer.TMS(
                                "基础层",
                                "http://127.0.0.1:8080/googlemaps/openlayers/roadmap/", {
                                    \'type\' : \'png\',
                                    \'getURL\' : get_my_url
                                });

                        map.addLayers([ layer ]);

                        var lonLat = new OpenLayers.LonLat(113.26080, 23.12649);
                        lonLat.transform(map.displayProjection, map
                                .getProjectionObject());
                        map.setCenter(lonLat, 12);
                        map.addControl(new OpenLayers.Control.PanZoomBar({position : new OpenLayers.Pixel(2, 15)}));

                        map.addControl(new OpenLayers.Control.MousePosition());
                        map.addControl(new OpenLayers.Control.KeyboardDefaults());

                        //新增部分,将对vector_line这个图层定义一个样式,不使用默认样式
                        var styleMap = new OpenLayers.StyleMap(
                                {
                                    "default" : new OpenLayers.Style(
                                            {
                                                fillOpacity : 1,
                                                strokeOpacity : 1,
                                                strokeColor : "#1f32e0",
                                                graphicWidth : 40,
                                                graphicHeight : 40,
                                                graphicYOffset : -40,
                                                //externalGraphic : ",
                                                externalGraphic : "${image}",
                                                labelXOffset : 0,
                                                labelYOffset : 50,
                                                label : "${label}",
                                                labelColor : "#efe9e2",
                                                pointRadius : 8,
                                                fillColor : "black",
                                                strokeColor : "#666666",
                                                strokeWidth : 4,
                                                graphicZIndex : 1
                                            }),
                                    "select" : new OpenLayers.Style(
                                            {
                                                fillOpacity : 0.6,
                                                strokeOpacity : 0.8,
                                                strokeColor : "#000000",
                                                graphicWidth : 40,
                                                graphicHeight : 40,
                                                graphicYOffset : -40,
                                                externalGraphic : "${image}",
                                                pointRadius : 8,
                                                fillColor : "black",
                                                strokeColor : "#666666",
                                                strokeWidth : 4,
                                                graphicZIndex : 1
                                            })
                                });
                        
                        var pointStyle = new OpenLayers.StyleMap(
                                {
                                    "default" : new OpenLayers.Style(
                                            {
                                                fillOpacity : 1,
                                                strokeOpacity : 1,
                                                strokeColor : "#1f32e0",
                                                graphicWidth : 40,
                                                graphicHeight : 40,
                                                graphicYOffset : -40,
                                                //externalGraphic : ",
                                                externalGraphic : "<%=request.getContextPath()%>/js/openlayers/img/marker.png",
                                                labelXOffset : 0,
                                                labelYOffset : 0,
                                                label : "${label}",
                                                labelColor : "#efe9e2",
                                                pointRadius : 8,
                                                fillColor : "black",
                                                strokeColor : "#666666",
                                                strokeWidth : 4,
                                                graphicZIndex : 1
                                            }),
                                    "select" : new OpenLayers.Style(
                                            {
                                                fillOpacity : 0.6,
                                                strokeOpacity : 0.8,
                                                strokeColor : "#000000",
                                                graphicWidth : 40,
                                                graphicHeight : 40,
                                                graphicYOffset : -40,
                                                externalGraphic : "<%=request.getContextPath()%>/js/openlayers/img/marker.png",
                                                pointRadius : 8,
                                                fillColor : "black",
                                                strokeColor : "#666666",
                                                strokeWidth : 4,
                                                graphicZIndex : 1
                                            })
                                });
                        geojson = new OpenLayers.Format.GeoJSON();
                        //创建GeoJSON类对象,用于解析JSON串    
                        vector_line = new OpenLayers.Layer.Vector("线路", {
                            styleMap : styleMap,
                            rendererOptions : {
                                zIndexing : true
                            }
                        });
                        vector_point = new OpenLayers.Layer.Vector("网点", {
                            styleMap : pointStyle,
                            rendererOptions : {
                                zIndexing : true
                            }
                        });
                        map.addLayer(vector_line);
                        //首先屏蔽掉默认的右键:
                        map.div.oncontextmenu = function () { return false;};
                         
                        // 创建select control
                        sf = new OpenLayers.Control.SelectFeature(vector_line);
                        // 创建select control
                        sf4Point = new OpenLayers.Control.SelectFeature(vector_point);
                        // 将select control添加到map上
                        map.addControl(sf);
                        // 注册Select事件
                        sf.onSelect = onFeatureSelect4Edit;
                        
                        // 注册取消Select事件
                        sf.onUnselect = onFeatureUnselect;
                        // 激活select control,否则select control不可用
                        sf.activate();

                        //取得路线
                        getLines();
                        getPoints();
                    });
    function getPoints(){
        //取得网点
        vector_point.removeAllFeatures();
        zNodes=[];
        $.getJSON("sys/geOrgJson.action",function(data) {
            for ( var i = 0; i < data.point.length; i++) {
                tempFeature = geojson.read(data.point[i]);
                if(data.point[i].features[0].geometry.type=="Point"){
                    tempFeature.data=data.point[i];
                    pointFeatures[i]=tempFeature;
                    vector_point.addFeatures(tempFeature);//read返回OpenLayers.Feature.Vector
                    zNodes.push({id:data.point[i].features[0].properties.serialNo,serialNo:data.point[i].features[0].properties.serialNo, pId:data.point[i].features[0].properties.pSerialNo, name:data.point[i].features[0].properties.name,open:false,checked:true,number:data.point[i].features[0].properties.number,x:data.point[i].features[0].geometry.coordinates[0],y:data.point[i].features[0].geometry.coordinates[1]});
                }
            }
         $.fn.zTree.init($("#treeDemo"), setting, zNodes);
        });
    }
    function getLines(huidiao){
        $("#lines").empty();
        var lines = "<ul>";
        var features= new Array();
        vector_line.removeAllFeatures();
        $.getJSON("sys/geRouteJson.action",function(data) {
            for ( var i = 0; i < data.line.length; i++) {
                tempFeature = geojson.read(data.line[i]);
                if (data.line[i].features[0].geometry.type == "LineString") {
                    features[i]=tempFeature;
                    vector_line.addFeatures(tempFeature);//read返回OpenLayers.Feature.Vector
                    lines += "<li><input class=\'chenckBoxItm\' type=\'checkbox\' checked=\'checked\' name="+i+" id=\'"+data.line[i].features[0].geometry.id+"\'><span style=\'font-weight:bold;\'>"+ data.line[i].features[0].geometry.name+"</span>";
                    lines+="<ul id=\'a"+i+"\' class=\'updown\' style=\'display:none;margin-left:20px;\'>";
                    //lines+="<ul>";
                    for(var j =1;j<data.line[i].features.length;j++){
                        lines+="<li>";
                        lines+=data.line[i].features[j].geometry.name;
                        if(j==1){
                            lines+="<img src=\'<%=request.getContextPath()%>/background/images/up_disabled.png\'/>";
                        }else{
                            lines+="<img src=\'<%=request.getContextPath()%>/background/images/up.png\' onclick=\'upOrder("+i+","+data.line[i].features[j-1].geometry.id+","+data.line[i].features[j].geometry.id+")\'/>";
                        }
                        if(j==data.line[i].features.length-1){
                            lines+="<img src=\'<%=request.getContextPath()%>/background/images/down_disabled.png\'/></li>";
                        }else{
                            lines+="<img src=\'<%=request.getContextPath()%>/background/images/down.png\' onclick=\'upOrder("+i+","+data.line[i].features[j+1].geometry.id+","+data.line[i].features[j].geometry.id+")\'/></li>";
                        }
                    }
                    lines+="</ul></li>";
                }
            }
            lines += "</ul>";
            $(lines).appendTo("#lines");
            $("#lines input[type=\'checkbox\']").bind("click",function() {
                var num=$(this).attr("name");
                $(this).parent().parent().find("ul").hide("fast");
                if ($(this).is(":checked")) {
                    vector_line.addFeatures(features[num]);
                    $(this).parent().find("ul").show("fast");
                } else {
                    $(this).parent().find("ul").hide("fast");
                    vector_line.removeFeatures(features[num]);
                }
            });
            $("#lines li span").bind("click",function() {
                $(".updown").hide("fast");
                if ($(this).parent().children("ul").is(":visible")) {
                    $(this).parent().children("ul").hide("fast");
                } else {
                    $(this).parent().children("ul").show("fast");
                }
            });
            if (huidiao) {
                huidiao();
            }
        });    
    
    }
    //调整顺序,+
    function upOrder(element,orgId,id2){
        $("#a"+element).show();
        $.getJSON("sys/upOrder.action",{"id":orgId,"id2":id2},function(data) {
            getLines(function(){$("#a"+element).css("display","block");});
        });
    }
    function removeAllPopup() {
        var len = map.popups.length;
        for ( var i = len - 1; i >= 0; i--) {
            map.removePopup(map.popups[i]);
        }
    }
    function get_my_url(bounds) {
        var res = this.map.getResolution();
        var x = Math.round((bounds.left - this.maxExtent.left)
                / (res * this.tileSize.w));
        var y = Math.round((this.maxExtent.top - bounds.top)
                / (res * this.tileSize.h));
        var z = this.map.getZoom();

        var path = "" + z + "/" + x + "/" + y + "." + this.type;
        var url = this.url;
        if (url instanceof Array) {
            url = this.selectUrl(path, url);
        }
        return url + path;
    }
    function deleteOrg(event) {
        var feature=vector_point.getFeatureFromEvent(event);
        if(feature.data.id)
        {
          if(confirm("确定要删除吗?"))
           {
              $.getJSON("sys/deleteOrgById.action",{ids:feature.data.id},function(data) {
                if (data==null||data==""||data.info == "1") {
                    alert("删除机构失败,机构可能被其他系统资源引用");
                } else {
                    removeAllPopup();
                    vector_point.removeFeatures(feature);
                    alert("删除成功");
                }
            });
           }
        }else{
            removeAllPopup();
            vector_point.removeFeatures(feature);  
        }
        getPoints();
    }

    //关闭弹出窗口的函数
    function onPopupClose(evt) {
        sf.unselect(selectedFeature);
        getPoints();
    }

    //构造弹出窗口的函数
    function onFeatureSelect4Edit(feature) {
        removeAllPopup();
        if(draw!=null){
            draw.deactivate();
        }

        var html;
        if (feature.data.id) {
            var html=\'<iframe src="sys/org!edit.action?ids=\'+feature.data.id+\'&xcode=\'+feature.geometry.x+\'&ycode=\'+feature.geometry.y+\'" width="400px" height="200px"></iframe> \';
        } else {
            var html=\'<iframe src="sys/org!edit.action?xcode=\'+feature.geometry.x+\'&ycode=\'+feature.geometry.y+\'" width="400px" height="200px"></iframe> \';
        }
        selectedFeature = feature;
        popup = new OpenLayers.Popup.Anchored("chicken", feature.geometry.getBounds().getCenterLonLat(),new OpenLayers.Size(250, 75), html,null, true, onPopupClose);
        feature.popup = popup;
        map.addPopup(popup);
        $(".olPopup").css("width", "inherit");
        $(".olPopup").css("height", "inherit");
        $(".olPopupContent").css("width", "inherit");
        $(".olPopupContent").css("height", "inherit");
    }
    //销毁弹出窗口的函数
    function onFeatureUnselect(feature) {
        map.removePopup(feature.popup);
        feature.popup.destroy();
        feature.popup = null;
    }
    function drag(feature){
        $.getJSON("sys/updateLocation.action",{"id":feature.data.id,"xcode":feature.geometry.x,"ycode":feature.geometry.y},function(data) {
            
        });    
    }
    function showLines() {
        removeAllPopup();
        $(\'#points\').hide("fast");
        $("#lineMenu").css("background", "rgba(25, 90, 198, 1)");
        $("#pointMenu").css("background", "#A0C3FD");
        if ($(\'#lines\').is(\':visible\')) {
            $(\'#lines\').hide("fast");
        } else {
            $(\'#lines\').show("fast");
        }
        getLines();
        if (navigater != null) {
            navigater.activate();
        }

        draw.deactivate();
        panel.addControls([ navigater ]);
        map.removeControl(draw);
        map.removeControl(panel);

        if (vector_point != null) {
            map.removeLayer(vector_point,false);
        }
        if (vector_line != null) {
            map.addLayer(vector_line);
        }
    }
    function showPoints() {
        removeAllPopup();
        $("#pointMenu").css("background", "rgba(25, 90, 198, 1)");
        $("#lineMenu").css("background", "#A0C3FD");
        if ($(\'#points\').is(\':visible\')) {
            $(\'#points\').hide("fast");
        } else {
            $(\'#points\').show("fast");
        }
        $(\'#lines\').hide("fast");
        if (vector_line != null) {
            map.removeLayer(vector_line,false);
        }
        if (vector_point != null) {
            map.addLayer(vector_point);
        }
        panel = new OpenLayers.Control.Panel({
            displayClass : "olControlEditingToolbar"
        });
        draw = new OpenLayers.Control.DrawFeature(vector_point,
                OpenLayers.Handler.Point, {
                    displayClass : "olControlDrawFeaturePoint",
                    title : "添加网点"
                });
        navigater = new OpenLayers.Control.Navigation({
            title : "Navigate"
        });
        dragFeature=new OpenLayers.Control.DragFeature(vector_point);
        dragFeature.onComplete=drag;
        panel.addControls([ navigater, draw ]);
        //navigater.activate();
        draw.featureAdded = onFeatureSelect4Edit;
        map.addControl(panel);
        map.addControl(dragFeature);
        //激活控件
        dragFeature.activate();
        // 将select control添加到map上
        map.addControl(sf4Point);
        // 激活select control,否则select control不可用
        sf4Point.activate();
        // 注册Select事件
        sf4Point.onSelect = onFeatureSelect4Edit;
        
        // 注册取消Select事件
        sf4Point.onUnselect = onFeatureUnselect;
        var mouseRight = new OpenLayers.Control();
        OpenLayers.Util.extend(mouseRight, {
        contextmenu: function(e) {deleteOrg(e); },
        setMap: function() { OpenLayers.Control.prototype.setMap.apply(this, arguments); this.map.events.register( \'contextmenu\', this, this.contextmenu); }});
        mouseRight.activate();
        map.addControl(mouseRight); 
        var treeObj = $.fn.zTree.getZTreeObj("treeDemo");
        if(treeObj!=null){
            treeObj.refresh();
        }
    }
    function onCheck(e, treeId, treeNode) {
        if (treeNode.checked) {
            var x = treeNode.x;
            var y = treeNode.y;
            var lonLat = new OpenLayers.LonLat(x, y);
            map.setCenter(lonLat);
            for ( var ii = 0; ii < zNodes.length; ii++) {
                var serialNo = zNodes[ii].id.substring(0, treeNode.serialNo.length);
                if (serialNo == treeNode.serialNo) {
                    vector_point .addFeatures(pointFeatures[zNodes[ii].number - 1]);
                }
            }
        } else {
            vector_point.removeFeatures(pointFeatures[treeNode.number - 1]);
            for ( var ii = 0; ii < zNodes.length; ii++) {
                var serialNo = zNodes[ii].id.substring(0,treeNode.serialNo.length);
                if (serialNo == treeNode.serialNo) {
                    vector_point.removeFeatures(pointFeatures[zNodes[ii].number - 1]);
                }
            }
        }
    }
    function full() {
        window.parent.full();
    }
    //网点点击事件
    function zTreeOnClick(e,treeId, treeNode) {
        var x = treeNode.x;
        var y = treeNode.y;
        var lonLat = new OpenLayers.LonLat(x, y);    
        map.setCenter(lonLat);
    }
    
</script>
</head>

<body>


<div id="map"></div>
<div class="nav">
<img id="fullScreen" src="<%=request.getContextPath()%>/background/images/fullScreen.png" onclick="full();"/>
<a href="<%=request.getContextPath()%>/openMap.action"><img src="<%=request.getContextPath()%>/background/images/task.png"/></a>
</div>
<button id="lineMenu" onclick="showLines()">线路</button>
<button id="pointMenu" onclick="showPoints()">网点</button>
<div id="lines" class="menuContent"></div>
<div id="points" class="menuContent">
    <div class="zTreeDemoBackground left">
        <ul id="treeDemo" class="ztree"></ul>
    </div>
</div>
</body>
</html>

解释下上述代码:

地图中有三个图层,一个基础图层,不可修改,一个点图层,一个线图层。

其中,点图层中,显示的是机构,图层中有一个菜单,是通过Ztree建立的树形结构。通过勾选显示,并且单击可定位。线图层中,显示的是网点的连线,同样也有一个菜单,通过菜单,可以调整线路中,点连线的顺序。

网点选择时候,会弹出菜单进行编辑。可以进行拖动,改变其位置。

另外,右键菜单是删除点操作。右键操作需要修改openlayers的库文件,如何修改,请参照:http://blog.csdn.net/sen2046/article/details/2735601即可。

话不多说,很伤心,之前写这文章,很详细的,可是快完成的时候,firefox崩溃了。我也跟着崩溃了。只好重写,没那么详细了!