构建合理的联系人列表网页"Component"

分享于 

28分钟阅读

Web开发

  繁體

更新

我的源代码已经为 CPian"。Kornfeld Eliyahu Peter"提供了一个 ASP.NET 实现,我将它添加到存储库,并更新了 ruby 格式与ASPX格式之间的细微差别。 关于 ASP.NET 实现,下面是来自Peter的注释/建议:

然而,当你查看你的项目时,我马上就知道 MVC,Ruby on Rails 几乎与它完全一样。 因为我决定使端口到 ASP.NET Web窗体,使它更有趣。 但是你可能会惊讶我必须改变。 事实上,我从未接触过JavaScript和 HTML ( 我相信,但有趣的是)。

实际上,我确实在两种情况下改变了 HTML,这并不。

  • 我已经关闭输入> 元素,我的环境有些疯狂,所以我关闭了它们来消除消息 !
  • 在 on switch 中,你使用了 <div> inside <label>。 我也不喜欢这种 HTML,我的IDE也不喜欢。 因此我将它们更改为 span 并添加了显示: block ;到相关的CSS。

,就像你看到的,差异不仅仅是两个框架/语言之间的区别- 你的逻辑是永久的 ! 坦白地说,在移植过程中,我对。 无论如何- 我不知道你的目的是什么,但是我仍然看到你的列表中存在大量的联系人。 我试了 700个联系人,页面变得有点慢。 我也想告诉你,这是你的代码的一个端口,不再是。

源代码

源代码在GitHub上: https://github.com/cliftonm/ContactListDemo,包括 ASP.NET 版本。

介绍

我决定把一个正确的联系人列表放在一起,最终成为一个网站的组件。 我有以下基本要求:

  • 联系人的table
  • 按第一个 NAME 和姓氏排序
  • 一个 slider 按钮,允许 switch 第一/最后一个 NAME 列( 影响排序)
  • 可以搜索一个z 索引( 就像一个物理地址簿"","b","c。"等等 选项卡
  • 以及用于电子邮件地址的列,可以由按钮集选择的home/work/cell 电话号码。

接下来是我将各种技术和finagling集成起来以获得我想要的行为和外观的冒险。 在各种挑战中:

  • 优化屏幕空间--单选按钮和复选框,除了有些古老,还吸收了of元素的默认行为。
  • 一致的字体--令人惊讶的是这些控件有多少不同的字体。大小和权重。
  • jquery/javascript来完成过滤 table 数据之类的事情
  • 每个组件都有不同的API,每个API都有不同的接口,如何使用组件。

跟随跟随

我决定为每一个步骤提供单独的页面,我将在这里浏览这些步骤。 因为我在组件中添加行为和样式,所以这样做是很重要的。 我将指出HTML文件的屏幕截图,以便你可以查看每个步骤的每个步骤的完整 HTML。

入门

虽然后端是 Ruby on Rails,但是你不会在这里看到很多 ruby 代码,因为本文几乎完全是客户端。

设置网页便笺簿

Ruby

在 RubyMine IDE中创建初始 Rails 项目之后,我创建了一个带有一个表的数据库架构:

create_table "contacts", :force =>truedo |t|
 t.string"first_name" t.string"last_name" t.string"email" t.string"home_phone" t.string"work_phone" t.string"cell_phone" t.datetime "created_at", :null =>false t.datetime "updated_at", :null =>falseend

我用一些随机数据( 对于任何一个对比性更大的读者来说,我的第一个名字都是男性的) 对它进行了种子分析:

Contact.delete_all
# http://en.wikipedia.org/wiki/List_of_most_popular_given_namesfirst_names = ['James', 'John', 'Robert', 'Michael', 'William', 'David', 'Richard', 'Charles', 'Joseph', 'Thomas']
# http://names.mongabay.com/most_common_surnames.htmlast_names = ['SMITH', 'JOHNSON', 'WILLIAMS','JONES', 'BROWN', 'DAVIS', 'MILLER', 'WILSON', 'MOORE', 'TAYLOR', 'ANDERSON', 'THOMAS', 'JACKSON', 'WHITE', 'HARRIS', 'MARTIN', 'THOMPSON', 'GARCIA', 'MARTINEZ', 'ROBINSON']20.times do fname = first_names[rand(first_names.length)].capitalize
 lname = last_names[rand(last_names.length)].capitalize
 home = rand.to_s[2..4]+'-'+rand.to_s[2..4]+'-'+rand.to_s[2..5]
 work = rand.to_s[2..4]+'-'+rand.to_s[2..4]+'-'+rand.to_s[2..5]
 cell = rand.to_s[2..4]+'-'+rand.to_s[2..4]+'-'+rand.to_s[2..5]
 Contact.create(:first_name => fname, :last_name => lname, :email =>"#{fname}.#{lname}@mail.com", :home_phone => home, :work_phone => work, :cell_phone => cell)
end

ASP.NET

using System;using System.Data;namespace ContactListDemo
{
 publicclass Schema : DataTable
 {
 public Schema()
 {
 TableName = "contacts";
 Columns.Add( "first_name", typeof( string ) );
 Columns.Add( "last_name", typeof( string ) );
 Columns.Add( "email", typeof( string ) );
 Columns.Add( "created_at", typeof( DateTime ) ).AllowDBNull = false;
 Columns.Add( "updated_at", typeof( DateTime ) ).AllowDBNull = false;
 Columns.Add( "home_phone", typeof( string ) );
 Columns.Add( "work_phone", typeof( string ) );
 Columns.Add( "cell_phone", typeof( string ) );
 }
 }
 publicclass Contacts : Schema
 {
 // http://en.wikipedia.org/wiki/List_of_most_popular_given_namesprivate string[ ] _FirstNames = { "James", "John", "Robert", "Michael", "William", "David", "Richard", "Charles", "Joseph", "Thomas" };
 // http://names.mongabay.com/most_common_surnames.htmprivate string[ ] _LastNames = { "SMITH", "JOHNSON", "WILLIAMS", "JONES", "BROWN", "DAVIS", "MILLER", "WILSON", "MOORE", "TAYLOR", "ANDERSON", "THOMAS", "JACKSON", "WHITE", "HARRIS", "MARTIN", "THOMPSON", "GARCIA", "MARTINEZ", "ROBINSON" };
 public Contacts ( )
 {
 Random oRnd = new Random( );
 for ( int i = 0; i <200; i++ )
 {
 string szFName = _FirstNames[ oRnd.Next( _FirstNames.Length ) ].ToUpper( );
 string szLName = _LastNames[ oRnd.Next( _LastNames.Length ) ].ToUpper( );
 string szEmail = string.Format( "{0}.{1}@mail.com", szFName, szLName );
 string szHome = string.Format( "{0}-{1}-{2}", oRnd.Next( 10, 9999 ), oRnd.Next( 10, 9999 ), oRnd.Next( 10, 99999 ) );
 string szWork = string.Format( "{0}-{1}-{2}", oRnd.Next( 10, 9999 ), oRnd.Next( 10, 9999 ), oRnd.Next( 10, 99999 ) );
 string szCell = string.Format( "{0}-{1}-{2}", oRnd.Next( 10, 9999 ), oRnd.Next( 10, 9999 ), oRnd.Next( 10, 99999 ) );
 Rows.Add( szFName, szLName, szEmail, DateTime.Today, DateTime.Today, szHome, szWork, szCell );
 }
 }
 }
}

这结束了我们对后端的浏览。

Javascript文件

但是,我们需要配置几个组件。 无论你使用哪个服务器平台,你都需要:

  • jQuery
  • jquery用户界面
  • jquery tablesorter

使用 jquery tablesorter

HTML: appviewscontactsbuild1.html.

在很多方面,这是最容易的。

要创建具有可以排序列的table,如下所示:

。put一些基本的HTML:

Ruby

<div><tableid='contactsTable'><thead><tr><th>Last Name</th><th>First Name</th><th>Email</th><th>Home</th><th>Work</th><th>Cell</th></tr></thead><% @contacts.each do |contact|%>
 <tr><td><%= contact.last_name%></td><td><%= contact.first_name%></td><td><%= contact.email%></td><td><%= contact.home_phone%></td><td><%= contact.work_phone%></td><td><%= contact.cell_phone%></td></tr><% end %>
 </table></div>

ASP.NET

<body><formid="form1"runat="server"><div><tableid='contactsTable'class='tablesorter-default'><thead><tr><th>Last Name</th><th>First Name</th><th>Email</th><th>Home</th><th>Work</th><th>Cell</th></tr></thead><% foreach ( System.Data.DataRow oContact in Contacts.Rows ) { %>
 <tr><td><%= oContact["last_name"]%></td><td><%= oContact["first_name"]%></td><td><%= oContact["email"]%></td><td><%= oContact["home_phone"]%></td><td><%= oContact["work_phone"]%></td><td><%= oContact["cell_phone"]%></td></tr><% } %>
 </table></div></form></body>

和一个 liner Javascript调用:

<scripttype="text/javascript"> $(document).ready(function()
 {
 $("#contactsTable").tablesorter();
 });</script>

可用性和演示问题

虽然在第一次采用时看起来相当不错,但它有一些问题。 主要的问题是:

  • 并非所有字段都应该可以排序。 对电子邮件地址和家庭。工作和手机号码进行排序是没有意义的。
  • 当我查找一个联系人时,我通常只想要一个东西,而不是整个信息。 如果我要包括物理地址和邮寄地址,这些地址会从 Collection的四个字段中添加两个字段。

中等问题:

  • 有时我知道 NAME的第一个,我想查看一下,有时我想看看他们最后的NAME。 我们先切换到第2 列,然后切换到列表中的相关信息,这样我大部分的注意力都是在屏幕上进行,而不是移动到第2 列。 我将在单独的部分中解决这个问题。

小问题是:

  • 它占据了整个屏幕。
  • 我希望"zebra"条能够创建 LESS 单色( 和单调的) 列表。

抛光桌子

HTML: appviewscontactsbuild2.html.

删除特定列的排序功能

首先要做的是删除对邮件和电话字段进行排序的能力。 jquery tablesorter是一个非常好的插件组件,并且让它不对特定列排序非常容易:

<script type="text/javascript">
$(document).ready(function() {
 $("#contactsTable").tablesorter({
 headers : {
 0: { sorter: "text" },
 1: { sorter: "text" },
 2: { sorter: false },
 3: { sorter: false },
 4: { sorter: false },
 5: { sorter: false },
 6: { sorter: false }
 }
 })
});
</script>
固定宽度

很简单,除非要修复某些宽度,否则将外部div设置为 100%,并将内部div宽度设置为。 这样,内部组件可以被重新使用,而不需要使用物理维度,这是应用程序特定的实现。 你还会注意到,这在以后是有用的 ! 所以:

<divstyle="width:500px"><divstyle="width:100%">. . . etc.. .

Yes,实际上,这个做法在某些情况下会使用这个组件,比如基础,删除固定宽度的,这主要是为了让我看到一个在 narrower 演示中显示的东西,其他的东西都要去 final 页面。

斑马条纹

可以在 tablesorter ( 文档中还可以读到许多其他漂亮的特性) 中轻松指定这里选项:

$("#contactsTable").tablesorter({
 widgets : [ 'zebra' ],
. . . etc.. .

我们现在拥有以下内容:

变得更好 !

去除噪音

HTML: appviewscontactsbuild3.html.

接下来,我们需要一种方法来选择我们想要的特定信息,而不是在我们查找联系人时对网格进行污染。 因为我将使用 jquery ui buttonset。 这需要少量的HTML:

<divid="MyButtonList"><inputtype="checkbox"id="toggle_email"><labelfor="toggle_email">email</label><inputtype="checkbox"id="toggle_home"><labelfor="toggle_home">home</label><inputtype="checkbox"id="toggle_work"><labelfor="toggle_work">work</label><inputtype="checkbox"id="toggle_cell"><labelfor="toggle_cell">cell</label></div>

在 document ready 事件中又有一个接口:

$('#MyButtonList').buttonset();

当然,它看起来很糟糕,因为它是巨大的,我们只是在布局中添加了第二个字体。 但以后我们会处理的。

现在我们需要编写单击按钮集的实现。 我们将编写四个低调事件单击处理程序:

$('#MyButtonList').buttonset(); $("#toggle_email").click(function()
{
 showOrHide('#toggle_email', 3)
});
$("#toggle_home").click(function()
{
 showOrHide('#toggle_home', 4)
});
$("#toggle_work").click(function()
{
 showOrHide('#toggle_work', 5)
});
$("#toggle_cell").click(function()
{
 showOrHide('#toggle_cell', 6)
});function showOrHide(button, colNum)
{
 if ($(button).is(":checked"))
 {
 $('#contactsTable tr *:nth-child('+colNum+')').removeClass('hidden');
 }
 else {
 $('#contactsTable tr *:nth-child('+colNum+')').addClass('hidden');
 }
}

可用性和演示问题

这里时我们有一个主要功能的实现( 它还缺少一个功能),但是还有一些可以用性和表示问题:

主要问题:

  • 当我们进行页面刷新时,网格不反映所选数据列
  • 字体不匹配,大量的可视化效果
  • 用灰色按钮表示buttonset意味着"选定"或者白按钮意味着"选定。"实际上,当我实现了基本的Javascript时意味着""。" !
  • 因为我们不再选择它们,所以列之间有大量的死空间。
在刷新时设置选定列

通过在 document ready 事件中强制设置列状态来处理这里问题:

showOrHide('#toggle_email', 3)
showOrHide('#toggle_home', 4)
showOrHide('#toggle_work', 5)
showOrHide('#toggle_cell', 6)
字体不匹配和大小调整

Poking tablesorter CSS,我发现使用的字体是:

font: 12px/18px Arial, Sans-serif;

。我将在MyButtonList的CSS中指定。 下一个问题是调整大小。 在大量烦恼之后,我决定了 line-height的0.8种风格。 通过将它与我将要实现的按钮 slider 高度匹配来确定它。

当按钮被选中时使它更清晰"

为了给按钮更多地指示它被选中,我还选择了加粗选定的文本。 按钮集的final CSS如下所示:

<style> #MyButtonList. ui-button.ui-state-active. ui-button-text {
 font: 12px/18px Arial, Sans-serif;line-height: 0.8;color: black;background-color: white;font-weight:bold;}
 #MyButtonList. ui-button. ui-button-text {
 font: 12px/18px Arial, Sans-serif;line-height: 0.8;color: black;background-color: #eeeeee; }</style>

现在的情况是:

删除死空间

现在我们已经删除了我们不想看到的列,让我们移除死空间,但保留网格 background的全宽度。 同样,作为可用性问题,我发现将名称放在左边,并将联系人数据( 电子邮件和电话) 放在右边是很有用。 我发现这是一种视觉上愉快的方式分离 NAME 与联系信息的其他人。 我们使用列样式实现这里功能:

<thstyle="white-space:nowrap">Last Name</th><thstyle="white-space:nowrap">First Name</th><thstyle="white-space:nowrap; width:99%"></th><thstyle="white-space:nowrap;">Email</th><thstyle="white-space:nowrap;">Home</th><thstyle="white-space:nowrap;">Work</th><thstyle="white-space:nowrap;">Cell</th>

我们对 table body 行执行同样的操作( 未显示)。

注意第三列是一个空列,宽度为 99%。 NAME 列现在调整以适应内容,其余的"数据"列将向右移动,例如:

选择第一个/上一个 NAME 列排序

HTML: appviewscontactsbuild4.html.

一个非常漂亮的CSS只翻转 switch ( 或者按钮滑块,我一直在叫它) 可以在这里找到 完整的CSS很笨重,不需要显示,但这是我最初的结果:

按钮 slider的实现是直接向前的。 再次监视单击事件并切换第一列和第二列的顺序:

$("#myonoffswitch").click(function()
{
 var tbl = $('#contactsTable');
 moveColumn(tbl, 1, 0);
});

此外,在 document ready 事件中,我们要设置刷新页面时列序列的状态:

if (!$("#myonoffswitch").is(":checked"))
{
 var tbl = $('#contactsTable');
 moveColumn(tbl, 1, 0);
}

moveColumn 函数完成所有工作:

function moveColumn(table, from, to) {
 var rows = $('tr', table);
 var cols;
 rows.each(function() {
 cols = $(this).children('th, td');
 cols.eq(from).detach().insertBefore(cols.eq(to));
 });
}

可用性和演示问题

  • 但是,字体是不同
  • 我不喜欢"关闭"模式有不同的background。 这并不是真正的switch/off,只是"状态"控件。
  • 它与按钮集的对齐方式不一致。 理想情况下,按钮集应该与网格的边缘对齐,slider 应该是相同的高度和垂直对齐。
字体,大小,颜色问题

修复这些问题是相当直接的。 字体与 table 使用的字体相同。 在你注意到的代码中,我有注释,这三个地方必须要触摸的时候,对控件宽度的。 我也把边界缩小了。

对齐问题

按钮 slider 和右键对齐按钮设置该按钮集需要一个小的div步长,它的宽度为 500像素:

对于按钮滑块:

<divstyle="width:100%">

对于按钮集:

<divid="MyButtonList"style="float:right">

我们还需要清除 table的div,以便它被强制为新行:

<divstyle="clear:left; width:100%">

我们现在有了类似这样的内容:

添加索引筛选器

HTML: appviewscontactsbuild5.html.

最后,我想向左添加一个A 到 z index。 用户单击某个字母时,它会过滤联系人列表,其中包含以该字母开头的人的姓名。 如果最后一个 NAME 是第一列,则它将过滤姓。 如果第一个 NAME 是第一列,那么它将过滤名字。

要实现这一点,需要通过 20像素移动所有内容,因此我们从 slider 按钮div开始:

<divstyle="margin-left:20px; width:100%">

我们还将 table 移动到 20像素,( 顺便说一下) 调整顶部 padding 一点,让我们从控件的上面 中得到一些空间:

<divstyle="margin-left:20px; width:100%; padding-top: 3px">

然后,在 table div之前,添加一个带有 ruby 代码的div来生成索引。集和用户单击的字母索引的Javascript函数:

Ruby

<divclass="index-filter"><tablestyle="font: 12px/18px Arial, Sans-serif;"><tr><td><ahref='#'id='filter-none'onclick='showAll()'>*</a></td></tr><% ('A'..'Z').each do |s| %>
 <tr><td><% filter_by = %Q|filterBy("#{s}")| %>
 <ahref='#'id='<%="filter-#{s}" %>'onclick='<%="#{filter_by}"%>'><%= "#{s}" %></a></td></tr><% end %>
 </table></div>

ASP.NET

<divclass="index-filter"><tablestyle="font: 12px/18px Arial, Sans-serif;"><tr><td><ahref='#'id='filter-none'onclick='showAll()'>*</a></td></tr><% foreach ( char s in Enumerable.Range( 'A', 'Z' - 'A' + 1 ).Select( x => x ) ) { %>
 <tr><td><ahref='#'id='filter-<%= s %>'onclick='filterBy("<%= s %>")'><%= s %></a></td></tr><% } %>
 </table></div>

( 是,table 样式应该是嵌入在HTML中的CSS。)

我们需要一些CSS来让列表出现在正确的位置,它在左边与 table body ( 不是标题)的顶部对齐:

.index-filter {
 clear:left;
 float:left;
 width:2px;
 margin-top: 25px;
 margin-left: 2px;
}

注意,在索引列表前面有一个星号以取消筛选。 showAllfilterBy 方法如下所示:

function showAll()
{
 $("#filterable").find("tr").each(function(idx, row){
 row.hidden=false;
 });
}// Filter by the first letter of the first column, which will be either last name or first name.function filterBy(letter)
{
 var rows = $("#filterable").find("tr");
 rows.each(function(idx, row)
 {
 if (row.children[0].innerHTML.indexOf(letter)==0)
 {
 row.hidden=false;
 }
 else {
 row.hidden=true;
 }
 });
}

我们还需要用"可以筛选"id将行包装在tbody标记中:

Ruby

<tbodyid='filterable'><% @contacts.each do |contact|%>
 <tr><tdstyle="white-space:nowrap"><%= contact.last_name%></td><tdstyle="white-space:nowrap"><%= contact.first_name%></td><tdstyle="white-space:nowrap; width:99%"></td><tdstyle="white-space:nowrap;"><%= contact.email%></td><tdstyle="white-space:nowrap;"><%= contact.home_phone%></td><tdstyle="white-space:nowrap;"><%= contact.work_phone%></td><tdstyle="white-space:nowrap;"><%= contact.cell_phone%></td></tr><% end %></tbody>

ASP.NET

<tdstyle="white-space: nowrap"><%= oContact["last_name"]%></td><tdstyle="white-space: nowrap"><%= oContact["first_name"]%></td><tdstyle="white-space: nowrap; width: 99%"></td><tdstyle="white-space: nowrap;"><%= oContact["email"]%></td><tdstyle="white-space: nowrap;"><%= oContact["home_phone"]%></td><tdstyle="white-space: nowrap;"><%= oContact["work_phone"]%></td><tdstyle="white-space: nowrap;"><%= oContact["cell_phone"]%></td>

我们现在有了一些工作,但看起来像这样:

重要的一课

另外,我最初使用的是jQuery函数,如下所示:

$("#filterable").find("tr").hide();
... show only selected rows.. .

但这给了我很多伤害,因为,jQuery设置 hide(),而我试图使用 hidden 属性使行可以见。 这是--非常重要的一课,请确保你对属性和CSS的使用与你想要的行为一致 !

可用性和演示问题

  • 索引显示为链接,垂直间距太宽。
修复索引的外观

CSS到救援:

.index-filtertrtd {
 line-height:9px;}
.index-filtertrtda {
 text-decoration: none;color: black;}
.index-filtertrtda:hover {
 color: white;background-color: black;font-weight:bold;}

现在我们已经删除了下划线,并且对鼠标悬停的索引字母有一个清晰的指示符:

关于滚动条。分页和颜色

我决定不实现滚动条或者分页。 我发现有一些内部滚动条是烦人的--我更喜欢滚动整个浏览器窗口。 另外,对于类似联系人列表,我不认为分页是合适的。 在一个列表中滚动,即使是一个很长的时间,它也是非常快速的。 分页只是在。 最后,我喜欢颜色为绿色选择和红色为选取,但是,这是技术上坏的用户界面的用户界面。

结束语

我希望你喜欢这个游览,并找到我创建的至少有点美观的联系表演示文稿。 特别感谢Peter将 ASP.NET 端口组合在一起 !


WEB  构建  lis  列表  Building  Contact  
相关文章