
在搭建网站之前,我们需要搭建一个网站的架子,我选择了Express基于 Node.js 平台,快速、开放、极简的 web 开发框架。
因为是node的项目,所以我们需要初始化项目,安装依赖
npm init -y // 生成pacjage.json
安装 Express 并将其保存到依赖列表中:(tips: 可以安装nrm切换到taobao镜像)
npm install nrm
npm install express --save
我们先看一下express基本的应用
touch app.js
var express = require('express'); //引用express
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
但是一个网站不可能是Hello World 这么简单,肯定需要更多的功能,那我们怎么做呢?
Express 应用生成器
- 应用生成器工具 express 可以快速创建一个应用的骨架。
$ npm install express-generator //最好安装到本地目录
-V, --version // 版本号
-e, --ejs add ejs engine support (defaults to jade)
--hbs add handlebars engine support // 模板引擎 ejs hbs等
-c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
--git add .gitignore // 默认less ,css编译器
-f, --force force on non-empty directory // 类似空文件夹
我们创建可以使用命令行
$ .node_modules/express-generator/bin/express . -f -e
// 安装依赖
$ cd myapp
$ npm install
npm start
// 然后在浏览器中打开 http://localhost:3000/
目录结构
.
├── app.js
├── bin // 可执行文件
│ └── www
├── package.json
├── public // 静态文件
│ ├── images
│ ├── javascripts
│ └── stylesheets
│ └── style.css
├── routes // 路由设置
│ ├── index.js
│ └── users.js
└── views // 模板语法
├── error.ejs
├── index.ejs
└── layout.ejs
那为什么打开localhost:3000会打开一个网站呢?
- 我们看一下我们是不是用了
npm start
-
npm start
在package.json
里写的
"scripts": {
"start": "node ./bin/www",
},
看一看bin/www
写了什么
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app'); // require app.js文件
var debug = require('debug')('express-stickynotes:server');
var http = require('http'); // node 模块 http
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000'); // 提供给环境的PORT,没有就是3000端口
// 修改是 $ PORT==4000 node bin/www
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app); // 启动服务器
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port); // 监听端口
server.on('error', onError); // 提示错误信息
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
app.js
内容
// 依赖的模块
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index'); //转到 router文件夹下的
var api = require('./routes/api');
var app = express(); // 调用express ,网站的逻辑就是由app处理
// view engine setup 设置模板引擎
app.set('views', path.join(__dirname, 'views')); // views 模板的文件路径
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public 中间件
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
//加载为静态目录 public
app.use(express.static(path.join(__dirname, 'public')));
//路由router/index 在里面设置内容
// 用户看到的就是经过模板和数据渲染的页面
app.use('/', index);
// app.use('/users', users);
app.use('/api',api)
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
MVC
M -- Module 模型专门和数据库交互
V -- views 视图模板引擎渲染的
C -- control 控制路由跳转的就是控制器 控制页面跳转
对于Express主要有三个概念路由 中间件 模板引擎
-
中间件 middleware
- 中间件就是作为一个中间层去做一个数据处理,相当于来了一个请求,交给一个环节处理,然后交给下一个环节,最终得到一个结果,发给前台,得到我们看到的页面和数据
-
中间件(Middleware) 是一个函数,它可以访问请求对象(request object (
req
)), 响应对象(response object (res
)), 和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为next
的变量。
-
路由 route 路由
- 路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。
- 路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄组成,它的结构如下:
app.METHOD(path, [callback...], callback)
,app
是express
对象的一个实例,METHOD
是一个 HTTP 请求方法,path
是服务器上的路径,callback
是当路由匹配时要执行的函
// 应用级
var app = express();
// 没有挂载路径的中间件,应用的每个请求都会执行该中间件
app.use(function (req, res, next) { // 请求数据 相应数据 下一个挂载点
console.log('Time:', Date.now());
next();
});
// 挂载至 /user/:id 的中间件,任何指向 /user/:id 的请求都会执行它
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
// 路由和句柄函数(中间件系统),处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
res.send('USER');
});
// 路由级
var app = express();
var router = express.Router();
// 没有挂载路径的中间件,通过该路由的每个请求都会执行该中间件
router.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
// 一个中间件栈,显示任何指向 /user/:id 的 HTTP 请求的信息
router.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
// 可以对照 app.js看看里面的路由做一下对比,然后看routers/index文件看一下路由
但是静态文件该怎么处理呢?配置webpack
// app.js
//加载为静态目录 public
app.use(express.static(path.join(__dirname, 'public')));

- 目录可以按功能划分
- 目录也可以按应用划分
因为我仅仅用
webpack
配置前端,所以我把webpack.config.js
放在了src
文件中学习webpack
使用webpack
1. 本地安装,不建议全局安装
npm install --save-dev webpack
npm install --save-dev webpack@<version> //特定版本
2. 设置npm script
"scripts": {
"start": "webpack --config webpack.config.js"
}
- 入口起点
(entry point)
指示webpack
应该使用哪个模块,来作为构建其内部依赖图的开始 - output 属性告诉
webpack
在哪里输出它所创建的bundles
,以及如何命名这些文件 - loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
- 插件(plugins)插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。
/**
* Created by yym on 2017/11/24.
*/
var webpack = require('webpack') // 引用webpack
var path = require('path') // node 内置path
module.exports = {
entry: path.join(__dirname, "js/app/index.js"), // 入口文件,相对于webpack.config.js的位置
output: { // 出口文件
filename: "index.js", // 文件名字
path: path.join(__dirname,"../public/js") // 出口位置
},
module: {
rules:[{ //一些规则
test : /\.less$/,
use: ["style-loader", "css-loader", "less-loader"]
}]
},
resolve: { // 解析
alias: { // 创建 import 或 require 的别名,来确保模块引入变得更简单。例如,一些位于 src/ 文件夹下的常用模块
jquery: path.join(__dirname,"js/lib/jquery.min.js"),
mod: path.join(__dirname,"js/mod"),
less: path.join(__dirname,"less")
}
},
plugins: [ //插件
new webpack.ProvidePlugin({ // 自动加载模块,而不必到处 import 或 require
$: "jquery"
})
]
}
为了自动监测webpack
变动,我们可以从npm
下载onchange
npm install --save onchange
"scripts": {
"watch": "onchange src/**/*.js src/**/*.less -- npm run webpack"
},
基本上写代码前的配置工作做到这里,后面如果有需要修改的地方,再慢慢修改
前端的备忘录,当我对这些进行删除,移动等操作时,我希望有提醒,写一个提醒组件
//提醒组件
require("less/toast.less");
function toast(message, time){
//信息
this.message = message;
//延迟时间
this.dismissTime = time||1000;
this.createNode();
this.showToast();
}
toast.prototype = {
//创建节点
createNode: function(){
var html = "<div class = 'toast'>" + this.message + "</div>";
this.$toast = $(html);
$('body').append(this.$toast);
},
//展示节点
showToast: function(){
var _this = this; // this指向变掉了
this.$toast.fadeIn(400, function(){
setTimeout(function(){
_this.$toast.fadeOut(400, function(){
_this.$toast.remove();
})
}, _this.dismissTime)
});
}
}
function Toast(message, time){
return new toast(message, time);
}
//暴露接口
window.Toast = Toast
module.exports.Toast = Toast;
还有几个组件的写法可以看代码
github地址src
下面就是备忘录的增删改查的处理,我们可以看一下路由
/*
* 路由设置 和后台约定接口
1. 获取所有的notes : /api/notes GET 数据req:{} 响应:res:{status:0,data:[{},{}]} {status:1,errorMsg:'失败的'原因}
2. 创建一个note: POST /api/notes/add 数据req{note: 'Hello'} 响应res :{status:0}
3. 修改一个note: POST /api/notes/edit 数据req{note: "new note", id:"100}
4. 删除一个note: POST /api/notes/delete 数据 req{id:100}
*
* */
- 我们看一下
app.js
里面的路由设置
// app.js
// 二级路由
var index = require('./routes/index');
var api = require('./routes/api');
//路由router/index
app.use('/', index);
// app.use('/users', users);
app.use('/api',api)
// index.js
// 如果是get请求,我们可以通过 req.query获得请求信息
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
console.log(req.query)
res.render('index', { title: 'Express' });
});
module.exports = router;
需要使用数据库来存储我们的数据,我用的是sequelize
// 开始
$ npm install --save sequelize
$ npm install --save sqlite3
// 连接
const path = require('path')
const Sequelize = require('sequelize');
const sequelize = new Sequelize(undefined, undefined, undefined, {
host: 'localhost',
dialect: 'sqlite',
// SQLite only 位置
storage: path.join(__dirname,'../database/database.sqlite'),
});
// 测试连接
sequelize
.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
//定义模型
/*
模型就是一个表,表里面是数据结构
对应条目:
1 hello 12345 3435366 id text Time
*/
const Note = sequelize.define('note', {
text: {
type: Sequelize.STRING
},
});
// force: true 如果表已经存在,将会丢弃表
// {raw:true} 得到真实的数据
// where :{id:2} 查询某一个
Note.sync().then(function(){
//创建数据
Note.create({text:'Hello World'})
}).then(function(){
//查找数据
Note.findAll({raw:true}).then(function(notes) {
console.log(notes)
})
});
看看路由怎么写
// api.js
var express = require('express');
var router = express.Router();
var Note = require('../model/note.js').Note
/* GET users listing. */
router.get('/notes', function(req, res, next) {
Note.findAll({raw:true}).then(function(notes){
console.log(notes)
res.send({status:0,data:notes})
})
});
//增加创建
router.post('/notes/add',function(req,res,next){
var note = req.body.note // post请求的信息
Note.create({text:note}).then(function(note) {
res.send({status:0})
}).catch(function(){
res.send({status:1,errMessage:'数据库出错'})
})
})
//修改,更新 update 或者 save
router.post('/notes/edit',function(req,res,next){
Note.update({text: req.body.note},{where: {id: req.body.id}}).then(function(){
console.log(arguments)
res.send({status:0})
}).catch(function(){
res.send({status:1,errMessage:'数据库出错'})
})
})
//删除
router.post('/notes/delete',function (req,res,next) {
Note.destroy({where:{id:req.body.id}}).then(function(){
res.send({status:0})
}).catch(function(){
res.send({status:1,errMessage:'数据库出错'})
})
})
module.exports = router;
项目到这里创建 删除 保存 更新等功能已经可以用了,可以自己修改自己喜欢的样式,自己添加功能
使用第三方github做登录/注册





上面部分内容讲了一点,没有具体讲,有问题可以看代码
github项目地址
欢迎star,给个小星星
还需完善,还能做什么???
修改UI
添加聊天功能
添加弹幕功能
清除所有note的功能
-
给note增加提醒的功能
chrome插件的Notification
iOS Android等移动端应用
网友评论