gpt4 book ai didi

javascript - 使用Knockout.js动态组成UI

转载 作者:行者123 更新时间:2023-11-29 09:52:14 26 4
gpt4 key购买 nike

我正在使用一个项目上很棒的Knockout.js库,并且正在寻找一种在运行时组成UI部分的方法。

例如,我有几个由子模板组成的模板(以下简化)。我想将 View 模型传递给这些模型并进行渲染,然后能够从标准表单中添加(和删除)内容。

<!-- used with LineGraphModel -->
<script type="text/html" name="linegraph-template">
<div id="LineGraph">
<div data-bind="contextTemplate: { name: 'series-template', data: seriesChoices, context: { selected: series } }"></div>
<div data-bind="contextTemplate: { name: 'xaxis-template', data: xAxisChoices, context: { selected: xaxis } }"></div>
<div data-bind="contextTemplate: { name: 'daterange-template', data: dateRangeChoices, context: { selected: dateRange } }"></div>
<div data-bind="template: { name: 'button-template', data: $data }"></div>
</div>
</script>

<!-- used with PieChartModel -->
<script type="text/html" name="piechart-template">
<div id="PieGraph">
<div data-bind="contextTemplate: { name: 'series-template', data: seriesChoices, context: { selected: series } }"></div>
<div data-bind="contextTemplate: { name: 'daterange-template', data: dateRangeChoices, context: { selected: dateRange } }"></div>
<div data-bind="template: { name: 'button-template', data: $data }"></div>
</div>
</script>

我已经开始在 ko.renderTemplate的路径上徘徊,但是似乎找不到关于如何创建新div并将结果附加到现有div的任何好的文档。这可能吗,还是我应该尝试另一种方法?

最佳答案

在写下所有这些内容之后,我意识到这可能超出您问题的范围。如果确实如此,我深表歉意。我希望您仍然可以从中获得一些值(value)。

这些东西来自一个我已经使用了几个月的真实应用程序。这是一个快速而肮脏的提取过程,可能包含错误或错别字,在这些地方我删除了特定于应用程序的代码或对其进行了简化以使其易于理解。

有了它,我可以

  • 任意嵌套 View 模型
  • 动态地添加 View 模型
  • 渲染绑定(bind)到这些嵌套viewmodel的Knockout模板,并灵活地使用结果

  • 这里是它的工作原理的快速概述。

    假装一秒钟,您将要构建一个显示消息列表的应用程序。用户可以单击消息以打开模式对话框并进行回复。我们有三个 View 模型:
  • 称为Main的根 View 模型
  • 一个MessageList,负责显示消息列表
  • 第三个名为MessageReply的代码,它负责回复功能。

  • 我们所有的viewmodel构造函数都在 app.viewmodels中巧妙地命名。让我们设置它们:
    $(document).ready(function() {
    var mainVm,
    messageListVm,
    messageReplyVm;

    // we start with Main as the root viewmodel
    mainVm = new app.viewmodels.Main();

    // MessageList is a child of Main
    messageListVm = mainVm.addChildVm('MessageList');

    // and MessageReply in turn is a child of MessageList
    messageReplyVm = messageListVm.addChildVm('MessageReply');

    // the root is the only one that gets bound directly
    ko.applyBindings(mainVm);
    });

    我们的标记看起来像这样:

    <body>
    <!-- context here: the Main viewmodel -->

    <div data-bind="childVm: 'MessageList'">
    <!-- context here: the MessageList viewmodel -->

    <ul data-bind="foreach: messages">
    <!-- context here: the individual message object -->
    <li>
    <p data-bind="text: body, modal: {viewmodelName: 'MessageReply', parentViewmodel: $parent, setupViewmodelWith: $data, templateName: 'message-reply-template'}">

    </p>
    </li>
    </ul>
    </div>
    </body>

    <script id="message-reply-template" type="text/html">
    <!-- context here: the MessageReply viewmodel -->
    <div>
    <textarea data-bind="value: message().body"></textarea>
    <input type="submit" data-bind="click: submit">
    </div>
    </script>

    那里有两个自定义绑定(bind), childVmmodal。前者只是查找 subview 模型并将其设置为绑定(bind)上下文,而 modal绑定(bind)负责在正确的上下文中呈现模板并将结果传递到单独的JS库。

    View 模型可以通过借用构造函数, ParentChild或同时使用两者来嵌套。 Here is the source for them

    parent

    如果一个 View 模型应该能够有 subview 模型,则它借用 Parent构造函数:
    app.viewmodels.Main = function Main() {
    app.viewmodels.Parent.apply(this);

    this.currentUser = //.. imagine the current user being loaded here from somewhere
    };

    作为父 View 模型, Main获得了三点好处:
  • .addChildVm(string):通过传递其名称来添加 subview 模型。它会在app.viewmodel命名空间中自动查找。
  • .getVm(name):返回名为“name”的 subview 模型
  • ._childVms:包含所有子
  • 的可观察列表

    child

    除根 Main之外的每个 View 模型都至少是一个 subview 模型。 MessageList既是 Main的子级,又是 MessageReply的父级。非常适合其名称,它包含要在列表中显示的消息。
    app.viewmodels.MessageList = function MessageList() {
    app.viewmodels.Parent.apply(this);
    app.viewmodels.Child.apply(this);

    // children need to set this, so we can find them by name through .getVm()
    this._viewmodelName = function() { return "MessageList"; };

    this.currentUser = null;

    this.messages = ko.observableArray([]);

    this.init = function init() {
    that.currentUser = that._parentVm.currentUser;

    var messages = GetMessages() // pseudocode - load our messages from somewhere
    this.messages( messages);
    };
    };

    作为 subview 模型, MessageList获得了:
  • 通过this._parentVm访问其父级的能力
  • 可选的init函数,如果存在
  • ,则由父级自动调用

    所以在上面,当我们将 MessageList添加到 Main中时,
    messageListVm = mainVm.addChildVm('MessageList');

    Main
  • 创建了MessageList的新实例
  • 将实例添加到自己的子级
  • 并称为 child 的init

  • 然后, child 通过获取对当前用户的引用来进行设置,该引用由父 Main View 模型维护。

    我们的最后一个 View 模型:MessageReply
    MessageReply只是一个 subview 模型;就像父 MessageList所做的一样,它在初始化时也会复制当前用户。它期望从模态绑定(bind)中传递一个Message对象,然后创建一个新的Message来响应它。该答复可以通过模式中的表单进行编辑和提交。
    app.viewmodels.MessageReply = function MessageReply() {
    app.viewmodels.Child.apply(this);

    this._viewmodelName = function() { return "MessageReply"; };

    var that = this;

    this.currentUser = null;

    // called automatically by the parent MessageList
    this.init = function init() {
    that.currentUser = that._parentVm.currentUser;
    };

    this.messageWeAreReplyingTo = ko.observable();

    // our reply
    this.message = ko.observable();

    // called by the 'modal' binding
    this.setup = function setup(messageWeAreReplyingTo) {

    // the modal binding gives us the message the user clicked on
    this.messageWeAreReplyingTo( messageWeAreReplyingTo );

    // imagine that Message is a model object defined somewhere else
    var ourReply = new Message({
    sender: that.currentUser,
    recipient: that.messageWeAreReplyingTo().sender();
    });

    this.message( ourReply );
    };

    // this is triggered by the form submit button in the overlay
    this.submit = function submit() {
    // send the message to the server
    }
    };

    'childVm'绑定(bind)

    Source code

    <body>
    <!-- context here: the Main viewmodel -->

    <div data-bind="childVm: 'MessageList'">
    <!-- context here: the MessageList viewmodel -->
    </div>

    这仅仅是围绕 knockout 自己的“with:”绑定(bind)的便利包装。它使用一个viewmodel名称作为其值访问器,在当前绑定(bind)上下文中查找该名称的 subview 模型,并使用“with:”绑定(bind)将该 subview 设置为新上下文。

    'waitForVm'绑定(bind)

    Source code

    上面的示例中未使用此方法,但是如果要在运行时动态添加 View 模型(而不是 ko.applyBindings之前),则该功能非常有用。这样,您可以延迟初始化应用程序的各个部分,直到用户真正想要与它们进行交互为止。
    waitForVm等待直到指定的 View 模型可用,然后再绑定(bind)其子元素。它不会修改绑定(bind)上下文。

    <div data-bind="waitForVm: 'MessageList'">
    <!-- bindings in here are not executed until 'MessageList' is loaded -->
    <div data-bind="childVm: 'MessageList'"> ... </div>
    </div>

    “模态”绑定(bind)

    Source code

    这需要一个Knockout模板,将其嫁接到一个 View 模型中,进行渲染,然后将结果传递给一个处理模式对话框的外部JS库。

    想象一下,这个模态库
  • 初始化后,在</body>
  • 之前创建一个DOM容器
    要求
  • 显示模式时,使用此容器并将其显示在页面的其余部分上,即灯箱样式

  • 让我们再次看一下模式绑定(bind):

          <!-- context here: the individual message object -->
    <li>
    <p data-bind="text: body, modal: {viewmodelName: 'MessageReply', parentViewmodel: $parent, setupViewmodelWith: $data, templateName: 'message-reply-template'}">

    </p>
    </li>
    modal
  • 使用父 View 模型MessageList,可以在我们当前的绑定(bind)上下文中找到$parent
  • 通过getVm()询问其 subview 模型实例MessageReply
  • 将单击绑定(bind)添加到<p>,当激活时
  • setup()上调用MessageReply,将其交给我们的$data-用户在
  • 上单击的当前消息
  • 准备模态和
  • 将绑定(bind)到MessageReply View 模型的模板“message-reply-template”呈现到模态DOM容器

  • 关于javascript - 使用Knockout.js动态组成UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20503524/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com