谁给一个XX个信网页版

那个外遇网站被黑后,终于变成了一场跨国撕X大战
来源:综合
作者:英国那些事
  话说。。最近几天黑客接连公布了外遇网站Ashley Madison的各种用户资料,在欧美澳各国掀起了一场腥风血雨...
  各大媒体每天各种追踪报道,一场年度狗血大戏就这么唱响了
  我们来梳理一下这场风波的来龙去脉
  19号公布了第一批用户资料..... .包括了3700万用户的用户名,姓名,电话号码,电子邮箱,家庭住址和银行卡信息
   结果公布当天网站CEO还不承认.. 表示不是所有的数据都是从我们这里泄露出去的......
  好吧,这惹怒了黑客,
  21号他们公布了第二批资料... 包括网站的源代码,手机APP源代码和CEO所有的商业Email..... 在文件里,黑客对CEO说,伙计,这下你该承认了么???
  好吧,事情还没有完...
  22号公布了第三批资料.... 进一步的各种用户信息和用户私信......
  黑客表示.... 这些还都只是冰山一角..... 裸照神马的,他们都有
  最近他们接受了匿名采访,表示他们在网站的系统里潜伏了很久。。。他们网站根本没有日常的安全监管!
  他们一共下载了超过200G的数据... 包括甚至包括各种用户之间互传的裸照和各种露骨的聊天记录......
  不过他们表示最近还不会打算把裸照公开... 只是希望CEO早日回头是岸,关闭网站......
  【具体影响范围多大?】
  一张分布图简单粗暴的告诉你地球上哪片地区是“重灾区”
    世界各城市用户数排名,巴西圣保罗遥遥领先,纽约第二悉尼第三,伦敦第九
  阿拉巴马被封为美国最不忠诚的州。住在这里的人在网站上花得最多
    数据公布没多久,有几个政府就宣布正式介入此事。 防止有人用这些数据敲诈政府官员。。
  为什么?
  因为,有一大群蠢官,是用自己的工作邮箱来注册
  数据库里有超过一万个以.gov (美国政府)和.mil ( 美国军队) 为结尾的邮箱
  哈弗,耶鲁,波音公司,摩根大通,美国银行,索尼的员工邮箱也都出现在了数据库里,人数还不少
  联合国邮箱也被找到好些个
    各种美国银行的,各种大学的。。。
    3700万的用户里,有120万被发现是英国人
  其中有124政府人员,92个国防部官员,56个NHS工作人员,还有其他各行各业的精英们
    一时间,网上还涌出了各种可以查询网站,只要输入手机号 和邮箱地址就能一键查询那种
  然而大部分这样的网站都关闭了,因为,需求量太大。来查自己伴侣的人数太多。。。把网站刷崩溃了!!!
  【我们看看挖出来的都有谁?】
  这个苏格兰女议员是英国第一个被曝光的......
  或者说。。她是第一个主动曝光的。
  事情一出来之后她马上对媒体表示...
  天呐。。这太可怕了。为什么我的名字会出现在上面。
  黑客怎么可以公布这么多人的email地址BLABLABLA
    一副受害者自居的形象............
  先把自己定调成受害者..... 以免被新闻媒体曝光挖出来颜面过不去....
  (这公关团队...... )
  美国那边也好不到哪去.....
  从前天开始,各大媒体接连曝出一些高官用户,包括白宫官员,国家安全局官员,助理检察官.. 反恐专家..
  不过这些官员目前都予以否认,表示自己是被诬陷的,邮箱是被别人盗用去注册的
  (Cai Bu shi!)
  【最伪君子】
  但是风口浪尖的一个....
  是一个美国电视明星,一个一直倡导夫妻忠诚的政治活动家Josh Duggar
    他在外界打造的完全是一副爱家爱妻爱子的暖男形象....
  他说自己没有婚前性行为,还曾经公开反对堕胎和离婚....
  呵呵...结果...
  他不仅被扒了邮箱,连注册用的银行卡信息和家庭住址都被扒出来,发现和他各种吻合。
  这下抵赖不掉了....
  技术宅掘坟的功力可不止这些
  他们同时还八出Joshua J. Duggar有一个假的脸书账号,虽然只有32个好友,但是绝大部分是女性
    其中包括了脱衣舞女
  还有性感的酒吧招待
  在各方的压力下,Joshua J. Duggar终于承认他的确对妻子有过不忠
  “在过去的婚姻生活中,我是一个彻头彻尾的伪君子,我痴迷于在网上看色情表演,我背叛了妻子”
  “我一直过的是假面人生,对于妻子造成的所有伤害,我深表歉意”
  网友给他两个字: 呵呵....
  【同时被玩坏的还有一个前自由党主席Damien Mantach】
    这家伙本来就不是什么好人。。最近刚被曝光说他私自挪用150万的公款。。
  结果就在同一天,别人发现他的email地址也在那个网站上.....
  他的妻子和女儿的反应令人震惊,她们没有表示支持与信任,而是第一时间和这位主席划清界限。。。
  呃。。
  好吧..
  不仅仅政要们现在要捏一把汗
  【网红也躲不掉】
  前一段时间,有一对恩爱的夫妻在油管上超火....
  有一个男主,觉得自己的老婆怀孕之后,趁一天晚上老婆晚上上厕所没有冲厕所,偷偷用验孕棒验了马桶里的尿.... 结果发现真的怀孕了....在早餐时告诉了妻子这个大好的消息
  温馨感人的视频1千万播放....
  为这对夫妻带来了36万的粉丝
    结果。。。
  没过几天他们又发了一个视频。。。
  表示孩子意外流产了.....
    因为这两人都是youtube上注明的网红视频博主。。
  各路网友都在猜测他们这说不定全部都是摆拍演戏博眼球赚播放量的。。
  好吧。。
  无论如何。。
  就在今天。。 男主被网友八出是这个网站资深付费用户
  各种证据确凿
    所以说
  呵呵。
  不要zuo。。。
  不要轻易秀恩爱。。
  【民众....】
  除了名人高官,数据库的泄露给普通夫妇的打击也是毁灭性的
  之前澳大利亚电台正在做一个这个事件的节目。。。。
    一个姑娘在节目直播的时候打电话进去...讨论之余顺手让主持人帮忙查询自己的丈夫是不是也在外遇网站上
  结果一查。还真有。。
  女子当场崩溃。。。
  “你们tm在逗我吗!!!”
  然后就伤心欲绝的把电话给挂了
  心拔凉拔凉的还有更多人
  好多被爆出邮箱的知名人士都急着出来澄清,由于注册网站不需要邮箱验证,所以很多人都说是恶搞的粉丝盗用了他们的邮箱
  (呵呵 随你说)
  也有人说,是为了安抚丧妻之痛,才去另约女人
  一个BBC的小哥甚至吓到直接出柜
  “我是gay啊!!怎么可能去网站上找女人!!”
  好吧。。。
  【最欢乐的人: 离婚律师】
  虽然大家都在血雨腥风。。。
  然而,这场事件中最欢乐的人... 那必须是各大律师行。。
  此时此刻的律师界,简直就跟过节一样欢乐
    他们已经预测即将会有一场离婚“海啸”席卷而来
  对于离婚律师来说,相当于圣诞节提前来到
  伦敦一所律师事务所表示,从信息泄露以来,他们的电话要被打爆了
  事不关己的律师建议外遇者赶紧坦白,不要等上新闻闹得世人皆知下不来台面
  就在昨天,一个英国律师所已经证实。 他们已经提交了第一起离婚案。。。 因为一个英国妻子她发现丈夫的名字出现了被公布的数据库中
  这也是第一起被证实是因为这场风波导致的离婚案件
    【公司也自身难保】
  到这个时刻,事情已经愈演愈烈。。
  这家外遇公司被用户联合起诉,将会面临高达6亿美元的赔偿和罚款,因为他们没有保护好用户资料
  他们之前让用户每个月交一笔钱,这样他们就会删除用户的个人信息
  结果最近被发现,他们根本就没有删除,就是在骗钱啊!!!
  有很多用户表示自己是在伴侣过世后才上网站找对象的,但他们的个人资料也被公布了,银行信息和住址泄露会影响他们的财产和人参安全
  于是他们提起了诉讼
    外遇网站的老板基本已经被整疯了,
  除了发了一则怒骂黑客的声明,就再也没出现过。。。
  他的网站也被各大网友段子手玩坏了
  【我们有超过38,630,00个破产的离婚案子被告人噢】
    你们之前口号不是
  “Life is short,Have an affair”人生苦短来场外遇吧
  现在估计要变成
  “Life is short, Hire an attorney”人生苦短,找个律师吧
  好吧。。。
  所以。。2015会不会成为近年来离婚率最高的一年。。。。
  对了。。
  最后的最后。。
  事儿君搜了一下中国的邮箱地址。。。
  下面是结果:
  qq.com: 32.8万
  163.com 9.5万
  126.com 3.6万@sina 2.1万....
  好吧...剩下那些在国内用gmail hotmail啥注册的...
  就不知道了.... ..
  ------
  社会主义一片大好:中国能打开这个网站: http://www.ashleyrnadison.com/ 并没有墙。
  PIHONGMIN:那网站打开那对胸吓我一跳
  Rannnnn_s2:坐标英国,昨天办公室整个疯了啊,我们老板特意跑过来说“谁注册了Ashley Madison的小心一点啊,必要的话今天可以休假回去处理家事” 233333 不过还好今天大家都有来上班.....
  ShanTheHippo:这个网站属于多伦多一家叫做Avid Life Media的多媒体公司。而且这次黑客不仅要他们关闭外遇网,也要求他们关闭旗下其它网站。比如专为爱吃小鲜肉的熟女准备的干妈网(CougarLife点com),还有帮助年轻漂亮女性牵手有钱人的干爹网(EstablishedMen点com)。多红娘的公司 [[doge]]
  一个在野设计师的日常:只有我特别好奇中国和朝鲜半岛尤其是北部的亮点吗 [[doge]]
  名字太长躲在草丛会被发现:中国为毛还有这么多,俄罗斯基本没有,说好的闭关锁国呢 [[doge]]
  月如_千茗一染:BBC那个被吓到直接出柜的小哥,23333
  甜瞰:这个网站没有被墙&&而且进去就是中文版&&
  赤焰钢狼:太欢乐了,地图上中国区也挺亮的,坐等各种大咖被扒出来 [[喵喵]]
  不懂事儿的这么多何必计较:这个时候是不是该说一句幸好中国要上外网得翻墙 [[思考]]
  方奕东:以前有个哥们到美国,说那些老外婚后如何如何忠诚:说他们一般婚前爱玩,婚后就完全不玩了。看到这个,我只有呵呵。
  年下美强控_窝要做善酿的人:中国长三角珠三角那里挺多,还有一片内陆地区 [[doge]]
  伊舟亢:中擞形⑿拍澳埃颤N出W站 [[doge]]
  Asue丁日的丁日:我是126中的一员 [[doge]] 今天下午注册的
  自来水不停安利最爱钱钱买买买:估计网站曝光后,更多人注册了,谁叫这么多好奇狗 [[笑cry]]
(责任编辑:un657)
&&&&&&</div
中国人哪来这么多钱?[]
客服热线:86-10-
客服邮箱:64被浏览8,575分享邀请回答82 条评论分享收藏感谢收起01 条评论分享收藏感谢收起4493人阅读
NodeJs(19)
博文已完成,版本号v1.0
范例网址已移除,请下载源码(下载后需要自行设置mysql)
附完整源代码下载链接(0积分下载):http://download.csdn.net/detail/qq8269
订正一个数据库查询重复内容的bug,在最后的models/blog.js里面
订正一个加载博客时,无法显示”加载中“的bug;并且更改加载条件,改为调用定时器
修复因为1.02版本而导致的登录、注册无法正常进行。解决办法是将主页的逻辑拆分出来,分拆为blog.js和index.js
【0】涉及到的框架、引擎、数据库:
① express 4.X
③ mysql 5.7.x
①内容较长,我会尽力把整个框架、结构、顺序、思考方式说明白。
②基础是《node.js开发指南》这本书,作者:BYVoid。但他书的版本较老,很多东西现在已经无法应用,故进行更新,使用目前普遍的express
4.x版本(原书&#20284;乎是2.X版本),mysql(原书是mongodb),jade(原书是ejs)
【1】基本需求:
①有首页;
②支持注册;
③支持登录、登出;
④可以发表博客,发表的博客可以保存到数据库;
⑤可以查看博客,博客从数据库中读取,为了简化,这里设置为查看所有人的博客;
⑥查看博客时,初始查看的数量有限,但可以无限加载新的博客,直到查看完全部博客;
⑦一定程度上实现多语言(即可以切换显示的语言版本),但由于复杂度所限,因此只部分实现(但框架已建立好,可以通过继续完善代码实现整体的国际化);
⑧根据登录状态,对可以访问的页面进行控制(某些允许某些禁止)
【2】前后端交互的简单过程:
【3】关于客户端请求的几种情况(涉及到数据库的)
npm是包管理器,在新版本里是默认安装好的,可以输入:
来查看npm的版本
【5】express框架:
首先安装基础的express框架,他是封装好的web开发框架,里面包含了:
①路由控制、
②log显示、
③解析客户端请求、
④cookies解析、
⑤静态文件的控制
等多种功能。
安装前注:
①有的人只需要简单的
npm install -g express
npm install -g express-generator
就可以愉快的跑起express了,有的人就像向我一样苦&#36924;,尝试各种办法,最后勉强可以用。
如果在这两行命令后,输入(V是大写的)
express -V
会返回版本号,那么直接跳到最后来看,如果不是这样,可以参考我写的记录来安装。
或者直接看后面的终极解决方案
②express设置全局方法:
ln -s /usr/nodejs4.4.7/node-v4.4.7-linux-x64/bin/express /usr/local/bin/express
其他需要全局的方法,理论上同理,即将nodejs安装目录下的bin文件夹下的模块,映射到/usr/local/bin/同名文件即可
③express命令可以使用的人:
express -t jade myblog
效果是建立一个文件夹名为myblog的文件夹,里面会有一些文件。
正常如下图:
npm install
这时,npm会根据package.json来安装一些东西。
按提示输入:
SET DEBUG=myblog:*
可以启动项目。
本机的话,通过访问http://127.0.0.1:3000/ 来查看效果
服务器的话,访问其公网ip,端口是3000
查看package.json
&scripts&: {
&start&: &node ./bin/www&
这条属性告诉我们,需要通过bin文件夹下的www来启动,这也就是上面npm start命令的作用。
www文件应该是设置自启动的,然而我这里并不需要。但若直接启动app.js是启动不了的,因为在www文件里面,设置了端口是3000,他是通过www文件来启动监听的。
解决办法:
在app.js里面,在最后一行代码之前,添加:
app.listen(80);
于是,便可以通过app.js来启动服务器了。
访问效果如图:
假如如果像我一样倒霉,无法用express命令,打开npm也特别慢,可以先找个系统,将这些文件下载好,然后将这些文件复制到不可以用express命令的linux系统下面。
或者看最后的终极解决方案
如果npm很慢的话,可以考虑装cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
然后在npm install这一步,使用cnpm install来替代
————————分割线————————
④超级终极解决方案:
我传一个装好express的压缩包,直接解压缩后就可以用。
http://download.csdn.net/detail/qq7054
⑤另一个启动方法
即不通过app.js来启动;
在之前④的基础上,打开app.js,删除
app.listen(80);
打开package.json,将
&start&:&node ./app.js&
start&:&node
./bin/www&
port =normalizePort(process.env.PORT||'3000');
port =normalizePort(process.env.PORT||'80');
启动成功,可以直接访问地址来访问页面
【6】把启动的app.js放在后台运行,并且在操作端解除控制后依然可以运行
原本使用npm start的地方,输入
nohup npm start&
【7】app.js之解释
app.js可以说是一切的根本,因此请看注释,解释了每行代码的作用:
var express = require(&#39;express&#39;);
//这个模块在node_modules文件夹中
var path = require(&#39;path&#39;); //nodejs自带的,路径相关
var favicon = require(&#39;serve-favicon&#39;); //node_modules文件夹中
var logger = require(&#39;morgan&#39;); //日志相关,node_modules文件夹中,具体看第19行代码
var cookieParser = require(&#39;cookie-parser&#39;);//node_modules文件夹中,用来解析cookie的,被express所调用
var bodyParser = require(&#39;body-parser&#39;);
//用于解析请求体的(应该),被express所调用
var routes = require(&#39;./routes/index&#39;); //这里是默认的路由,路径是routes/index.js
var users = require(&#39;./routes/users&#39;); //这里是默认的路由,路径是routes/users.js
//关于路由的更多内容看下面的app.use(&#39;/&#39;, routes);和app.use(&#39;/users&#39;, users);的注释
var app = express();
//生成一个express的实例
//设置模板引擎
app.set(&#39;views&#39;, path.join(__dirname, &#39;views&#39;));
//__dirname表示绝对路径
//console.log(__dirname)
//可以取消这一行注释,然后看看__dirname的效果
app.set(&#39;view engine&#39;, &#39;jade&#39;); //表示express是使用jade格式的模板的
//下面这行代码是设置左上角的小图标的,将其命名为favicon.ico并放在public文件夹下,如果有的话,取消这行注释
//app.use(favicon(path.join(__dirname, &#39;public&#39;, &#39;favicon.ico&#39;)));
app.use(logger(&#39;dev&#39;)); //设置日志显示,如果不需要的话可以注释掉这行代码,建议练手的时候不要注释掉
//可替换参数有default,combined,common,short,tiny,dev(相对tiny有染色)。可以自己试试效果,默认是dev
app.use(bodyParser.json()); //解析客户端的请求,通常是通过post发送的内容
app.use(bodyParser.urlencoded({extended: false})); //另一种解析方式,具体不太明白(如果上面解析失败的话会通过这个来)
app.use(cookieParser());
//cookies的解析
app.use(express.static(path.join(__dirname, &#39;public&#39;)));
//普通静态html文件、js文件、css文件,都放在public文件夹下,可以直接通过url来访问
//路由的处理
app.use(&#39;/&#39;, routes);
//假如访问的网址是根目录,例如http://121.41.66.68/,交给routes这个js文件来处理,具体请查看routes
app.use(&#39;/users&#39;, users);
//假如访问的是/users这样的路径,那么交给users这个js文件来处理,具体略
//我们最后要对这个路由进行处理,让他按照我们想要的方式来做
//这里对非法路径进行处理的,next表示这是一个中间件(即执行完他之后,还会执行下一个,而不是直接在这里结束了)
//如果上面没有静态文件(29行)、没有找到被路由处理的文件(32,33行),就会交给这个来处理。
app.use(function (req, res, next) {
var err = new Error(&#39;Not Found&#39;);
err.status = 404;
next(err);
//由下面的2个app.use中的一个来处理(一般是第一个,除非第一个被注释)
//原注释说是会对错误进行加亮处理
//这部分和下面的区别在于,这部分会将错误信息暴露给用户,而下面的不会,因此注释掉这部分
//if (app.get(&#39;env&#39;) === &#39;development&#39;) {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render(&#39;error&#39;, {
message: err.message,
error: err
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render(&#39;error&#39;, {
//这里的error指调用views下的error模板
message: err.message,
//这是我自行添加的,用于显示服务器启动的时间
console.log(&Server start at :& + new Date());
//导出app,在./bin/www里会被调用
module.exports =
【8】页面关系结构
请忽略文件名的大小写问题(手动微笑)
因此,首先有三个需要我们自定义的路由:
①当访问根/时,输出index;
②当访问/login时,输出login
③当访问/reg时,输出reg
其他可能的路由:
④后续可能添加的页面,暂缺;
⑤不符合要求的页面,输出404(express已经完成)
【9】index页面需要包含的功能:
【10】index的路由:
查看app.js中的代码:
app.use(&#39;/&#39;, routes);
这部分代码已经说明了,当访问根的时候,交给routes来处理;
再次查看导入routes的地方:
var routes = require(&#39;./routes/index&#39;);
说明负责这部分的文件是routes文件夹的index文件
这时打开index.js,
router.get(&#39;/&#39;, function(req, res, next) {
res.render(&#39;index&#39;, { title: &#39;Express&#39; });
这部分代码,表示当访问根的 ’/’&页面时,由index这个引擎模板来处理,模板中的title变量,其&#20540;为Express。
————————————————————————
代码说明:
router.get('/'
以上这段代码是在路由基础上进行二段捕获url的,举例:
①假如在app.js里,
app.use('/',
然后在路由的处理里,是
outer.get('/'
那么最终针对的url是/
②假如在app.js里,
app.use('/test',
然后在路由的处理里,是
outer.get('/'
那么最终针对的url是/test
③假如在app.js里,
app.use('/,
然后在路由的处理里,是
outer.get('/test'
那么最终针对的url依然是/test
④假如在app.js里,
app.use('/testA,
然后在路由的处理里,是
outer.get('/testB'
那么最终针对的url是/testA/testB
⑤捕获优先度说明:
首先根据app.js中的app.use出现顺序决定,假如②和③同时出现,那么看②和③在app.js中的代码谁先出现,就交给谁来处理;
再不调用next()方法的情况下,只会被最先出现的那个处理;
如果第一个调用了next()方法,那么第一个处理完后会执行第二个的
————————————————————————
index.js代码说明:
var express = require(&#39;express&#39;); //调用express
var router = express.Router();
//生成express的Router方法的一个实例
//处理函数
router.get(&#39;/&#39;, function (req, res, next) {
//捕获根url
res.render(&#39;index&#39;, {title: &#39;Express&#39;});
//res.render方法渲染一个引擎模板,
//第二个参数是一个对象,对象里的变量可以在引擎中使用,
//第三个参数是回调函数,提供两个参数,分别是err和html,err是错误,html是渲染后的页面。如果使用这个回调函数,那么将不会自动响应,即要用户自己写返回html的命令
module.exports =
注意,被引擎渲染的文件,默认是在myblog/views文件夹下
【11】使用Bootstrap界面
让我们自己设计界面不是不可以,不过太麻烦,因此我和原书保持一致,使用Twitter Bootstrap风&#26684;的页面。
下载他的压缩包文件,并解压缩他,
将css文件放在项目myblog/public/stylesheets下;
将img文件夹直接复制粘贴在myblog/public下;
将js文件放在myblog/public/javascripts下,
我的Bootstrap的版本是v2.3.2
另外,下载jquery,命名为jq.js,放在myblog/public/javascripts下
【12】index.jade说明
下来我们就要修改jade文件了,如果不知道怎么使用的话,可以看我的博客:
extends layout
block content
p Welcome to #{title}
第一行的extends layout表示他导入的layout模板(即layout.jade)
block content表示以下这部分将套入layout的content位置
这时候再过去看layout.jade
doctype html
title= title
link(rel=&#39;stylesheet&#39;, href=&#39;/stylesheets/style.css&#39;)
block content
他导入的是style.css这个样式表,页面的title是变量title
上面的index.jade中的内容将导入这里的block content区域(因为变量名一样,会对应替换)。
其结构大概如下:
然后我们根据自己实际需求来改造:
直接给出代码:
首先在stylesheets文件夹下创建一个blog.css文件,内里样式为:
padding-top: 60
padding-botom: 40
#textarea {
width: 300
height: 100
#postBlog {
vertical-align:
#clearBlog {
width: 110
height: 44
.myalert {
.displayNONE {
#scrollToFoot {
border: 1px solid #
text-align:
font-size: 18
padding: 20px 0;
fotter p {
margin-top: 40
padding-top: 20
border-top: 1px solid #
font-size: 18
color: #555;
其次是layout.jade
doctype html
title MyBlog By qq
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/bootstrap.min.css&#39;)
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/bootstrap-responsive.min.css&#39;)
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/blog.css&#39;)
script(type=&text/javascript&,src=&#39;javascripts/jq.js&#39;)
script(type=&text/javascript&,src=&#39;javascripts/bootstrap.min.js&#39;)
script(type=&text/javascript&,src=&#39;javascripts/blog.js&#39;)
div.navbar.navbar-fixed-top
div.navbar-inner
div.container
a.btn.btn-navbar(data-toggle=&collapse&,data-target=&.nav-collapse&)
span.icon-bar
span.icon-bar
span.icon-bar
a.brand(href=&/&) MyBlog
div.nav-collapse
a(href=&/&) 首页
a(href=&/logout&) 登出
a(href=&/login&) 登入
a(href=&/reg&) 注册
a(href=&/language&) 切换语言
div#contrainer.container
block content
作者:王冬   QQ:
效果如图:
然后是index.jade:
extends layout
block content
div.hero-unit
这个是基于Nodejs作为后台,jade作为模板来,使用了Express作为框架
//这部分暂时用1替代,后续会被更新
a.btn.btn-primary.btn-large(href=&/login&)
a.btn.btn-large(href=&/reg&)
textarea#textarea.uneditable-input
button#postBlog.btn.btn-large 提交微博
button#clearBlog.btn.btn-large 清空
div#submitError.alert.alert-error.displayNONE.myalert
div#submitSuccess.alert.alert-success.displayNONE
div.row.content
烟雨江南说
当欲望没有了枷锁,就没有了向前的路
只有转左,或者向右
左边是地狱,右边也是地狱
烟雨江南说
那些都是极好极好的
可是我偏偏不喜欢
烟雨江南说
可以让我变傻的人
烟雨江南说
人在年轻的时候总会有些莫名的坚持,
并且以此感动着自己,
却时常会在不经意间让真正重要的东西从指间流走。
烟雨江南说
记忆真是一种奇怪的东西,
有时候会涤荡所有的苦难,只留下温情,
有时候却磨灭掉曾有的欢乐,唯剩下苍白和丑陋。
烟雨江南说
那存在的,都是幻影。
那永恒的,终将毁灭。
世界万物,缤纷色彩,都是被蒙蔽的人心罢了。
烟雨江南说
诸神以真相示人,而世人却视而不见
烟雨江南说
只有绵羊会向狮子要求平等,
而狮子们从来不会这样想。
烟雨江南说
愿迷途的旅人,从此得享安息。
因理想而不朽,因归返而救赎。
div#scrollToFoot 滚动到底部然后加载内容
效果如图:
但此时,上面的页面切换目前还都是无效状态;
滚动然后加载内容,也正处于无效状态;
注册和登录按钮,点击后也无法正常跳转;
我们需要依次解决这些问题。
【13】登录页面
接下来我们添加登录页面的路由和模板。
路由,打开app.js,在
app.use(&#39;/&#39;, routes);
app.use(&#39;/users&#39;, users);
var reg = require(&#39;./routes/reg&#39;);
var login = require(&#39;./routes/login&#39;);
之后添加:
app.use(&#39;/reg&#39;, reg);
//注册的,reg.js来处理
app.use(&#39;/login&#39;, login);
//登录的,login来处理
这样的话,就添加了注册和登录页面的路由了,但目前,我们还缺其具体文件和代码。
进入routes文件夹,创建reg.js和login.js
var express = require(&#39;express&#39;); //调用express模块
var router = express.Router();
//调用模块的Router方法
router.get(&#39;/&#39;, function (req, res, next) {
res.render(&#39;reg&#39;)
module.exports =
var express = require(&#39;express&#39;); //调用express模块
var router = express.Router();
//调用模块的Router方法
router.get(&#39;/&#39;, function (req, res, next) {
res.render(&#39;login&#39;)
module.exports =
现在又缺模板文件了。
进入views文件夹,创建reg.jade和login.jade
extends layout
block content
form.form-horizontal(method=&post&)
div.control-group
label.control-label(for=&username&) 用户名
div.controls
input.input-xlarge#username(type=&text&,name=&username&)
p.help-block
你的账户名称,用于登录和提示
div.control-group
label.control-label(for=&password&) 口令
div.controls
input.input-xlarge#password(type=&password&,name=&password&)
div.control-group
label.control-label(for=&password-repeat&)
重复输入口令
div.controls
input.input-xlarge#password-repeat(type=&password&,name=&password-repeat&)
div.form-actions
button.btn.btn-priamry(type=&submit&)
login.jade
extends layout
block content
form.form-horizontal(method=&#39;post&#39;)
div.control-group
label.control-label(for=&#39;username&#39;) 用户名
div.controls
input.input-xlarge#username(name=&#39;username&#39;,type=&#39;text&#39;)
div.control-group
label.control-label(for=&#39;password&#39;) 密码
div.controls
input.input-xlarge#password(name=&#39;password&#39;,type=&#39;password&#39;)
div.form-actions
button.btn.btn-primary(type=&submit&) 登录
这个时候,注册和登录页面已经可以访问了(虽然还没有添加逻辑)
【14】在和MySQL交互之前的准备工作
首页、注册、登录页面的页面布局已经做完,下来我们需要完成注册和登录功能。
注册功能的流程:
第①和②略过;
第③步由js完成,因此要对reg.jade进行修改,同时也需要添加处理登录逻辑的js代码;
第④步在第③步验证一致后发起ajax请求,和第③步一并完成;
第⑤步由后端完成,具体流程为:
第⑥步是ajax请求的回调函数,在屏幕上提示不同的内容。
也可以通过服务器重定位,推送一个提示注册成功的页面。
第③步修改:
extends layout
block content
script(type=&text/javascript&,src=&#39;javascripts/reg.js&#39;)
div.form-horizontal
div.control-group
label.control-label(for=&username&) 用户名
div.controls
input.input-xlarge#username(type=&text&,name=&username&)
p.help-block#tips
你的账户名称,用于登录和提示
p.help-block.displayNONE#usrname-error
用户名不能为空
p.help-block.displayNONE#error-alert
div.control-group
label.control-label(for=&password&) 口令
div.controls
input.input-xlarge#password(type=&password&,name=&password&)
p.help-block.displayNONE#pw-error
密码不能为空
div.control-group
label.control-label(for=&password-repeat&)
重复输入口令
div.controls
input.input-xlarge#password-repeat(type=&password&,name=&password-repeat&)
p.help-block.displayNONE#pw-rp-error
两次密码需要一致
div.form-actions
button.btn.btn-priamry#submit-button
在这里,取消掉原生的表单提交功能,更改为用ajax发起请求。
注册页面的逻辑单独写在一个js里面,因此在public/javascripts下创建文件:
$(document).ready(function () {
var time = 0;
//用于计时
$(&#submit-button&).click(function () {
//获取账号密码
var name = $(&#username&).val();
var pw = $(&#password&).val();
var pwRepeat = $(&#password-repeat&).val();
//未输入账号名
if (name.length === 0) {
$(&#username&).parent().parent().addClass(&error&);
$(&#usrname-error&).removeClass(&displayNONE&);
$(&#tips&).addClass(&displayNONE&);
setTimeout(function () {
$(&#username&).parent().parent().removeClass(&error&);
$(&#usrname-error&).addClass(&displayNONE&);
$(&#tips&).removeClass(&displayNONE&);
//密码为空
if (pw.length === 0) {
$(&#password&).parent().parent().addClass(&error&);
$(&#pw-error&).removeClass(&displayNONE&);
setTimeout(function () {
$(&#password&).parent().parent().removeClass(&error&);
$(&#pw-error&).addClass(&displayNONE&);
//密码不相同
if (pw !== pwRepeat) {
$(&#pw-rp-error&).parent().parent().addClass(&error&);
$(&#pw-rp-error&).removeClass(&displayNONE&);
setTimeout(function () {
$(&#pw-rp-error&).parent().parent().removeClass(&error&);
$(&#pw-rp-error&).addClass(&displayNONE&);
var obj = {
name: name,
password: pw
//防止连续点击,先禁用提交按钮,防止重复提交
if (new Date() - time & 3000) {
//发起请求前,更新提交时间,
time = new Date();
//发起请求,回调内容是一个对象,注册成功会有success,注册失败会有error属性
$.post(&/reg&, obj, function (data) {
if (&error& in data) {
$(&#error-alert&).removeClass(&displayNONE&)
$(&#error-alert&).text(data.error);
$(&#error-alert&).parent().parent().addClass(&error&);
setTimeout(function () {
$(&#error-alert&).addClass(&displayNONE&)
$(&#error-alert&).parent().parent().removeClass(&error&);
//注册失败,清空time计时,允许再次提交
} else if (&success& in data) {
location.href = data.
//注册成功则重定向
这里的验证逻辑很简单:
①账号不能为空;
②密码不能为空;
③两次密码应该相同;
为了简化,目前只设置这么多,不考虑例如最短密码长度、最长密码长度、密码需要由字母、数字、特殊符号混合的情况
打开blog.css,添加这样一个样式,用于隐藏某些暂时不需要显示的内容:
.displayNONE {
【15】和MySQL交互
这里采用连接池的模式和MySQL交互;
①毫无疑问,我们首先应该安装MySQL模块;
进入项目的根目录,输入
npm install mysql
等待出现以下画面就表示装好了:
②在项目的根目录下面创建文件夹models,这个文件夹用于保存各种类模型
并在其中新建db.js
ar mysql = require(&mysql&);
//调用nodejs和mysql交互的模块;
var pool = mysql.createPool({
//创建连接池
host: &#39;127.0.0.1&#39;,
//表示本地的数据库
user: &#39;root&#39;,
password: &#39;;, //密码
port: &#39;3306&#39;,
//默认端口
database: &#39;blog&#39;
var db = {};
db.con = function (callback) {
//callback是回调函数,连接建立后的connection作为其参数
pool.getConnection(function (err, connection) { //创建一个链接
if (err) {
//对异常进行处理
//抛出异常
callback(connection);
//如果正常的话,执行回调函数(即请求),具体请求在回调函数中写
connection.release();
//释放连接
module.exports =
这段代码做了这些事
我们该如何使用呢,很简单。
①生成一个db的实例;
②调用db的con方法,将请求写在回调函数之中,请求对象是回调函数的参数;
我们打开routes/reg.js,将代码修改为如下样子:
var express = require(&#39;express&#39;); //调用express模块
var router = express.Router();
//调用模块的Router方法
var db = require(&#39;../models/db&#39;);
router.get(&#39;/&#39;, function (req, res, next) {
res.render(&#39;reg&#39;)
router.post(&#39;/&#39;, function (req, res, next) {
//当路由捕捉到url为/reg的post请求时,会执行以下函数
db.con(function (connect) {
//db是我们导入的对象,connect是数据库的连接,此时数据库连接无错误,是一个正常的连接
//这是我们自定义的回调函数
connect.query(&SELECT 1 + 1 AS solution&, function (err, result) {
//这里是一个对数据库的请求
if (err) {
//假如请求出错,抛出异常
console.log(result);
//控制台输出结果
res.send({
//将结果作为对象的error属性发送给客户端
error: result
}) //执行完回调函数后,会跳回db的con方法,执行接下来的属性(即释放连接)
module.exports =
这些代码做了一件事,在用户发起reg请求时,将查询结果(返回);
还记不记得我们在注册页面的js回调函数,假如返回&#20540;有error属性,那么他会将error属性显示出来;
当然,由于并不能显示对象(error属性是一个对象),因此显示出来的是这样的
这只是一个测试用的代码,但通过这样的方法,说明我们的前后端交互是走通了的
【16】封装涉及到user的代码
初步考虑,我们现在要注册,因此应该写一个向MySQL插入项的方法;
那是否我们就应该直接将这部分代码直接写在reg.js里面呢?
显然是不好的,这种做法违背了OOP的思想——封装;
简单来说,我们应该将用户视为一个类:
①至少包含两个方法:注册(reg)、查询(login);
②至少包含两个属性:用户名(username)、密码(password)。
因此,新建user.js,放置于models文件夹内。
内容如下:
var db = require(&#39;./db&#39;)
function User(user) {
// 这是一个User类,传递的参数是一个对象,这个对象可以具有两个属性,分别是name和password
this.name = user.
// 如果传递的user不是空,那么将其赋值给User类的实例的name属性
this.password = user.
// 同上,赋给password属性
// 这个是插入方法
User.prototype.save = function (callback) {
var self = this
if (this.name.length == 0 || this.password.length == 0) {
//如果在没账号/密码的情况下就调用插入方法,则提示错误并返回
console.log(&You can&#39;t save user information without NAME or PASSWORD!&);
return callback(&You can&#39;t save user information without NAME or PASSWORD!&);
db.con(function (connect) {
// 数据库的表名为user,字段名为name和password
connect.query(&INSERT INTO user(name,password) VALUES (?,?)&, [self.name, self.password], function (err, result) {
// 上面的两个问号,表示第二个参数的self.name和self.password依次被替换到问号的位置;
// 需要注意的是:
// ①必须以数组形式依次排列;
// ②必须是字符串形式(不能是number)
if (err) {
//如果出错,那么错误信息作为回调函数的参数返回
console.log(&INSERT name:& + self.name + &, password:& + self.password + & error, the err information is & + err);
return callback(err);
callback(null, result); //如果正常执行,那么第一个参数为null(无错误),第二个参数为返回的结果
// 这个是查询方法
User.prototype.get = function (callback) {
var self =
if (this.name.length == 0) {
//如果在没账号/密码的情况下就调用插入方法,则提示错误并返回
console.log(&You can&#39;t select user information without NAME!&);
return callback(&You can&#39;t select user information without NAME!&);
var selectR
db.con(function (connect) {
connect.query(&#39;SELECT * FROM user WHERE name = ?&#39;, [self.name], function (err, result) {
if (err) {
console.log(&select name:& + self.name + & error, the err information is & + err);
return callback(err);
//注意,这里返回的是带账号和密码的,另外,理论上是有可能有多个元素的,但由于在注册时,用户名限制了重复,因此只会返回一个
selectResult =
//这里的result是一个数组,只包含一个元素(或者是空)
if (selectResult.length) {
//查询到的话,数组是有元素的(即length & 0)
return callback(null, selectResult[0]) //这里的selectResult就是user对象,包含name和password属性
return callback(null, null);
//如果查询不到,两个参数都为空
module.exports = U
这个封装好的User类满足了我们的需求,下来需要在reg里面调用这个类。
下面是修改后的routes/reg.js的代码
var express = require(&#39;express&#39;); // 调用express模块
var router = express.Router();
// 调用模块的Router方法
var User = require(&#39;../models/user&#39;);
// 调用刚才封装好的user类
var crypto = require(&crypto&); // 这个是加密用,nodejs本身提供
router.get(&#39;/&#39;, function (req, res, next) {
res.render(&#39;reg&#39;)
router.post(&#39;/&#39;, function (req, res, next) {
//当路由捕捉到url为/reg的post请求时,会执行以下函数
// 获取md5这个对象;(表示调用这个对象的方法,加密的形式是MD5);
var md5 = crypto.createHash(&#39;md5&#39;);
// 调用md5的update方法,update的第一个参数是被处理的内容,第二个是可选的,但如果要对中文进行处理,那么就需要加上&#39;utf-8&#39;这个参数;
// 因此,我们的密码其实可以支持中文(理论上)
// digest指的是以什么形式进行编码,这里选择了base64,除此之外,还有hex(十六进制)、binary(二进制)这两种方法;
var password = md5.update(req.body.password, &#39;utf-8&#39;).digest(&#39;base64&#39;);
var newUser = new User({
//生成一个User的实例,并赋给他name和passowrd属性
name: req.body.name,
password: password
//这里的password是加密过的(存储在数据库里也是加密过后的形式)
newUser.save(function (err, result) {
//do something
module.exports =
这部分并没有完成,之所以这样,是因为还欠缺一个东西,那就是登录状态的设置。
【17】登录状态和session
如何确定一个人是否在登录中?
有两个办法:①cookie;②session;
简单来说,他们之间的区别在于:
cookie保存在客户端,session保存在服务器端;
顺便补一个Cookie、LocalStorage和SessionStorage之间区别的链接:
注意,这里的SessionStorage和session并不是同一个东西,前者保存在浏览器端,后者保存在服务器端。
再补一个express使用cookie和session的文章:
由于cookie可以在本地被修改,因此用cookie来保存用户状态是不安全的。
这里采用session来保存用户状态。
在高版本的express里(4.x及以上),cookie和session等模块并不直接包含在express里了,因此我们要安装express-session。
在项目的根目录输入:
npm install express-session
安装好后如图:
打开app.js,在
app = express();
后添加如下代码:
var session = require(&#39;express-session&#39;);
app.use(session({
secret: &#39;recommend 128 bytes random string&#39;,
cookie: {maxAge: 3600 * 1000}
这种设置表示:
①默认session存储在内存中(默认设置,效果是重启后session失效);
②最大有效时间(过期时间)是3600秒;
然后重新打开reg.js,在原先的空白处,添加以下代码:
if (user) { //如果第二个参数存在,说明用户名重复了,返回提示
return res.send({
error: &Username already exists.&
if (err) {
//如果报错,返回报错信息
console.log(err);
return res.send({
error: err
//此时说明无重复无报错,可以将用户信息存入到数据库之中
newUser.save(function (err, result) {
if (err) {
//如果存入时报错
return res.send({
error: err
//以上,done
//存储成功后返回还有点问题,需要搞明白
req.session.user = {
name: this.name,
password: this.password
req.session.success = &注册成功!&;
//添加session的注册成功信息
res.send({
//发送一个对象,属性为success,值为/
success: &/&
但此时还没结束,我们需要对数据库进行操作:(建议用数据库软件完成)
先建立一个库,库名为blog
在库中建立一个表,表名为user;
表中有三个字段:
①第一个为id,类型为int,自动增量,不允许为空;
②第二个为name,类型为varchar,长度为255,字符集为utf8,不允许为空;
③第三个为password,类型为varchar,长度为255,字符集为utf8,不允许为空;
于是,注册流程已经走通,用户可以顺利注册了
账号和密码用软件创建时设置如图:
【18】设置登录状态
在之前,已经可以通过session保存用户了,下来,需要根据session的记录,区分用户登录和未登录的状态。
简单来说,有两种情况:
①session中的user属性为空,用户未登录;
②session中的user属性不为空,用户已登录,登录人士为user的name属性;
为了简化,这里并没有对同时登录的检测(避免一个账号在两个地方登录)。
而在访问页面时,应该检测登录状态:
①假如已经登录,那么就不应该显示登录窗口、注册窗口,以及发表微博相关的内容;
②假如还没有登录,那么就不应该显示登出的按钮;
为了完成这个目的,那么应该在引擎渲染时进行检查,最笨的做法是,将变量设置于res.render的第二个参数的属性之中:
打开layout.jade,将代码如下修改:
doctype html
title MyBlog By qq
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/bootstrap.min.css&#39;)
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/bootstrap-responsive.min.css&#39;)
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/blog.css&#39;)
script(type=&text/javascript&,src=&#39;javascripts/jq.js&#39;)
script(type=&text/javascript&,src=&#39;javascripts/bootstrap.min.js&#39;)
script(type=&text/javascript&,src=&#39;javascripts/blog.js&#39;)
div.navbar.navbar-fixed-top
div.navbar-inner
div.container
a.btn.btn-navbar(data-toggle=&collapse&,data-target=&.nav-collapse&)
span.icon-bar
span.icon-bar
span.icon-bar
a.brand(href=&/&) MyBlog
div.nav-collapse
a(href=&/&) 首页
//以下是修改后的部分
if(user())
a(href=&/logout&) 登出
a(href=&/login&) 登入
a(href=&/reg&) 注册
a(href=&/language&) 切换语言
div#contrainer.container
block content
作者:王冬   QQ:
打开index.jade
extends layout
block content
div.hero-unit
这个是基于Nodejs作为后台,jade作为模板来,使用了Express作为框架
//修改以下部分
if(!user())
a.btn.btn-primary.btn-large(href=&/login&)
a.btn.btn-large(href=&/reg&)
textarea#textarea.uneditable-input
button#postBlog.btn.btn-large 提交微博
button#clearBlog.btn.btn-large 清空
div#submitError.alert.alert-error.displayNONE.myalert
div#submitSuccess.alert.alert-success.displayNONE
div.row.content
烟雨江南说
当欲望没有了枷锁,就没有了向前的路
只有转左,或者向右
左边是地狱,右边也是地狱
烟雨江南说
那些都是极好极好的
可是我偏偏不喜欢
烟雨江南说
可以让我变傻的人
烟雨江南说
人在年轻的时候总会有些莫名的坚持,
并且以此感动着自己,
却时常会在不经意间让真正重要的东西从指间流走。
烟雨江南说
记忆真是一种奇怪的东西,
有时候会涤荡所有的苦难,只留下温情,
有时候却磨灭掉曾有的欢乐,唯剩下苍白和丑陋。
烟雨江南说
那存在的,都是幻影。
那永恒的,终将毁灭。
世界万物,缤纷色彩,都是被蒙蔽的人心罢了。
烟雨江南说
诸神以真相示人,而世人却视而不见
烟雨江南说
只有绵羊会向狮子要求平等,
而狮子们从来不会这样想。
烟雨江南说
愿迷途的旅人,从此得享安息。
因理想而不朽,因归返而救赎。
div#scrollToFoot 滚动到底部然后加载内容
打开routes/index.js,将代码如下修改:
var express = require(&#39;express&#39;); //调用express
var router = express.Router();
//生成express的Router方法的一个实例
//处理函数
router.get(&#39;/&#39;, function (req, res, next) {
//捕获根url
res.render(&#39;index&#39;, {
user: function () { //user将读取session的属性,然后给予不同的返回值
if (req.session.user)
return req.session.
//res.render方法渲染一个引擎模板,
//第二个参数是一个对象,对象里的变量可以在引擎中使用,
//第三个参数是回调函数,提供两个参数,分别是err和html,err是错误,html是渲染后的页面。如果使用这个回调函数,那么将不会自动响应,即要用户自己写返回html的命令
module.exports =
代码解释:
①在之前的代码中,我们如果注册成功,那么会将user属性设置在session之中;
②而在index.js里,会传递一个变量,那就是user;
③这个user会读取session的user属性,由于session默认的属性是没有user的,因此返回&#20540;为null(空),而注册成功后,返回&#20540;则为user(不为空);
④在layout.jade中,会执行这个user函数。假如未登录,user为空,那么执行else语句(显示登入和注册标签);否则显示登出标签;
⑤在index.jade中,同样执行,假如未登录,显示登录、注册按钮;假如已经登录了,显示输入微博的窗口和提交按钮;
于是,登录后的页面是这样的:
但是这种行为个人觉得比较傻,并且也不利于做多语言扩展,因此换一种方式。
【19】动态视图助手和多语言支持
关于动态视图助手的说明请看我之前的博客:
简单来说,使用动态视图助手时,我们可以在引擎渲染的时候,直接调用视图助手中的变量;
首先在models下面建立language.js文件,内容如下
function internation() {
internation.prototype.languagePacks = {
title: &我的博客&,
description: &这个是基于Nodejs作为后台,jade作为模板来,使用了Express作为框架&,
login: &登录&,
regNow: &立即注册&,
submit: &提交微博&,
emptyInput: &清空&
title: &MyBlog By qq&,
topTitle: &MyBlog&,
indexButton: &首页&,
logout: &登出&,
login: &登入&,
reg: &注册&,
language: &切换语言&,
foot: &作者:王冬   QQ:&
title: &My blog&,
description: &I use NodeJS, Express, and MySQL to design this site.&,
login: &Login&,
regNow: &Reg&,
submit: &Submit&,
emptyInput: &Clear&
title: &MyBlog By qq&,
topTitle: &MyBlog&,
indexButton: &Index&,
logout: &Logout&,
login: &Login&,
reg: &Reg&,
language: &Language&,
foot: &I&#39;m WangDong, you can contact me with QQ:&
//如果有语言设置,则设置为对应的语言,否则,设置为中文;
internation.prototype.getPacks = function (setting) {
if (!setting) {
return this.languagePacks[&zh_cn&]
if (setting in this.languagePacks) {
return this.languagePacks[setting];
return this.languagePacks[&zh_cn&]
internation.prototype.set = function (app) {
var self =
app.use(function (req, res, next) {
//这个是示例,定义一个动态视图助手变量
//如果有语言设置,则设置为对应的语言,否则,设置为中文;
res.locals = self.getPacks(req.session.language)
//下面两个因为要调用req和res,所以特殊设置
res.locals.user = function () {
if (&#39;session&#39; in req && &#39;user&#39; in req.session)
return req.session.
//这里不能用error这个变量名
res.locals.err = function () {
//如果session不存在,或者session中没有err属性
if (!&#39;session&#39; in req || !&#39;err&#39; in req.session)
//否则返回err,并将session中的err重置为空(因此只返回一次)
var err = req.session.
req.session.err =
//注册成功的提示
res.locals.success = function () {
//原理同err
if (!&#39;session&#39; in req || !&#39;success&#39; in req.session)
var success = req.session.
req.session.success =
module.exports =
在以上代码中,程序做了以下事情:
①创建一个语言包,他包含中文和英文两种;
②设置了一个方法,他可以根据session的language属性来决定获取哪个语言包;
但也有一定缺陷:
①假如在zh_cn的index中有一条test属性,他有一个对应的字符串;但在eng中相应的位置不存在,那么切换为eng时,这里就会显示错误;
②调用的时候,需要通过例如index.title这样的形式来调用
然后我们将这个模块加入到我们的代码之中;
打开app.js,在之前添加的关于session的代码后面,添加如下代码:
var language = require(&#39;./models/language&#39;);
var internation = new language();
internation.set(app);
修改layout.jade
octype html
title #{layout.title}
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/bootstrap.min.css&#39;)
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/bootstrap-responsive.min.css&#39;)
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/blog.css&#39;)
script(type=&text/javascript&,src=&#39;javascripts/jq.js&#39;)
script(type=&text/javascript&,src=&#39;javascripts/bootstrap.min.js&#39;)
script(type=&text/javascript&,src=&#39;javascripts/blog.js&#39;)
div.navbar.navbar-fixed-top
div.navbar-inner
div.container
a.btn.btn-navbar(data-toggle=&collapse&,data-target=&.nav-collapse&)
span.icon-bar
span.icon-bar
span.icon-bar
a.brand(href=&/&) #{layout.topTitle}
div.nav-collapse
a(href=&/&) #{layout.indexButton}
//以下是修改后的部分
if(user())
a(href=&/logout&) #{layout.logout}
a(href=&/login&) #{layout.login}
a(href=&/reg&) #{layout.reg}
a(href=&/language&) #{layout.language}
div#contrainer.container
block content
#{layout.foot}
重新访问页面,我们会发现页面跟以前并没有什么区别,说明我们的语言包已经正常运行了。
【20】添加语言切换功能;
根据我们之前的代码,语言切换很简单,只需要在session添加属性即可;
首先,设置路由,routes文件夹下新建language.js
var express = require(&#39;express&#39;); //调用express
var router = express.Router();
//生成express的Router方法的一个实例
//处理函数
router.get(&#39;/&#39;, function (req, res, next) {
//捕获根url
if (!(&#39;language&#39; in req.session) || req.session.language === &#39;zh_cn&#39;)
req.session.language = &#39;eng&#39;;
//更改属性
req.session.language = &#39;zh_cn&#39;;
res.redirect(&#39;/&#39;);
module.exports =
在app.js的路由代码附近添加如下代码:
var lan = require(&#39;./routes/language&#39;);
app.use(&#39;/language&#39;, lan);
//切换语言的
重启程序,然后进入首页点击切换语言,页面顶端变为如下状态:
此时如果再次点击‘Language’,那么页面又会切回中文;
我们顺便修改layout.jade文件为:
doctype html
title #{layout.title}
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/bootstrap.min.css&#39;)
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/bootstrap-responsive.min.css&#39;)
link(rel=&#39;stylesheet&#39;, href=&#39;./stylesheets/blog.css&#39;)
script(type=&text/javascript&,src=&#39;javascripts/jq.js&#39;)
script(type=&text/javascript&,src=&#39;javascripts/bootstrap.min.js&#39;)
script(type=&text/javascript&,src=&#39;javascripts/blog.js&#39;)
div.navbar.navbar-fixed-top
div.navbar-inner
div.container
a.btn.btn-navbar(data-toggle=&collapse&,data-target=&.nav-collapse&)
span.icon-bar
span.icon-bar
span.icon-bar
a.brand(href=&/&) #{layout.topTitle}
div.nav-collapse
a(href=&/&) #{layout.indexButton}
//以下是修改后的部分
if(user())
a(href=&/logout&) #{layout.logout}
a(href=&/login&) #{layout.login}
a(href=&/reg&) #{layout.reg}
a(href=&/language&) #{layout.language}
div#contrainer.container
block content
#{layout.foot}
再修改routes/index.js为:
var express = require(&#39;express&#39;); //调用express
var router = express.Router();
//生成express的Router方法的一个实例
//处理函数
router.get(&#39;/&#39;, function (req, res, next) {
//捕获根url
res.render(&#39;index&#39;);
module.exports =
【21】登录功能的完成
与注册(reg.js)功能的代码类&#20284;,
首先在models的语言包中分别添加如下属性:
message: {
reg_success: &注册成功!&,
reg_fail: &注册失败!&,
login_success: &登录成功!&,
login_fail: &登录失败&,
errorName: &用户名不存在&,
errorPW: &密码错误!&
message: {
reg_success: &Reg Success!&,
reg_fail: &Reg Failed!&,
login_success: &Login Success!&,
login_fail: &Login Failed!&,
errorName: &The username is not exists.&,
errorPW: &Error Password!&
打开routes/login.js文件
将代码修改如下:
var express = require(&#39;express&#39;); //调用express模块
var router = express.Router();
//调用模块的Router方法
var User = require(&#39;../models/user&#39;);
// 调用刚才封装好的user类
var crypto = require(&crypto&); // 这个是加密用,nodejs本身提供
router.get(&#39;/&#39;, function (req, res, next) {
res.render(&#39;login&#39;)
router.post(&#39;/&#39;, function (req, res, next) {
var md5 = crypto.createHash(&#39;md5&#39;);
var password = md5.update(req.body.password, &#39;utf-8&#39;).digest(&#39;base64&#39;);
var newUser = new User({
//生成一个User的实例,并赋给他name和passowrd属性
name: req.body.name
newUser.get(function (err, user) {
if (!user) {
//用户名不存在
return res.send({errorName: res.locals.message.errorName});
else if (user) { //如果第二个参数存在,说明用户名重复了,那么监测密码是否相同
if (user.password === password) {
//密码正确,登录成功
req.session.user =
req.session.success = res.locals.message.login_
return res.send({success: &#39;/&#39;});
return res.send({errorPW: res.locals.message.errorPW});
else if (err) {
//如果报错,返回报错信息
console.log(err);
return res.send({
error: err
module.exports =
修改login.jade
xtends layout
block content
script(type=&text/javascript&,src=&#39;javascripts/login.js&#39;)
div.form-horizontal
div.control-group
label.control-label(for=&#39;username&#39;) 用户名
div.controls
input.input-xlarge#username(name=&#39;username&#39;,type=&#39;text&#39;)
p.help-block.displayNONE#name-alert
div.control-group
label.control-label(for=&#39;password&#39;) 密码
div.controls
input.input-xlarge#password(name=&#39;password&#39;,type=&#39;password&#39;)
p.help-block.displayNONE#pw-alert
div.form-actions
button.btn.btn-primary#submit 登录
在public/javascripts下新建login.js,内容如下:
$(document).ready(function () {
var time = 0;
$(&#submit&).click(function () {
var user = {
name: $(&#username&).val(),
password: $(&#password&).val()
//禁止用户名、密码为空
if (user.name.length === 0) {
$(&#name-alert&).text(&用户名不能为空&);
} else if (user.password.length === 0) {
$(&#pw-alert&).text(&密码不能为空&);
if (new Date() - time & 3000)
time = new Date();
//发起ajax请求
$.post(&login&, user, function (data) {
if (&errorName& in data) {
$(&#name-alert&).removeClass(&displayNONE&)
$(&#name-alert&).text(data.errorName);
$(&#name-alert&).parent().parent().addClass(&error&);
setTimeout(function () {
$(&#name-alert&).addClass(&displayNONE&)
$(&#name-alert&).parent().parent().removeClass(&error&);
} else if (&errorPW& in data) {
$(&#pw-alert&).removeClass(&displayNONE&)
$(&#pw-alert&).text(data.errorPW);
$(&#pw-alert&).parent().parent().addClass(&error&);
setTimeout(function () {
$(&#pw-alert&).addClass(&displayNONE&)
$(&#pw-alert&).parent().parent().removeClass(&error&);
} else if (&success& in data) {
location.href = data.
//注册成功则重定向
于是,登录相关的内容算是做完了(但没有做多语言);
【22】登出功能的完成
相比较登录,登出功能就要简单的多,只需要将session的user属性重置为null即可。
在app.js的路由代码附近添加以下代码:
var logout = require(&#39;./routes/logout&#39;);
app.use(&#39;/logout&#39;, logout);
在routes文件夹下新建logout.js,代码非常简单:
var express = require(&#39;express&#39;); //调用express模块
var router = express.Router();
//调用模块的Router方法
//登出只需要清空session的user属性即可
router.get(&#39;/&#39;, function (req, res, next) {
req.session.user =
res.redirect(&#39;/&#39;);
module.exports =
【23】清点需求
重新打开我们之前的需求表:
①有首页;
②支持注册;
③支持登录、登出;
④可以发表博客,发表的博客可以保存到数据库;
⑤可以查看博客,博客从数据库中读取,为了简化,这里设置为查看所有人的博客;
⑥查看博客时,初始查看的数量有限,但可以无限加载新的博客,直到查看完全部博客;
⑦一定程度上实现多语言(即可以切换显示的语言版本),但由于复杂度所限,因此只部分实现(但框架已建立好,可以通过继续完善代码实现整体的国际化);
⑧根据登录状态,对可以访问的页面进行控制(某些允许某些禁止)
红色部分是已经完成的,蓝色部分是尚未完成的。
下来,我们的任务是完成④⑤⑥这三项。
【24】博客的发表
在登录之后,我们会在首页看到一个文本输入框,还有提交和清空按钮;
但目前尚没有逻辑,需要进行添加,打开public\javascripts\blog.js,添加如下代码:
$(document).ready(function () {
//根据url,设置高亮
if (window.location.pathname === &#39;/&#39;) {
$(&.nav-collapse .nav li:first-child&).addClass(&active&);
else if (window.location.pathname === &#39;/login&#39;) {
$(&.nav-collapse .nav li:nth-child(2)&).addClass(&active&);
else if (window.location.pathname === &#39;/reg&#39;) {
$(&.nav-collapse .nav li:nth-child(3)&).addClass(&active&);
//清空输入框
$(&#clearBlog&).click(function () {
$(&#textarea&).val(&&);
var lastSubmit =
var timeer =
var successSubmit =
//防止连续点击
function ErrorAlert() {
if (new Date() - lastSubmit & 3000) {
clearTimeout(timeer);
lastSubmit = new Date();
timeer = setTimeout(function () {
$(&#submitError&).addClass(&displayNONE&);
//提交输入框
$(&#postBlog&).click(function () {
//防止重复发表,因此需要间隔10秒
if (successSubmit && new Date() - successSubmit & 10000) {
//这里是警告提示,防止连续发送消息
$(&#submitError&).text(&你发的太快了,喝喝茶吧!距离下次可以发送消息的时间还有:& + (new Date() - successSubmit).toFixed(0) + & 秒。&);
$(&#submitError&).removeClass(&displayNONE&);
//防止连续点击
ErrorAlert()
var text = $(&#textarea&).val();
if (text.length === 0) {
//禁止发送空内容
$(&#submitError&).text(&请填写输入内容&);
$(&#submitError&).removeClass(&displayNONE&);
//防止连续点击
ErrorAlert()
var length = 0;
//获取输入长度,英文字母为1,中文汉字为2
for (var i = 0; i & text. i++) {
if (text[i].match(/[^\x00-\xff]/ig) != null)
length += 2;
length += 1;
if (length & 255) {
$(&#submitError&).text(&字符长度过长,限制字符长度为255个字节,你的文本长度为& + length + &个字节&);
$(&#submitError&).removeClass(&displayNONE&);
ErrorAlert()
//先清除输入框再提交
$(&#textarea&).val(&&);
successSubmit = new Date();
$.post(&#39;/post&#39;, {text: text}, function (item) {
if (item.code == 500) {
successSubmit = 0;
$(&#submitError&).text(item.data);
$(&#submitError&).removeClass(&displayNONE&);
setTimeout(function () {
$(&#submitError&).addClass(&displayNONE&);
} else if (item.code == 200) {
$(&#submitSuccess&).text(item.data);
$(&#submitSuccess&).removeClass(&displayNONE&);
setTimeout(function () {
$(&#submitSuccess&).addClass(&displayNONE&);
这段代码做了以下事:
①根据当前的url,给对应的标签高亮;
②点击清空按钮,会清除输入框的内容;
③点击提交按钮,会验证输入框内字符串的长度,禁止发送空内容和超过255字节长度的内容;
④当成功发出post请求后,禁止在短时间内连续发送post请求;当发送失败后,取消禁止状态,可以立刻再次发送
⑤验证通过后,将消息内容以post请求发送到服务器,并清空输入框;
⑥返回&#20540;有两种,一种是code属性为200,一种为500;前者为发送成功,发出提示消息;后者发送失败,提示失败原因。
接下来首先要在MySQL里创建一张表,用于保存发送的文本内容;
表名为text,字符类型为utf8,表项如下:
id为自动增量;
user为发表这个博客的用户;
text博客的内容;
ctime为博客的创建时间;
然后在routes文件夹下新建post.js
var express = require(&#39;express&#39;); //调用express模块
var router = express.Router();
//调用模块的Router方法
var db = require(&#39;../models/db&#39;)
//给原生的Date添加一个方法,传递的参数是格式
Date.prototype.Format = function (fmt) { //author: meizz
var obj = {
&M+&: this.getMonth() + 1, //月份
&d+&: this.getDate(), //日
&H+&: this.getHours(), //小时
&m+&: this.getMinutes(), //分
&s+&: this.getSeconds(), //秒
&q+&: Math.floor((this.getMonth() + 3) / 3), //季度
&S&: this.getMilliseconds() //毫秒
if (/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + &&).substr(4 - RegExp.$1.length));
for (var key in obj)
if (new RegExp(&(& + key + &)&).test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (obj[key]) : ((&00& + obj[key]).substr((&& + obj[key]).length)));
console.log(fmt);
//返回值是格式化好之后的时间
function BlogSubmit(user) {
this.user = user.
this.text = user.
this.time = new Date().Format(&yyyy-MM-dd HH:mm:ss&);
//存储文本内容
BlogSubmit.prototype.save = function (callback) {
var self =
console.log(self.user);
db.con(function (connect) {
connect.query(&INSERT INTO text(user,text,ctime) VALUES (?,?,?)&, [self.user, self.text, self.time], function (err, result) {
if (err) {
console.log(&INSERT text user:& + self.user + &, text:& + self.text + &, ctime: & + self.time + & error, the err information is & + err);
return callback(err);
callback(null, result);
router.post(&#39;/&#39;, function (req, res, next) {
//如果不登录是不能发表的(这个是为了防止登录过期,但是页面还保持在登录时的情况)
if (!req.session.user) {
req.session.err = &请登录&;
//因为这里,需要修改layout.jade
return res.redirect(&#39;/login&#39;);
//console.log(req.session.user);
//登录后值为(示例)
//{ Id: 23,
username: &#39;1&#39;,
userpassword: &#39;xMpCOKC5I4INzFCab3WEmw==&#39; }
var blog = new BlogSubmit({
name: req.session.user.name,
text: req.body.text
blog.save(function (err, result) {
if (err) {
return res.send({
code: 500,
data: &错误描述& + err
return res.send({
code: 200,
data: &成功发表!&
module.exports =
这部分代码干了以下几件事:
①给Date()添加了一个方法,用于&#26684;式化日期;
②创建了一个BlogSubmit的类,传递的参数是一个对象,他有name属性和text属性,会将其&#20540;传递给这个类的实例的user属性和text属性中。同时,会在创建这个类的时候获取当前时间。于是,text表的三项内容有了;
③给BlogSubmit类添加了一个方法,这个方法的作用是将这个类的实例的属性,存储在MySQL之中;
④由于表限制text中必须保存内容,因此假如用户通过其他方法直接发起一个post请求,也是不可能成功的(会报错);
⑤保存的前提是用户已登录,未登录的时候发表(比如登录过期)会提示错误。
⑥无论成功或者失败,都会给用户返回一个对象,成功的code属性为200,失败的为500;
最后不要忘记在app.js里添加路由:
var postBlog = require(&#39;./routes/post&#39;);
app.use(&#39;/post&#39;, postBlog);
//提交博客
此时发表博客,会提示:
查看数据库,数据库对应的表是有内容的,说明成功发表了。
【25】博客的加载
博客要满足这些功能;
①初始加载一些博客内容;
②当滚动条拖到最下面的时候,发起ajax请求,取得更多博客内容;
③将博客内容添加到最下方;
④当读取完所有内容时,提示无新博客;
首先,在路由之中添加:
app.use(&#39;/loadblog&#39;, users);
//用户主页,users来处理
将博客的发送交给user来处理;
将以下代码添加进models/blog.js
//读取文本内容(读取所有的),从第count条偏移量开始取9条
BlogSubmit.prototype.getAll = function (count, callback) {
var self =
db.con(function (connect) {
//第一次查询数据库还有多少数据
connect.query(&SELECT count(*) FROM text&, null, function (err, result) {
if (err) {
console.log(&SELECT
* FROM text limit :& + count + &, 9 error, the err information is & + err);
return callback(err);
//console.log(result[0][&#39;count(*)&#39;]);
//这个是查询出来的值
//只有当请求数据的编号(已经查询到多少个),小于最大数据量的时候,才会从数据库内读取数据
if (Number(count) & result[0][&#39;count(*)&#39;]) {
connect.query(&SELECT * FROM text limit ?,9&, [Number(count)], function (err, result) {
if (err) {
console.log(&SELECT
* FROM blogtext limit :& + count + &, 9 error, the err information is & + err);
return callback(err);
result.offset = Number(count) + result.
callback(null, result);
callback(null, null);
修改routes/users.js
var express = require(&#39;express&#39;);
var router = express.Router();
var BlogSubmit = require(&../models/blog&);
/* GET users listing. */
router.get(&#39;/&#39;, function (req, res, next) {
res.send(&#39;respond with a resource&#39;);
router.get(&#39;/:count&#39;, function (req, res, next) {
var blog = new BlogSubmit({
username: null,
text: null
blog.getAll(req.params.count, function (err, result) {
if (err) {
res.send({
code: 500,
data: &错误描述& + err
} else if (result === null) {
res.send({
code: 501,
data: &服务器已经没有更多数据了&
res.send({code: 200, data: result, offset: result.offset});
module.exports =
修改public/javascripts/blog.js,添加以下内容:(此处有bug,请参照【27】的方式修改)
var lastLoad = 0;
//初始时间设置为0
var lastLoadCount = 0;
//偏移量,防止读取到重复数据
var loadingBlog = //加载用的定时器
//加载更多的内容
function loadMoreContent() {
//控制加载间隔,时间差大于2秒,且当前不处于加载中
if (new Date() - lastLoad & 2000 && $(&#scrollToFoot&).innerHTML !== &加载中~~~&) {
lastLoad = new Date();
$(&#scrollToFoot&)[0].innerHTML = &加载中~~~&;
//设置重置,假如超时10秒,那么允许再次提交
setTimeout(function () {
if ($(&#scrollToFoot&).innerHTML === &加载中~~~&) {
$(&#scrollToFoot&).text(&加载失败&);
}, 10000);
$.get(&#39;/loadblog/&#39; + lastLoadCount, function (obj) {
console.log(obj);
//这里假设item的格式:
if (obj.code === 500) {
$(&#scrollToFoot&).text(&加载失败&);
} else if (obj.code === 501) {
//加载完毕
$(&#scrollToFoot&).text(obj.data);
lastLoad = new Date() + ;
//禁止继续请求
clearInterval(loadingBlog);
obj.data.forEach(function (item) {
$(&#content&).append(&#39;&div class=&span4&&&h2&&#39; + item.user + &#39;说&/h2&&#39; +
&#39;&p&&#39; + item.text + &#39;&/p&&/div&&#39;);
$(&#scrollToFoot&).innerHTML = &滚动到底部然后加载内容&;
lastLoadCount += obj.
//加载完毕时,加载一次内容
loadMoreContent();
//向下滚动时加载内容
loadingBlog = setInterval(function () {
if ($(document).height() - $(window).scrollTop() - $(window).height() & 200) {
loadMoreContent();
修改index.jade中的
div.row.content
div.row.content#content
到目前为止,可以自动无限加载博客了。
【26】路由控制
现在,就差最后一步了。
毫无疑问,在用户未登录的时候,应该禁止掉用户发送只有登录过的用户才可以做的事情;而用户在登录之后,也应该禁止掉用户在非登录情况下才能做的事情;
前者典型是登出,而后者典型是登录和注册。
比如这样就是不对的
解决办法,利用“路由中间件”来解决问题,这就是我们在router.get之类的函数中,第二个参数的第三个参数next;
所谓路由中间件,首先要理解请求;
假如有一个url为/reg的post请求,当他遇见router.post(‘/reg’,xxxxx)时,执行完这行代码的回调函数后便停止了。
假如我们需要他被两段这样的代码来先后处理,那么显然是不可行的,路由会自动结束请求。
这个时候在第一段代码最后执行回调函数中的第三个参数next,那么就会继续执行第二段代码。
更具体的请看我的博客:
打开app.js,在之前所有路由代码之前,添加以下代码:
//路由的处理
app.use(&#39;/login&#39;, checkNotLogin);
app.use(&#39;/reg&#39;, checkNotLogin);
//必须在已登录情况下才能访问
app.use(&#39;/logout&#39;, checkLogin);
//未登录检测(已登录情况下执行)
function checkNotLogin(req, res, next) {
if (req.session.user) {
req.session.err = &已登录,请不要重复登录&;
return res.redirect(&#39;/&#39;);
//已登录检测(未登录情况下执行)
function checkLogin(req, res, next) {
if (!req.session.user) {
req.session.err = &你还没有登录,请登录&;
return res.redirect(&#39;/login&#39;);
此时重启nodejs程序,登录博客,然后url地址输入/reg,会有以下提示
这说明,我们的路由权限控制已经顺利完成了。
这篇博客的总体结构也基本完成了。
虽然还有很多需要修补的问题,但那已经是下一篇博客的故事了。
【27】bug修复
之前因为更改为定时刷新之后,只有当处于首页时,js才能正常自行;
当进入登录、注册页时,由于无法找到#textarea这个dom,因此会报错,导致代码无法正常运行。
因此,将blog.js分拆,新建一个index.js在public\javascripts目录下,代码分拆后结果如下:
$(document).ready(function () {
//根据url,设置高亮
if (window.location.pathname === &#39;/&#39;) {
$(&.nav-collapse .nav li:first-child&).addClass(&active&);
else if (window.location.pathname === &#39;/login&#39;) {
$(&.nav-collapse .nav li:nth-child(2)&).addClass(&active&);
else if (window.location.pathname === &#39;/reg&#39;) {
$(&.nav-collapse .nav li:nth-child(3)&).addClass(&active&);
$(document).ready(function () {
//清空输入框
$(&#clearBlog&).click(function () {
$(&#textarea&).val(&&);
var lastSubmit =
var timeer =
var successSubmit =
//防止连续点击
function ErrorAlert() {
if (new Date() - lastSubmit & 3000) {
clearTimeout(timeer);
lastSubmit = new Date();
timeer = setTimeout(function () {
$(&#submitError&).addClass(&displayNONE&);
//提交输入框
$(&#postBlog&).click(function () {
//防止重复发表,因此需要间隔10秒
if (successSubmit && new Date() - successSubmit & 10000) {
//这里是警告提示,防止连续发送消息
$(&#submitError&).text(&你发的太快了,喝喝茶吧!距离下次可以发送消息的时间还有:& + (10 - (new Date() - successSubmit) / 1000).toFixed(0) + & 秒。&);
$(&#submitSuccess&).addClass(&displayNONE&);
$(&#submitError&).removeClass(&displayNONE&);
//防止连续点击
ErrorAlert()
var text = $(&#textarea&).val();
if (text.length === 0) {
//禁止发送空内容
$(&#submitError&).text(&请填写输入内容&);
$(&#submitError&).removeClass(&displayNONE&);
//防止连续点击
ErrorAlert()
var length = 0;
//获取输入长度,英文字母为1,中文汉字为2
for (var i = 0; i & text. i++) {
if (text[i].match(/[^\x00-\xff]/ig) != null)
length += 2;
length += 1;
if (length & 255) {
$(&#submitError&).text(&字符长度过长,限制字符长度为255个字节,你的文本长度为& + length + &个字节&);
$(&#submitError&).removeClass(&displayNONE&);
ErrorAlert()
//先清除输入框再提交
$(&#textarea&).val(&&);
successSubmit = new Date();
$.post(&#39;/post&#39;, {text: text}, function (item) {
console.log(item);
if (item.code == 403) {
location.href = item.
else if (item.code == 500) {
successSubmit = 0;
$(&#submitError&).text(item.data);
$(&#submitError&).removeClass(&displayNONE&);
setTimeout(function () {
$(&#submitError&).addClass(&displayNONE&);
} else if (item.code == 200) {
$(&#submitSuccess&).text(item.data);
$(&#submitError&).addClass(&displayNONE&);
$(&#submitSuccess&).removeClass(&displayNONE&);
setTimeout(function () {
$(&#submitSuccess&).addClass(&displayNONE&);
var lastLoad = 0;
//初始时间设置为0
var lastLoadCount = 0;
//偏移量,防止读取到重复数据
var loadingBlog = //加载用的定时器
//加载更多的内容
function loadMoreContent() {
//控制加载间隔,时间差大于2秒,且当前不处于加载中
if (new Date() - lastLoad & 2000 && $(&#scrollToFoot&).innerHTML !== &加载中~~~&) {
lastLoad = new Date();
$(&#scrollToFoot&)[0].innerHTML = &加载中~~~&;
//设置重置,假如超时10秒,那么允许再次提交
setTimeout(function () {
if ($(&#scrollToFoot&).innerHTML === &加载中~~~&) {
$(&#scrollToFoot&).text(&加载失败&);
}, 10000);
$.get(&#39;/loadblog/&#39; + lastLoadCount, function (obj) {
console.log(obj);
//这里假设item的格式:
if (obj.code === 500) {
$(&#scrollToFoot&).text(&加载失败&);
} else if (obj.code === 501) {
//加载完毕
$(&#scrollToFoot&).text(obj.data);
lastLoad = new Date() + ;
//禁止继续请求
clearInterval(loadingBlog);
obj.data.forEach(function (item) {
$(&#content&).append(&#39;&div class=&span4&&&h2&&#39; + item.user + &#39;说&/h2&&#39; +
&#39;&p&&#39; + item.text + &#39;&/p&&/div&&#39;);
$(&#scrollToFoot&).innerHTML = &滚动到底部然后加载内容&;
lastLoadCount += obj.
//加载完毕时,加载一次内容
loadMoreContent();
//向下滚动时加载内容
loadingBlog = setInterval(function () {
if ($(document).height() - $(window).scrollTop() - $(window).height() & 200) {
loadMoreContent();
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:362297次
积分:7327
积分:7327
排名:第3430名
原创:385篇
评论:77条
文章:16篇
阅读:1534
文章:19篇
阅读:81295
文章:37篇
阅读:48593
(12)(21)(12)(10)(10)(6)(12)(8)(4)(5)(6)(5)(9)(5)(10)(15)(17)(15)(14)(12)(11)(16)(19)(34)(102)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'}

我要回帖

更多关于 哪个网页游戏好玩 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信