javascript - 如何使用 RequireJS 分解大型 Javascript 文件

标签 javascript requirejs require

我是 Javascript 新手,因此 requireJS - 我目前正在使用 Openlayers 3 示例自学,其中我刚刚附加到一个大型 JS 文件。看到这很快变得不守规矩,我阅读了有关 RequireJS 的内容,并认为我应该从一开始就养成正确做事的习惯; “这就是我遇到问题的地方”。

[我认为这并不重要,但我正在使用 Asp.net MVC] 基本上,我希望将文件分成较小的相关模块,例如

  • map [由所有模块使用并启动基础层 map ]
  • 绘制[处理点/多边形等并添加到 map 中 另一层]
  • 地理位置[包含用于绘图的地理定位功能]
  • 等等,等等

...可以灵活地立即激活所有层,或者使用易于管理的 JS 代码来选择少数层。

我曾多次尝试将此代码分解为单独的 JS 文件,[ map /绘制/地理定位],但都失败了,因为我觉得我没有掌握 requireJS 方法(以免让读者感到困惑以及我自己,我忽略了添加我的尝试)。

这是有效的基本代码:

require.config({
    baseUrl: "/Scripts",
    paths: {
        //jquery: "/lib/jquery-1.11.1.min",
        ol: [
            "http://openlayers.org/en/v3.8.1/build/ol",
            "/lib/ol"
        ],
        domReady: "/lib/domReady"
    },
    //map: { main: { test: "/Modules/Test/scripts/test" } },
    //The shim section is to tell RequireJS about any dependencies your files have before they can be used.  
    //Here, we are saying if we call “ol” to load that module, we have to load “jquery” first.
    //shim: {
        //ol: ["jquery"]
    //},
    //packages: [
    //    {
    //name: 'test',
    //location: 'http://...
    //main: 'main'                
    //}]
});

我想分手的文件:

define(["ol"], function (ol) {

    $(document).ready(function () {

        //****************
        //------MAP-------

        //Setup Map Base
        // creating the view
        var view = new ol.View({
            center: ol.proj.fromLonLat([5.8713, 45.6452]),
            zoom: 19
        });

        // creating the map
        var map = new ol.Map({
            layers: [
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                })
            ],
            target: "map",
            controls: ol.control.defaults({
                attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
                    collapsible: false
                })
            }),
            view: view
        });

        //****************
        //-----DRAW------

        var features = new ol.Collection();
        var featureOverlay = new ol.layer.Vector({
            source: new ol.source.Vector({ features: features }),
            style: new ol.style.Style({
                fill: new ol.style.Fill({
                    color: "rgba(255, 255, 255, 0.2)"
                }),
                stroke: new ol.style.Stroke({
                    color: "#ffcc33",
                    width: 2
                }),
                image: new ol.style.Circle({
                    radius: 7,
                    fill: new ol.style.Fill({
                        color: "#ffcc33"
                    })
                })
            })
        });
        featureOverlay.setMap(map);

        var modify = new ol.interaction.Modify({
            features: features,
            // the SHIFT key must be pressed to delete vertices, so
            // that new vertices can be drawn at the same position
            // of existing vertices
            deleteCondition: function (event) {
                return ol.events.condition.shiftKeyOnly(event) &&
                    ol.events.condition.singleClick(event);
            }
        });
        map.addInteraction(modify);

        var draw; // global so we can remove it later
        function addInteraction() {
            draw = new ol.interaction.Draw({
                features: features,
                type: /** @type {ol.geom.GeometryType} */ (typeSelect.value)
            });
            map.addInteraction(draw);
        }

        var typeSelect = document.getElementById("type");


        /**
         * Let user change the geometry type.
         * @param {Event} e Change event.
         */
        typeSelect.onchange = function (e) {
            map.removeInteraction(draw);
            addInteraction();
        };

        addInteraction();

        //****************
        //---GEOLOCATION---//

        // Common app code run on every page can go here
        // Geolocation marker
        var markerEl = document.getElementById("geolocation_marker");
        var marker = new ol.Overlay({
            positioning: "center-center",
            element: markerEl,
            stopEvent: false
        });
        map.addOverlay(marker);

        // LineString to store the different geolocation positions. This LineString
        // is time aware.
        // The Z dimension is actually used to store the rotation (heading).
        var positions = new ol.geom.LineString([],
            /** @type {ol.geom.GeometryLayout} */ ("XYZM"));

        // Geolocation Control
        var geolocation = new ol.Geolocation( /** @type {olx.GeolocationOptions} */({
            projection: view.getProjection(),
            trackingOptions: {
                maximumAge: 10000,
                enableHighAccuracy: true,
                timeout: 600000
            }
        }));

        var deltaMean = 500; // the geolocation sampling period mean in ms

        // Listen to position changes
        geolocation.on("change", function (evt) {
            var position = geolocation.getPosition();
            var accuracy = geolocation.getAccuracy();
            var heading = geolocation.getHeading() || 0;
            var speed = geolocation.getSpeed() || 0;
            var m = Date.now();

            addPosition(position, heading, m, speed);

            var coords = positions.getCoordinates();
            var len = coords.length;
            if (len >= 2) {
                deltaMean = (coords[len - 1][3] - coords[0][3]) / (len - 1);
            }

            var html = [
                "Position: " + position[0].toFixed(2) + ", " + position[1].toFixed(2),
                "Accuracy: " + accuracy,
                "Heading: " + Math.round(radToDeg(heading)) + "°",
                "Speed: " + (speed * 3.6).toFixed(1) + " km/h",
                "Delta: " + Math.round(deltaMean) + "ms"
            ].join("<br />");
            document.getElementById("info").innerHTML = html;
        });

        geolocation.on("error", function () {
            alert("geolocation error");
            // FIXME we should remove the coordinates in positions
        });

        // convert radians to degrees
        function radToDeg(rad) {
            return rad * 360 / (Math.PI * 2);
        }

        // convert degrees to radians
        function degToRad(deg) {
            return deg * Math.PI * 2 / 360;
        }

        // modulo for negative values
        function mod(n) {
            return ((n % (2 * Math.PI)) + (2 * Math.PI)) % (2 * Math.PI);
        }

        function addPosition(position, heading, m, speed) {
            var x = position[0];
            var y = position[1];
            var fCoords = positions.getCoordinates();
            var previous = fCoords[fCoords.length - 1];
            var prevHeading = previous && previous[2];
            if (prevHeading) {
                var headingDiff = heading - mod(prevHeading);

                // force the rotation change to be less than 180°
                if (Math.abs(headingDiff) > Math.PI) {
                    var sign = (headingDiff >= 0) ? 1 : -1;
                    headingDiff = -sign * (2 * Math.PI - Math.abs(headingDiff));
                }
                heading = prevHeading + headingDiff;
            }
            positions.appendCoordinate([x, y, heading, m]);

            // only keep the 20 last coordinates
            positions.setCoordinates(positions.getCoordinates().slice(-20));

            // FIXME use speed instead
            if (heading && speed) {
                markerEl.src = "/OrchardLocal/Media/Default/Map/geolocation_marker.png"; //"data/geolocation_marker_heading.png";F:\DeleteMeThree\_Orchard-19x\src\Orchard.Web\Modules\Cns.OL\Contents/Images/geolocation_marker.png
            } else {
                //alert(markerEl.src); PETE: Not sure if this is std OL practice, but this is achieved by already having an element
                //called "geolocation_marker" in the dom as an img, which this uses? Strange to me
                markerEl.src = "/OrchardLocal/Media/Default/Map/geolocation_marker.png"; //I added img via media module - ridiculous?!
            }
        }

        var previousM = 0;
        // change center and rotation before render
        map.beforeRender(function (map, frameState) {
            if (frameState !== null) {
                // use sampling period to get a smooth transition
                var m = frameState.time - deltaMean * 1.5;
                m = Math.max(m, previousM);
                previousM = m;
                // interpolate position along positions LineString
                var c = positions.getCoordinateAtM(m, true);
                var view = frameState.viewState;
                if (c) {
                    view.center = getCenterWithHeading(c, -c[2], view.resolution);
                    view.rotation = -c[2];
                    marker.setPosition(c);
                }
            }
            return true; // Force animation to continue
        });

        // recenters the view by putting the given coordinates at 3/4 from the top or
        // the screen
        function getCenterWithHeading(position, rotation, resolution) {
            var size = map.getSize();
            var height = size[1];

            return [
                position[0] - Math.sin(rotation) * height * resolution * 1 / 4,
                position[1] + Math.cos(rotation) * height * resolution * 1 / 4
            ];
        }

        // postcompose callback
        function render() {
            map.render();
        }

        //EMP
        //$("#geolocate").click(function () {
        //    alert("JQuery Running!");
        //});

        // geolocate device
        var geolocateBtn = document.getElementById("geolocate");
        geolocateBtn.addEventListener("click", function () {
            geolocation.setTracking(true); // Start position tracking

            map.on("postcompose", render);
            map.render();

            disableButtons();
        }, false);
    });
})

考虑到我将来会附加更多模块,使用 RequireJS 分解此代码以提高效率和编码功能/维护的最佳方法是什么。

非常感谢您的指导/想法,为WL干杯

最佳答案

每个 require 模块(使用 Define 定义)都应该返回一个函数/对象。所显示的分解并没有,而是只是拆分了代码。考虑一些假设的模块桶,并将每段代码(或函数)放入一个模块中。然后将代码分组到 require js 模块中并返回该模块的接口(interface)。

让我尝试用一​​个例子进一步解释。

ma​​in.js

$(document).ready(function(){
  $("#heyINeedMap").click(function(){
    require(['map'],function(Map){
      Map.render($target);
    });  
  });
});

或者

$(document).ready(function(){
  require(['map','geolocation'],function(Map,Geolocation){
      window.App.start = true;
      window.App.map = Map;              //won't suggest, but you can do.
      window.App.geolocation = Geolocation; 

      //do something.
      $("#lastCoords").click(function(){
        var coords = App.geolocation.getLastSavedCoords();
        if(!!coords){
          coords = App.geolocation.fetchCurrentCoords();
        }
        alert(coords);
      });
  });
});

ma​​p.js

define(['jquery'],function($){
  var privateVariableAvailableToAllMapInstances = 'something';
  var mapType = 'scatter';
  return function(){
    render: function(el){
      //rendering logic goes here
    },
    doSomethingElse: function(){
      privateVariable = 'some new value';
      //other logic goes here
    },
    changeMapType: function(newType){
      mapType = newType;
      //...
    }
  }
});

geolocation.js

//Just assuming that it needs jquery & another module called navigation to work.
define(['jquery','navigation'], function($,Gnav){
  return {
    var coordinates = Gnav.lastSavedCoords;
    fetchCurrentCoords: function(){
      //coordinates = [79.12213, 172.12342];  //fetch from API/something
      return coordinates;
    },
    getLastSavedCoords: function(){
      return coordinates;
    }
  }
});

希望这能提供有关如何继续的想法。

关于javascript - 如何使用 RequireJS 分解大型 Javascript 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31932996/

相关文章:

node.js - 按需require()

javascript - Angular 形式保存不适用于动态推送数据

javascript - RequireJS:优化脚本并在其中包含 RequireJS 本身

php - 在 PHP 中使用 javascript 设置 session 变量

javascript - 使用 RequireJS 在生产中需要大量小文件是否有意义

javascript - Davis.js 作为 AMD 模块?

module - 从其他文件扩展名加载脚本?

javascript - 在 HTML 中使用 Node.js 模块

javascript - 通过 Selenium 驱动程序执行 Javascript elementFromPoint

javascript - 在 HTML5 中播放来自 SVG 图像的动画