Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/6.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 大规模KnockoutJS应用程序体系结构_Javascript_Asp.net Mvc 3_Knockout.js_Knockout 2.0 - Fatal编程技术网

Javascript 大规模KnockoutJS应用程序体系结构

Javascript 大规模KnockoutJS应用程序体系结构,javascript,asp.net-mvc-3,knockout.js,knockout-2.0,Javascript,Asp.net Mvc 3,Knockout.js,Knockout 2.0,我喜欢KnockoutJS,但一直在努力找出用它构建大规模Javascript应用程序的最佳方法 现在,我处理代码的方法是使用根视图模型进行构建,该模型通常从母版页级别开始,然后在此基础上进行扩展。我只在主视图上使用了ko.applyBindings()。下面是我的示例代码: var companyNamespace = {}; // Master page. (a.k.a _Layout.cshtml) (function(masterModule, $, ko, window, docum

我喜欢KnockoutJS,但一直在努力找出用它构建大规模Javascript应用程序的最佳方法

现在,我处理代码的方法是使用根视图模型进行构建,该模型通常从母版页级别开始,然后在此基础上进行扩展。我只在主视图上使用了
ko.applyBindings()
。下面是我的示例代码:

var companyNamespace = {};

// Master page. (a.k.a _Layout.cshtml)
(function(masterModule, $, ko, window, document, undefined) {
    var private = "test";

    masterModule.somePublicMethod = function() {};
    masterModule.viewModel = function() {
        this.stuff = ko.observable();
    };
}(companyNamespace.masterModule = companyNamespace.masterModule || {}, jQuery, ko, window, document));

// Index.cshtml.
(function(subModule, $, ko, window, document, undefined) {
    var private = "test";

    subModule.somePublicMethod = function() {};
    subModule.viewModel = function() {
        this.stuff = ko.observable();
    };

    $(document).ready(function() {
        ko.applyBindings(companyNamespace.masterModule);
    });
}(companyNamespace.masterModule.subModule = companyNamespace.masterModule.subModule || {}, jQuery, ko, window, document));
我只是担心,因为这是一个树结构,如果我需要插入一个双母版页或类似的东西,这将是非常麻烦的重新因素

想法

编辑


我知道可以对单独的元素应用绑定来更改绑定的范围,但是如果我有嵌套的视图模型呢

我喜欢使用原型继承设置视图模型。和你一样,我有一个“主”视图模型。该视图模型包含其他视图模型的实例或视图模型的可观察数组,从中可以使用标记中的“foreach”和“with”绑定。在“foreach”和“with”绑定中,可以使用$data、$parent、$parents和$root绑定上下文来引用父视图模型

以下是KO文档中的相关文章


如果你愿意,我可以凑一把小提琴。让我知道。

我有一个相当大的knockout.js单页应用程序。(目前有超过20K行代码)这对于任何人来说都非常容易维护和添加额外的部分。我有数百台可观测设备,性能仍然很好,即使是在像旧iPodtouch这样的移动设备上。它基本上是一个承载一套工具的应用程序。以下是对我使用的应用程序的一些见解:

1.只有一个视图模型。它让事情变得简单。 视图模型处理任何单页应用程序的基础,例如每个页面(应用程序)的可见性、导航、错误、加载和toast对话框等。视图模型的示例片段:(我将其进一步分离出js文件,但这是为了让您大致了解它的外观)

2.所有模型都进入一个单独的.js文件。 我将模型视为类,所以它们真正做的只是存储变量和一些基本的格式化函数(我尽量使它们保持简单)。示例模型:

    //Message Class
    function Message {
        var self = this;

        self.id = ko.observable(data.id);
        self.subject = ko.observable(data.subject);
        self.body = ko.observable(data.body);
        self.from = ko.observable(data.from);

    }
3.将AJAX数据库调用保存在自己的js文件中。 最好用部分或“app”分隔。例如,文件夹树可能是js/database/,其中app1.js和app2.js作为js文件,包含基本的创建、检索、更新和删除功能。数据库调用示例:

vm.getMessagesByUserId = function ()
{

    $.ajax({
        type: "POST",
        url: vm.serviceUrl + "GetMessagesByUserId", //Just a default WCF url
        data: {}, //userId is stored on server side, no need to pass in one as that could open up a security vulnerability
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        cache: false,
        success: function (data, success, xhr)
        {
            vm.messaging.sent.messagesLoaded(true);

            for (var i = 0; i < data.messages.length; i++)
            {
                var message = new Message({
                    id: data.messages[i].id,
                    subject: data.messages[i].subject,
                    from: data.messages[i].from,
                    body: data.messages[i].body
                });
                vm.messaging.sent.messages.push(message);
            }
        },
        error: function (jqXHR)
        {
            vm.error.handle(jqXHR.getResponseHeader("error"), jqXHR.status);
        }
    });
    return true;
};
footer.js:

//put all views and view models in this
$(document).ready(function()
{
//ends the jquery on document ready function
});
5.分离HTML内容。 不要保存一个难以浏览的庞大html文件。由于knockout的绑定和HTTP协议的无状态性,使用knockout很容易陷入这个陷阱。但是,我使用两个选项进行分离,这取决于我是否将该作品视为被用户大量访问:

服务器端包括:(只是指向另一个html文件的指针。如果我觉得这部分应用程序被用户频繁使用,我会使用它,但我想把它分开)

6.保持页面/应用程序的可视性易于管理 显示和隐藏knockout.js应用程序的不同部分很容易会因为大量难以管理和记住的代码而变得疯狂,因为您必须设置许多不同的开关。首先,我将每个页面或应用程序保存在自己的“div”中(并保存在自己的html文件中以便于分离)。HTML示例:

<!-- Begin App 1 -->

<div data-bind="visible: app1.visible()">
<!-- Main app functionality here (perhaps splash screen, load, or whatever -->
</div>

<div data-bind="visible: app1.section1.visible()">
<!-- A branch off of app1 -->
</div>

<div data-bind="visible: app1.section2.visible()">
<!-- Another branch off of app1 -->
</div>

<!-- End App 1 -->


<!-- Begin App 2 -->
<div data-bind="visible: app2.visible()">
<!-- Main app functionality here (perhaps splash screen, load, or whatever -->
</div>
<!-- End App 2 -->
然后只需调用应用程序或页面的加载功能:

<button data-bind="click: app1.load">Load App 1</button>

这应该涵盖大型单页应用程序的基础知识。可能有比我提出的更好的解决方案,但这并不是一个坏方法。多个开发人员可以轻松地处理应用程序的不同部分,而不会与版本控制发生冲突。

您知道您可以将绑定应用于特定元素并进行多次调用吗?为什么不将不同的视图模型分开?@Tyrsius-是的,我知道这一点,我只是偶然发现了这个答案:但是如果我有嵌套的视图模型呢?我将更新我的答案,提供更多细节。我还没有看过这个演示文稿,但它不是别人,正是Steve Sanderson,Knockout的作者,标题是“使用Knockout.js构建大型单页应用程序”,所以它必须是相关的:这是一个非常简单的小把戏。如你所见,我有一个主视图模型。Person和Child的每个实例还充当其自己的视图模型,在
foreach
绑定中,您编写标记时就像您单独编写了
applyBindings
一样。但是您也可以通过绑定上下文访问父视图模型。顺便说一句,我知道为您拥有的每个对象手动创建构造函数的前景可能看起来是一项艰巨的任务。但这正是敲除映射插件可以提供帮助的地方。我认为,在这个问题的背景下,先看看它是如何手动完成的会对您更有好处。+1我非常喜欢通过#include将HTML内容分割成部分的想法。虽然我在一个方面与你们有所不同:我更喜欢每页/每节都有单独的视图模型。一流的、极好的真实世界示例很好你们如何将所有内容分离,很棒的东西
<!-- Begin Messaging -->    
    <!--#include virtual="Content/messaging.html" -->
<!-- End Messaging -->
        // #messaging is a div that wraps all the html of the messaging section of the app
        $('#messaging').load('Content/messaging.html', function ()
        {
            ko.applyBindings(vm, $(this)[0]); //grabs any ko bindings from that html page and applies it to our current view model
        });
<!-- Begin App 1 -->

<div data-bind="visible: app1.visible()">
<!-- Main app functionality here (perhaps splash screen, load, or whatever -->
</div>

<div data-bind="visible: app1.section1.visible()">
<!-- A branch off of app1 -->
</div>

<div data-bind="visible: app1.section2.visible()">
<!-- Another branch off of app1 -->
</div>

<!-- End App 1 -->


<!-- Begin App 2 -->
<div data-bind="visible: app2.visible()">
<!-- Main app functionality here (perhaps splash screen, load, or whatever -->
</div>
<!-- End App 2 -->
vm.visibility:
{
    set: function (page)
    {
      vm.app1.visible(page === "app1");
      vm.app1.section1.visible(page === "app1section1");
      vm.app1.section2.visible(page === "app1section2");
      vm.app2.visible(page === "app2");     
    }
};
<button data-bind="click: app1.load">Load App 1</button>
vm.visibility.set("app1");