You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Knockout.js提交后在页面展示动态表单内容

解决Knockout.js动态表单实时展示内容的问题

嘿,我来帮你搞定这个需求!你想要在表单下方实时显示动态添加的字段内容,完全不用再用document.getElementById()或者jQuery去DOM里扒值——Knockout的核心就是数据驱动视图,咱们直接利用它的observable特性就能轻松实现。

先说说你现有代码的小问题

  1. 你现在添加的字段都是普通的JS对象属性(比如fname: "var" + noTracker),不是Knockout的observable,所以用户输入内容时,数据不会自动同步更新,自然没法实时展示。
  2. 你的printField函数写错啦,直接把myFieldList重置成空数组了,这肯定不是你想要的效果😅。
  3. 最后绑定ViewModel的时候漏了new关键字,这样Knockout没法正确初始化实例。

改造方案来啦!

我们需要做这几步:

  • 给每个动态字段创建一个子ViewModel,把需要跟踪的输入值改成observable
  • 给输入框和textarea加上value绑定,让用户输入自动同步到数据里
  • 在表单下方添加一个展示区域,用foreach遍历数据,实时渲染内容

修改后的JavaScript代码

// 子ViewModel:封装单个动态字段的所有属性
function DynamicField(id) {
  var self = this;
  self.label = "First " + id;
  self.label1 = "Second " + id;
  self.fname = ko.observable("var" + id); // 改成observable,跟踪输入值
  self.lname = ko.observable("varry" + id); // 改成observable
  self.label2 = "Textarea" + id;
  self.texting = ko.observable("newtext" + id); // 改成observable
}

function fieldModel() {
  var self = this;
  var noTracker = 0;

  self.myFieldList = ko.observableArray([]);

  self.removeField = function(dynamicField) {
    self.myFieldList.remove(dynamicField);
  }

  self.addField = function() {
    noTracker++;
    self.myFieldList.push(new DynamicField(noTracker)); // 用子ViewModel创建实例
  }
}

ko.applyBindings(new fieldModel()); // 这里要new一个实例!

修改后的HTML代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>

<div id="container">
  <header>
    <h1>Test with Knockout</h1>
  </header>

  <section id="main">
    <form method="post">
      <div data-bind="foreach: myFieldList">
        <p>
          <label data-bind="text: label"></label>
          <!-- 加上value绑定,实现输入值和数据的双向同步 -->
          <input data-bind="attr: { id: fname, name: fname}, value: fname"><br/>
          <label data-bind="text: label1"></label>
          <input data-bind="attr: { id: lname, name: lname}, value: lname"><br/>
          <label data-bind="text: label2"></label><br/>
          <textarea data-bind="attr: { id: texting }, value: texting"></textarea>
          <!-- 用$parent调用父ViewModel的removeField方法 -->
          <span class="removeVar" data-bind="click: $parent.removeField">Remove</span>
        </p>
      </div>

      <p>
        <span id="addVar" data-bind="click: addField">Add</span>
      </p>

      <p class="alignRight">
        <input type="submit" value="Submit">
      </p>
    </form>

    <!-- 新增的表单内容展示区域 -->
    <hr>
    <h3>当前表单详情</h3>
    <div data-bind="foreach: myFieldList">
      <div style="border:1px solid #eee; padding:10px; margin:10px 0; border-radius:4px;">
        <p><strong>First 字段:</strong> <span data-bind="text: fname"></span></p>
        <p><strong>Second 字段:</strong> <span data-bind="text: lname"></span></p>
        <p><strong>Textarea 内容:</strong> <br><span data-bind="text: texting"></span></p>
      </div>
    </div>
  </section>

  <footer>
  </footer>
</div>

CSS代码可以保留你原来的,不用改

body {
  font-family: Verdana, Arial, Helvetica, sans-serif;
  font-size: 14px;
}

#container {
  width: 980px;
  margin: 20px auto;
  padding: 15px;
}

#addVar:hover,
.removeVar:hover {
  cursor: pointer;
}

.alignRight {
  text-align: right;
}

.displayHeader {
  margin: auto;
  padding: 5px;
  width: 650px;
}

#action {
  margin-left: 320px;
  border: 4px solid #E3BE8D;
  -moz-border-radius: 4px;
  -moz-border-radius: 4px;
  -webkit-border-radius: 4px;
  -webkit-border-radius: 4px;
  -o-border-radius: 4px;
  -o-border-radius: 4px;
  border-radius: 4px;
  border-radius: 4px;
  background-color: #DAEDE2;
  display: inline-block;
  padding: 5px;
}

.msg {
  margin-left: 320px;
}

input,
textarea {
  padding: 5px;
  font-size: 16px;
}

input:focus,
textarea:focus {
  background-color: #F6F792;
}

.submit {
  text-align: right;
  margin-right: 50px;
}

footer {
  clear: both;
  margin-top: 20px;
  border-top: 1px solid #005;
}

为啥这么改?

  1. 子ViewModel:把单个字段的属性封装成DynamicField,让每个输入值都是observable——这样用户输入时,数据会自动更新,Knockout会帮我们同步到视图上。
  2. value绑定:原来的代码只绑定了id和name,现在加上value: fname,就能实现输入框内容和数据的双向绑定,改数据视图更,改视图数据更。
  3. 展示区域:用foreach: myFieldList遍历所有字段,然后用text: fname把实时数据显示出来,完全不用手动去DOM里取值!

现在你试试:点击Add添加字段,输入内容,下面的详情区域会实时跟着变;点击Remove,对应的条目也会立刻消失。完美实现你想要的效果~

内容的提问来源于stack exchange,提问作者new_coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:16:37