如何用Knockout.js提交后在页面展示动态表单内容
解决Knockout.js动态表单实时展示内容的问题
嘿,我来帮你搞定这个需求!你想要在表单下方实时显示动态添加的字段内容,完全不用再用document.getElementById()或者jQuery去DOM里扒值——Knockout的核心就是数据驱动视图,咱们直接利用它的observable特性就能轻松实现。
先说说你现有代码的小问题
- 你现在添加的字段都是普通的JS对象属性(比如
fname: "var" + noTracker),不是Knockout的observable,所以用户输入内容时,数据不会自动同步更新,自然没法实时展示。 - 你的
printField函数写错啦,直接把myFieldList重置成空数组了,这肯定不是你想要的效果😅。 - 最后绑定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; }
为啥这么改?
- 子ViewModel:把单个字段的属性封装成
DynamicField,让每个输入值都是observable——这样用户输入时,数据会自动更新,Knockout会帮我们同步到视图上。 - value绑定:原来的代码只绑定了id和name,现在加上
value: fname,就能实现输入框内容和数据的双向绑定,改数据视图更,改视图数据更。 - 展示区域:用
foreach: myFieldList遍历所有字段,然后用text: fname把实时数据显示出来,完全不用手动去DOM里取值!
现在你试试:点击Add添加字段,输入内容,下面的详情区域会实时跟着变;点击Remove,对应的条目也会立刻消失。完美实现你想要的效果~
内容的提问来源于stack exchange,提问作者new_coder
相关产品推荐
相关产品推荐

