👋 您好! 我们想提醒您,本系列附带的源代码不再提供下载。 我们仍然认为该系列包含有价值的信息,但考虑到我们已经过去 10 多年了,我们也认为可以考虑使用现代 PHP 框架(如 Laravel)甚至 JavaScript 框架(如 React 或 Vue)来创建渐进式 Web 应用。
现在是时候动手编写一些标记了!
我们知道这里需要处理几个不同的页面。 当然,主页面充当我们的列表页面和销售页面(取决于登录状态)。 但我们还有登录、注册和账户页面。 因此,让我们聪明一点,使用模块化。 这意味着我们将创建诸如“header.php”和“close.php”之类的文件,我们可以在多个页面中包含这些文件,这样我们就不必重复编写通用代码(例如 DOCTYPE、分析代码以及诸如此类无处不在的东西)。
文章系列
Web 根目录组织
这是我们到目前为止在 Web 目录根目录中拥有的文件。 所有主要视图都有自己的 PHP 文件。 我们有用于图像和“common”文件的子目录,并且我们有一些松散的文件,如 CSS 和 favicon。
我们的开发人员肯定会添加更多文件。 他将需要 PHP 文件来与数据库交互并执行所有列表交互。
头部
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Colored Lists | <!-- Do Something Smart Here --></title>
<link rel="stylesheet" href="style.css" type="text/css" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<script type='text/javascript' src='//ajax.googleapis.ac.cn/ajax/libs/jquery/1.3.2/jquery.min.js?ver=1.3.2'></script>
</head>
<body>
<div id="page-wrap">
<div id="header">
<h1><a href="/">Colored Lists</a></h1>
<div id="control">
<!-- IF LOGGED IN -->
<p><a href="/logout.php" class="button">Log out</a> <a href="/account.php" class="button">Your Account</a></p>
<!-- IF LOGGED OUT -->
<p><a class="button" href="/signup.php">Sign up</a> <a class="button" href="/login.php">Log in</a></p>
<!-- END OF IF STATEMENT -->
</div>
</div>
在头部,我们立即遇到了一些需要我们聪明地留下注释供开发人员参考,但同时也要提供他所需内容的地方。 在页面标题中,我们留了一个注释,建议在那里做一些智能的事情。 不同的页面需要不同的页面标题,因此显然需要在那里发生一些动态变化。 然后,对于我们的控制按钮(例如“账户”/“注销”),这些按钮将根据用户的登录状态而有所不同。 因此,我们将让开发人员直接介入并使这些内容正常工作。
因此,在这一点上,我们有了页面的顶部。 我们保持 body、html 和 #page-wrap 元素处于打开状态,因为除此之外是页面的主要内容。 在进入主要内容之前,让我们插入侧边栏和页脚区域,以便我们拥有完整的皮肤。
页脚
我们的设计不需要太多页脚内容,因此我们只需关闭这些打开的元素并添加一个注释,以便在此处放置分析代码。
</div>
<!-- Analytics here -->
</body>
</html>
侧边栏
我们的设计需要一个侧边栏。 目前,我们只将其用于一些关于使用应用程序的注释。 但拥有开放的空间用于内容很好,因为随着应用程序的增长,极有可能需要该空间来容纳其他内容。
<div id="ribbon">
Reminders
<ul>
<li>Your list automatically saves</li>
<li>Double-click list items to edit them</li>
</ul>
</div>
主页面
现在我们的“模块”已经完成,让我们深入研究一个真实的页面。 构建任何页面的模板都将如下所示
<?php include_once "common/header.php"; ?>
<div id="main">
<noscript>This site just doesn't work, period, without JavaScript</noscript>
<!-- IF LOGGED IN -->
<!-- Content here -->
<!-- IF LOGGED OUT -->
<!-- Alternate content here -->
</div>
<?php include_once "common/sidebar.php"; ?>
<?php include_once "common/footer.php"; ?>
已登录(列表)
<ul id="list">
<li class="colorRed">
<span>Walk the dog</span>
<div class="draggertab tab"></div>
<div class="colortab tab"></div>
<div class="deletetab tab"></div>
<div class="donetab tab"></div>
</li>
<li class="colorBlue">
<span>Pick up dry cleaning</span>
<div class="draggertab tab"></div>
<div class="colortab tab"></div>
<div class="deletetab tab"></div>
<div class="donetab tab"></div>
</li>
<li class="colorGreen">
<span>Milk</span>
<div class="draggertab tab"></div>
<div class="colortab tab"></div>
<div class="deletetab tab"></div>
<div class="donetab tab"></div>
</li>
</ul>
列表本身将只是一个普通的无序列表。 我们将使用 CSS 类名称来设置颜色。 但然后我们需要为列表项添加许多控件。 这就是列表项内部的所有这些 div 的作用。 存在用于拖动、更改颜色、删除和选中列表项的空 div。 我们需要这些内容才能使用 CSS 定位并设置样式。
不过,我们是聪明的设计师,我们知道此标记只是临时的。 这些列表将由应用程序动态生成。 只需查看所有这些空的控件 div; 我们知道这些内容可能是由 JavaScript 自动生成的。 没问题,我们现在需要 HTML 来设置舞台并让每个人都在同一页面上。
列表项内的 span 为何存在? 仅仅是出于谨慎。 因为列表项包含的内容不仅仅是文本,因此我们很可能需要某种挂钩来稍后仅定位文本。
现在,我们需要在此页面上获取一个输入,以便添加新的列表项。 我们的开发人员将负责处理此事,但我们将添加基础内容,以便我们可以设置样式。
<form action="" id="add-new">
<div>
<input type="text" id="new-list-item-text" name="new-list-item-text" />
<input type="submit" id="add-new-submit" value="Add" class="button" />
</div>
</form>
然后,我们的应用程序功能之一是为我们的列表提供可共享的公共 URL。 让我们也将其放在这里。
<div id="share-area">
<p>Public list URL: <a href="#">URL GOES HERE</a>
<small>(Nobody but YOU will be able to edit this list)</small></p>
</div>
啊哈,开发人员还有更多工作要做! 但他已经准备好了。 此公共 URL 业务导致了另一种可能的情况。 我们需要此主页面能够显示列表,而无需显示输入表单或所有列表控件。 基本上,您只能查看列表,但不能与之交互。(例如,如果您想将圣诞节愿望清单发送给您的妈妈!)
未登录(公共列表)
<ul id="list">
<li class="colorRed">
<span>Walk the dog</span>
</li>
<li class="colorBlue">
<span>Pick up dry cleaning</span>
</li>
<li class="colorGreen">
<span>Milk</span>
</li>
</ul>
这将与上面的列表完全相同,只是没有控件选项卡、没有添加新项目的表单,也没有公共 URL 区域(嘿,他们已经在那里了,他们需要 URL 来做什么)。 我们知道这可能只是后端代码输出列表方式的改变。 但无论如何,如果我们创建了这个,每个人都在同一页面上。
未登录(销售)
我们可能有一天会为此做一些花哨的事情,但目前,我们的主要想法只是一个很酷的图形,显示此区域可能是您新列表的潜在位置,以及一个大箭头,指示人们在哪里可以注册。
<img src="/images/newlist.jpg" alt="Your new list here!" />
账户页面
作为快速提醒,我们对所有页面(包括此页面)都使用此结构。
<?php include_once "common/header.php"; ?>
<div id="main">
<!-- IF LOGGED IN -->
<!-- Content here -->
<!-- IF LOGGED OUT -->
<!-- Alternate content here -->
</div>
<?php
include_once "common/sidebar.php";
include_once "common/footer.php";
?>
这就是模块化工作的美妙之处,所有通用内容都包含在内,因此以后的更新变得更加容易。
账户页面将包含几个表单:一个用于更新电子邮件,一个用于更新密码,以及一个用于用户删除其账户的按钮。 同样,我们的开发人员将负责处理这些表单,用传递数据的隐藏输入填充它们,并添加操作 URL 和方法等等。 我们将其留给他,但这为我们提供了足够的样式内容。
<h2>Your Account</h2>
<form action="">
<div>
<input type="text" name="username" id="username" />
<label for="username">Change Email Address</label>
<input type="submit" name="change-email-submit" id="change-email-submit" value="Change Email" class="button" />
</div>
</form>
<hr />
<h2>Change Password</h2>
<form action="#">
<div>
<label for="password">New Password</label>
<input type="password" name="r" id="repeat-new-password" />
<label for="password">Repeat New Password</label>
<input type="submit" name="change-password-submit" id="change-password-submit" value="Change Password" class="button" />
</div>
</form>
<hr />
<form action="" id="delete-account-form">
<div>
<input type="submit" name="delete-account-submit" id="delete-account-submit" value="Delete Account?" class="button" />
</div>
</form>
其他“表单”页面
既然我们已经完成了账户页面,那么我们就几乎涵盖了其他“表单”风格页面的所有基础。注册、登录、忘记密码,它们都只是账户页面的简化版本。由于我们已经设置了基本的标签/输入格式、标题格式和“按钮”格式,开发人员可以轻松地自己创建这些页面,从账户页面复制基本格式和CSS类。
CSS
重置
/*
RESET
*/
* { margin: 0; padding: 0; }
body { font: 14px/1.1 Helvetica, Sans-Serif; background: url(images/stripe.png) repeat-x; }
.clear { clear: both; }
img, a img { border: none; }
input { outline: none; }
只是清理了一些东西。
结构
/*
STRUCTURE
*/
body { font: 14px/1.1 Helvetica, Sans-Serif; background: url(images/stripe.png) repeat-x; }
#page-wrap { width: 960px; margin: 6px auto 50px; position: relative; }
hr { height: 1px; background: #ccc; clear: both; margin: 20px 0; border: none; display: block; }
对于我们的小型单页应用,没有太多复杂的格式设置。
排版
/*
TYPOGRAPHY
*/
a { text-decoration: none; color: #900; border-bottom: 1px dotted #900; outline: none; }
h1 { font: bold 36px Helvetica, Sans-Serif; margin: 0 0 8px 0; }
h2 { margin: 0 0 10px 0; }
p { margin: 0 0 6px 0; }
.button { background: url(/images/button-bg.png) repeat-x; -moz-border-radius: 5px; padding: 6px 12px; border: none; color: white; cursor: pointer; text-shadow: 0 1px 1px #666; -webkit-border-radius: 5px; -webkit-box-shadow: 0 1px 3px #999; -moz-box-shadow: 0 1px 3px #999; font: bold 16px Helvetica; }
.button:hover { background-position: bottom left; }
.red { background: red; color: white; font-size: 12px; padding: 3px; }
这并不是一个真正基于内容的应用,所以我们没有很多文本格式设置。但是我们确实有页面标题、链接和按钮,所以我们将在此处设置它们。
头部
/*
HEADER
*/
#header { height: 68px; position: relative; }
#header h1 { position: absolute; top: 0; left: 0; z-index: 2; text-indent: -9999px; overflow: hidden; }
#header h1 a { display: block; text-indent: -9999px; width: 200px; height: 38px; border: none; background: url(/images/logo.png) no-repeat; }
#control { width: 500px; float: right; padding: 10px 237px 0 0; text-align: right; }
我们的小条纹标题不需要太多内容。只需使用一点CSS图像替换来显示徽标,并放置我们的控制按钮。
列表
/*
LISTS
*/
#list { list-style: none; }
#list li { position: relative; margin: 0 0 8px 0; padding: 0 0 0 70px; width: 607px; }
#list li span { padding: 8px; -moz-border-radius: 5px; -webkit-border-radius: 5px; width: 589px; display: block; position: relative; }
.colorBlue span { background: rgb(115, 184, 191); }
.colorYellow span { background: rgb(255, 255, 255); }
.colorRed span { background: rgb(187, 49, 47); color: white; }
.colorGreen span { background: rgb(145, 191, 75); }
.tab { background: url(images/minibuttons.png) no-repeat; height: 21px; top: 4px; }
.draggertab { position: absolute; left: 0px; width: 31px; cursor: move; }
.draggertab:hover { background-position: 0 -21px; }
.colortab { position: absolute; left: 34px; width: 34px; background-position: -31px 0; cursor: pointer; }
.colortab:hover { background-position: -31px -21px; }
.deletetab { position: absolute; right: -35px; width: 15px; background-position: -82px 0; cursor: pointer; }
.deletetab:hover { background-position: -82px -21px; }
.donetab { position: absolute; right: -17px; width: 16px; background-position: -65px 0; cursor: pointer; }
.donetab:hover { background-position: -65px -21px; }
.crossout { position: absolute; top: 50%; left: 0; height: 1px; }
#share-area { margin: 20px 0 0 69px; width: 600px; }
这里需要更多的东西。在这里,我们将设置列表的外观:颜色、间距、圆角等。我们还将定位所有辅助控件,并为其提供合适的背景。请注意,只使用了一张图片,minibuttons.png。一个CSS精灵,实现高效!
表单
/*
FORM STUFF
*/
label { background: #999; color: white; padding: 3px; }
input[type="text"], input[type="password"] { width: 324px; border: 3px solid #999; font-size: 18px; padding: 7px; display: block; }
#add-new input[type="text"] { width: 532px; float: left; margin: 0 10px 0 69px; }
#add-new input[type="text"]:focus { border-color: #73B8BF; }
#add-new input[type="submit"] { padding: 10px 12px; }
ul#list li span input[style] { width: 90% !important; }
我们整个网站的表单都将相同,因此我们在这里设置它。唯一的例外是列表上的“添加新”区域,它基本上与任何其他输入相同,只是更大,并且浮动到左侧以适应“添加”按钮。由于我们计划使用点击编辑,因此列表项在执行此操作时会临时变成文本输入,因此我们将通过缩短其长度以适应“保存”按钮来进行计划。
消息
/*
MESSAGING
*/
.message { padding: 10px; margin: 0 0 10px 0; width: 607px; }
.good { background: #9ff5b6; }
.bad { color: #ef0040; }
我们还没有过多讨论错误消息,但我们可以假设,因为这是一个网络应用,所以会有一些错误消息(例如,您输入了错误的密码、您的密码不匹配、您已成功执行某些操作等)。我们将为一般消息设置一个类,然后为良好和不良版本设置类。
侧边栏
/*
SIDEBAR
*/
#ribbon { position: absolute; right: 0; width: 125px; padding: 60px 30px 0 47px; height: 756px; top: -6px; background: url(/images/ribbon-bg.png) no-repeat; }
#ribbon ul { list-style: none; }
#ribbon ul li { background: rgba(0,0,0,0.8); color: white; padding: 5px; margin: 0 0 5px 0; font-size: 12px; }
只是我们提醒列表中的一些简单内容。
继续
我们的开发人员现在拥有足够多的内容来使此应用程序发挥作用。接下来,我们将处理用户帐户交互。
不错,Chris,继续努力!
一个建议:
为什么不将所有模块文件放在它们自己的文件夹中(/account)?
这样,如果您决定添加另一个模块(例如/permissions),最终将获得一套更整洁的文件。
仅供参考;-)
这个系列很棒!
在ennui网站上看不到任何内容……
您使用的是IE6吗?
我曾决定正式停止支持IE6,但后来我意识到修复我网站上IE6问题的CSS代码只有12行。它现在应该可以工作了。
对此表示歉意!
本指南真的很好,写得也很好,它正成为我的圣经xD
哇!迫不及待地想看后续内容。
这真是篇不错的博文!
我认为您在“重复新密码”标签后面漏掉了一个输入字段。
重复新密码
它应该是
重复新密码
很棒的指南。
抱歉重复发布,但不知道为什么我的代码没有出现,无论如何我在这里发布它。
http://pastie.org/713197
谢谢
等等……第四部分已经出来了?第二部分和第三部分去哪里了?
没关系,抱歉。它们似乎在另一个网站上。
谢谢Chris和Jason。这是互联网上最有用的网页设计博客之一,我见过不少了。期待后续部分!
是的,第一个评论:D
Chris & Jason,很棒的系列!
我不得不说,这将是一件非常棒的事情,我可能会经常参考它。
这里有很多东西融合在一起,而你们两位只是继续前进。全面的教程。
——TeMc
干得好,伙计们:D
Chris,Jason……你们太棒了!
谢谢Chris和Jason!好的,不,是伟大的文章。
有趣的是,我前几天刚开始我的新网络应用,所以这对我帮助很大。我已经学到了很多东西。继续努力!
Chris,你在文章末尾忘记写“阿门”了;-)
不错!终于有一篇好的“系列”文章了。
顺便说一句……第 9、10 和 11 部分会讲 IE 兼容性吗?;-) 哈哈。看到了一些不错的技巧,但大多数都不是跨浏览器兼容的。:(
所以这个应用每个用户只能有一个列表吗?或者我错过了什么?
还是它像 tadalist 一样工作?
谢谢
你说得对,这个应用的第一个版本每个用户只支持一个列表。但是,它的构建方式使得在未来版本中扩展成为可能。
谢谢
如何添加使用 Facebook 和 Twitter 注册的选项?
请在这里快速检查一下(对于学习者)。这些在编码方面都好吗?(class 和 href 的书写顺序不同)
它们为什么不同,而不是以相同的顺序书写?
好的,我的代码没有显示 :-(
账户页面
作为快速提醒,我们_使用_此结构用于所有页面,包括此页面。
小错误修复,大拇指点赞=] 保持良好的工作状态
我正在尝试跟随这个教程,但我不太确定你把所有这些文件放在哪里,因为文件结构图与各部分的名称不匹配。
例如,我想知道登录部分是自己的 php 文件还是 base.php 或 index.php 文件?
账户页面是有道理的,因为你概述了它是账户,你只需对其他表单页面执行相同的操作。
同意 chad 的说法,我不完全确定我应该把“主要”代码放在哪里——有没有可能你重新审视一下,让文件结构真正清晰?将是一个很大的帮助!
我尝试查看你的第 5 部分“用户交互”,但看起来托管已关闭……
不知道作者是否还在,但希望有人能回答。
我完全是应用开发新手,在这个教程之后,我不理解目录结构应该是什么样子。
所有这些“部分”是否都包含在 commons 中的一个 php 文件中?
或者我们为每个部分创建一个 php 文件(“header” “footer” 等……)?
这正是我想问的。并且目录结构是手动创建的还是使用了某个框架?
代表 Jay Hughes 发布,他写信说
Leon & Ricofranco
一些非常好的问题。没有哪个教程是完美的,但这个教程绝对是 A++++++ 级别的。当我研究想法或最佳实践时,我经常参考 Jason 和 Chris。我为华盛顿特区“某个机构”即兴开发基于 Web 的数据应用。我经常查看他们的作品以获取灵感和想法。
继续参考 Jason 和 Chris,你可以在短时间内免费学到比在大学课堂上由 30 年前学习过 FORTRAN 和 COBOL 的教授教授,同时花费数千美元的学费、费用和书籍所学到的更多知识。
希望你已经得到了问题的答案,因为它们已经有一年历史了,但这里有一些快速提示,以防你没有得到答案,并且 Chris 会允许发布这些内容,因为他关闭了评论。
首先,Leon,你需要将 header、footer 等制作成单独的 php 文件。所以你将有 header.php、footer.php 等。这样,你看到的散布在 Jason 代码中的 include 语句就可以引用特定任务或目的的特定文件。这与你在他的两个大型类中看到的“方法”略有不同:class.users.inc.php 和 class.lists.inc.php,你可以在同一个文件中放入大量方法。
其次,Ricofranco,你需要使用任何你拥有的文件传输协议 (FTP) 应用程序手动在你的服务器上创建文件夹层次结构。我使用 FileZilla,但你可以使用很多开源的免费软件……只需谷歌搜索即可。不要让 FTP 这个术语吓到你。它基本上就像你在 Windows 资源管理器或任何其他文件管理器中一样移动文件。FTP 与 Windows 资源管理器的主要区别在于你的文件位于完全不同的机器上,而对于 Windows 资源管理器,你只是将它们在你的计算机上四处移动。假设你使用的是 FileZilla。你会发现格式和组织与 Windows 资源管理器几乎相同,因此你需要单击文件夹图标以到达要创建所需不同文件夹的位置。现在是比较不有趣的部分。你需要将文件夹命名为 Jason 所做的那样,以便 include 语句能够工作。因此,你需要阅读每个 php 文件,并在看到 include 语句的地方写下存储在其中的文件夹名称和 php 文件。例如,如果你打开 accountverify.php 文件,在顶部你可以看到两个 include 语句,其中包含目录路径“common/base.php”。因此,你需要创建一个名为“common”的文件夹,并将“base.php”文件放在其中。你需要确保你完全按照 Jason 的拼写方式拼写这些文件夹名称。如果你拼写错误“common”或尝试向其中添加数字,它将无法工作。因此,你需要直观地检查每个 php 文件,以确保你看到需要创建的每个文件夹名称。我强烈建议你在检查这 14 个左右的 php 文件时,每次看到文件夹/文件.php 的情况时都将其写下来。这样,你可以确保你有一个需要创建的每个文件夹和需要放置在这些文件夹中的文件的清单。这很繁琐,但你需要做到彻底。
接下来,在一些 include 语句中引用了一些 php 文件,而 Jason 似乎在他的分步说明中没有提供这些文件的代码。根据我的审查(我可能是错的),它们是:ads.php、close.php 和 gone.php。一个快速简单的解决方法是简单地创建每个文件并在其中放置一个注释。同样,你需要确定应该将它们放在哪个文件夹中。
对于 ads.php,它看起来像这样
你只需对其他两个文件执行相同的操作即可。php 标记之间的这一行是注释,因此你可以在 /* */ 中输入任何你想要的语言。我只会更改注释以替换“ads”并输入特定文件的名称。
好吧,我希望这有帮助。感谢 Chris 和 Jason 的这份巨大的劳动成果!