目录
脚手架
草地鹨旅行社网站
初始步骤
Welcome to Meadowlark Travel
About Meadowlark Travel
404 - Not Found
500 - Server Error
小结
首页 web前端 html教程 用Express 框架创建草地鹨旅行社网站_html/css_WEB-ITnose

用Express 框架创建草地鹨旅行社网站_html/css_WEB-ITnose

Jun 24, 2016 am 11:26 AM

脚手架

脚手架并不是一个新想法,但很多人(包括我自己)都是通过Ruby才接触到这个概念的。这个想法很简单:大多数项目都需要一定数量的“套路化”代码,谁会想每次开始新项目时都重新写一次这些代码呢?对此有个简单的方法,那就是创建一个通用的项目骨架,每次开始新项目时,只需复制这个骨架,或者说是模板。

RoR把这个概念向前推进了一步,它提供了一个可以自动生成脚手架的程序。相对于从一堆模板中作出选择,这种方式的优点是可以生成更复杂的框架。

Express借鉴了RoR的这一做法,提供了一个生成脚手架的工具,从而可以让你开始一个新的Express项目。

尽管Express有可用的脚手架工具,但它目前并不能生成我推荐使用的框架。特别是它不支持我所选择的模板语言(Handlebars),也没有遵循我所偏好的命名规则(尽管这很容易解决)。

尽管我们不用这个脚手架工具,但我还是建议你看一下它:到那时,你就能够充分了解它生成的脚手架是否对你有用了。

套路化对最终发送到客户端的真正HTML也是有用的。我推荐非常出色的HTML5 Boilerplate( http://html5boilerplate.com/),它能生成一个很不错的空白HTML5网站。最近HTML5 Boilerplate又新增加了可定制的功能,其中一个定制选项包含Twitter Bootstrap,这个是我高度推荐的前端框架。

草地鹨旅行社网站

本文以一个可运行的网站为例:假想的草地鹨旅行社网站,该旅行社是一家为到俄勒冈州旅游的人提供服务的公司。如果你对创建REST应用程序更感兴趣,不用担心,因为草地鹨旅行社网站除了作为功能性网站外,也提供REST服务。

初始步骤

先给你的项目创建一个新目录,这将作为项目的根目录。本文中,凡提到“项目目录”“程序目录”或“项目根路径”,指的都是这个目录。

提示:或许你会把Web程序文件跟项目相关的其他文件全都分开存放,比如会议纪要、文档等。因此,我建议你把项目根路径作为项目目录的子目录。比如,对于草地鹨旅行社网站而言,我会把项目放在~/projects/meadowlark,而项目根路径放在~/projects/meadowlark/site。

npm在package.json文件中管理项目的依赖项以及项目的元数据。要创建这个文件,最简单的办法是运行 npm init:它会问一系列的问题,然后为你生成一个package.json文件帮你起步(对于“入口点”的问题,用meadowlark.js或项目的名字作为答案)。

提示:如果你的package.json文件中没有指定一个存储库的URL,以及一个非空的README.md文件,那么你每次运行npm时都会看到警告信息。package.json文件中的元数据只有在发布到npm存储库时才是真正必要的,但为了消除npm的警告信息,做这些工作依然是值得的。

第一步是安装Express。运行下面这条npm命令:

npm install --save express
登录后复制

运行 npm install会把指定名称的包安装到node_modules目录下。如果你用了 --save选项,它还会更新package.json文件。因为node_modules随时都可以用npm重新生成,所以我们不会把这个目录保存在我们的代码库中。为了确保不把它添加到代码库中, 我们可以创建一个.gitignore文件:

# ignore packages installed by npmnode_modules# put any other files you don't want to check in here,# such as .DS_Store (OSX), *.bak, etc.
登录后复制

接下来创建meadowlark.js文件,这是我们项目的入口。本文中将这个文件简单称为“程序文件”:

var express = require('express');var app = express();app.set('port', process.env.PORT || 3000);// 定制404页面app.use(function(req, res){ res.type('text/plain'); res.status(404); res.send('404 - Not Found');});//定制500页面app.use(function(err, req, res, next){ console.error(err.stack); res.type('text/plain'); res.status(500); res.send('500 - Server Error');});app.listen(app.get('port'), function(){ console.log( 'Express started on http://localhost:' + app.get('port') + '; press Ctrl-C to terminate.' );});
登录后复制

提示:很多教程,甚至是Express的脚手架生成器会建议你把主文件命名为app.js(或者有时是index.js或server.js)。除非你用的托管服务或部署系统对程序主文件的名称有特定的要求,否则我认为这么做是没有道理的,我更倾向于按照项目命名主文件。凡是曾在编辑器里见过一堆index.html标签的人都会立刻明白这样做的好处。 npm init默认是用index.js,如果要使用其他的主文件名,要记得修改package.json文件中的 main属性。

现在你有了一个非常精简的Express服务器。你可以启动这个服务器(node meadowlark.js),然后访问http://localhost:3000。结果可能会让你失望,因为你还没给Express任何路由信息,所以它会返回一个404页面,表示你访问的页面不存在。

注释:注意我们指定程序端口的方式: app.set(port, process.env.PORT || 3000)。这样我们可以在启动服务器前通过设置环境变量覆盖端口。如果你在运行这个案例时发现它监听的不是3000端口,检查一下是否设置了环境变量 PORT。

提示:我高度推荐你安装一个能显示HTTP请求状态码和所有重定向的浏览器插件。这样在解决重定向问题或者不正确的状态码时会更加容易,它们经常被忽视。对于Chrome来说,Ayima的Redirect Path特别好用。在大多数浏览器中, 都能在开发者工具的网络部分看到状态码。

我们来给首页和关于页面加上路由。在404处理器之前加上两个新路由:

app.get('/', function(req, res){ res.type('text/plain'); res.send('Meadowlark Travel');});app.get('/about', function(req, res){ res.type('text/plain'); res.send('About Meadowlark Travel');});// 定制404页面app.use(function(req, res, next){ res.type('text/plain'); res.status(404); res.send('404 - Not Found');});
登录后复制

app.get是我们添加路由的方法。在Express文档中写的是 app.VERB。这并不意味着存在一个叫 VERB的方法,它是用来指代HTTP动词的(最常见的是“get” 和“post”)。这个方法有两个参数:一个路径和一个函数。

路由就是由这个路径定义的。 app.VERB帮我们做了很多工作:它默认忽略了大小写或反斜杠,并且在进行匹配时也不考虑查询字符串。所以针对关于页面的路由对于/about、/About、/about/、/about?foo=bar、/about/?foo=bar等路径都适用。

路由匹配上之后就会调用你提供的函数,并把请求和响应对象作为参数传给这个函数。现在我们只是返回了状态码为200的普通文本(Express默认的状态码是200,不用显式指定)。

我们这次使用的不是Node的 res.end,而是换成了Express的扩展 res.send。我们还用 res.set和 res.status替换了Node的 res.writeHead。Express还提供了一个 res.type方法,可以方便地设置响应头 Content-Type。尽管仍然可以使用 res.writeHead和 res.end,但没有必要也不作推荐。

注意,我们对定制的404和500页面的处理与对普通页面的处理应有所区别:用的不是 app.get,而是 app.use。 app.use是Express添加 中间件的一种方法。你可以把它看作处理所有没有路由匹配路径的处理器。这里涉及一个非常重要的知识点:在Express中,路由和中间件的添加顺序至关重要。如果我们把404处理器放在所有路由上面,那首页和关于页面就不能用了,访问这些URL得到的都是404。现在我们的路由相当简单,但其实它们还能支持通配符,这会导致顺序上的问题。比如说,如果要给关于页面添加子页面,比如/about/contact和/about/directions会怎么样呢?下面这段代码是达不到预期效果的:

app.get('/about*',function(req,res){            // 发送内容....})app.get('/about/contact',function(req,res){            // 发送内容....})app.get('/about/directions',function(req,res){            // 发送内容....})
登录后复制

本例中的 /about/contact和 /about/directions处理器永远无法匹配到这些路径,因为第一个处理器的路径中用了通配符: /about*。

Express能根据回调函数中参数的个数区分404和500处理器。

你可以再次启动服务器,现在首页和关于页面都可以运行了。

截至目前我们所做的事情,即使不用Express也很容易完成,但Express所提供的一些功能并非那么显而易见。还记得如何规范化 req.url来确定所请求的资源吗?我们必须手动剥离查询字符串和反斜杠,并转化为小写。而Express的路由器会自动帮我们处理好这些细节。尽管目前看起来这并非什么大不了的事情,但这只是Express路由器能力的冰山一角。

视图和布局

如果你熟知“模型-视图-控制器”模式,那你对视图这个概念应该不会感到陌生。视图本质上是要发送给用户的东西。对网站而言,视图通常就是HTML,尽管也会发送PNG或PDF,或者其他任何能被客户端渲染的东西。

视图与静态资源(比如图片或CSS文件)的区别是它不一定是静态的:HTML可以动态构建,为每个请求提供定制的页面。

Express支持多种不同的视图引擎,它们有不同层次的抽象。Express比较偏好的视图引擎是Jade(因为它也是TJ Holowaychuk开发的) 。Jade所采用的方式非常精简:你写的根本不像是HTML,因为没有尖括号和结束标签,这样可以少敲好多次键盘。然后,Jade引擎会将其转换成HTML。

Jade是非常吸引人的,但这种程度的抽象也是有代价的。如果你是一名前端开发人员,即便你实际上是用Jade编写视图,也必须理解HTML,并且有足够深入的认识。我认识的大多数前端开发人员都不喜欢他们主要的标记语言被抽象化处理。因此我推荐使用另外一个抽象程度较低的模板框架Handlebars。Handlebars(基于与语言无关的流行模板语言Mustache)不会试图对HTML进行抽象:你编写的是带特殊标签的HTML,Handlebars可以借此插入内容。

为了支持Handlebars,我们要用到Eric Ferraiuolo的 express3-handlebars包(尽管名字中是express3,但这个包在Express 4.0中也可以使用)。在你的项目目录下执行:

npm install --save express3-handlebars
登录后复制

然后在创建app之后,把下面的代码加到meadowlark.js中:

var app = express();// 设置handlebars视图引擎var handlebars = require('express3-handlebars')            .create({ defaultLayout:'main' });app.engine('handlebars', handlebars.engine);app.set('view engine', 'handlebars');
登录后复制

这段代码创建了一个视图引擎,并对Express进行了配置,将其作为默认的视图引擎。接下来创建views目录,在其中创建一个子目录layouts。如果你是一位经验丰富的Web开发人员,可能已经熟悉 布局的概念了(有时也被称为“母版页”)。在开发网站时,每个页面上肯定有一定数量的HTML是相同的,或者非常相近。在每个页面上重复写这些代码不仅非常繁琐,还会导致潜在的维护困境:如果你想在每个页面上做一些修改,那就要修改所有文件。布局可以解决这个问题,它为网站上的所有页面提供了一个通用的框架。

所以我们要给网站创建一个模板。接下来我们创建一个views/layouts/main.handlebars文件:

<!doctype html><html><head>      <title>Meadowlark Travel</title></head><body> {{{body}}}</body></html>
登录后复制

以上内容你未曾见过的可能只有 {{{body}}}。这个表达式会被每个视图自己的HTML取代。在创建Handlebars实例时,我们指明了默认布局( defaultLayout:'main')。这就意味着除非你特别指明,否则所有视图用的都是这个布局。

接下来我们给首页创建视图页面,views/home.handlebars:

<h1 id="Welcome-to-Meadowlark-Travel">Welcome to Meadowlark Travel</h1>
登录后复制

关于页面,views/about.handlebars:

<h1 id="About-Meadowlark-Travel">About Meadowlark Travel</h1>
登录后复制

未找到页面,views/404.handlebars:

<h1 id="Not-Found">404 - Not Found</h1>
登录后复制

最后是服务器错误页面,views/500.handlebars:

<h1 id="Server-Error">500 - Server Error</h1>
登录后复制

提示:你或许想在编辑器中把.handlebars和.hbs (另外一种常见的Handlebars文件扩展名)跟HTML相关联,以便启用语法高亮和其他编辑器特性。如果是vim,你可以在~/.vimrc文件中加上一行 au BufNewFile,BufRead *.handlebars set file type=html。其他编辑器请参考相关文档。

现在视图已经设置好了,接下来我们必须将使用这些视图的新路由替换旧路由:

app.get('/', function(req, res) { res.render('home');});app.get('/about', function(req, res) { res.render('about');});// 404 catch-all处理器(中间件)app.use(function(req, res, next){ res.status(404); res.render('404');});// 500错误处理器(中间件)app.use(function(err, req, res, next){ console.error(err.stack); res.status(500); res.render('500');});
登录后复制

需要注意,我们已经不再指定内容类型和状态码了:视图引擎默认会返回 text/html的内容类型和200的状态码。在catch-all处理器(提供定制的404页面)以及500处理器中,我们必须明确设定状态码。

如果你再次启动服务器检查首页和关于页面,将会看到那些视图已呈现出来。如果你检查源码,将会看到views/layouts/main.handlebars中的套路化HTML。

视图和静态文件

Express靠中间件处理静态文件和视图。只需了解中间件是一种模块化手段,它使得请求的处理更加容易。

static中间件可以将一个或多个目录指派为包含静态资源的目录,其中的资源不经过任何特殊处理直接发送到客户端。你可以在其中放图片、CSS文件、客户端JavaScript文件之类的资源。

在项目目录下创建名为public的子目录 (因为这个目录中的所有文件都会直接对外开放,所以我们称这个目录为public)。接下来,你应该把 static中间件加在所有路由之前:

app.use(express.static(__dirname + '/public'));
登录后复制

static中间件相当于给你想要发送的所有静态文件创建了一个路由,渲染文件并发送给客户端。接下来我们在public下面创建一个子目录img,并把logo.png文件放在其中。

现在我们可以直接指向/img/logo.png (注意:路径中没有public,这个目录对客户端来说是隐形的), static中间件会返回这个文件,并正确设定内容类型。接下来我们修改一下布局文件,以便让我们的logo出现在所有页面上:

<body>    <header>    <img src="/static/imghw/default1.png"  data-src="/img/logo.png"  class="lazy" alt="Meadowlark Travel Logo">    </header> {{{body}}}</body>
登录后复制

注释:`是HTML5中引入的元素,它出现在页面顶部,提供一些与内容有关的额外语义信息,比如logo、标题文本或导航等。

视图中的动态内容

视图并不只是一种传递静态HTML的复杂方式(尽管它们当然能做到)。视图真正的强大之处在于它可以包含动态信息。

比如在关于页面上发送“虚拟幸运饼干”。我们在meadowlark.js中定义一个幸运饼干数组:

var fortunes = [  "Conquer your fears or they will conquer you.",  "Rivers need springs.",  "Do not fear what you don't know.",  "You will have a pleasant surprise.", "Whenever possible, keep it simple.",];
登录后复制

修改视图(/views/about.handlebars)以显示幸运饼干:

<h1 id="About-Meadowlark-Travel">About Meadowlark Travel</h1>

Your fortune for the day:

{{fortune}}
登录后复制

接下来修改路由/about,随机发送幸运饼干:

app.get('/about', function(req, res){  var randomFortune = fortunes[Math.floor(Math.random() * fortunes.length)]; res.render('about', { fortune: randomFortune });  );
登录后复制

重启服务器,加载/about页面,你会看到一个随机发放的幸运饼干。模板真的是非常有用。

小结

我们刚用Express创建了一个非常基本的网站。尽管简单,但这个网站包含了功能完备的网站所需的一切。

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

&gt; gt;的目的是什么 元素? &gt; gt;的目的是什么 元素? Mar 21, 2025 pm 12:34 PM

本文讨论了HTML&lt; Progress&gt;元素,其目的,样式和与&lt; meter&gt;元素。主要重点是使用&lt; progress&gt;为了完成任务和LT;仪表&gt;对于stati

&lt; datalist&gt;的目的是什么。 元素? &lt; datalist&gt;的目的是什么。 元素? Mar 21, 2025 pm 12:33 PM

本文讨论了html&lt; datalist&gt;元素,通过提供自动完整建议,改善用户体验并减少错误来增强表格。Character计数:159

HTML5中跨浏览器兼容性的最佳实践是什么? HTML5中跨浏览器兼容性的最佳实践是什么? Mar 17, 2025 pm 12:20 PM

文章讨论了确保HTML5跨浏览器兼容性的最佳实践,重点是特征检测,进行性增强和测试方法。

&lt; meter&gt;的目的是什么。 元素? &lt; meter&gt;的目的是什么。 元素? Mar 21, 2025 pm 12:35 PM

本文讨论了HTML&lt; meter&gt;元素,用于在一个范围内显示标量或分数值及其在Web开发中的常见应用。它区分了&lt; meter&gt;从&lt; progress&gt;和前

我如何使用html5&lt; time&gt; 元素以语义表示日期和时间? 我如何使用html5&lt; time&gt; 元素以语义表示日期和时间? Mar 12, 2025 pm 04:05 PM

本文解释了HTML5&lt; time&gt;语义日期/时间表示的元素。 它强调了DateTime属性对机器可读性(ISO 8601格式)的重要性,并在人类可读文本旁边,增强Accessibilit

如何使用HTML5表单验证属性来验证用户输入? 如何使用HTML5表单验证属性来验证用户输入? Mar 17, 2025 pm 12:27 PM

本文讨论了使用HTML5表单验证属性,例如必需的,图案,最小,最大和长度限制,以直接在浏览器中验证用户输入。

视口元标签是什么?为什么对响应式设计很重要? 视口元标签是什么?为什么对响应式设计很重要? Mar 20, 2025 pm 05:56 PM

本文讨论了视口元标签,这对于移动设备上的响应式Web设计至关重要。它解释了如何正确使用确保最佳的内容缩放和用户交互,而滥用可能会导致设计和可访问性问题。

&lt; iframe&gt;的目的是什么。 标签?使用时的安全考虑是什么? &lt; iframe&gt;的目的是什么。 标签?使用时的安全考虑是什么? Mar 20, 2025 pm 06:05 PM

本文讨论了&lt; iframe&gt;将外部内容嵌入网页,其常见用途,安全风险以及诸如对象标签和API等替代方案的目的。

See all articles