ejs概述

概述在web项目中渲染页面,我们很多时候,会用json或者拼接字符串的方式,不够美观,破坏原有html结构,大量的html拼接会使代码难以阅读。 ejs是一种nodejs模板引擎,通过数据和模板,可以生成HTML标记文本。可以说EJS是一个JavaScript库,EJS可以同时运行在客户端和服务器端,客户端安装直接引入文件即可,服务器端用npm包安装。 ejs的特点: 1、快速编译和渲染 2、简单的模板标签 3、自定义标记分隔符 4、支持文本包含 5、支持浏览器端和服务器端 6、模板静态缓存 7、支持express视图系统 简单示例npm install ejs命令安装EJSejs.js。将模板字符串和数据作为参数传递给 EJS,HTML 就出来了。 var ejs = require('ejs'), test = ['001', '002', '003'], html = ejs.render('<%= test.join(", "); %>', {test: test}); ejs模板文件后缀名 .ejs ejs默认是开启模版缓存。这样在一个页面中多次请求模版文件时,只会请求一次 可通过代码设置是否开启缓存:EJS.config({cache: false});//关闭缓存 基本语法常用方法ejs.compile(str,[option]) //str指需要解析的字符串模板//option指配置信息/* cache 缓存编译后的函数,需要提供 filename filename 被 cache 参数用做键值,同时也用于 include 语句 context 函数执行时的上下文环境 compileDebug 当为 false 时不编译调试语句 client 返回独立的编译后的函数 delimiter 放在角括号中的字符,用于标记标签的开与闭 debug 将生成的函数体输出 _with 是否使用 with() {} 结构。如果为 false,所有局部数据将存储在 locals 对象上。 localsName 如果不使用 with ,localsName 将作为存储局部变量的对象的名称。默认名称是 locals rmWhitespace 删除所有可安全删除的空白字符,包括开始与结尾处的空格。对于所有标签来说,它提供了一个更安全版本的 -%> (在一行的中间并不会剔除标签后面的换行符)。 escape 为 <%= 结构设置对应的转义(escape)函数。它被用于输出结果以及在生成的客户端函数中通过 .toString() 输出。(默认转义 XML)。*/var tpl = ejs.compile('<%=test %>');var result = tpl();console.log(result);//testejs.render(ste,data,[option]) ...

June 14, 2019 · 1 min · jiezi

全栈开发入门实战后台管理系统

本文首发于 GitChat 平台,免费 Chat,链接:全栈开发入门实战:后台管理系统 感谢你打开了这篇 Chat,在阅读之前,需要让你了解一些事情。 第一,本 Chat 虽然免费,不代表没有价值,我会将个人全栈开发的经历叙述给你,希望对你有一些帮助;第二,文中所使用的技术栈并非最新,也并非最优。后台管理系统更多是 2B 端的产品,通常是业务优先。本 Chat 的目的是为了让你能够快速上手全栈开发。第三,本 Chat 虽然名为全栈开发,但是不会带你做完一个完整的后台管理系统项目。一是由于篇幅有限,二是由于时间关系,个人精力也有限。 正文本 Chat 的内容,正如 Chat 简介中所描述,将分为以下 5 大块: 开发准备前台样式数据库连接前后台交互线上部署你可能会发现,好像不知道要做什么,没错,后台管理系统一般都是企业内部定制开发,通常是对业务的数据管理,具体做什么功能由业务决定,但多数功能都是围绕着表格或者表单。 上面列举的仅仅是全栈开发的大致流程。首先,要做一些准备工作,例如:开发环境、编辑器环境以及依赖包配置等等工作;其次,我们要选定一个后台模版样式,快速套用,实现业务功能。(当然,你要自己开发也行,但不建议这么做,除非为了学习);然后,根据业务做数据库的设计,编写后台数据处理逻辑,以及前后台数据交互等功能;最后,测试并部署上线。 这里的示例,将实现一个学生数据的在线管理需求,其实就是一个在线表格,包括添加,删除功能,系统层面包括登录退出功能。麻雀虽小,五脏俱全,整体架子搭好了,再在上面添加功能就简单多了。好了,现在就开始全栈之旅吧。 开发准备启动项目首先要做的是,开发环境的安装,这里就不多说了,关于 Node 环境的安装,默认你已经搞定了。 既然采用 Express 作为 Web 框架,Express 也是要安装的,有了 Node 环境,安装 Express 就简单多了。我们直接上手 Express 的脚手架,全栈开发关键要速度。 npm install express-generator -g一定记得是全局安装。安装完成之后,输入 express -h 可以查看帮助。这里选用 ejs 模版引擎,为什么?因为我顺手而已,这个不重要。找个合适的目录,运行下面命令: express -e node-web-fullstack-demo生成项目目录之后,首先要安装依赖,如下命令: cd example-node-web-fullstacknpm install等待安装完成,我们就可以启动项目了,使用命令 npm start ,去浏览器中,打开网址:http://localhost:3000,看到写着 Express 的首页,代表你的项目启动成功了。 编辑器环境配置一个好的编码环境,可以让你项目开发效率加倍。 首先介绍一个编辑器配置 EditorConfig,这是一个编辑器的小工具。它有什么作用呢?简而言之,就是让你可以在不同的编辑器上,获得相同的编码风格,例如:空格缩进还是 Tab 缩进?缩进几个空格? 你可能觉得诧异,这个不是在编辑器上设置就可以了吗?没错,假设你从始至终都是在同一个电脑同一个编辑器上编码,那么可以忽略它。如果存在多电脑配合,亦或是多个编辑器配合,那么它就是神器。它几乎支持所有的主流编辑器,不用单独去编辑器中设置,配置文件就在项目中,用那个编辑器打开项目,都能获得一致的编码风格。 ...

May 30, 2019 · 5 min · jiezi

<译>创建一个Hexo主题-Part1:首页

前言:本系列文章翻译自@Jonathan Klughertz的博客,将会用三篇文章的篇幅详细讲解如何制作一个Hexo主题。我不是学翻译出身,若有翻译错误或是不到位之处,请指正。在这个系列教程中,你将学习怎么从零开始制作一个Hexo主题。我很喜欢Hexo,并且每天都在使用,不幸的是,直到今天关于主题制作的文档还是相当稀缺。所以我打算弥补这个空缺。预先准备Hexo博客的基础使用。如果你是第一次接触,请前往官网阅读教程了解Bootstrap了解Javascript模板引擎(我们将使用EJS)项目描述这个项目旨在制作一个Hexo主题并详细了解Hexo引擎的工作方式。我不想在HTML和CSS上花费太多时间,所以我们将重置下面这个Hexo主题:https://getbootstrap.com/docs… 。它是Bootstrap文档中的一个标准初始模板样例。我们将一步步地重用CSS、复制粘贴HTML,直到最后实现想要的效果。如果你感到困惑或者只对它的代码感兴趣,请前往github。项目结构创建一个新的hexo博客让我们从搭建一个全新的hexo博客开始吧# Create a new foldermkdir hexo-theme-creation cd hexo-theme-creation# Initialise Hexohexo init创建主题文件夹# Enter the theme foldercd themes# bootstrap-blog-hexo is also going to be the name of our thememkdir bootstrap-blog-hexo注意:如果你想在git中保存主题的话(你也应该这么做),请在/themes/bootstrap-blog-hexo/中初始化git。文件夹结构这是我们开始工作所需要的文件和文件夹:|– layout // .ejs templates |– source // source files (CSS, scripts)|– _config.yml创建以下两个文件夹和_config.yml文件。/layout/ 将包含我们所有的EJS模板/source/ 将包含我们所有的资源(CSS文件、外部脚本和库)_config.yml 包含我们的主题配置。现在暂且不写入任何内容。复制bootstrap blog源码从bootstrap blog template复制所有我们需要的源码并放在source文件夹里。你可以选择通过浏览器查看源码并复制下来,或者是下载该压缩包,之后解压到source文件夹里。|– layout |– source |– bootstrap // Copy the boostrap library files here |– css // Copy the blog’s css file here |– favicon |– favicon.ico // Your choice of favicon |– js // Copy the blog’s js file here|– _config.ymlHexo的基本要素在我们开始写第一个模板文件之前,先来看看Hexo博客生成过程的基本要素。页面类型我们能够在主题中定义6种页面类型,与之相对应地,在public文件夹生成的每一个单独的HTML页面都属于下面模板中的其中一个:模板备用模板页面描述index无这是博客的首页,也是网站的主要入口。本教程中我们将让其显示文章摘要列表postindex这是文章的详情页。我们将展示一篇完整的文章以及一个评论区pageindex这是页面的详情页,与post一样,但是是page类型的postarchiveindex这是归档页。它将显示我们博客中所有文章的标题和详情页链接categoryarchive这是分类页。与归档页类似,但是会根据类别进行筛选tagarchive这是标签页。与分类页类似,但是会根据标签进行筛选在本篇教程中我们将创建index模板。在页面生成过程中,Hexo将会搜索名字为index.ejs,post.ejs,page.ejs等的文件,这些模板之后用于创建静态HTML页面。公共布局Hexo支持使用公共的布局文件,上面的模板都将使用到该文件。该文件命名为layout.ejs。不同页面类型的模板会创建一些内容,而这个文件就好比这些内容的“外壳”。在我们的主题中,公共布局将包括:<html>标签、<head>标签、头部、菜单、底部和侧边栏。基本上是所有类型的页面都具备的元素。不同的页面模板将只负责创建实际内容,这些内容将放在我们的主体部位。变量在所有的模板中,我们都可以使用hexo引擎提供的内置变量。以下是部分变量:Site:site包含了网站的信息。例如,我们可以通过site.posts访问博客中的所有文章。当我们想要显示统计数据的时候,这将派上用场。Page:page是主要变量,包含了许多与当前页面相关的信息,包括所有的文章标题、日期、内容等。Config:config是一个指向站点_config.yml文件的JavaScript对象Theme:theme是一个指向主题_config.yml文件的JavaScript对象主题的布局创建上面提及了/layout/layout.ejs文件,现在我们开始来创建它。顶部标签首先创建layout.ejs文件并插入<html></html>标签//layout/layout.ejs<html><!– Head tag –>< partial(’_partial/head’) %></html>这里我们将所有<head>标签里的代码提取出来并放在局部视图中,这有助于实现关注点分离和代码重用。语法是partial(‘path’ [, arguments])在创建layout/_partial/head.ejs文件后,从bootstrap源码中复制head标签里的代码:// layout/_partial/head.ejs<head> <meta charset=“utf-8”> <meta http-equiv=“X-UA-Compatible” content=“IE=edge”> <meta name=“viewport” content=“width=device-width, initial-scale=1”> <meta name=“description” content=""> <meta name=“author” content=""> <link rel=“icon” href=“favicon/favicon.ico”> <title>Blog Template for Bootstrap</title> <!– Bootstrap core CSS –> < css(‘bootstrap/css/bootstrap.min.css’) %> <!– IE10 viewport hack for Surface/desktop Windows 8 bug –> < css(‘css/ie10-viewport-bug-workaround.css’) %> <!– Custom styles for this template –> < css(‘css/blog.css’) %> <!– HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries –> <!–[if lt IE 9]> <script src=“https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src=“https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]–></head>这很简单,我们只需使用CSS helper插入样式表。source文件夹中的文件将会被复制到站点根目录下,所以不要在路径中包含source/我们将让<title>和<meta>标签保持动态,不过现在先暂且不管它们。底部标签底部标签位于</body>之前。我们将在这个局部视图中包含所有脚本。先修改一下布局:// layout/layout.ejs<html><!– Head tag –>< partial(’_partial/head’) %><body> <!– After footer scripts –> < partial(’_partial/after-footer’) %></body></html>然后创建layout/_partial/after-footer.ejs的内容:// layout/_partial/after-footer.ejs<script src=“https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>< js(‘bootstrap/js/bootstrap.min.js’) %><!– IE10 viewport hack for Surface/desktop Windows 8 bug –>< js(‘js/ie10-viewport-bug-workaround.js’) %>注意JS helper function的使用,它将引用本地js文件。顶部菜单类似地,在<body>标签后创建顶部菜单。// layout/layout.ejs// […]<body> <!– Menu –> < partial(’_partial/menu’) %> // […]layout/_partial/menu.ejs 的内容:// layout/_partial/menu.ejs<div class=“blog-masthead”> <div class=“container”> <nav class=“blog-nav”> <% for (var i in theme.menu){ %> <a class=“blog-nav-item” href="< url_for(theme.menu[i]) %>"><%= i %></a> <% } %> </nav> </div></div>注意theme全局变量的使用,它指向的是主题的_config.yml文件。为了可以在主题配置中配置菜单,我们需要在_config.yml文件中添加配置:_config.yml# Headermenu: Home: / Archives: /archives在menu.ejs中我们遍历了配置文件中所有的菜单项目并创建对应的链接。顶部顶部将位于顶部菜单下面,它包含了博客标题和子标题:// layout/_partial/header.ejs<div class=“blog-header”> <h1 class=“blog-title”><%= config.title %></h1> <p class=“lead blog-description”><% if (config.subtitle){ %><%= config.subtitle %><% } %></p></div>这里我们使用了指向站点_config.yml文件的config变量,它包含了可供配置的标题和子标题属性。注意在布局的<div class=“container”><div>中嵌套顶部:// layout/layout.ejs<html><!– Head tag –>< partial(’_partial/head’) %><body> <!– Menu –> < partial(’_partial/menu’) %> <div class=“container”> <!– Blog Header: title and subtitle –> < partial(’_partial/header’) %> </div> // […]底部底部现在是完全静态的,内容如下:// layout/_partial/footer.ejs<footer class=“blog-footer”> <p>Blog template built for <a href=“http://getbootstrap.com”>Bootstrap</a> by <a href=“https://twitter.com/mdo">@mdo</a>.</p> <p>Adapted to Hexo by <a href=“http://www.codeblocq.com/">klugjo</a>.</p> <p><a href=”#">Back to top</a></p></footer>主要内容和侧边栏此时,我们再加上主要内容和侧边栏,基本就差不多了。下面是最终的layout.ejs:// layout/layout.ejs<html><!– Head tag –>< partial(’_partial/head’) %><body> <!– Menu –> < partial(’_partial/menu’) %> <div class=“container”> <!– Blog Header: title and subtitle –> < partial(’_partial/header’) %> <div class=“row”> <!– Main Content –> <div class=“col-sm-8 blog-main”> < body %> </div> <!– Sidebar –> <div class=“col-sm-3 col-sm-offset-1 blog-sidebar”> < partial(’_partial/sidebar’) %> </div> </div> </div> <!– Footer –> < partial(’_partial/footer’) %> <!– After footer scripts –> < partial(’_partial/after-footer’) %></body></html>body变量对应了不同页面类型模板创建的内容(参见上面)。至于侧边栏,我们现在暂且使用来自bootstrap模板的硬编码:// layout/_partial/sidebar.ejs<div class=“sidebar-module sidebar-module-inset”> <h4>About</h4> <p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p></div><div class=“sidebar-module”> <h4>Archives</h4> <ol class=“list-unstyled”> <li><a href=”#">March 2014</a></li> <li><a href=”#">February 2014</a></li> <li><a href=”#">January 2014</a></li> <li><a href=”#">December 2013</a></li> <li><a href="#">November 2013</a></li> </ol></div><div class=“sidebar-module”> <h4>Elsewhere</h4> <ol class=“list-unstyled”> <li><a href="#">GitHub</a></li> <li><a href="#">Twitter</a></li> <li><a href="#">Facebook</a></li> </ol></div>首页文件布局到位后,我们就可以开始创建第一个页面类型模板inde.ejs了。这是比较简陋的第一个版本:// layout/index.ejs<span>Content</span>别小瞧它,我们可以用这个在浏览器中测试主题:# Verify that everything is alrighthexo generate# Start hexo serverhexo server访问 http://localhost:4000/ 。哇!注意:不要忘记在站点的config文件中更新主题:_config.yml# Extensions## Plugins: http://hexo.io/plugins/## Themes: http://hexo.io/themes/theme: bootstrap-blog-hexo遍历博客文章我们想要在首页显示各篇文章的摘要。首先,在我们的index.ejs文件中遍历文章:// layout.index.ejs<% page.posts.each(function(item){ %> < partial(’_partial/article-excerpt’, {item: item}) %><% }); %>通过page.posts获取该页面的所有文章通过< partial(’name’, args) %>给partial传参文章布局创建article-excerpt.ejs文件,添加适合主题的代码。这是我的布局:// layout/_partial/article-excerpt.ejs<div class=“blog-post”> <!– Title –> <h2 class=“blog-post-title”> <a href="< config.root %>< item.path %>"> < item.title %> </a> </h2> <!– Date and Author –> <p class=“blog-post-meta”> <%= item.date.format(config.date_format) %> <% if(item.author) { %> by < item.author %> <% } %> </p> <!– Content –> < item.excerpt || item.content %> <!– Only display the Read More link if we are displaying an excerpt –> <% if(item.excerpt) { %> <p> <a href="< config.root %>< item.path %>"> <%= theme.excerpt_link %> </a> </p> <% } %></div>全文链接全文链接是由config.root(配置选项,相当于/)和item.path(相对路径或者绝对路径,指向全文)连接组成的。文章作者默认情况下,Hexo没有关于作者属性的的文章变量。不过我们可以在front matter中添加任意自己想要的变量。如果你想要在文章中显示作者名字,那么文章的front matter应该类似如下进行设置:title: Hello Worldauthor: Klughertz Jonathan—Item excerpt 和 Item content当用Hexo编辑文章时,你可以用<!– more –>标签从文章内容中截取摘要。在本教程中,因为我们展示的是文章列表,所以选择显示摘要。之后用户可以通过点击文章标题或者“阅读更多”的链接浏览全文。“阅读更多”文本别忘了,你需要像我这样在主题的配置文件中添加一个新的属性:_config.yml# Read More textexcerpt_link: Read More希望接下来的代码容易理解。现在,我建议你写一些除了默认的Hello World之外的文章并享受这个结果。分页器在本篇文章中,我们最后需要处理的是首页的分页器。在index.ejs文件中增加一个分页器的partial:// layout/index.ejs<% page.posts.each(function(item){ %> < partial(’_partial/article-excerpt’, {item: item}) %><% }); %>< partial(’_partial/pagination’) %>之后开始创建分页器的内容,layout/_partial/pagination.ejs:// layout/_partial/pagination.ejs<nav> <ul class=“pager”> <% if (page.prev){ %> <li><a href="< config.root %>< page.prev_link %>">Previous</a></li> <% } %> <% if (page.next){ %> <li><a href="< config.root %>< page.next_link %>">Next</a></li> <% } %> </ul></nav>page.prev:上一页的页码。如果当前页是第一页,则为0page.next:下一页的页码。如果当前页是最后一页,则为0page.next_link和page.prev_link是什么就不用多说了。如果你没有足够的文章用来查看分页器的工作效果,可以在主配置文件中(per_page属性)调整每一页的文章数。这就是今天的内容,在下一篇教程中,我们将完成博客剩下的所有页面。 ...

March 19, 2019 · 3 min · jiezi

用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件

本文首发于个人博客:Vince’Blog项目源码:NodeMail,欢迎star,说不定哪天脱单了就能用到了写在前面自从用邮箱注册了很多账号后,便会收到诸如以下类似的邮件,刚开始还以为是一张图片,后来仔细一看不是图片呀,好像还是HTML呀,于是好奇宝宝我Google一下,查阅多篇资料后总结出怎么用前端知识和Node做一个这样的“邮件网页”。确认主题知道怎么实现功能后,思考着我该写什么主题呢,用一个HTML模板随便给小伙伴们发个邮件炫个技?不行,作为一个很cool的程序员怎么能这么low呢,最近天气变化幅度大,温度捉摸不定,女朋友总是抱怨穿少了又冷穿多了又热,嗨呀,要不我就写个每天定时给宝宝发送天气预报的邮件,另外想起宝宝喜欢看ONE·一个这个APP上的每日更新,要不发天气预报的同时,再附赠一个“ONE的每日订阅”?机智又浪漫,开始搬砖~剧透本来是想最后放效果图的,怕你们看到一半就没兴趣了,就在前面剧透一下我最后做出来的效果图吧~待解决的问题1. 如何获取天气预报和ONE上的data?答:获取data有两种方法,第一种方法是获取天气预报和ONE的API,第二种是用node爬虫获取天气预报和ONE网页的信息。后来找了下,发现ONE并没有API接口,为了让两者统一,于是决定使用node上的一个插件叫cheerio,配合superagent能够很方便地爬取网页上的信息。2. 如何做出HTML的这种邮件?答:之前学过一段时间的express这个框架,接触到模版引擎这个概念,传入data便可获得html文件,再结合node的fs模块,获取到这个html文件,便可以结合node的邮件插件发送HTML邮件啦!3. 如何用node发送邮件?感谢无私的开源开发者,开发了一款发送邮件的Node插件nodemailer,兼容主流的Email厂商,只需要配置好邮箱账号和smtp授权码,便可以用你的邮箱账号在node脚本上发文件,很cool有没有~4. 如何做到每日定时发送?其实可以通过各种hack的方式写这么一个定时任务,但是既然node社区有这个定时的轮子,那我们直接用就好了,node-schedule是一个有着各种配置的定时任务发生器,可以定时每个月、每个礼拜、每天具体什么时候执行什么任务,这正符合每天早晨定时给宝宝发送邮件的需求。一切准备就绪,开始做一次浪漫的程序员编写代码网页爬虫这里我们使用到superagent和cheerio组合来实现爬虫:分析网页DOM结构,如下图所示:用superagent来获取指定网页的所有DOM:superagent.get(URL).end(function(err,res){ //}用cheerio来筛选superagent获取到的DOM,取出需要的DOMimgUrl:$(todayOne).find(’.fp-one-imagen’).attr(‘src’),type:$(todayOne).find(’.fp-one-imagen-footer’).text().replace(/(^\s*)|(\s*$)/g, “”),text:$(todayOne).find(’.fp-one-cita’).text().replace(/(^\s*)|(\s*$)/g, “")以下就是爬取ONE的代码,天气预报网页也是一个道理:const superagent = require(‘superagent’); //发送网络请求获取DOMconst cheerio = require(‘cheerio’); //能够像Jquery一样方便获取DOM节点const OneUrl = “http://wufazhuce.com/"; //ONE的web版网站superagent.get(OneUrl).end(function(err,res){ if(err){ console.log(err); } let $ = cheerio.load(res.text); let selectItem=$(’#carousel-one .carousel-inner .item’); let todayOne=selectItem[0]; //获取轮播图第一个页面,也就是当天更新的内容 let todayOneData={ //保存到一个json中 imgUrl:$(todayOne).find(’.fp-one-imagen’).attr(‘src’), type:$(todayOne).find(’.fp-one-imagen-footer’).text().replace(/(^\s*)|(\s*$)/g, “”), text:$(todayOne).find(’.fp-one-cita’).text().replace(/(^\s*)|(\s*$)/g, “”) }; console.log(todayOneData);})EJS模版引擎生成HTML通过爬虫获取到了数据,那么我们就能够通过将date输入到EJS渲染出HTML,我们在目录下创建js脚本和ejs模版文件:app.jsconst ejs = require(’ejs’); //ejs模版引擎const fs = require(‘fs’); //文件读写const path = require(‘path’); //路径配置//传给EJS的数据let data={ title:’nice to meet you~’}//将目录下的mail.ejs获取到,得到一个模版const template = ejs.compile(fs.readFileSync(path.resolve(__dirname, ‘mail.ejs’), ‘utf8’));//将数据传入模版中,生成HTMLconst html = template(data);console.log(html)mail.ejs<!DOCTYPE html><html lang=“en”><head> <meta charset=“UTF-8”> <meta name=“viewport” content=“width=device-width, initial-scale=1.0”> <meta http-equiv=“X-UA-Compatible” content=“ie=edge”> <title>Document</title></head><body> <h1> <%= title %> </h1></body></html>用Node发送邮件这里我们可以发送纯text也可以发送html,注意的是邮箱密码不是你登录邮箱的密码,而是smtp授权码,什么是smtp授权码呢?就是你的邮箱账号可以使用这个smtp授权码在别的地方发邮件,一般smtp授权码在邮箱官网的设置中可以看的到,设置如下注释。const nodemailer = require(’nodemailer’); //发送邮件的node插件let transporter = nodemailer.createTransport({ service: ‘126’, // 发送者的邮箱厂商,支持列表:https://nodemailer.com/smtp/well-known/ port: 465, // SMTP 端口 secureConnection: true, // SSL安全链接 auth: { //发送者的账户密码 user: ‘账户@126.com’, //账户 pass: ‘smtp授权码’, //smtp授权码,到邮箱设置下获取 } });let mailOptions = { from: ‘“发送者昵称” <地址@126.com>’, // 发送者昵称和地址 to: ’like@vince.studio’, // 接收者的邮箱地址 subject: ‘一封暖暖的小邮件’, // 邮件主题 text: ’test mail’, //邮件的text // html: html //也可以用html发送 }; //发送邮件transporter.sendMail(mailOptions, (error, info) => { if (error) { return console.log(error); } console.log(‘邮件发送成功 ID:’, info.messageId);}); Node定时执行任务这里我们用到了node-schedule来定时执行任务,示例如下:var schedule = require(“node-schedule”); //1. 确定的时间执行var date = new Date(2017,12,10,15,50,0); schedule.scheduleJob(date, function(){ console.log(“执行任务”);});//2. 秒为单位执行 //比如:每5秒执行一次var rule1 = new schedule.RecurrenceRule(); var times1 = [1,6,11,16,21,26,31,36,41,46,51,56]; rule1.second = times1; schedule.scheduleJob(rule1, function(){ console.log(“执行任务”); });//3.以分为单位执行//比如:每5分种执行一次var rule2 = new schedule.RecurrenceRule(); var times2 = [1,6,11,16,21,26,31,36,41,46,51,56]; rule2.minute = times2; schedule.scheduleJob(rule2, function(){ console.log(“执行任务”); }); //4.以天单位执行//比如:每天6点30分执行var rule = new schedule.RecurrenceRule();rule.dayOfWeek = [0, new schedule.Range(1, 6)];rule.hour = 6;rule.minute =30;var j = schedule.scheduleJob(rule, function(){ console.log(“执行任务”); getData();});思路与步骤当所有的问题都解决后,便是开始结合代码成一段完整的程序,思路很简单,我们来逐步分析:由于获取数据是异步的,并且不能判断出哪个先获取到数据,这个是可以将获取数据的函数封装成一个Promise对象,最后在一起用Promise.all来判断所有数据获取完毕,再发送邮件// 其中一个数据获取函数,其他的也是类似function getOneData(){ let p = new Promise(function(resolve,reject){ superagent.get(OneUrl).end(function(err, res) { if (err) { reject(err); } let $ = cheerio.load(res.text); let selectItem = $("#carousel-one .carousel-inner .item”); let todayOne = selectItem[0]; let todayOneData = { imgUrl: $(todayOne) .find(".fp-one-imagen”) .attr(“src”), type: $(todayOne) .find(".fp-one-imagen-footer") .text() .replace(/(^\s*)|(\s*$)/g, “”), text: $(todayOne) .find(".fp-one-cita") .text() .replace(/(^\s*)|(\s*$)/g, “”) }; resolve(todayOneData) }); }) return p}将爬取数据统一处理,作为EJS的参数,发送邮件模板。function getAllDataAndSendMail(){ let HtmlData = {}; // how long with let today = new Date(); let initDay = new Date(startDay); let lastDay = Math.floor((today - initDay) / 1000 / 60 / 60 / 24); let todaystr = today.getFullYear() + " / " + (today.getMonth() + 1) + " / " + today.getDate(); HtmlData[“lastDay”] = lastDay; HtmlData[“todaystr”] = todaystr; Promise.all([getOneData(),getWeatherTips(),getWeatherData()]).then( function(data){ HtmlData[“todayOneData”] = data[0]; HtmlData[“weatherTip”] = data[1]; HtmlData[“threeDaysData”] = data[2]; sendMail(HtmlData) } ).catch(function(err){ getAllDataAndSendMail() //再次获取 console.log(‘获取数据失败: ‘,err); })}发送邮件具体代码function sendMail(HtmlData) { const template = ejs.compile( fs.readFileSync(path.resolve(__dirname, “email.ejs”), “utf8”) ); const html = template(HtmlData); let transporter = nodemailer.createTransport({ service: EmianService, port: 465, secureConnection: true, auth: EamilAuth }); let mailOptions = { from: EmailFrom, to: EmailTo, subject: EmailSubject, html: html }; transporter.sendMail(mailOptions, (error, info={}) => { if (error) { console.log(error); sendMail(HtmlData); //再次发送 } console.log(“Message sent: %s”, info.messageId); }); }安装与使用如果你觉得这封邮件的内容适合你发送的对象,可以按照以下步骤,改少量参数即可运行程序;git clone https://github.com/Vincedream…打开main.js,修改配置项//纪念日let startDay = “2016/6/24”;//当地拼音,需要在下面的墨迹天气url确认const local = “xiangtan”;//发送者邮箱厂家let EmianService = “163”;//发送者邮箱账户SMTP授权码let EamilAuth = { user: “xxxxxx@163.com”, pass: “xxxxxx”};//发送者昵称与邮箱地址let EmailFrom = ‘“name” <xxxxxx@163.com>’;//接收者邮箱地let EmailTo = “like@vince.studio”;//邮件主题let EmailSubject = “一封暖暖的小邮件”;//每日发送时间let EmailHour = 6;let EmialMinminute= 30;终端输入npm install安装依赖,再输入node main.js,运行脚本,当然你的电脑不可能不休眠,建议你部署到你的云服务器上运行。最后冬天到了,是不是也该用程序员的专业知识给身边的人带来一些温暖呢,源代码与demo已经放到github上,要不试一试?GitHub:https://github.com/Vincedream/NodeMail ...

February 27, 2019 · 3 min · jiezi