使用 Knockout 和 ASP.NET 的单页应用程序






4.86/5 (13投票s)
如何使用 Knockout 和 ASP.NET 创建一个示例单页应用程序。
引言
在本文中,我将讨论如何使用 Knockout 和 ASP.NET 创建一个示例单页应用程序。该应用程序会根据用户类型(例如用户、管理员用户、超级管理员用户)显示用户列表,并在选择用户时显示用户详细信息。
构建此应用程序需要具备 Knockout、SAMMY 库、WCF RESTful 服务和 JavaScript 的基本知识。
在开始本文之前,让我们先了解一下 Knockout 的标准定义。
Knockout 是一个 JavaScript 库,可帮助您创建丰富、响应迅速的显示和编辑器用户界面,并具有干净的基础数据模型。 只要您有 UI 部分会动态更新(例如,根据用户操作或外部数据源更改而更改),KO 都可以帮助您更简单、更易于维护地实现它。
Sammy.js 是一个出色的轻量级路由 JavaScript 库。 您可以执行类似的操作,以便与 Knockout 配对使用(来自教程网站或 KnockoutJS)。
- 创建 WCF RESTful 服务
- 创建 ASP.NET 网站
- 定义 ViewModel
- 定义 View
- 定义样式
- 输出屏幕
创建 WCF RESTful 服务
我们将定义两种方法
GetUsers
:根据用户类型返回用户列表GetUserData
:根据用户 ID 和用户类型返回用户列表
这些服务将返回一个 JSON 对象。 代码如下所示。 要了解有关如何构建 RESTful 服务的更多信息,请参阅我的文章:https://codeproject.org.cn/Articles/275279/Developing-WCF-Restful-Services-with-GET-and-POST。
我已将我的服务定义为 ServiceOne.svc,因此我的接口将类似于这样
[ServiceContract]
public interface IServiceOne
{
[OperationContract(Name = "GetUsers")]
[WebInvoke(Method = "GET", UriTemplate = "GetUsers/utypeid/{userTypeId}",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
myCustomObject GetUsers(string userTypeId);
[OperationContract(Name = "GetUserData")]
[WebInvoke(Method = "GET", UriTemplate = "GetUserData/utypeid/{userTypeId}/uid/{userId}",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
users GetUserData(string userTypeId, string userid);
}
此外,为了进行此操作,我定义了我的用户类 myCustomObject
。
这是定义
public class myCustomObject
{
public string userTypeId { get; set; }
public List<users> users { get; set; }
}
public class users
{
public string userid { get; set; }
public string usertypeid { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public string address { get; set; }
}
以下是接口中定义的方法的实现。 我避免调用数据库,因为这是一个示例,并且我定义了静态值
public class ServiceOne : IServiceOne
{
public myCustomObject GetUsers(string userTypeId)
{
myCustomObject myObj = new myCustomObject();
myObj.userTypeId = userTypeId;
List<users> usersList = new List<users>();
if (userTypeId == "Users")
{
usersList.Add(new users() { usertypeid = "Users", userid = "1",
firstname = "user fname 1", lastname = "user lname 1", address = "user address 1" });
usersList.Add(new users() { usertypeid = "Users", userid = "2",
firstname = "user fname 2", lastname = "user lname 2", address = "user address 2" });
}
else if (userTypeId == "AdminUsers")
{
usersList.Add(new users() { usertypeid = "AdminUsers", userid = "3",
firstname = "admin user fname 1", lastname = "admin user lname 1",
address = "admin user address 1" });
usersList.Add(new users() { usertypeid = "AdminUsers", userid = "4",
firstname = "admin user fname 2", lastname = "admin user lname 2",
address = "admin user address 2" });
}
else if (userTypeId == "SuperAdminUsers")
{
usersList.Add(new users() { usertypeid = "SuperAdminUsers", userid = "5",
firstname = "super admin user fname 1", lastname = "super admin user lname 1",
address = "super admin user address 1" });
usersList.Add(new users() { usertypeid = "SuperAdminUsers", userid = "6",
firstname = "super admin user fname 2", lastname = "super admin user lname 2",
address = "super admin user address 2" });
}
myObj.users = usersList;
return myObj;
}
public users GetUserData(string userTypeId, string userid)
{
List<users> usersList = new List<users>();
usersList.Add(new users() { usertypeid = "Users", userid = "1",
firstname = "user fname 1", lastname = "user lname 1", address = "user address 1" });
usersList.Add(new users() { usertypeid = "Users", userid = "2",
firstname = "user fname 2", lastname = "user lname 2", address = "user address 2" });
usersList.Add(new users() { usertypeid = "AdminUsers", userid = "3",
firstname = "admin user fname 1", lastname = "admin user lname 1",
address = "admin user address 1" });
usersList.Add(new users() { usertypeid = "AdminUsers", userid = "4",
firstname = "admin user fname 2", lastname = "admin user lname 2",
address = "admin user address 2" });
usersList.Add(new users() { usertypeid = "SuperAdminUsers", userid = "5",
firstname = "super admin user fname 1", lastname = "super admin user lname 1",
address = "super admin user address 1" });
usersList.Add(new users() { usertypeid = "SuperAdminUsers", userid = "6",
firstname = "super admin user fname 2", lastname = "super admin user lname 2",
address = "super admin user address 2" });
users obj = (from user in usersList.Where(val => val.userid ==
userid && val.usertypeid == userTypeId)
select user).First();
return obj;
}
}
将您的服务托管在 IIS 中,并使用 URL 进行测试,在我的情况下如下:https:///wcfrestservice/ServiceOne.svc/GetUsers/id/Users。
单击它后,您应该能够看到 JSON 对象。 确保您不使用端口号运行应用程序。
创建 ASP.NET 网站
创建一个 ASP.NET 网站,并添加一个名为 userslist.aspx 的新网页。
到目前为止,您应该已经理解了 KnockOut 遵循 MVVM 模式,即模型、视图、ViewModel 模式。
将以下脚本引用添加到您的页面
<!-- JQUERY Library -->
<script type="text/javascript" src="http://learn.knockoutjs.com/Scripts/CDNHosted/jquery-1.7.1.min.js"></script>
<!-- KNOCKOUT Library -->
<script type="text/javascript" src="http://learn.knockoutjs.com/Scripts/Lib/knockout-2.1.0.js"></script>
<!-- SAMMY Library -->
<script src="http://learn.knockoutjs.com/scripts/lib/sammy.js" type="text/javascript"></script>
定义 ViewModel
让我们将以下脚本代码添加到页面,请参阅内联代码注释
<script type="text/javascript">
function UsersViewModel() {
// Data
var self = this;
// defines usertypes
self.userTypes = ['Users', 'AdminUsers', 'SuperAdminUsers'];
// holds usertypeid, when usertype is selected
self.chosenuserTypeId = ko.observable();
// holds list of users for a selected usertype
self.chosenUserTypesData = ko.observable();
// hold userdata for a selected user
self.chosenUserData = ko.observable();
// Behaviours
self.goToUserType = function (usertypeid) { location.hash = usertypeid };
self.goToUserData = function (userdata) { location.hash = userdata.usertypeid + '/' + userdata.userid };
// Client-side routes, can be defined by using SAMMY library
Sammy(function () {
// below segment is used to fetch userslist based on usertypeid
this.get('#:usertypeid', function () {
// sets selected usertypeid
self.chosenuserTypeId(this.params.usertypeid);
// destroy userdata, because at this point we need to have userslist instead of userdata
self.chosenUserData(null);
// make a call to wcf restful service, to fetchs users based on usertypeid
// response from service would contains "userslist", which is filled
// into chosenUserTypesData, whenever we statement "self.chosenUserTypesData"
$.get("https:///wcfmailservice/ServiceOne.svc/GetUsers/Id/" +
this.params.usertypeid, self.chosenUserTypesData);
});
// below segment is used to fetch userdata based on usertypeid & userid
this.get('#:usertypeid/:userid', function () {
// sets selected usertypeid
self.chosenuserTypeId(this.params.usertypeid);
// destroys userslist, because at this point we need to have userdata instead of userslist
self.chosenUserTypesData(null);
// make a call to wcf service, to fetch user data based on usertypeid & userid
$.get("https:///wcfmailservice/ServiceOne.svc/GetUserData/utypeid/" +
this.params.usertypeid + "/uid/" + this.params.userid, self.chosenUserData);
});
// when page load happens show default data, using sammy routing mechanism
this.get('', function () { this.app.runRoute('get', '#Users') });
}).run();
};
// allows to bind viewmodel defined above
ko.applyBindings(new UsersViewModel());
</script>
定义 View
<!-- Users Types, to show list of usertypes based on usertype defined -->
<!-- foreach allows to iterate through the usertypes declared -->
<ul class="userTypes" data-bind="foreach: userTypes">
<li data-bind="text: $data,
css: { selected: $data == $root.chosenuserTypeId() },
click: $root.goToUserType"></li>
</ul>
<!-- Users Grid: with keyword allows below section to be
shown only when data in chosenUserTypesData is available -->
<table class="userslist" data-bind="with: chosenUserTypesData">
<thead><tr><th>First Name</th><th>Last Name</th><th>Address</th></tr></thead>
<tbody data-bind="foreach: users">
<tr data-bind="click: $root.goToUserData">
<td data-bind="text: firstname"></td>
<td data-bind="text: lastname"></td>
<td data-bind="text: address"></td>
</tr>
</tbody>
</table>
<!-- Selected User: with key allows to below section to be shown only when chosenUserData is available-->
<div class="userData" data-bind="with: chosenUserData">
<div class="userdetails">
<p><label>First Name</label>: <span data-bind="text: firstname"></span></p>
<p><label>Last Name</label>: <span data-bind="text: lastname"></span></p>
</div>
</div>
定义样式
.userTypes { background-color: #bbb; list-style-type: none; padding: 0; margin: 0; border-radius: 7px;
background-image: -webkit-gradient(linear, left top, left bottom,
color-stop(0, #d6d6d6), color-stop(0.4, #c0c0c0), color-stop(1,#a4a4a4));
margin: 10px 0 16px 0;
font-size: 0px;
}
.userTypes li:hover { background-color: #ddd; }
.userTypes li:first-child { border-left: none; border-radius: 7px 0 0 7px; }
.userTypes li { font-size: 16px; font-weight: bold; display: inline-block; padding: 0.5em 1.5em;
cursor: pointer; color: #444; text-shadow: #f7f7f7 0 1px 1px;
border-left: 1px solid #ddd; border-right: 1px solid #888; }
.userTypes li { *display: inline !important; } /* IE7 only */
.userTypes .selected { background-color: #444 !important; color: white;
text-shadow:none; border-right-color: #aaa; border-left: none;
box-shadow:inset 1px 2px 6px #070707; }
.userslist { width: 100%; table-layout:fixed; border-spacing: 0; }
.userslist thead { background-color: #bbb; font-weight: bold; color: #444; text-shadow: #f7f7f7 0 1px 1px; }
.userslist tbody tr:hover { cursor: pointer; background-color: #68c !important; color: White; }
.userslist th, .userslist td { text-align:left; padding: 0.4em 0.3em;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.userslist th { border-left: 1px solid #ddd; border-right: 1px solid #888; padding: 0.4em 0 0.3em 0.7em; }
.userslist th:nth-child(1), .userslist td:nth-child(1) { width: 20%; }
.userslist th:nth-child(2), .userslist td:nth-child(2) { width: 15%; }
.userslist th:nth-child(3), .userslist td:nth-child(3) { width: 45%; }
.userslist th:nth-child(4), .userslist td:nth-child(4) { width: 15%; }
.userslist th:last-child { border-right: none }
.userslist tr:nth-child(even) { background-color: #EEE; }
.userData .userdetails { background-color: #dae0e8; padding: 1em 1em 0.5em 1.25em; border-radius: 1em; }
.userData .userdetails h1 { margin-top: 0.2em; font-size: 130%; }
.userData .userdetails label { color: #777; font-weight: bold; min-width: 2.75em; text-align:right; display: inline-block; }
.userData .message { padding: 0 1.25em; }
输出屏幕
编码愉快… 希望这有帮助!