以为我理解了Knockout.js,现在我不太确定

时间:2017-05-10 22:27:48

标签: javascript mvvm knockout.js knockout-3.0

我不确定我以前是否理解,现在不理解它,或者我是否理解它,现在我开始...或者如果我没有,仍然不知道#39;吨

我正在构建一个允许用户预约的应用。

屏幕1:选择位置和服务类型(选项列表,确认和继续按钮)

屏幕2:选择可用的约会时间(表格,按钮以确认并继续)

屏幕3:输入姓名和联系信息(文本输入,按钮确认并继续)

屏幕4:输入验证码(发送给用户,按钮确认并继续)

屏幕5:显示确认码

我正在重构,因为我意识到一切都在我的ViewModel中,并且不确定我的模型中属于什么以及属于我的ViewModel的内容。我只是在模型中放入了selectedLocation(用户从列表中选择的项),但我需要它可以被View访问,所以我这样做了:

self.selectedLocation = ko.pureComputed({
    read: function() {
        return self.model.selectedLocation();
    },
    write: function(value){
        self.model.selectedLocation(value);
    }
});

这似乎只是疯了。

这应该在ViewModel中吗?我是否应该在Model中有一个selectedLocation变量,在ViewModel中有一个currentSelectedLocation,然后在用户确认位置和服务类型时更新model.selectedLocation?

每个单独的屏幕都应该拥有自己的视图模型吗?我使用单个.html文件并更新显示的内容而不是从一个页面到另一个页面。

我确定我没有提供某种重要的信息,我很抱歉,很乐意回答任何问题。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

关于可观察对象的一个​​很酷的事情是你可以在其他对象中使用它们:

self.selectedLocation = self.model.selectedLocation;

但我建议直接绑定到model.selectedLocation也没关系。在Knockout中,没有必要对模型/视图模型进行区分;一切都是视图模型。

答案 1 :(得分:1)

将模型和视图模型分开是个好主意。他们看待它的方式是模型是您正在使用的数据的表示,并且viewmodel将各种模型组合在一起并添加类似控制器的功能来运行页面的逻辑(处理UI交互,获取数据,数据绑定等)。您的模型将只是一组属性,也可能是一些辅助属性,可以执行诸如从模型的原始数据中提供格式化的显示文本。但该模型在其中没有任何真正的逻辑。如果您需要对模型属性本身进行双向数据绑定,那么您只需将它们定义为KO可观察对象。

鉴于你想在一个html文件(基本上是SPA)中完成所有这一切,你绝对想要将其分解为几个" viewmodels"。我把引号放在" viewmodels"在这种情况下,因为Knockout只能将绑定应用于单个viewmodel对象,但是您可以嵌套具有KO可观察量n级深度的Javascript对象,并且KO可以跟随对象图(如Michael Best的回答中所述)。让我们称这些嵌套的#34; viewmodels"子的ViewModels。

我建议创建一个主视图模型,它代表整个应用程序,并且每个应用程序的页面至少有一个子视图模型。所以它可能看起来像这样:

var AppViewModel = function (screen1Vm, screen2Vm, ...) {
    var self = this;

    self.screen1ViewModel = screen1Vm;
    self.screen2ViewModel = screen2Vm;
    ...
}

var Screen1ViewModel = function () {
    var self = this;

    self.selectedLocation = ko.observable(null); //Initialize as null
    self.locations = ko.observableArray([]); //assuming they're selecting from a list of Location objects.  Initialize as empty array.
    ...
    //More logic to handle UI events, like a KO click event binding when one of the locations is selected, which is where self.selectedLocation would get set.  Something like this
    self.locationSelected = function (location) {
        //When bound to a control inside a KO foreach context, the actual object in the KO observable array will be passed in.
        self.selectedLocation(location);
    }
}

var Location = function (description, city, state, ...) {
    var self = this;

    self.description = ko.observable(description);
    self.city = ko.observable(city);
    self.state = ko.observable(state);
    ...
}

...

var screen1Vm = new Screen1ViewModel();
var screen2Vm = new Screen2ViewModel();
...
var myAppVm = new AppViewModel(screen1Vm, screen2Vm, ...)
ko.applyBindings(myAppVm);

然后你有一些看起来像这样的HTML(显然将DOM元素改为你需要的视图):

<div data-bind="foreach: screen1ViewModel.locations">
    <!--Bind the click event to the viewmodel handler, and display the description of the location in the button-->
    <button data-bind="click: $parent.locationSelected"><span data-bind="text: description"></span></button>
</div>

最后一点。由于您在一个页面中执行此操作,我建议尽可能使用KO模板来组织HTML,并将每个子视图模型放在它们自己的.js文件中,但是在您定义的全局命名空间下为您的应用程序。