asp.net-mvc 如何在 ASP.NET MVC ViewModels 中使用knockout.js?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11055336/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 02:02:02  来源:igfitidea点击:

How to use knockout.js with ASP.NET MVC ViewModels?

asp.net-mvcasp.net-mvc-3knockout.js

提问by chobo2

Bounty

赏金

It's been awhile and I still have a couple outstanding questions. I hope by adding a bounty maybe these questions will get answered.

已经有一段时间了,我仍然有几个悬而未决的问题。我希望通过增加赏金,也许这些问题会得到解答。

  1. How do you use html helpers with knockout.js
  2. Why was document ready needed to make it work(see first edit for more information)

  3. How do I do something like this if I am using the knockout mapping with my view models? As I do not have a function due to the mapping.

    function AppViewModel() {
    
        // ... leave firstName, lastName, and fullName unchanged here ...
    
        this.capitalizeLastName = function() {
    
        var currentVal = this.lastName();        // Read the current value
    
        this.lastName(currentVal.toUpperCase()); // Write back a modified value
    
    };
    
  4. I want to use plugins for instance I want to be able to rollback observables as if a user cancels a request I want to be able to go back to the last value. From my research this seems to be achieved by people making plugins like editables

    How do I use something like that if I am using mapping? I really don't want to go to a method where I have in my view manual mapping were I map each MVC viewMode field to a KO model field as I want as little inline javascript as possible and that just seems like double the work and that's why I like that mapping.

  5. I am concerned that to make this work easy (by using mapping) I will lose a lot of KO power but on the other hand I am concerned that manual mapping will just be a lot of work and will make my views contain too much information and might become in the future harder to maintain(say if I remove a property in the MVC model I have to move it also in the KO viewmodel)

  1. 你如何在knockout.js 中使用html helpers
  2. 为什么需要准备好文档才能使其工作(有关更多信息,请参阅第一次编辑)

  3. 如果我在视图模型中使用敲除映射,我该怎么做?由于映射,我没有功能。

    function AppViewModel() {
    
        // ... leave firstName, lastName, and fullName unchanged here ...
    
        this.capitalizeLastName = function() {
    
        var currentVal = this.lastName();        // Read the current value
    
        this.lastName(currentVal.toUpperCase()); // Write back a modified value
    
    };
    
  4. 我想使用插件,例如我希望能够回滚可观察对象,就好像用户取消了一个请求我希望能够回到最后一个值。从我的研究来看,这似乎是通过制作可编辑插件之类的人来实现的

    如果我使用映射,我该如何使用类似的东西?我真的不想去我的视图手动映射中的方法是我将每个 MVC viewMode 字段映射到 KO 模型字段,因为我想要尽可能少的内联 javascript,这似乎是工作的两倍,这就是为什么我喜欢那个映射。

  5. 我担心为了使这项工作变得容易(通过使用映射)我会失去很多 KO 能力,但另一方面我担心手动映射只会是很多工作并且会使我的视图包含太多信息和将来可能会变得更难维护(比如如果我在 MVC 模型中删除了一个属性,我也必须在 KO 视图模型中移动它)



Original Post原帖

I am using asp.net mvc 3 and I looking into knockout as it looks pretty cool but I am having a hard time figuring out how it works with asp.net mvc especially view models.

我正在使用 asp.net mvc 3,我正在研究淘汰赛,因为它看起来很酷,但我很难弄清楚它如何与 asp.net mvc 一起工作,尤其是视图模型。

For me right now I do something like this

对我来说,我现在做这样的事情

 public class CourseVM
    {
        public int CourseId { get; set; }
        [Required(ErrorMessage = "Course name is required")]
        [StringLength(40, ErrorMessage = "Course name cannot be this long.")]
        public string CourseName{ get; set; }


        public List<StudentVm> StudentViewModels { get; set; }

}

I would have a Vm that has some basic properties like CourseName and it will have some simple validation on top of it. The Vm model might contain other view models in it as well if needed.

我会有一个 Vm,它有一些基本属性,比如 CourseName,它上面会有一些简单的验证。如果需要,Vm 模型也可能包含其他视图模型。

I would then pass this Vm to the View were I would use html helpers to help me display it to the user.

然后我会将这个 Vm 传递给视图,如果我会使用 html 帮助程序来帮助我将它显示给用户。

@Html.TextBoxFor(x => x.CourseName)

I might have some foreach loops or something to get the data out of the collection of Student View Models.

我可能有一些 foreach 循环或其他东西来从学生视图模型的集合中获取数据。

Then when I would submit the form I would use jquery and serialize arrayand send it to a controller action method that would bind it back to the viewmodel.

然后,当我提交表单时,我将使用 jquery 并将serialize array其发送到控制器操作方法,该方法将其绑定回视图模型。

With knockout.js it is all different as you now got viewmodels for it and from all the examples I seen they don't use html helpers.

使用knockout.js,一切都不同了,因为您现在为它提供了视图模型,并且从我看到的所有示例中,它们都不使用html 帮助程序。

How do you use these 2 features of MVC with knockout.js?

你如何在knockout.js 中使用MVC 的这两个特性?

I found this videoand it briefly(last few minutes of the video @ 18:48) goes into a way to use viewmodels by basically having an inline script that has the knockout.js viewmodel that gets assigned the values in the ViewModel.

我找到了这个视频,它简要地(视频的最后几分钟 @ 18:48)通过基本上拥有一个内联脚本来使用视图模型,该脚本具有在 ViewModel 中分配值的knockout.js 视图模型。

Is this the only way to do it? How about in my example with having a collection of viewmodels in it? Do I have to have a foreach loop or something to extract all the values out and assign it into knockout?

这是唯一的方法吗?在我的示例中包含一组视图模型怎么样?我是否必须有一个 foreach 循环或其他东西来提取所有值并将其分配给淘汰赛?

As for html helpers the video says nothing about them.

至于 html 助手,视频没有提及它们。

These are the 2 areas that confuses the heck out of me as not many people seem to talk about it and it leaves me confused of how the initial values and everything is getting to the view when ever example is just some hard-coded value example.

这是两个让我感到困惑的领域,因为似乎没有多少人谈论它,这让我对初始值和所有内容如何进入视图感到困惑,而当示例只是一些硬编码的值示例时。



Edit编辑

I am trying what Darin Dimitrov has suggested and this seems to work(I had to make some changes to his code though). Not sure why I had to use document ready but somehow everything was not ready without it.

我正在尝试 Darin Dimitrov 的建议,这似乎有效(不过我不得不对他的代码进行一些更改)。不知道为什么我必须使用文档就绪,但不知何故,没有它,一切都没有准备好。

@model MvcApplication1.Models.Test

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>Index</title>
    <script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
    <script src="../../Scripts/knockout-2.1.0.js" type="text/javascript"></script>
    <script src="../../Scripts/knockout.mapping-latest.js" type="text/javascript"></script>
   <script type="text/javascript">

   $(function()
   {
      var model = @Html.Raw(Json.Encode(Model));


// Activates knockout.js
ko.applyBindings(model);
   });

</script>

</head>
<body>
    <div>
        <p>First name: <strong data-bind="text: FirstName"></strong></p>
        <p>Last name: <strong data-bind="text: LastName"></strong></p>
        @Model.FirstName , @Model.LastName
    </div>
</body>
</html>

I had to wrap it around a jquery document ready to make it work.

我不得不将它包装在一个 jquery 文档中,以使其工作。

I also get this warning. Not sure what it is all about.

我也收到此警告。不知道这是怎么回事。

Warning 1   Conditional compilation is turned off   -> @Html.Raw

So I have a starting point I guess at least will update when I done some more playing around and how this works.

所以我有一个起点,我想至少会在我做更多的尝试以及它是如何工作的时候更新。

I am trying to go through the interactive tutorials but use the a ViewModel instead.

我正在尝试阅读交互式教程,但使用 ViewModel 代替。

Not sure how to tackle these parts yet

不确定如何处理这些部分

function AppViewModel() {
    this.firstName = ko.observable("Bert");
    this.lastName = ko.observable("Bertington");
}

or

或者

function AppViewModel() {
    // ... leave firstName, lastName, and fullName unchanged here ...

    this.capitalizeLastName = function() {
        var currentVal = this.lastName();        // Read the current value
        this.lastName(currentVal.toUpperCase()); // Write back a modified value
    };



Edit 2编辑 2

I been able to figure out the first problem. No clue about the second problem. Yet though. Anyone got any ideas?

我能够弄清楚第一个问题。对第二个问题一无所知。然而尽管如此。有人有任何想法吗?

 @model MvcApplication1.Models.Test

    @{
        Layout = null;
    }

    <!DOCTYPE html>

    <html>
    <head>
        <title>Index</title>
        <script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
        <script src="../../Scripts/knockout-2.1.0.js" type="text/javascript"></script>
        <script src="../../Scripts/knockout.mapping-latest.js" type="text/javascript"></script>
       <script type="text/javascript">

       $(function()
       {
        var model = @Html.Raw(Json.Encode(Model));
        var viewModel = ko.mapping.fromJS(model);
        ko.applyBindings(viewModel);

       });

    </script>

    </head>
    <body>
        <div>
            @*grab values from the view model directly*@
            <p>First name: <strong data-bind="text: FirstName"></strong></p>
            <p>Last name: <strong data-bind="text: LastName"></strong></p>

            @*grab values from my second view model that I made*@
            <p>SomeOtherValue <strong data-bind="text: Test2.SomeOtherValue"></strong></p>
            <p>Another <strong data-bind="text: Test2.Another"></strong></p>

            @*allow changes to all the values that should be then sync the above values.*@
            <p>First name: <input data-bind="value: FirstName" /></p>
            <p>Last name: <input data-bind="value: LastName" /></p>
            <p>SomeOtherValue <input data-bind="value: Test2.SomeOtherValue" /></p>
            <p>Another <input data-bind="value: Test2.Another" /></p>

           @* seeing if I can do it with p tags and see if they all update.*@
            <p data-bind="foreach: Test3">
                <strong data-bind="text: Test3Value"></strong> 
            </p>

     @*took my 3rd view model that is in a collection and output all values as a textbox*@       
    <table>
        <thead><tr>
            <th>Test3</th>
        </tr></thead>
          <tbody data-bind="foreach: Test3">
            <tr>
                <td>    
                    <strong data-bind="text: Test3Value"></strong> 
<input type="text" data-bind="value: Test3Value"/>
                </td>
            </tr>    
        </tbody>
    </table>

Controller

控制器

  public ActionResult Index()
    {
              Test2 test2 = new Test2
        {
            Another = "test",
            SomeOtherValue = "test2"
        };

        Test vm = new Test
        {
            FirstName = "Bob",
            LastName = "N/A",
             Test2 = test2,

        };
        for (int i = 0; i < 10; i++)
        {
            Test3 test3 = new Test3
            {
                Test3Value = i.ToString()
            };

             vm.Test3.Add(test3);
        }

        return View(vm);
    }

回答by Jupaol

I think I have summarized all your questions, if I missed something please let me know (If you could summarize up all your questions in one place would be nice=))

我想我已经总结了你所有的问题,如果我错过了什么,请告诉我(如果你能在一个地方总结你所有的问题会很好=))

Note. Compatibility with the ko.editableplug-in added

笔记。与ko.editable插件的兼容性添加

Downloadthe full code

下载完整代码

How do you use html helpers with knockout.js

你如何在knockout.js 中使用html helpers

This is easy:

这很简单:

@Html.TextBoxFor(model => model.CourseId, new { data_bind = "value: CourseId" })

Where:

在哪里:

  • value: CourseIdindicates that you are binding the valueproperty of the inputcontrol with the CourseIdproperty from your model and your script model
  • value: CourseId表示您正在valueinput控件的CourseId属性与来自模型和脚本模型的属性绑定

The result is:

结果是:

<input data-bind="value: CourseId" data-val="true" data-val-number="The field CourseId must be a number." data-val-required="The CourseId field is required." id="CourseId" name="CourseId" type="text" value="12" />

Why was document ready needed to make it work(see first edit for more information)

为什么需要准备好文档才能使其工作(有关更多信息,请参阅第一次编辑)

I do not understand yet why you need to use the readyevent to serialize the model, but it seems that it is simply required(Not to worry about it though)

我还不明白为什么你需要使用ready事件来序列化模型,但似乎它只是必需的(不过不用担心)

How do I do something like this if I am using the knockout mapping with my view models? As I do not have a function due to the mapping.

如果我在视图模型中使用敲除映射,我该怎么做?由于映射,我没有功能。

If I understand correctly you need to append a new method to the KO model, well that's easy merging models

如果我理解正确,您需要在 KO 模型中附加一个新方法,这很容易合并模型

For more info, in the section -Mapping from different sources-

有关更多信息,请参见 - 来自不同来源的映射 -

function viewModel() {
    this.addStudent = function () {
        alert("de");
    };
};

$(function () {
    var jsonModel = '@Html.Raw(JsonConvert.SerializeObject(this.Model))';
    var mvcModel = ko.mapping.fromJSON(jsonModel);

    var myViewModel = new viewModel();
    var g = ko.mapping.fromJS(myViewModel, mvcModel);

    ko.applyBindings(g);
});

About the warning you were receiveing

关于您收到的警告

Warning 1 Conditional compilation is turned off -> @Html.Raw

警告 1 条件编译已关闭 -> @Html.Raw

You need to use quotes

您需要使用引号

Compatibility with the ko.editable plug-in

与 ko.editable 插件的兼容性

I thought it was going to be more complex, but it turns out that the integration is really easy, in order to make your model editable just add the following line: (remember that in this case I am using a mixed model, from server and adding extension in client and the editable simply works... it's great):

我以为它会更复杂,但事实证明集成真的很容易,为了使您的模型可编辑,只需添加以下行:(请记住,在这种情况下,我使用的是混合模型,来自服务器和在客户端中添加扩展名,可编辑的工作很简单......很棒):

    ko.editable(g);
    ko.applyBindings(g);

From here you just need to playwith your bindings using the extensions added by the plug-in, for example, I have a button to start editing my fields like this and in this button I start the edit process:

从这里你只需要发挥与使用由添加的扩展插件,例如,我有一个按钮,开始编辑我的领域,如这和这个按钮我开始编辑过程中您的绑定:

    this.editMode = function () {
        this.isInEditMode(!this.isInEditMode());
        this.beginEdit();
    };

Then I have commit and cancel buttons with the following code:

然后我使用以下代码提交和取消按钮:

    this.executeCommit = function () {
        this.commit();
        this.isInEditMode(false);
    };
    this.executeRollback = function () {
        if (this.hasChanges()) {
            if (confirm("Are you sure you want to discard the changes?")) {
                this.rollback();
                this.isInEditMode(false);
            }
        }
        else {
            this.rollback();
            this.isInEditMode(false);
        }
    };

And finally, I have one field to indicate whether the fields are in edit mode or not, this is just to bind the enable property.

最后,我有一个字段来指示这些字段是否处于编辑模式,这只是为了绑定 enable 属性。

this.isInEditMode = ko.observable(false);

About your array question

关于你的阵列问题

I might have some foreach loops or something to get the data out of the collection of Student View Models.

Then when I would submit the form I would use jquery and serialize array and send it to a controller action method that would bind it back to the viewmodel.

我可能有一些 foreach 循环或其他东西来从学生视图模型的集合中获取数据。

然后当我提交表单时,我将使用 jquery 和序列化数组并将其发送到控制器操作方法,该方法将其绑定回视图模型。

You can do the same with KO, in the following example, I will create the following output:

您可以对 KO 执行相同操作,在以下示例中,我将创建以下输出:

enter image description here

在此处输入图片说明

Basically here, you have two lists, created using Helpersand binded with KO, they have a dblClickevent binded that when fired, remove the selected item from the current list and add it to the other list, when you post to the Controller, the content of each list is sent as JSON data and re-attached to the server model

基本上在这里,您有两个列表,使用HelpersKO创建并与 KO 绑定,它们绑定了一个dblClick事件,当触发时,从当前列表中删除所选项目并将其添加到另一个列表中,当您发布到 时Controller,每个的内容列表作为 JSON 数据发送并重新附加到服务器模型

Nuggets:

掘金:

External scripts.

外部脚本

Controller code

控制器代码

    [HttpGet]
    public ActionResult Index()
    {
        var m = new CourseVM { CourseId = 12, CourseName = ".Net" };

        m.StudentViewModels.Add(new StudentVm { ID = 545, Name = "Name from server", Lastname = "last name from server" });

        return View(m);
    }

    [HttpPost]
    public ActionResult Index(CourseVM model)
    {
        if (!string.IsNullOrWhiteSpace(model.StudentsSerialized))
        {
            model.StudentViewModels = JsonConvert.DeserializeObject<List<StudentVm>>(model.StudentsSerialized);
            model.StudentsSerialized = string.Empty;
        }

        if (!string.IsNullOrWhiteSpace(model.SelectedStudentsSerialized))
        {
            model.SelectedStudents = JsonConvert.DeserializeObject<List<StudentVm>>(model.SelectedStudentsSerialized);
            model.SelectedStudentsSerialized = string.Empty;
        }

        return View(model);
    }

Model

模型

public class CourseVM
{
    public CourseVM()
    {
        this.StudentViewModels = new List<StudentVm>();
        this.SelectedStudents = new List<StudentVm>();
    }

    public int CourseId { get; set; }

    [Required(ErrorMessage = "Course name is required")]
    [StringLength(100, ErrorMessage = "Course name cannot be this long.")]
    public string CourseName { get; set; }

    public List<StudentVm> StudentViewModels { get; set; }
    public List<StudentVm> SelectedStudents { get; set; }

    public string StudentsSerialized { get; set; }
    public string SelectedStudentsSerialized { get; set; }
}

public class StudentVm
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Lastname { get; set; }
}

CSHTML page

CSHTML 页面

@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>CourseVM</legend>

        <div>
            <div class="editor-label">
                @Html.LabelFor(model => model.CourseId)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.CourseId, new { data_bind = "enable: isInEditMode, value: CourseId" })
                @Html.ValidationMessageFor(model => model.CourseId)
            </div>

            <div class="editor-label">
                @Html.LabelFor(model => model.CourseName)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.CourseName, new { data_bind = "enable: isInEditMode, value: CourseName" })
                @Html.ValidationMessageFor(model => model.CourseName)
            </div>
            <div class="editor-label">
                @Html.LabelFor(model => model.StudentViewModels);
            </div>
            <div class="editor-field">

                @Html.ListBoxFor(
                    model => model.StudentViewModels,
                    new SelectList(this.Model.StudentViewModels, "ID", "Name"),
                    new
                    {
                        style = "width: 37%;",
                        data_bind = "enable: isInEditMode, options: StudentViewModels, optionsText: 'Name', value: leftStudentSelected, event: { dblclick: moveFromLeftToRight }"
                    }
                )
                @Html.ListBoxFor(
                    model => model.SelectedStudents,
                    new SelectList(this.Model.SelectedStudents, "ID", "Name"),
                    new
                    {
                        style = "width: 37%;",
                        data_bind = "enable: isInEditMode, options: SelectedStudents, optionsText: 'Name', value: rightStudentSelected, event: { dblclick: moveFromRightToLeft }"
                    }
                )
            </div>

            @Html.HiddenFor(model => model.CourseId, new { data_bind="value: CourseId" })
            @Html.HiddenFor(model => model.CourseName, new { data_bind="value: CourseName" })
            @Html.HiddenFor(model => model.StudentsSerialized, new { data_bind = "value: StudentsSerialized" })
            @Html.HiddenFor(model => model.SelectedStudentsSerialized, new { data_bind = "value: SelectedStudentsSerialized" })
        </div>

        <p>
            <input type="submit" value="Save" data-bind="enable: !isInEditMode()" /> 
            <button data-bind="enable: !isInEditMode(), click: editMode">Edit mode</button><br />
            <div>
                <button data-bind="enable: isInEditMode, click: addStudent">Add Student</button>
                <button data-bind="enable: hasChanges, click: executeCommit">Commit</button>
                <button data-bind="enable: isInEditMode, click: executeRollback">Cancel</button>
            </div>
        </p>
    </fieldset>
}

Scripts

脚本

<script src="@Url.Content("~/Scripts/jquery-1.7.2.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/knockout-2.1.0.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/knockout.mapping-latest.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/ko.editables.js")" type="text/javascript"></script>

<script type="text/javascript">
    var g = null;
    function ViewModel() {
        this.addStudent = function () {
            this.StudentViewModels.push(new Student(25, "my name" + new Date(), "my last name"));
            this.serializeLists();
        };
        this.serializeLists = function () {
            this.StudentsSerialized(ko.toJSON(this.StudentViewModels));
            this.SelectedStudentsSerialized(ko.toJSON(this.SelectedStudents));
        };
        this.leftStudentSelected = ko.observable();
        this.rightStudentSelected = ko.observable();
        this.moveFromLeftToRight = function () {
            this.SelectedStudents.push(this.leftStudentSelected());
            this.StudentViewModels.remove(this.leftStudentSelected());
            this.serializeLists();
        };
        this.moveFromRightToLeft = function () {
            this.StudentViewModels.push(this.rightStudentSelected());
            this.SelectedStudents.remove(this.rightStudentSelected());
            this.serializeLists();
        };
        this.isInEditMode = ko.observable(false);
        this.executeCommit = function () {
            this.commit();
            this.isInEditMode(false);
        };
        this.executeRollback = function () {
            if (this.hasChanges()) {
                if (confirm("Are you sure you want to discard the changes?")) {
                    this.rollback();
                    this.isInEditMode(false);
                }
            }
            else {
                this.rollback();
                this.isInEditMode(false);
            }
        };
        this.editMode = function () {
            this.isInEditMode(!this.isInEditMode());
            this.beginEdit();
        };
    }

    function Student(id, name, lastName) {
        this.ID = id;
        this.Name = name;
        this.LastName = lastName;
    }

    $(function () {
        var jsonModel = '@Html.Raw(JsonConvert.SerializeObject(this.Model))';
        var mvcModel = ko.mapping.fromJSON(jsonModel);

        var myViewModel = new ViewModel();
        g = ko.mapping.fromJS(myViewModel, mvcModel);

        g.StudentsSerialized(ko.toJSON(g.StudentViewModels));
        g.SelectedStudentsSerialized(ko.toJSON(g.SelectedStudents));

        ko.editable(g);
        ko.applyBindings(g);
    });
</script>

Note: I just added these lines:

注意:我刚刚添加了这些行:

        @Html.HiddenFor(model => model.CourseId, new { data_bind="value: CourseId" })
        @Html.HiddenFor(model => model.CourseName, new { data_bind="value: CourseName" })

Because when I submit the form my fields are disabled, so the values were not transmitted to the server, that's why I added a couple of hidden fields to do the trick

因为当我提交表单时,我的字段被禁用,所以值没有传输到服务器,这就是为什么我添加了几个隐藏字段来解决这个问题

回答by Darin Dimitrov

You could serialize your ASP.NET MVC view model into a javascript variable:

您可以将 ASP.NET MVC 视图模型序列化为 javascript 变量:

@model CourseVM
<script type="text/javascript">
    var model = @Html.Raw(Json.Encode(Model));
    // go ahead and use the model javascript variable to bind with ko
</script>

There are lots of examples in the knockout documentationthat you could go through.

您可以阅读淘汰文档中的许多示例。

回答by Paul Tyng

To achieve the additional computed properties after server mapping you will need to further enhance your viewmodels on the client side.

为了在服务器映射后获得额外的计算属性,您需要在客户端进一步增强您的视图模型。

For example:

例如:

var viewModel = ko.mapping.fromJS(model);

viewModel.capitalizedName = ko.computed(function() {...}, viewModel);

So everytime you map from raw JSON you would need to reapply the computed properties.

因此,每次从原始 JSON 映射时,您都需要重新应用计算属性。

Additionally the mapping plugin provides the ability to incrementally update a viewmodel as opposed to recreating it every time you go back and forth (use an additional parameter in fromJS):

此外,映射插件提供了增量更新视图模型的能力,而不是每次来回重新创建它(在 中使用附加参数fromJS):

// Every time data is received from the server:
ko.mapping.fromJS(data, viewModel);

And that executes an incremental data update on your model of just properties that are mapped. You can read more about that in the mapping documentation

这会在您的仅映射属性的模型上执行增量数据更新。您可以在映射文档中阅读更多相关信息

You mentioned in the comments on Darin's answer the FluentJSONpackage. I'm the author of that, but its use case is more specific than ko.mapping. I would generally only use it if your viewmodels are one way (ie. server -> client) and then data is posted back in some different format (or not at all). Or if your javascript viewmodel needs to be in a substantially different format from your server model.

您在 Darin 的回答FluentJSON包的评论中提到。我是它的作者,但它的用例比 ko.mapping 更具体。如果您的视图模型是一种方式(即服务器-> 客户端),然后数据以某种不同的格式发回(或根本不发回),我通常只会使用它。或者,如果您的 javascript 视图模型需要与您的服务器模型采用完全不同的格式。