由于工作中做实时通信的项目,需要用到Nodejs做通讯转接功能,刚开始接触,很多都不懂,于是我和同事就准备去学习nodejs,结合nodejs之MEAN栈实战书籍《Getting.MEAN.with.Mongo.Express.Angular.and.Node.2015.11》,我们完成了一个小型的ReadClubing项目,结合书中讲解和步骤,我们完成了不同的功能,当然由于时间原因,还有很多不完善的地方,后续我们会继续开发。

同事负责开发的内容为:

Nodejs之MEAN栈开发(一)---- 路由与控制器

Nodejs之MEAN栈开发(二)----视图与模型

Nodejs之MEAN栈开发(三)---- 使用Mongoose创建模型及API

Nodejs之MEAN栈开发(四)---- form验证及图片上传

Nodejs之MEAN栈开发(五)---- Angular入门与页面改造

Nodejs之MEAN栈开发(六)---- 用Angular创建单页应用(上)

Nodejs之MEAN栈开发(七)---- 用Angular创建单页应用(下)

Nodejs之MEAN栈开发(八)---- 用户认证与会话管理详解

我开发的内容为:

Nodejs之MEAN栈开发(九)---- 用户评论的增加/删除/修改

针对这次Nodejs之MEAN栈开发ReadClubing项目,我主要负责是标题详情页面,包括页面布局、数据展示、评论的增加/删除/修改等工作。

1、标题详情页面布局和数据展示

标题详情页操作如图:

因为ReadClub的项目的结构是按照MVC的形式来开发的,首先找到程序入口,即路由app_client/app.js,app.js主要是按照Angular提供的内置模块$routeProvider实现路由转接功能,链接到详情页的代码如下:

(function() {
angular.module('readApp', ['ngRoute', 'ngSanitize'])
.config(['$routeProvider', '$locationProvider', config]);
function config($routeProvider, $locationProvider) {
$routeProvider
.when('/topicDetail/:topicid', {
templateUrl: 'topicDetail/topicDetail.html',
controller: 'topicDetailCtrl',
caseInsensitiveMatch: true,
controllerAs: 'vm'
})
.otherwise({ redirectTo: '/' });
$locationProvider.html5Mode(true);
}
)();

因此页面被跳转到详情页topicDetail.html,详情页的数据依赖于控制器topicDetailCtrl。

同样是遵循Angular页面获取数据的方式,页面中需要展示数据的地方都以{{value}}的形式表示,中间value的输出是依靠控制器topicDetailCtrl从数据库获取到的数据。topicDetail.html代码如下:

<navigation></navigation>
<div id="bodycontent" class="container">
<div class="row">
<div class="col-md-9">
<div class="content">
<div class="topic_top backcolor">
<div class="title">{{vm.topic.title}}</div>
<div class="topic_content">{{vm.topic.content}}</div>
</div>
<div class="comment backcolor">
<div class="commenttip">{{vm.topic.comments.length}} 回复</div>
<div id="commentcontent" ng-repeat="comments in vm.topic.comments">
<div class="cell reply_area reply_item ">
<div class="author_content">
<a href="" class="user_avatar">
<img src="https://avatars.githubusercontent.com/u/3088175?v=3&s=120"/>
</a>
<div class="user_info">
<a class="dark reply_author" href="/user/{{vm.topic.author}}">{{vm.topic.author}}</a>
<a class="reply_time">{{comments.createdOn | jsonDate:'yyyy-MM-dd HH:mm:ss'}}</a>
</div>
<div class="user_action">
<a ng-href="#" ng-click="vm.editReply(comments._id)" id="{{comments._id}}">
<i class="fa fa-pencil-square-o" title="编辑"></i>
</a>
<a ng-href="#" ng-click="vm.deleteReply(comments._id)">
<i class="fa fa-trash" title="删除"></i>
</a>
</div>
</div>
<div class="reply_content from-rochael">
<div class="markdown-text" ng-bind-html="comments.content | trustHtml">
</div>
</div>
</div>
</div>
</div>
<div class="commentarea backcolor">
<div class="header">添加回复</div>
<div class="inner">
<div id="summernote" ng-model="summernote" ng-summernote ></div>
<input id="topicid" type="hidden" value="{{vm.topic._id}}" />
<input id="username" type="hidden" value="Smartlin" />
<div class="editor_buttons">
<span ng-show="vm.reply" class="submit" ng-click="vm.submitReply()">回复</span>
<span ng-show="!vm.reply" class="submit" ng-click="vm.updateReply()">回复</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="userinfo">
<p>stoneniqiu</p>
</div>
</div>
</div>
<footer-nav></footer-nav>

理解控制器获取数据:同理,在topicDetail文件下新建topicDetail.controller.js。遵循Angular的路由规则,由于实现的视图和控制器的绑定关系,视图加载时,控制器会立即调取数据给页面输出。

我们来看看topicDetail.controller.js的逻辑,代码如下:

(function () {
angular.module('readApp')
.controller('topicDetailCtrl', topicDetailCtrl)
.directive('ngSummernote', getSummernote) topicDetailCtrl.$inject = ['$scope','$http', '$routeParams', 'topicData'];
function topicDetailCtrl($scope,$http, $routeParams, topicData) {
var vm = this;
vm.topicid = $routeParams.topicid;
vm.reply = true;
topicData.getTopicById(vm.topicid).success(function (data) {
vm.topic = data;
}).error(function (e) {  
vm.message = "Sorry, something's gone wrong ";
})
} function getSummernote(){
return {
restrict : 'A',
require : 'ngModel',
link : function($scope, $element, $attrs, $ngModel){
if (!$ngModel) {
return;
}
$($element).summernote({
height: ,
minHeight: ,
maxHeight: ,
focus: true
})
},
};
}
})();
topicData.getTopicById(vm.topicid),通过传入topicid查询数据库,链接到app_client/common/services/ReadData.service.js,主要通过angular定义的service,请求数据模块$http,实现路由转接功能,代码如下:
angular
.module('readApp')
.service('topicData', topicData) topicData.$inject = ['$http'];
function topicData($http) {
var getTopicById = function (topicid) {
return $http.get('/api/topics/' + topicid);
};
return {
getTopicById: getTopicById
};
};
$http.get('/api/topics/' + topicid),根据路由跳转到app_api/routes/index.js,通过node的router规则实现跳转。代码如下:
router.get('/topics/:topicid', topicCtrl.topicReadOne);

在app_api/controller/topic.js中实现路由方法,代码如下:

module.exports.topicReadOne = function (req, res) {
var topicid = req.params.topicid;
console.log("topicid:"+topicid);
if (!topicid) {
sendJSONresponse(res, , {
"message": "Not found, topicid is required"
});
return;
}
TopicModel.findById(topicid).exec(function (err, topic) {
if (!topic) {
sendJSONresponse(res, , {
"message": "topicid not found"
});
return;
} else if (err) {
sendJSONresponse(res, , err);
return;
}
sendJSONresponse(res, , topic); });
}

返回的数据topic在topicDetail.controller.js中通过vm.topic = data来接收,到这里,视图中通过vm.topic依赖的数据就会展现出来。

详情页面展示需要注意的几点细节:

(1)、富文本框summernote的显示

没有运用angular的html页面,显示summernote的方法:首先,在html中写入标签 <div id="summernote"></div>;其次,引入支持相应的summernote.css和summernote.js文件即可,代码如下:

 <link rel='stylesheet' href='http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.1/summernote.css'/>
<div id="summernote"></div>
<script src='http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.1/summernote.js'></script>

但在使用angular框架加载html页面时,会导致富文本框summernote无法显示,解决方法为:

第一步:在html页面中增加ng-model,ng-summernote,代码如下:

 <div id="summernote" ng-model="summernote" ng-summernote ></div>

第二步:在控制器topicDetail.controller.js中,嵌入指令directive('ngSummernote', getSummernote),代码如下:

angular.module('readApp',[])
.directive('ngSummernote', getSummernote)
function getSummernote(){
return {
restrict : 'A',
require : 'ngModel',
link : function($scope, $element, $attrs, $ngModel){
if (!$ngModel) {
return;
}
$($element).summernote({//初始化方法
height: ,
minHeight: ,
maxHeight: ,
focus: true
})
},
};
}

(2)、编辑和删除图标的显示

编辑和删除图标的显示,需要引用font-awesome.min.css,fontawesome是一套绝佳的图标字体库和CSS框架,为您提供可缩放的矢量图标,您可以使用CSS所提供的所有特性对它们进行更改,包括:大小、颜色、阴影或者其它任何支持的效果。引入的方式如下:

<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css"/>

(3)、编辑事件editReply()和删除事件deleteReply()传参

在ng-repeat执行循环过程中,因为这两个事件需要传入评论的id,方法为:vm.editReply(comments._id)和vm.deleteReply(comments._id),直接传入comments._id,不需要用{{}};而其他不需要作为参数传递给方法的值,显示的方法是需要加{{}},如:{{comments.createdOn}},代码如下:

(4)、关于angularJS绑定数据时自动转义html标签

因为我们追加的评论保存到数据库时会有带html标签的情况,如加粗、设置颜色的字体,图片等,当取出展示在评论区时会带有html标签,因此需要转义,实现转义的方法如下:

第一步:在html中绑定过滤器trustHtml,代码如下:

 <div class="markdown-text" ng-bind-html="comments.content | trustHtml"></div>

第二步:在控制器topicDetail.controller.js中,设置过滤器,代码如下:

angular.module('readApp',[])
.filter('trustHtml', getTrust)
getTrust.$inject = ['$sce']; function getTrust($sce) {
return function (input) {
return $sce.trustAsHtml(input);
}
}

2、追加评论

追加评论通过回复按钮,但是当我们修改评论时,将要修改的评论内容放到富文本框中,也要点击回复按钮,因此会出现冲突,解决方法:

首先,在html页面中定义两个绑定不同事件的回复按钮,通过angular内置指令ng-show来实现两个按钮的显示和隐藏,从而来实现不同的功能,代码如下:

<span ng-show="vm.reply" class="submit" ng-click="vm.submitReply()">回复</span>
<span ng-show="!vm.reply" class="submit" ng-click="vm.updateReply()">回复</span>

其次,在初进详情页时,设置vm.reply = true来显示增加评论的按钮,当点击编辑评论时,则设置vm.reply = false来显示编辑评论的按钮,最后修改的评论成功提交后,又设置vm.reply = true切换到增加评论的按钮。

通过入口回复按钮submitReply(),链接到控制器topicDetail.controller.js,代码如下:

vm.submitReply = function () {
var code = $('#summernote').summernote('code');
if (code == "") {
alert("输入的内容不能为空~");
return;
}
var params = {
topicid: vm.topicid,
content: code
};
topicData.addComment(params).success(function (data) {
vm.message = data.length > ? "" : "暂无数据";
vm.topic.comments.push(data);//数据库和页面上的comments对象都要进行数据更新;
$('#summernote').summernote('code', '');
}).error(function (e) {
console.log(e);
});
};

通过topicData.addComment(params),链接到ReadData.service.js,通过绑定service()显示路由,代码如下:

function topicData ($http) {
var addComment = function(data){
return $http({
method: 'POST',
url: "/api/topics/" + data.topicid,
data: data
})
};
return {
addComment: addComment,
}
}

通过$http()请求,链接到app_api/routes/index.js,代码如下:

router.post('/topics/:topicid', topicCtrl.commentAppendOne);

通过topicCtrl.commentAppendOne,链接到app_api/controller/topic.js,代码如下:

//读取所有的有关这个topicid的评论
module.exports.commentAppendOne = function (req, res) {
var topicid = req.params.topicid;
if (!topicid) {
sendJSONresponse(res, , {
"message": "Not found, topicid is required"
});
return;
}
TopicModel.findById(topicid)
.select('comments')
.exec(function (err, topic) {
if (!topic) {
sendJSONresponse(res, , {
"message": "topic not found"
});
return;
} else if (err) {
sendJSONresponse(res, , err);
return;
}
doAddComment(req, res, topic);
});
} var doAddComment = function (req, res, topic) {
if (!topic) {
sendJSONresponse(res, , "topicid not found");
} else {
//console.log("user:", req.body.user);
//console.log(req.body.content);
topic.comments.push({
user: req.body.user,
createdOn: req.body.createdOn,
content: req.body.content
});
topic.save(function (err, topic) {
var thisReview;
if (err) {
sendJSONresponse(res, , err);
} else {
var length = topic.comments.length - ;
//console.log("length:",length);
thisReview = topic.comments[length];
//console.log("thisReview:", querystring.stringify(thisReview));
sendJSONresponse(res, , thisReview);
}
});
}
}

最后,在控制器中通过成功之后的回调函数,通过push()方法将要追加的数据放到数组topic.comments中,实现数据更新;评论追加成功后,记得清空富文本框里面的值,方法为:$('#summernote').summernote('code', '');

3、删除评论

点击删除图标,触发删除评论事件vm.deleteReply(comments._id),需要传入评论id,确保要删除的是哪条评论。根据入口,链接到控制器topicDetail.controller.js,代码如下:

vm.deleteReply = function (commentid) {
var params = {
topicid: vm.topicid,
commentid: commentid
};
topicData.deleteComment(params).success(function (data) {
if (confirm("确定删除?")) {
for (var i = ; i < vm.topic.comments.length; i++) {
if (vm.topic.comments[i]._id == commentid) {
vm.topic.comments.splice(vm.topic.comments.indexOf(vm.topic.comments[i]._id), );
}
}
}
}).error(function (e) {
console.log(e);
});
}

通过topicData.deleteComment(params),链接到ReadData.service.js,代码如下:

function topicData ($http) {
var deleteComment = function (data) {
console.log("deleteComment,topicid:", data.topicid, "commentid:", data.commentid);
return $http.delete('/api/topics/' + data.topicid + '/comments/' + data.commentid);
};
return {
deleteComment: deleteComment
}
}

通过$http.delete()请求,链接到app_api/routes/index.js,代码如下:

router.delete('/topics/:topicid/comments/:commentid', topicCtrl.commentDeleteOne);

通过topicCtrl.commentDeleteOne,链接到app_api/controllers/topic.js,代码如下:

module.exports.commentDeleteOne = function (req, res) {
if (!req.params.topicid || !req.params.commentid) {
sendJSONresponse(res, , {
"message": "Not found, topicid and commentid are both required"
});
return;
}
TopicModel
.findById(req.params.topicid)
.select('comments')
.exec(
function (err, topic) {
if (!topic) {
sendJSONresponse(res, , {
"message": "topicid not found"
});
return;
} else if (err) {
sendJSONresponse(res, , err);
return;
}
if (topic.comments && topic.comments.length > ) {
console.log("length:", topic.comments.length);
if (!topic.comments.id(req.params.commentid)) {
sendJSONresponse(res, , {
"message": "commentid not found"
});
} else {
topic.comments.id(req.params.commentid).remove();
topic.save(function (err) {
if (err) {
sendJSONresponse(res, , err);
} else {
sendJSONresponse(res, , null);
}
});
}
} else {
sendJSONresponse(res, , {
"message": "No comment to delete"
});
}
}
);
};

最后,在控制器中通过成功之后的回调函数,变量评论数组找到要删除的那条评论,通过splice()从数组中删除,实现页面数据更新。

4、修改评论

点击编辑图标,触发编辑评论事件vm.editReply(comments._id),需要传入评论id,确保要编辑的是哪条评论。根据入口,链接到控制器topicDetail.controller.js,注意编辑评论需要分为两步:

第一步、将要编辑的评论内容追加到富文本框中,进行修改,代码如下:

vm.editReply = function (commentid) {
document.getElementsByTagName('BODY')[].scrollTop=document.getElementsByTagName('BODY')[].scrollHeight;
var editContent = angular.element(document.getElementById(commentid)).parent('.user_action').parent('.author_content').next('.reply_content').children().text();
$('#summernote').summernote('code', editContent);
vm.reply = false;
vm.commentid = commentid;
}

第二步、通过点击编辑评论的回复按钮,来实现修改评论的提交,代码如下:

vm.updateReply = function () {
vm.code = $('#summernote').summernote('code');
var params = {
topicid: vm.topicid,
commentid: vm.commentid,
editContent: vm.code
};
topicData.updateComment(params).success(function (data) {
console.log(data);
for(var i = ;i < data.comments.length;i++){
if(data.comments[i]._id == vm.commentid){
console.log('id into');
data.comments[i].content = vm.code;
vm.topic.comments = data.comments;
$('#summernote').summernote('code', '')
}
}
vm.reply = true; }).error(function (e) {
console.log(e);
});
}

根据topicData.updateComment(params),链接到ReadData.service.js,代码如下:

function topicData ($http) {
var updateComment = function (data) {
return $http({
method:'POST',
url:'/api/topics/' + data.topicid + '/comments/' + data.commentid,
data: { editContent: data.editContent}
})
};
return {
updateComment: updateComment
};
}

通过$http(),post方式请求,链接到app_api/routes/index.js,代码如下:

router.post('/topics/:topicid/comments/:commentid', topicCtrl.commentUpdateOne);

通过topicCtrl.commentUpdateOne,链接到app_api/controllers/topic.js,代码如下:

module.exports.commentUpdateOne = function (req, res) {
if (!req.params.topicid || !req.params.commentid) {
sendJSONresponse(res, , {
"message": "Not found, topicid and commentid are both required"
});
return;
}
TopicModel
.findById(req.params.topicid)
.select('comments')
.exec(
function (err, topic) {
if (!topic) {
sendJSONresponse(res, , {
"message": "topicid not found"
});
return;
} else if (err) {
sendJSONresponse(res, , err);
return;
}
if (topic.comments && topic.comments.length > ) {
if (!topic.comments.id(req.params.commentid)) {
sendJSONresponse(res, , {
"message": "commentid not found"
});
} else { for(var i= ;i<topic.comments.length;i++){
if(topic.comments[i]._id == req.params.commentid){
topic.comments[i].content = req.body.editContent;
topic.save(function (err, topic) {
if (err) {
sendJSONresponse(res, , err);
} else {
sendJSONresponse(res, , topic);
}
});
}
} }
} else {
sendJSONresponse(res, , {
"message": "No comment to update"
});
}
}
);
}; var updateContentById = function (req, res, commentid) {
CommentModel
.findById(commentid)
.select('content')
.exec(
function (err, content) {
if (!content) {
sendJSONresponse(res, , {
"message": "content not found"
});
return;
} else if (err) {
sendJSONresponse(res, , err);
return;
}
sendJSONresponse(res, , content);
topic.save(function (err, comments) {
if (err) {
sendJSONresponse(res, , err);
} else {
sendJSONresponse(res, , book);
}
});
}
);
}

最后,通过控制器中执行成功后的回调函数,通过循环找到要修改的那个评论id,根据那条id去更新对应的评论内容,实现页面数据更新。

细节:如果在node页面console.log("汉字")或者后端接收到带有中文的数据或者使用node提供的代码压缩uglifyJs.minify(),cmd窗口会报错,原因是windows系统自带的cmd窗口不能识别utf-8字符编码,解决方法如下:

1、打开CMD.exe命令行窗口;

2、通过 chcp命令改变代码页,UTF-8的代码页为65001;

3、修改窗口属性,改变字体

在命令行标题栏上点击右键,选择"属性"->"字体",将字体修改为True Type字体"Lucida Console",然后点击确定将属性应用到当前窗口。如下图所示:

这时使用type命令就可以显示UTF-8文本文件的内容了:

type filename.txt

4、通过以上操作并不能完全解决问题,因为显示出来的内容有可能不完全。可以先最小化,然后最大化命令行窗口,文件的内容就完整的显示出来了。

5、另外提供一些chcp命令的参考:

chcp 65001  就是换成UTF-8代码页

chcp 936 可以换回默认的GBK

chcp 437 是美国英语

源码:https://github.com/stoneniqiu/ReadingClub (注意不同分支)

小结:这一节主要讲到了如何在Angular页面来加载Jquery组件如富文本框summernote,调取数据和展示数据时应该注意的几点细节,评论的增加、删除、修改,其实内容不是很多,主要要理清思路,根据项目mvc的逻辑结构,自己走一遍,应该就没问题了。

 

Nodejs之MEAN栈开发(九)---- 用户评论的增加/删除/修改的更多相关文章

  1. Nodejs之MEAN栈开发(三)---- 使用Mongoose创建模型及API

    继续开扒我们的MEAN栈开发之路,前面两节我们学习了Express.Jade引擎并创建了几个静态页面,最后通过Heroku部署了应用. Nodejs之MEAN栈开发(一)---- 路由与控制器 Nod ...

  2. AutoCad 二次开发 .net 之层表的增加 删除 修改图层颜色 遍历 设置当前层

    AutoCad 二次开发 .net 之层表的增加 删除 修改图层颜色 遍历 设置当前层 AutoCad 二次开发 .net 之层表的增加 删除 修改图层颜色 遍历 设置当前层我理解的图层的作用大概是把 ...

  3. Nodejs之MEAN栈开发(二)----视图与模型

    上一节做了对Express做了简单的介绍,提出了controller,介绍了路由.这一节将重点放到视图和模型上,完成几个静态页面并部署到heroku上. 导航 前端布局使用bootstrap,从官网下 ...

  4. Nodejs之MEAN栈开发(八)---- 用户认证与会话管理详解

    用户认证与会话管理基本上是每个网站必备的一个功能.在Asp.net下做的比较多,大体的思路都是先根据用户提供的用户名和密码到数据库找到用户信息,然后校验,校验成功之后记住用户的姓名和相关信息,这个信息 ...

  5. Nodejs之MEAN栈开发(一)---- 路由与控制器

    因为工作需要,最近再次学习了node,上一次学习node是2014年,纯粹是个人兴趣,学了入门之后没有运用,加上赶别的项目又不了了之.这次正好捡起来.废话不多说,这里的MEAN指的是Mongodb.E ...

  6. Python 全栈开发九 日志模块

    日志是一种可以追踪某些软件运行时所发生事件的方法.软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情.一个事件可以用一个可包含可选变量数据的消息来描述.此外,事件也有重要性的概念 ...

  7. Nodejs之MEAN栈开发(七)---- 用Angular创建单页应用(下)

    上一节我们走通了基本的SPA基础结构,这一节会更彻底的将后端的视图.路由.控制器全部移到前端.篇幅比较长,主要分页面改造.使用AngularUI两大部分以及一些优化路由.使用Angular的其他指令的 ...

  8. Nodejs之MEAN栈开发(六)---- 用Angular创建单页应用(上)

    在上一节中我们学会了如何在页面中添加一个组件以及一些基本的Angular知识,而这一节将用Angular来创建一个单页应用(SPA).这意味着,取代我们之前用Express在服务端运行整个网站逻辑的方 ...

  9. Nodejs之MEAN栈开发(五)---- Angular入门与页面改造

    这个系列一共会涉及两个JavaScript框架的讲解,一个是Express用做后端,一个是Angular用于前端.和Express一样,Angular分离内容,处理视图.数据和逻辑.和MVC模式很相似 ...

随机推荐

  1. Socket开发框架之框架设计及分析

    虽然在APP应用.Web应用.Winform应用等大趋势下,越来越多的企业趋向于这些应用系统开发,但是Socket的应用在某些场合是很必要的,如一些停车场终端设备的接入,农业或者水利.压力监测方面的设 ...

  2. C#中是否可以继承String类

    C#中是否可以继承String类? 答:String类是sealed类故不可以继承. 当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承. 在下面的示例中,类 HoverTree ...

  3. [水煮 ReSharper] 高效开发—十个实用的快捷键

    所有 ReSherper 的功能都可以使用快捷键.大部分功能都有默认快捷键,剩下的少数功能可以自定义快捷键. ReSharper 提供了两种快捷键的方式 Visual Studio:这种方式可以减少与 ...

  4. C#单纯的字母数字ASCII码转换

    字母转换成数字 byte[] array = new byte[1];   //定义一组数组array            array = System.Text.Encoding.ASCII.Ge ...

  5. Scalaz(29)- Free :Coyoneda - Functor for free

    很多时候我们会遇到一些高阶类型F[_],但又无法实现它的map函数,也就是虽然形似但F不可能成为Functor.看看下面的例子: trait Interact[A] case class Ask(pr ...

  6. JS this,call和apply以及回调函数

    this this引用,引用的是一个对象,对象不同或函数调用方式的不同,this引用会根据代码的上下文语境自动改变引用对象的特性. 引用规则 1,在最外层代码中,this引用引用的是全局对象(wind ...

  7. tmpfs:一种基于内存的文件系统

    tmpfs是一种基于内存的文件系统, tmpfs有时候使用rm(物理内存),有时候使用swap(磁盘一块区域).根据实际情况进行分配. rm:物理内存.real memery的简称? 真实内存就是电脑 ...

  8. GJM :FPSCalc-简单FPS观测类 [转载]

    版权声明:本文原创发表于 [请点击连接前往] ,未经作者同意必须保留此段声明!如有侵权请联系我删帖处理! FPSCalc--简单FPS观测类 利用Unity做的手游项目很多时候要保证流畅度,流畅度最直 ...

  9. Hibernate(七)__多对一 、一对多、 一对一、多对多

    1.many-to-one 以学生和部门之间的关系为例: Department.hbm.xml <?xml version="1.0" encoding="utf- ...

  10. Ajax+PHP+MySQL 登陆示例

    PHP是一门很好的语言,可以很方便的开发web应用程序,下面介绍一下PHP如何通过AJAX方式实现登录功能: 1 login.php 登录界面中,javascript脚本用ajax方式异步请求dolo ...