Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Backbone.js“;fat路由器“;设计难题_Javascript_Design Patterns_Backbone.js_Marionette_Eventaggregator - Fatal编程技术网

Javascript Backbone.js“;fat路由器“;设计难题

Javascript Backbone.js“;fat路由器“;设计难题,javascript,design-patterns,backbone.js,marionette,eventaggregator,Javascript,Design Patterns,Backbone.js,Marionette,Eventaggregator,在过去的两周里,我学习了主干网和相关工具,并编写了一个应用程序。我遇到了一个设计问题,我想知道什么样的解决方案是可用的,骨干专家是否认为这是一个问题 问题:我最终不得不将所有视图依赖项放在我的router.js中,并且无法确定它们是否可以解决这个问题。下面是my router.js中的代码: // router.js define([ 'jquery', 'underscore', 'backbone', 'text', 'views/landing', 'views/d

在过去的两周里,我学习了主干网和相关工具,并编写了一个应用程序。我遇到了一个设计问题,我想知道什么样的解决方案是可用的,骨干专家是否认为这是一个问题

问题:我最终不得不将所有视图依赖项放在我的router.js中,并且无法确定它们是否可以解决这个问题。下面是my router.js中的代码:

// router.js
define([
  'jquery',
  'underscore',
  'backbone',
  'text',
  'views/landing',
  'views/dashboard',
],  
    function($, _, Backbone, t,LandingView,DashboardView){
        var AppRouter = Backbone.Router.extend({
        routes: {
          // Define some URL routes
          '': 'showLanding',
          'projects': 'showProjects',
          // Default
          '*actions': 'defaultAction'
        },
        navigate_to: function(model){
                alert("navigate_to");
            },

        showProjects: function() {},
        showLanding: function() {},
    });

    var initialize = function() {
        var app_router = new AppRouter;
        Backbone.View.prototype.event_aggregator = _.extend({}, Backbone.Events);
        // Extend the View class to include a navigation method goTo
        Backbone.View.prototype.goTo = function (loc) {
            app_router.navigate(loc, true);
        };
        app_router.on('route:showLanding', function(){
            var landing = new LandingView();
        });
        app_router.on('route:showProjects', function(){
            var dashboard=new DashboardView();
        });
        app_router.on('defaultAction', function(actions){
            alert("No routes");
            // We have no matching route, lets just log what the URL was
            console.log('No route:', actions);
        });
        Backbone.history.start({pushState: true});
    };
    return {
        initialize: initialize
    };
});
router.js包括着陆视图仪表板视图视图,它们依次获取各自的模板。初始路由加载具有登录模板的LandingView。登录后,它调用router.js的goTo方法生成DashboardView()。虽然这样做有效,但我觉得有点难看。但是我不知道如果不直接从LandingView()内部或路由器引用DashboardView(),如何从LandingView生成新的DashboardView

如果我继续通过router.js这样做,我将直接或间接地从路由器中提取我的所有视图js文件。听起来有点难看


我查看了Derick Baileys的事件聚合器模式,但面临的问题是,如果DashboardView的实例还不存在,DashboardView如何订阅LandingView生成的事件?必须有人创建并初始化它才能订阅事件聚合器,对吗?如果有人是路由器,我需要在路由器前面实例化所有视图吗?这没有道理。

我解决了这个问题,只在第一次点击路线时导入视图:

define(['backbone'], function(Backbone) {
    var AppRouter = Backbone.Router.extend({
        routes: {
            '':      'home',
            'users': 'users'
        },

        home: function() {
            requirejs(["views/home/mainview"], function(HomeView) {
                //..initialize and render view
            });
        },

        users: function() {
            requirejs(["views/users/mainview"], function(UsersView) {
                //..initialize and render view
            });
        }
    });

    return AppRouter;
});
它不能解决最终必须将所有视图导入路由器的问题,但是惰性的
requirejs
调用不会强制加载和评估所有脚本和模板

事实是,必须有人在某处导入模块。路由器是一个合理的位置,因为它通常是用户导航到某个页面(视图)时遇到的第一段代码。如果你觉得一个路由器负责太多,你应该考虑把路由器分成多个路由器,每个路由器负责你的应用程序的不同“部分”。为了更好地进行类比,请考虑典型MVC场景中的控制器

多路由器示例 userrouter.js处理所有与用户相关的视图(“users/”下的路由):

postwrouter.js处理所有与Post相关的视图(“posts/”下的路由):

approuter.js是主路由器,它在应用程序启动时启动,并初始化所有其他路由

define(['backbone', 'routers/userrouter', 'routers/postrouter'], 
function(Backbone, UserRouter, PostRouter) {

    var AppRouter = Backbone.Router.extend({

        routes: {
            '',        'home',
        },
        initialize: function() {
            //create all other routers
            this._subRouters = {
                'users' : new UserRouter(),
                'posts' : new PostRouter()
            };
        },
        start: function() {
            Backbone.history.start();
        },
        home: function() {
            requirejs(["views/home/mainview"], function(HomeView) {
                //..initialize and render view
            });
        }
    });
    return UserRouter;
});
最后是应用程序的main.js,它启动应用程序路由器:

new AppRouter().start();
通过这种方式,您可以保持每个路由器的精简,并避免在实际需要之前解析依赖关系树

侧注:如果使用嵌套的
requirejs
调用,并且使用
r.js
进行构建,请记住设置构建选项
findnestedependencies:true
,以便在构建中包含延迟加载的模块


编辑:这里有一个。

我们为此使用工厂,它只返回一个视图实例,还可以缓存实例:

define(function() {
  // Classes are defined like this { key1: Class1, key2: Class2 }
  // not cachedObjects are defined like this { notCached : { key3: Class3 }}
  return function(Classes) {
    var objectCache = {};

    return {
      get: function(key, options) {
        var cachedObject = objectCache[key];
        if (cachedObject){
          return cachedObject;
        }

        var Class = Classes[key];
        if (Class) {
          cachedObject = new Class(options);
          objectCache[key] = cachedObject;
          return cachedObject;
        }

        Class = Classes.notCached[key];
        if (Class) {
          return new Class(options);
        }
      }
    };
  };
});
然后我们有一个创建工厂的模块:

define([
  'common/factory',
  'views/view1',
  'views/view2',
  'views/view3',
  ], function(
    viewCache,
    View1,
    View2,
    View3
  ) {

  var views = {
    route1: View1,
    route2: View2,
    notCached: {
      route3: View3,
    }
  };

  return viewCache(views);
});
在路由器中,您可以通过调用viewCache.get(route)轻松获取视图。好处是将视图的创建/缓存解耦,现在可以单独测试


此外,当我们使用木偶时,我们不在路由器中使用viewCache,而是在RegionManager中使用viewCache,后者更适合创建视图。我们的路由器只是用应用程序的实际状态和路由触发事件。

我想我是在你更新它的同时更新了它,并意外地还原了你的一些更改。我想中介模式会解决你的问题:谢谢-现在就检查中介。@nimrod所以中介与木偶的事件聚合器相同,对吗?@Sid这是基于那个模式的,但据我所知,木偶做的更多,而且有很多依赖性。如果你想专注于调解,我建议你写博客。另外,如果你想构建一个大的应用程序,可以查看提供所有结构的其他框架,这样你就不需要过多地考虑架构,比如angular.js,或者ember…+1谢谢,延迟加载听起来是个好主意。我会等待更多的答案。嘿,好主意。但是,最后一个函数不应该返回AppRouter而不是UserRouter吗?你能告诉我什么是“\u子例程”吗?它的定义是什么?它是主干的一部分吗?它是如何工作的?我在任何地方都没有看到这方面的参考资料,我已经努力寻找了好几天了:)我喜欢工厂的想法,但这不是“转移”了将所有视图从路由器提前加载到工厂的问题吗?与中一样,下载所有与视图相关的.js文件。是的,这将加载视图的所有代码,但它将路由器与视图的创建分离。但是你可以重构工厂来使用requirejs,所以你只存储require模块的路径,而不是模块本身。更新以展示如何使用requirejs(未经测试)。@AndreasKöberle你的requirejs模式很棒,但不幸的是,我认为它不起作用。例如,
require
API是异步的,因此您必须使工厂也异步。更大的问题是
r.js
编译器只有在
require
调用与文本字符串路径一起使用时才能解析嵌套依赖项,比如
require(['module/name'],cb)
@AndreasKöberle,事实上您可以同步调用
require
,但这要感谢RequireJS为你表演的一些诡计。根据您使用的是AMD还是CommonJS样式的头,它同步调用
require
只能是wo
define(function() {
  // Classes are defined like this { key1: Class1, key2: Class2 }
  // not cachedObjects are defined like this { notCached : { key3: Class3 }}
  return function(Classes) {
    var objectCache = {};

    return {
      get: function(key, options) {
        var cachedObject = objectCache[key];
        if (cachedObject){
          return cachedObject;
        }

        var Class = Classes[key];
        if (Class) {
          cachedObject = new Class(options);
          objectCache[key] = cachedObject;
          return cachedObject;
        }

        Class = Classes.notCached[key];
        if (Class) {
          return new Class(options);
        }
      }
    };
  };
});
define([
  'common/factory',
  'views/view1',
  'views/view2',
  'views/view3',
  ], function(
    viewCache,
    View1,
    View2,
    View3
  ) {

  var views = {
    route1: View1,
    route2: View2,
    notCached: {
      route3: View3,
    }
  };

  return viewCache(views);
});