【问题标题】:I don't understand how knockout.js mapping or components work at all?我根本不明白 knockout.js 映射或组件是如何工作的?
【发布时间】:2015-10-17 11:37:00
【问题描述】:

在过去的几周里,我一直(尝试)使用 Knockout.js 映射和组件,坦率地说,这很糟糕。我发誓我错过了一些能让一切正常工作的神奇作品,因为目前我试图用它制作的所有东西都感觉非常脱节和凌乱,因此大部分都没有功能。

我已通读文档,但几乎没有满意或没有帮助。

用例

我有一个主视图模型,但它不是这个故事的主角。这是我正在尝试构建的可重用组件。我们称之为TweetViewModel。这个组件,取决于 params.action 设置为“创建”还是“显示”,将允许用户输入有关推文的信息,或者将其显示给他们:

组件视图模型

define(['knockout','ko.mapping', 'jquery', 'text!components/tweet/tweet.html'], function(ko, koMapping, $, htmlString) {
    function TweetViewModel(params) {

        var self = this;

        self.tweet = params.tweet;
        self.action = params.action;

        self.tweetUrl = ko.observable();
        self.tweetUrl.subscribe(function(value) {
            var valueOfTwitterUrlField = value;

            // Check that the entered URL contains 'twitter' before sending a request (perform more thorough validation serverside)
            if (valueOfTwitterUrlField.indexOf('twitter.com') !== -1) {

                var explodedVals = valueOfTwitterUrlField.split('/');
                var id = explodedVals[explodedVals.length - 1];

                $.ajax('/myproj/create/retrievetweet/' + id, {
                    dataType: 'json',
                    type: 'GET',
                    success: function (response) {
                    }
                });
            }
            // Allow default action
            return true;
        });
    }

    return { viewModel: TweetViewModel, template: htmlString };
});

模板

<!-- ko if: action == 'show' -->
<div class="card twitter-card">

</div>
<!-- /ko -->
<!-- ko if: action == 'create' -->
<div class="card twitter-card create">
    <label>Tweet URL</label>
    <input type="url" name="tweet_url" id="tweet_url" data-bind="textInput: tweetUrl" />
    <hr/>
    <p>Alternatively, if the tweet is no longer available, enter the tweet information below</p>
    <div class="tweeter-details">
        <img src="" />
        <span class="tweeter-screen-name" data-bind="text: tweet.tweet_user_screen_name"></span>
        <label>Username</label>
        <input type="text" class="tweeter-name" data-bind="value: tweet.tweet_user_name" />
    </div>
    <textarea class="tweet-text" data-bind="text: tweet.tweet_text"></textarea>
    <div class="date-input">
        <datetime params="value: tweet.tweet_created_at, type: 'datetime'"></datetime>
    </div>
</div>
<ul class="tweet-images-list" data-bind="template: { name: 'tweet-images-template', foreach: tweet.images }">
</ul>
<div class="tweet-images-details"></div>
<!-- /ko -->
<script type="text/html" id="tweet-images-template">

</script>

此模板通过以下 HTML 调用:

<tweet params="action: 'create', tweet: tweetData"></tweet>

action 是我感兴趣的模板部分,tweet: tweetData 是我希望父视图模型与组件通信的方式。 tweetData 可能是具有以下属性的对象:

self.tweet = {
    tweet_id: ko.observable(),
    tweet_text: ko.observable(),
    tweet_user_name: ko.observable(),
    tweet_user_screen_name: ko.observable(),
    tweet_created_at: ko.observable(),
    tweet_parent_id: ko.observable(),
    images: ko.observableArray()
}

目前,我主要关心的是展示事物的“创造”方面。简单地显示推文数据非常简单。具体来说,我想知道我的组件上的输入/输出应该如何工作。

问题

1) 如果我通过一些 JSON/JS 对象/数据集从 parentviewmodel 传递到我的组件,为什么我需要在组件中重新定义 observable?

我的意思是:

self.tweet = params.tweet;

为什么这是必要的?如果我不这样做,并尝试在我的模板上引用tweet.tweet_user_name(或params.tweet.tweet_user_name),我会收到以下错误:

ReferenceError: tweet is not defined

为什么我的模板不知道传递给组件构造函数的变量?回想一下,我的构造函数是这样定义的:

function TweetViewModel(params) {  //SNIP

如果我必须在我的组件上重新定义我的对象,对它所做的更改是否会映射回父视图模型上的tweetData

2) 当我有多个输入和多个输出源时,我怎样才能使它们都与剔除映射保持一致,而不会对未定义的属性产生影响并且不观察变化?

如果您查看我的组件,您会发现我有两个用于推文信息的输入源。一个是来自params 的数据,另一个是我向服务器发出的AJAX 请求,以从Twitter API 获取数据。

这些数据源看起来完全不同。理想情况下,我希望我的“模型”看起来就像我在上面定义的那样,一个具有 7 个可观察属性的“推文”对象,范围从 imagestweet_id。在我的 parentviewmodel 上来自tweetData 的数据应该看起来像这样,但是当我期望创建一条推文时它可能是空的。来自我的 AJAX 请求的数据将是来自我需要格式化的 twitter API 的原始响应。

具体来说,我有以下几种情况和问题:

  • 我不能保证tweetData 将始终包含我首选模型的信息或轮廓。

这通常发生在一条推文被完全创建并且除了我的 parentviewmodel 上的可观察对象之外不存在时。我传递给我的组件的变量是我期望由我的组件上的 Knockout 映射填充的 - 我不需要传递一个所有属性都已格式化的空对象。

  • 当我用从 AJAX 请求返回的数据覆盖我的 params.tweet 值时,它实际上不会覆盖 self.tweet 中的值,也不会更新我的数据绑定 .

考虑这段代码:

self.tweet.tweet_text = ko.observable("foo")

$.ajax('/myproj/create/retrievetweet/' + id, {
dataType: 'json',
type: 'GET',
success: function (response) {
    self.tweet = {
        tweet_id: ko.observable(response.id),
        tweet_text: ko.observable(response.text),
        tweet_user_name: ko.observable(response.user.name),
        tweet_user_screen_name: ko.observable(response.user.screen_name),
        tweet_created_at: ko.observable(response.created_at),
        tweet_parent_id: ko.observable(response.in_reply_to_status_id),
        images: ko.observableArray(response.entities.media)
    }
}
});

由于某种原因,此成功回调实际上不会在我的模板上设置任何内容。我的绑定到tweet.tweet_text 的文本绑定仍然会显示“foo”,即使在我收到有效的响应并且应该按照我上面定义的那样重置它之后。

对来自服务器的响应使用敲除映射更加恶心。没有办法将我想要观察的属性列入白名单,我只能通过ignore 选项设置将其列入黑名单——考虑到 Twitter 返回的数据量,有很多属性需要手动忽略!此外,Twitter 返回的属性名称与我尝试使用的属性名称不匹配(见上文),因此我什至不确定剔除映射是否适合此处。

3) 我如何错误地使用了 Knockout.js + 映射 + 组件,对于我正在尝试创建的组件来说,什么是一个好的起始结构?

在这里,我已经束手无策了,我很乐意尝试向我提出的任何和所有建议。理想情况下,我希望尽可能多地回答我的问题。

【问题讨论】:

  • 如果你不能有建设性,走开。
  • 我想说的是,如果你能把它缩短,你会得到更多的答案。粗鲁会让你无处可去。注意你的举止。祝你好运
  • 不,这根本不是你想说的。您说“要广泛地看甚至尝试回答”。那里没有任何建设性的批评,从根本上说它没有任何贡献。现在你在这个毫无意义的小对话上浪费了我和你自己的时间。

标签: javascript knockout.js knockout-mapping-plugin


【解决方案1】:
  1. 组件有自己的视图模型,因为在设计上它们是可重用的,并且可以在具有不同视图模型的不同应用程序中使用。如果要引用主视图模型,请将其作为参数传递。

  2. 不要重新分配绑定的 observable 或包含绑定 observable 的变量。您可以使用普通函数调用(例如self.tweet.tweet_id(newValue))设置它们的值,但如果您使用等号,您通常会丢弃绑定的变量。

  3. 我认为,如果您想将值列入白名单,不妨创建并分配变量。 ko.mapping 不会为您节省任何东西。

【讨论】:

  • 坦率地说,听起来 ko.mapping 或 knockout 并不是很有用。在这一点上,我不妨试试 Angular。
猜你喜欢
  • 2021-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-03
相关资源
最近更新 更多