leaflet生成地图封装成jquery插件使用

 公司业务里一直都有使用leaflet地图插件来做地图展示、绘图等操作。公司有个项目已经有好几年了,由于项目原因一直在使用,今年由于google 地图 api过期,导致已经使用的地图无法加载。我作为现在该项目的维护者,虽然未参与项目的开发阶段,但是事情在我手上了还是要处理的。

上面说到api过期,无法加载地图了。我首先想到的是更换api key,FQ出去,搞了许久,没有成功。想想也是,就我这个英语水平成功就是偶然。当然也不全是英语问题,在我在墙外的世界捣鼓来捣鼓去的时候,隐约的发现谷歌api 有关的认证加强了(事情过了1一个月了,也忘记了)。

在最简单的方法尝试无效后,下定决心重写吧。好,写,一顿搜索猛如虎(差点写成:猛如狗了^_^),最后找了个现成的代码来改吧改吧就可用了。其实改完效果还可以,比以前多了 图层切换功能,而且使用国内地图也不怕哪天项目上说用谷歌不行了。

上面的事情距离我现在写这个文章的时候有一个月了。我是按照用一个项目改一个项目的原则,有些项目无人问津了,我便没改了。按照之前的套路,合并了其他已改项目的分支,项目类似,基本合并无冲突。代码到了现在的项目上了,由于这个项目用到了这套系统且要更新功能,我真nm的欲哭无泪,好老的项目了(用的还是php yii1的框架,前端用的是一框bjui的框架,说起它可能知道的人不多,但是jui框架应该要多点,它就是基于jui的框架)。

埋怨项目老,技术老之后还是要做事,因为在系统升级完成之前必须用它苟延残喘下去。翻看着代码,终于忍不住了,怎么可以这么重复的做某件事呢,难道是对它不想忘记吗? 重复不说,js里面混入php的判断,这些老的套路,越看越那啥了

又吐槽了代码之后,我先来展示一下那些 旋转代码吧(╯﹏╰)

    var mainLayer = new L.Google('HYBRID', {
        // maxNativeZoom : 3,
         // maxZoom : 4,
        // minZoom : 3,
        // noWrap : true,
        errorTileUrl : '<?php echo Yii::app()->baseUrl; ?>/images/tiles/empty.jpg?t=<?php echo time(); ?>',
        // continuousWorld : true,
        attribution : ''
    });

    var mainMap = L.map('map', {
            zoomControl: false
        })
        .setView([31.2288614009,104.0252005317], 17)
        .addLayer(mainLayer);

    <?php foreach ($lands as $key => $land) {
        if (!empty($land->polygon)) {
            $isBindPopup = $hasWarning = 'false';
            $labelContent = $land->name;
            if ((!empty($land->nodes) && count($land->nodes[0]->tempDataArr > 0) || count($land->devices) > 0)) {
                $isBindPopup = 'true';
            }
            if ($land->hasWarning()) {
                $hasWarning = 'true';
                $labelContent .= '<br><span style="font-weight:normal; color:#c00;">' . $land->warningMessage . '</span>';
            }
            ?>
            land_polygon(<?php echo $land->polygon; ?>, mainMap, '<?php echo $labelContent; ?>', <?php echo $land->id; ?>, <?php echo $isBindPopup; ?>, <?php echo $hasWarning; ?>);

    <?php } } ?>

    <?php foreach ($hikvideos as $video) {
        if (!empty($video->marker)) {
            $isNull = 'true';
            if (!empty($video->land->nodes) && count($video->land->nodes[0]->tempDataArr) > 0) {
                $isNull = 'false';
            }
            
            if (BUtils::isLocalClient()) {
                $video->ip = $video->local_ip;
                $video->http_port = $video->local_http_port;
            }
    ?>

        videoMarker(mainMap, <?php echo $video->marker; ?>, <?php echo $video->id; ?>, '<?php echo $video->name; ?>', <?php echo CJSON::encode($video); ?>, <?php echo $isNull ?>);

    <?php } } ?>

    <?php if (!empty($this->_config['xph_marker'])) {?>
        (function weatherStationMarker (map, latLng, labelContent) {
            var myIcon = L.divIcon({
                iconSize: [50, 67],
                className: 'weather-station-marker'
            });
            var marker = new L.Marker(latLng, {
                icon: myIcon
            });
            map.addLayer(marker);
            if (labelContent) {
                // marker.bindLabel(labelContent, {noHide: false}).addTo(map);
                var label = new L.Label({
                    noHide: true
                });
                label.setContent(labelContent).setLatLng({lat: latLng.lat, lng:latLng.lng + 1.4});
                map.showLabel(label);
            }
            marker.on('popupopen', function(event) {
                $('#map').bjuiajax('refreshDiv', 'leaflet_land_popup_xph');
            }).on('mouseout', function(event) {

            }).bindPopup(document.getElementById('leaflet_land_popup_xph'), {
                minWidth: 500,
                className: 'leaflet-popup'
            });
        })(mainMap, <?php echo $this->_config['xph_marker']; ?>, '气象站');
    <?php }?>

    <?php if (!empty($this->_config['xph_soil_marker'])) {?>
        (function soilStationMarker (map, latLng, labelContent) {
            var myIcon = L.divIcon({
                iconSize: [50, 67],
                className: 'soil-station-marker'
            });
            var marker = new L.Marker(latLng, {
                icon: myIcon
            });
            map.addLayer(marker);
            if (labelContent) {
                // marker.bindLabel(labelContent, {noHide: false}).addTo(map);
                var label = new L.Label({
                    noHide: true
                });
                label.setContent(labelContent).setLatLng({lat: latLng.lat, lng:latLng.lng + 1.4});
                map.showLabel(label);
            }
            marker.on('popupopen', function(event) {
                $('#map').bjuiajax('refreshDiv', 'leaflet_land_popup_xph_soil');
            }).on('mouseout', function(event) {

            }).bindPopup(document.getElementById('leaflet_land_popup_xph_soil'), {
                minWidth: 500,
                className: 'leaflet-popup'
            });
        })(mainMap, <?php echo $this->_config['xph_soil_marker']; ?>, '土壤墒情监测点');
    <?php }?>

    function videoMarker (map, latLng, id, labelContent, videoOption, isNull) {
        var myIcon = L.divIcon({
            iconSize: [25, 41],
            className: 'video-marker'
        });
        var marker = new L.Marker(latLng, {
            icon: myIcon
        });

        wth = 350;
        if (!isNull) {
            wth = 800;
        }

        map.addLayer(marker);
        if (labelContent) {
            marker.bindLabel(labelContent, {noHide: false}).addTo(map);
            // var label = new L.Label({
            //     noHide: true
            // });
            // label.setContent(labelContent).setLatLng(latLng);
            // map.showLabel(label);
        }
        marker.on('mouseover', function(event) {

        }).on('mouseout', function(event) {

        }).bindPopup(document.getElementById('leaflet_video_popup'), {
            minWidth: wth,
            className: 'leaflet-popup',
        });

        marker.on('popupopen', function(event) {
            setTimeout(function () {
                $('#leaflet_video_refresh').show();
                $('#leaflet_video_name').text(videoOption.name);

                video_window = '';
                var html = $('#bjui-navtab .tabsPageContent').find('#video_window').html();
                if (html) {
                    video_window = $('#video_window').remove();

                    $('#leaflet_video_window').html(video_window);
                    $('#video_window').addClass('video_window');

                    WebVideoCtrl.I_ChangeWndNum(1);
                }

                videoInit();
                videoLogin(videoOption);

                if (!isNull) {
                    $('#refresh_land_info').show();
                } else {
                    $('#refresh_land_info').hide();
                }

                $('#leaflet_video_window').bjuiajax('doLoad', {url:"<?php echo $this->createUrl('land/realdata', ['id' => '_ID_']); ?>".replace('_ID_', videoOption.land_id), target:"#refresh_land_info"});

            }, 10);
        }).on('popupclose', function(event) {
            console.log('popupclose', videoOption);
        });
    }

    function land_polygon (polygon, map, labelContent, id, isBindPopup, hasWarning) {
        var initColor = 'pink',
            initOpacity = 0.3,
            hoverColor = 'orange',
            hoverOpacity = 0.3;
        if (hasWarning) {
            initColor = 'red';
        }
        var land = new L.Polygon(polygon, {
            weight: 2,
            opacity: initOpacity,
            fillOpacity: initOpacity,
            color: initColor
        });
        var domId = 'leaflet_land_popup_' + id;
        map.addLayer(land);
        var label = new L.Label();
        label.setContent(labelContent).setLatLng(land.getBounds().getCenter());
        map.showLabel(label);
        land.on('mouseover', function(event) {
            land.setStyle({
                color: hoverColor,
                opacity: hoverOpacity,
                fillOpacity: hoverOpacity,
            });
        }).on('mouseout', function(event) {
            land.setStyle({
                color:initColor,
                opacity: initOpacity,
                fillOpacity: initOpacity,
            });
        }).on('popupopen', function(event) {
            $('#map').bjuiajax('refreshDiv', domId);
        });

        if (isBindPopup) {
            land.bindPopup(document.getElementById(domId), {
                minWidth: 500,
                className: 'leaflet-popup'
            });
        }
    }
</script>

 

就这样的代码,能在一个代码里面好几个地方重复出现,你说是有多大的心去维护啊,又难受了。

说了这么的故事,该说重点了,基于上面的情况呢,必须有个什么东西来优化它,想来想去,考虑地图是基于dom生成加载的,那这样的话,写一个jquery的插件应该是比较好的了,当然的话自己封装一个类也行。

对于jquery插件的话,我分享一个网址吧:jquery插件

附上巨人的肩膀

1、ChineseTmsProviders:Leaflet.ChineseTmsProviders

2、tileLayer.baidu

L.CRS.Baidu = new L.Proj.CRS('EPSG:3395', '+proj=merc +lon_0=0 +k=1 +x_0=1440 +y_0=255 +datum=WGS84 +units=m +no_defs', {
    resolutions: function () {
        level = 19
        var res = [];
        res[0] = Math.pow(2, 18);
        for (var i = 1; i < level; i++) {
            res[i] = Math.pow(2, (18 - i))
        }
        return res;
    }(),
    origin: [0, 0],
    bounds: L.bounds([20037508.342789244, 0], [0, 20037508.342789244])
});

L.tileLayer.baidu = function (option) {
    option = option || {};

    var layer;
    var subdomains = '0123456789';
    switch (option.layer) {
        //单图层
        case "vec":
        default:
            //'http://online{s}.map.bdimg.com/tile/?qt=tile&x={x}&y={y}&z={z}&styles=pl&b=0&limit=60&scaler=1&udt=20170525'
            layer = L.tileLayer('http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=' + (option.bigfont ? 'ph' : 'pl') + '&scaler=1&p=1', {
                name:option.name,subdomains: subdomains, tms: true
            });
            break;
        case "img_d":
            layer = L.tileLayer('http://shangetu{s}.map.bdimg.com/it/u=x={x};y={y};z={z};v=009;type=sate&fm=46', {
                name: option.name, subdomains: subdomains, tms: true
            });
            break;
        case "img_z":
            layer = L.tileLayer('http://online{s}.map.bdimg.com/tile/?qt=tile&x={x}&y={y}&z={z}&styles=' + (option.bigfont ? 'sh' : 'sl') + '&v=020', {
                name: option.name, subdomains: subdomains, tms: true
            });
            break;

        case "custom"://Custom 各种自定义样式
            //可选值:dark,midnight,grayscale,hardedge,light,redalert,googlelite,grassgreen,pink,darkgreen,bluish
            option.customid = option.customid || 'midnight';
            layer = L.tileLayer('http://api{s}.map.bdimg.com/customimage/tile?&x={x}&y={y}&z={z}&scale=1&customid=' + option.customid, {
                name: option.name, subdomains: "012", tms: true
            });
            break;

        case "time"://实时路况
            var time = new Date().getTime();
            layer = L.tileLayer('http://its.map.baidu.com:8002/traffic/TrafficTileService?x={x}&y={y}&level={z}&time=' + time + '&label=web2D&v=017', {
                name: option.name, subdomains: subdomains, tms: true
            });
            break;

        //合并
        case "img":
            layer = L.layerGroup([
                L.tileLayer.baidu({ name: "底图", layer: 'img_d', bigfont: option.bigfont }),
                L.tileLayer.baidu({ name: "注记", layer: 'img_z', bigfont: option.bigfont })
            ]);
            break;
    }
    return layer;
};

 

再谈谈我心路吧,其实也是司空见惯的东西了。

  1. 为了更好的配置,我选择了两种配置,也就是除了自己传递配置参数的话,也可以通过标签属性传递
  2. 不好解决坐标系问题,我选择了加一个参数来区分百度和其它地图
  3. 外部更好的使用,必须在需要的地方添加回调参数
  4. 为了统一的管理和不重复的添加,我选择了使用一个变量存储所有加载的图层。在设置的时候,已经出现的图层会直接返回

最后我贴上目前的一个代码,改代码下午才写,不完善,下周应该会完善自己需要使用的地方。虽然已过了青葱的岁月,可是代码水平还是难^_^。

 

/**
 * jQuery and leaflet Plugin createMap
 * jquery插件:生成百度、谷歌、高德、天地图等地图到页面
 *
 * version 1.0, 2020-03-20
 * by jcy
 * Git repository : https://github.com/jiechengyang/jqLeafletCreateMap
 */

/**
 * example:
 *
 * 默认生成谷歌等多图层【查看地图右上角图层管理工具】:var mapService = $("#map").createMap({center: [lat, lng]});
 *
 * 生成百度地图:var mapService = $("#map").createMap({center: [lat, lng], imap: 'Bd.Normal.Map'});
 *
 * 生成单张地图请传递:single:true
 *
 * 修改默认加载地图请传:iLayer:'对应chinaProviderKeys的key值'
 * */

/**
 * add method:
 * iconMarker: 图标加载
 * addPolygon: 面加载
 *
 */
(function ($) {
    function arrIndexOf(array, find, field) {
        var index = -1;
        for (var i = 0; i < array.length; i++) {
            var arr = array[i];
            if (arr[field] === find) {
                index = i;
                break;
            }
        }

        return index;
    }

    function mapService() {
        this.layers = [];
        this.chinaProviderKeys = [
            {
                key: 'Geoq.Normal.Map',
                name: '智图地图',
                group: 'Geog'
            },
            {
                key: 'Geoq.Normal.PurplishBlue',
                name: '智图午夜蓝',
                group: 'Geog'
            },
            {
                key: 'Geoq.Normal.Gray',
                name: '智图灰色',
                group: 'Geog'
            },
            {
                key: 'Geoq.Normal.Warm',
                name: '智图暖色',
                group: 'Geog'
            },
            {
                key: 'TianDiTu.Normal.Map',
                name: '天地图',
                group: 'TianDiTu'
            },
            {
                key: 'TianDiTu.Normal.Annotion',
                name: '',
                group: 'TianDiTu'
            },
            {
                key: 'TianDiTu.Satellite.Map',
                name: '天地图影像',
                group: 'TianDiTu'
            },
            {
                key: 'TianDiTu.Satellite.Annotion',
                name: '',
                group: 'TianDiTu'
            },
            {
                key: 'Google.Normal.Map',
                name: '谷歌地图',
                group: 'Google'
            },
            {
                key: 'Google.Satellite.Map',
                name: '谷歌影像',
                group: 'Google'
            },
            {
                key: 'GaoDe.Normal.Map',
                name: '高德地图',
                group: 'GaoDe'
            },
            {
                key: 'GaoDe.Satellite.Map',
                name: '高德影像',
                group: 'GaoDe'
            },
            {
                key: 'GaoDe.Satellite.Annotion',
                name: '',
                group: 'GaoDe'
            }
        ];
        this.map = null;
        this.get = function (key) {
            return this.layers.indexOf(key) === 1 ? this.layers[key] : null;
        }
        this.set = function (key, options) {
            if (this.layers.indexOf(key) >= 0) {
                return this.get(key);
            }

            if (arrIndexOf(this.chinaProviderKeys, key, 'key') === -1) {
                return null;
            }

            var layer = L.tileLayer.chinaProvider(key, options);
            this.layers[key] = layer;
            return layer;
        }

        this.delete = function (key) {
            delete this.layers[key];
        }

        this.getMap = function () {
            return this.map;
        }

        this.destroy = function () {
            this.layers = [];
            this.map = null;
        }

        this.init = function (domId, settings) {
            if (!settings.hasOwnProperty('iLayer')) {
                settings.iLayer = settings.imap;
            }
            var defaultMapOpts = {
                zoom: settings.zoom,
                zoomControl: settings.zoomControl,
                center: settings.center
            };

            var bdMap = false;
            if (settings.imap === 'Bd.Normal.Map') {
                defaultMapOpts.crs = L.CRS.Baidu;
                bdMap = true;
            }

            var mainMap = L.map(domId, defaultMapOpts);
            this.map = mainMap;
            var opts = {
                maxZoom: settings.maxZoom,
                minZoom: settings.minZoom,
            };

            if (bdMap) {
                opts.layer = settings.bdLayer ? settings.bdLayer : 'custom';
                opts.customid = settings.bdCustomid ? settings.bdCustomid : 'googlelite';
                var firstLayer = this.getBdMap(opts);
                settings.single = true;
            } else {
                var firstLayer = this.set(settings.iLayer, opts);
            }
            if (firstLayer) {
                mainMap.addLayer(firstLayer);
            }

            if (!settings.single) {
                var baseLayers = this.addLayers(settings.method, opts);
                if (baseLayers) {
                    var providerName = this.chinaProviderKeys[arrIndexOf(this.chinaProviderKeys, settings.iLayer, 'key')]['name'];
                    baseLayers[providerName] = firstLayer;
                    L.control.layers(baseLayers, null).addTo(mainMap);
                }
            }
            L.Util.requestAnimFrame(mainMap.invalidateSize, mainMap, !1, mainMap._container);
        }

        this.addLayers = function (method, opts) {
            method = 'add' + method;
            if (this.hasOwnProperty(method)) {
                return this[method].call(this, opts);
            }

            return {};
        }

        /**
         * 智图内容
         */
        this.addGeoNorMaps = function (options) {
            var layers = {};
            for (var i = 0; i < this.chinaProviderKeys.length; i++) {
                var provider = this.chinaProviderKeys[i];
                if (provider.group !== 'Geog') continue;
                var layer = this.set(provider.key, options);
                if (layer) {
                    layers[provider.name] = layer;
                }
            }

            return layers;
        }


        /**
         * 百度地图
         */
        this.getBdMap = function (options) {
            options = $.extend({
                // maxZoom: 18,
                // minZoom: 4,
                attribution: 'ⓒ 2020 Bd Map',
                layer: 'custom',
                customid: 'grassgreen',
                // crs: L.CRS.Baidu
            }, options);
            //百度:titleLayer.baidu.js
            //TODO: 请引入 proj4.js 和 proj4leaflet.js
            var layer = new L.tileLayer.baidu(options);
            this.layers['Bd.Normal.Map'] = layer;
            return layer;
        }

        /**
         * 天地图内容
         */
        this.addTianDiMaps = function (options) {
            var normalm = this.set('TianDiTu.Normal.Map', options),
                normala = this.set('TianDiTu.Satellite.Annotion', options),
                imgm = this.set('TianDiTu.Satellite.Map', options),
                imga = this.set('TianDiTu.Normal.Map', options);
            var normal = L.layerGroup([normalm, normala]),
                image = L.layerGroup([imgm, imga]);

            return {
                "天地图": normal,
                "天地图影像": image,
            }
        }

        /**
         * 谷歌地图内容
         */
        this.addGoogleMaps = function (options) {
            var normalMap = this.set('Google.Normal.Map', options),
                satelliteMap = this.set('Google.Satellite.Map', options);
            return {
                "谷歌地图": normalMap,
                "谷歌影像": satelliteMap,
            }
        }

        /**
         * 高德地图
         */
        this.addGaoDeMaps = function (options) {
            var Gaode = this.set('GaoDe.Normal.Map', options);
            var Gaodimgem = this.set('GaoDe.Satellite.Map', options);
            var Gaodimga = this.set('GaoDe.Satellite.Annotion', options);
            var Gaodimage = L.layerGroup([Gaodimgem, Gaodimga]);
            return {
                "高德地图": Gaode,
                "高德影像": Gaodimage,
            }

        }

        /**
         *  所有地图
         */
        this.addAllMaps = function (options) {
            var keys = [
                'GeoNorMaps',
                'TianDiMaps',
                'GoogleMaps',
                'GaoDeMaps',
            ];
            var layers = {};
            for (var i in keys) {
                var method = 'add' + keys[i];
                if (this.hasOwnProperty(method)) {
                    layers = $.extend(layers, this[method](options));
                }
            }

            return layers;
        }
    }

    /**
     *
     * 图表标记
     */
    mapService.prototype.iconMarker = function (icon, marker, labelContent, popupOpts, events) {
        events = events || null;
        labelContent = labelContent || null;
        var defaultOpts = {
            minWidth: 500,
            className: 'leaflet-popup'
        };
        popupOpts = $.extend(defaultOpts, popupOpts);
        var marker = new L.Marker(marker, {
            icon: icon
        });
        this.getMap().addLayer(marker);
        if (labelContent) {
            var label = new L.Label({
                noHide: true
            });
            label.setContent(labelContent).setLatLng({lat: marker.lat, lng: marker.lng + 1.4});
            this.getMap().showLabel(label);
        }
        if (popupOpts.id) {
            marker.bindPopup(document.getElementById(popupOpts.popupId), popupOpts);
        }

        if (events) {
            for (var eKey in events) {
                marker.on(eKey, events[eKey]);
            }
        }

        return marker;
    };

    /**
     *
     * 多边形地块
     */
    mapService.prototype.landPolygon = function (polygonObj, opts, events) {
        var defaultOpts = {
            initColor: 'pink',
            initOpacity: 0.3,
            hoverColor: 'orange',
            hoverOpacity: 0.3,
            domId: 'leaflet_land_popup_' + polygonObj.id,
        };
        events = events || {};
        opts = $.extend(defaultOpts, opts);
        if (polygonObj.hasWarning) {
            opts.initColor = 'red';
        }
        var land = new L.Polygon(polygonObj.polygon, {
            weight: 2,
            opacity: opts.initOpacity,
            fillOpacity: opts.initOpacity,
            color: opts.initColor
        });
        this.getMap().addLayer(land);
        var label = new L.Label();
        label.setContent(polygonObj.labelContent).setLatLng(land.getBounds().getCenter());
        this.getMap().showLabel(label);
        var defaultEvent = {
            mouseover: function (event) {
                land.setStyle({
                    color: opts.hoverColor,
                    opacity: opts.hoverOpacity,
                    fillOpacity: opts.hoverOpacity,
                });
            },
            mouseout: function (event) {
                land.setStyle({
                    color: opts.initColor,
                    opacity: opts.initOpacity,
                    fillOpacity: opts.initOpacity,
                });
            }
        };

        events = $.extend(defaultEvent, events);

        for (var eKey in events) {
            land.on(eKey, events[eKey]);
        }

        if (polygonObj.isBindPopup) {
            land.bindPopup(document.getElementById(polygonObj.domId), {
                minWidth: 500,
                className: 'leaflet-popup'
            });
        }

        return land;
    };

    var methods = {
        init: function (options) {
            var tData = this.data() || {};
            // TODO: 参数合并:隐式参数与显示参数;隐式参数:dom标签的data-属性 显示参数:调用对象传参
            options = $.extend(tData, options);
            var settings = $.extend({
                maxZoom: 18,// leaflet 参数
                minZoom: 5,// leaflet 参数
                zoom: 14,// leaflet 参数
                zoomControl: false,// leaflet 参数
                center: [30.29898916168688, 103.57831210632321],// leaflet 参数
                imap: 'Google.Normal.Map',// 插件 参数:默认地图加载谷歌地图,Bd.Normal.Map:由于坐标系问题,暂时只能加载它一个地图
                bdLayer: 'custom',// 百度地图图层选择,
                bdCustomid: 'googlelite',// 插件 参数:百度地图图层样式选择
                single: false,// 插件 参数:是否加载单个地图图层:默认是加载多张
                method: 'AllMaps'// 插件 参数:加载多张地图图层时有几种类型选择:智图、天地图、百度、谷歌、高德
            }, options);
            var service = new mapService();
            service.init(this.attr('id'), settings);
            return service;
        },
        destroy: function () {
            this.empty();
        }
    };

    $.fn.createMap = function (method) {
        method = method || null;
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
            // return methods.init(this, methods);
        } else {
            $.error('Method' + method + 'does not exist on jQuery.tooltip');
        }
    }
})(jQuery);

 

 最后再说一下,我们提升代码质量的唯一途径只有看源码。愿得到指点,愿共勉。

 

                                                                                                                                     -------------------------垃圾猿

posted @ 2020-03-21 00:28  yangboom  阅读(655)  评论(1编辑  收藏  举报
TOP