下面是我在学习HTML和CSS的时候整理的一些笔记,有兴趣的可以看下:
进阶阶段
进阶阶段,开始攻 JS,对于刚接触 JS 的初学者,确实比学习 HTML 和 CSS 有难度,但是只要肯下功夫,这部分对于你来说,也不是什么大问题。
JS 内容涉及到的知识点较多,看到网上有很多人建议你从头到尾抱着那本《JavaScript高级程序设计》学,我是不建议的,毕竟刚接触 JS 谁能看得下去,当时我也不能,也没那样做。
我这部分的学习技巧是,增加次数,减少单次看的内容。就是说,第一遍学习 JS 走马观花的看,看个大概,去找视频以及网站学习,不建议直接看书。因为看书看不下去的时候很打击你学下去的信心。
然后通过一些网站的小例子,开始动手敲代码,一定要去实践、实践、实践,这一遍是为了更好的去熟悉 JS 的语法。别只顾着来回的看知识点,眼高手低可不是个好习惯,我在这吃过亏,你懂的。
1、JavaScript 和 ES6
在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。
2、前端框架
前端框架太多了,真的学不动了,别慌,其实对于前端的三大马车,Angular、React、Vue 只要把其中一种框架学明白,底层原理实现,其他两个学起来不会很吃力,这也取决于你以后就职的公司要求你会哪一个框架了,当然,会的越多越好,但是往往每个人的时间是有限的,对于自学的学生,或者即将面试找工作的人,当然要选择一门框架深挖原理。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
以 Vue 为例,我整理了如下的面试题。
})
Events.trigger(‘loginsuccess’)
Events.trigger(‘loginsuccess’)
## File System
* 得到文件与目录的信息:stat
* 创建一个目录:mkdir
* 创建文件并写入内容:writeFile,appendFile
* 读取文件的内容:readFile
* 列出目录的东西:readdir
* 重命名目录或文件:rename
* 删除目录与文件:rmdir,unlink
const fs = require(‘fs’);
//创建一个文件,添加内容,异步方式,回调函数:错误优先的原则
fs.writeFile(‘./log.txt’, ‘hello world’, function (err) {
})
//同步创建文件,不用写回调函数
fs.writeFileSync(‘./log1.txt’, ‘hello’)
//异步删除文件
fs.unlink(‘./log1.txt’, function () {
})
//同步删除文件
fs.unlinkSync()
//修改文件的名字
fs.renameSync(‘log.txt’, ‘lognew.txt’)
console.log(‘hello world’)
//追加内容
fs.appendFileSync(‘lognew.txt’, ‘gp18’)
//文件内容的读取
let rs = fs.readFileSync(‘lognew.txt’)
console.log(rs.toString());
//文件夹
//创建文件夹
if (!fs.existsSync(‘./log’)) {//如果不存在文件夹,就创建一个
fs.mkdirSync(‘./log’)
}
fs.writeFileSync(‘./log/1.txt’, ‘hello world !’);
//如果文件内,存在内容,不能直接删除
fs.rmdirSync(‘./log’)
//删除文件夹使用递归
//删除文件夹
function delfile(src) {
//读取文件的状态信息
var rs = fs.statSync(src);
if (rs.isDirectory()) {
//读取文件夹下的数据
var files = fs.readdirSync(src)
files.forEach((item, index) => {
let curPath = src + ‘/’ + item;
//if (fs.statSync(curPath).isDirectory()) {
delfile(curPath);
//} else {
// fs.unlinkSync(curPath);
//}
})
fs.rmdirSync(src);
} else {
fs.unlinkSync(src)
}
}
delfile(‘./log’)
json的基本操作
const fs = require(‘fs’);
var data = require(‘./data.json’)
let user = {
name: ‘wanghao’,
age: 20
}
//创建并添加内容
// fs.writeFileSync(‘data.json’, JSON.stringify(user));
console.log(data);
//修改json文件的内容
data.address = ‘beijing’;
fs.writeFileSync(‘data.json’, JSON.stringify(data));
### Stream
读取文件流
可读流的事件
可写的文件流
pipe链式使用
pipe
const fs = require(‘fs’);
const zlib = require(‘zlib’);
fs.writeFileSync(‘log.txt’, ‘gp18’);
fs.createReadStream(‘log.txt’)
.pipe(zlib.createGzip())//这时候压缩文件还在内存中
.pipe(fs.createWriteStream(‘log.txt.gzip’));//输出到物理目录
## crypto数据加密
crypto模块的目的是为了提供通用的加密和哈希算法。用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢。Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。
### MD5和SHA1
MD5是一种常用的哈希算法,用于给任意数据一个“签名”。这个签名通常用一个十六进制的字符串表示.
const crypto = require(‘crypto’);
const hash = crypto.createHash(‘md5’);
hash.update(‘hello world’);
console.log(hash.digest(‘hex’));
### Hmac
Hmac算法也是一种哈希算法,它可以利用MD5或SHA1等哈希算法。不同的是,Hmac还需要一个密钥;
只要密钥发生了变化,那么同样的输入数据也会得到不同的签名,因此,可以把Hmac理解为用随机数“增强”的哈希算法。
const crypto = require(‘crypto’);
const hash = crypto.createHmac(‘sha256’, ‘secret-key’);
hash.update(‘hello world’);
console.log(hash.digest(‘hex’));
### AES
对称加密算法,加密和解密都用相同的秘钥
const crypto = require(‘crypto’);
//数据加密
function aesEncrypt(data, key) {
//用指定的算法和秘钥,返回一个cipher对象
const cipher = crypto.createCipher(‘aes192’, key)
var crypted = cipher.update(data, ‘utf8’, ‘hex’)
crypted += cipher.final(‘hex’);
return crypted;
}
//数据解密
function aesDecrypt(encrypted, key) {
const decipher = crypto.createDecipher(‘aes192’, key)
var decrypted = decipher.update(encrypted, ‘hex’, ‘utf8’);
decrypted += decipher.final(‘utf8’)
return decrypted;
}
var data = ’ hello gp18’;
var key = ‘password’;
//d:加密数据
var encrypted = aesEncrypt(data, key)
console.log(‘encrypted:’, encrypted)
//d:解密数据
var decrypted = aesDecrypt(encrypted, key)
console.log(‘decrypted:’, decrypted)
## 路由
### 入门
通过启动一个服务访问index.html页面,并且加载图片和css资源
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719122206186.png)
const http = require(‘http’);
const fs = require(‘fs’)
const data = require(‘./user.json’)
http.createServer((req, res) => {
var url = req.url;
//d:设置默认路径加载 index.html
if (url === ‘/’) {
url = ‘/index.html’
}
if (url.indexOf(‘favicon.ico’) > -1) {
res.end(‘’)
}
//d:获取该服务下的完整路径
var fullpath = __dirname + url;
console.log(url);
//d:通过url判断文件类型
switch (url) {
case “/index.html”:
res.setHeader(‘Content-Type’, ‘text/html’);
break;
case “/logo.png”:
res.setHeader(‘Content-Type’, ‘image/png’);
break;
case “/index.js”:
res.setHeader(‘Content-Type’, ‘application/x-javascript’);
break;
case “/api/getlist”:
res.setHeader(‘Content-Type’, ‘application/json;chartset=utf-8;’)
res.write(JSON.stringify(data))
res.end()
return;
}
//d:读取路由内容并输出
let result = fs.readFileSync(fullpath)
res.write(result);
res.end()
})
.listen(3000, function () {
console.log(‘localhost 3000 start…’)
})
### 静态资源服务实战
d:步骤:
1、在本地启动一个server,等待来自客户端的请求
2、当请求抵达时,根据请求的url,设置静态资源的路径为`www`,映射到文件的位置
3、检查文件是否存在,如果不存在,返回错误页面,如果存在
* 判断文件是文件还是文件夹,打开文件待读取
* 设置response header
* 发送文件到客户端
4、等待来自客户端的下一个请求
Server.js
const http = require(‘http’);
const content = require(‘./util/content’)
const proxy = require(‘http-proxy-middleware’)
const mimeTypes = require(‘./util/mimeTypes’)
const path = require(‘path’);
//静态资源的路径
const statPath = __dirname + ‘/www’;
//解决History强制刷新的问题
function refershHistory(res) {
res.writeHead(302, {
‘location’: ‘http://localhost:3000/’
})
res.end();
return false;
}
//设置代理
function setProxy(url, req, res) {
if (//api/.test(url)) {
console.log(‘proxy’)
let options = {
target: ‘http://localhost:3005’,
changeOrigin: true,
pathRewrite: {
‘^/api’: ‘’
}
}
let statProxy = proxy(options);
return statProxy(req, res)
}
if (//static/.test(url)) {
console.log(‘proxy’)
let options = {
target: ‘https://www.lgstatic.com’,
changeOrigin: true,
pathRewrite: {
‘^/static’: ‘’
}
}
let statProxy = proxy(options);
return statProxy(req, res)
}
}
var app = http.createServer((req, res) => {
let url = req.url;
//默认索引页
if (url === ‘/’) {
url = “/index.html”
}
//history强制刷新问题
if (/?position|search|profile/.test(url)) {
return refershHistory(res);
}
//代理
if (//api/.test(url) || //static/.test(url)) {
return setProxy(url, req, res);
}
let extname = path.extname(url).substring(1);
let conentType = mimeTypes[extname] ? mimeTypes[extname] : “text/html”;
res.setHeader(‘Content-Type’, conentType)
let result = content(url, statPath);
res.write(result);
res.end();
})
app.listen(3000, function (err) {
if (!err) {
console.log(‘localhost 3000 start …’)
}
})
util/content.js 根据url读文件内容
const fs = require(‘fs’);
//d:statPath绝对路径
function content(src, statPath) {
let fullPath = statPath + src;
console.log(‘fullPath:’, fullPath)
//d:判断是文件夹还是文件
if (fs.existsSync(fullPath)) {
let stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
return readDir(fullPath);
} else {
return fs.readFileSync(fullPath);
}
} else {
return ‘file not found’
}
}
//d:读取文件夹里内容
function readDir(src) {
let files = fs.readdirSync(src);
let result = [‘
-
’];
files.forEach((item, index) => {
result.push(<li>${item}</li>
)
})
result.push(‘
return result.join(’ ')
}
module.exports = content;
util/mimeType.js
let mimes = {
‘css’: ‘text/css’,
‘less’: ‘text/css’,
‘gif’: ‘image/gif’,
‘html’: ‘text/html’,
‘ico’: ‘image/x-icon’,
‘jpeg’: ‘image/jpeg’,
‘jpg’: ‘image/jpeg’,
‘js’: ‘text/javascript’,
‘map’: ‘text/javascript’,
‘json’: ‘application/json’,
‘pdf’: ‘application/pdf’,
‘png’: ‘image/png’,
‘svg’: ‘image/svg+xml’,
‘swf’: ‘application/x-shockwave-flash’,
‘tiff’: ‘image/tiff’,
‘txt’: ‘text/plain’,
‘wav’: ‘audio/x-wav’,
‘wma’: ‘audio/x-ms-wma’,
‘wmv’: ‘video/x-ms-wmv’,
‘xml’: ‘text/xml’,
‘woff2’: ‘application/octet-stream’,
‘woff’: ‘application/octet-stream’,
‘ttf’: ‘application/octet-stream’
}
module.exports = mimes;
###
## socket
### websocket
<https://www.runoob.com/html/html5-websocket.html>
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200720213721494.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)
d:
#### websocket实现思路
* new WebSocket, WebSocket 有自己独有的协议`ws`
* WebSocket服务端使用 `ws第三方模块`,接收客户端发来的信息并做处理返回给客户端
websocket的五步法:
第一步:new WebSocket(“ws://localhost:9998/echo”); 打开一个websocket
第二步:onopen :连接建立时触发
第三步:onmessage:客户端接收服务端数据时触发
第四步:onerror:通信发生错误时触发
第五步:close:连接关闭时触发
#### 实现原理
##### index.html
##### websocketServer.js
`ws`第三方模块<https://www.npmjs.com/package/ws>
const ws = require(‘ws’);
var websocketServer = new ws.Server({ port: 8099 });
//所有的客户端列表
var clientlist = {}
var id = 0;
websocketServer.on(‘connection’, (client) => {
client.id = id++;
clientlist[id] = client;
console.log(‘connection…’)
client.send(‘welcome to back’)
client.on(‘message’, (msg) => {
console.log(msg)
boardcast(client.id + “:” + msg);
})
//client退出时的事件
client.on(‘close’, () => {
boardcast(client.id + " 下线了");
delete clientlist[client.id];
})
})
//广博通知,所有客户端
function boardcast(message) {
for (let o in clientlist) {
clientlist[o].send(message)
}
}
### Socket.io
### Net
## Express介绍和安装
<https://www.expressjs.com.cn/>
这个翻译的版本比较好<http://caibaojian.com/expressjs/index.html>
npm install express --save
### helloworld
const express = require(‘express’);
const app = express();
app.get(‘/’, (req, res) => {
res.send(‘hello world’);// res.write + res.end
})
app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})
### 路由
const express = require(‘express’);
const app = express();
app.get(‘/’, (req, res) => {
res.send(‘hello world’);// res.write + res.end
})
app.post(‘/’, (req, res) => {
res.write(‘post hello world’);
res.end()
})
app.put(‘/’, (req, res) => {
res.send(‘put hello world’)
})
app.delete(‘/’, (req, res) => {
res.send(‘delete hello world’)
})
app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})
### 静态文件
文件目录结构
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200720225907241.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)
const express = require(‘express’);
const path = require(‘path’)
const app = express();
//可以配置多个静态资源目录, d:静态资源目录可以直接用server+文件名进行访问
app.use(express.static(‘public’))
// app.use(express.static(‘files’))
//可以给目录添加前缀
// app.use(‘/static’, express.static(‘files’))
//配置为绝对路径 d:当server目录和静态资源目录不在同级下时,可以配置绝对路径
app.use(‘/static’, express.static(path.resolve(__dirname, ‘./files’)))
app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})
### 中间件
* 执行任何代码
* 修改请求和响应对象
* 决定是否执行或结束请求响应周期
* 调用堆栈中的下一个中间件
const express = require(‘express’);
const path = require(‘path’)
const app = express();
var myLogger = function (req, res, next) {
console.log(‘log …’)
//转向下一个路由,中间件
next();
}
var requestTime = function (req, res, next) {
console.log(new Date().getTime())
next();
}
//应用中间件,中间件有前后顺序
app.use(requestTime, myLogger);
// app.use(myLogger);
app.get(‘/’, function (req, res) {
res.send(‘hello world’);
})
app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})
#### 自定义中间件外部引入
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200720232619702.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)
myself-middleware.js
module.exports = function (){
return function (req,res,next){
console.log(“myselt middleware”)
next()
}
}
app.js内导入
const mySelfMidd = require(“./myself-middleware.js”)
app.use(mySelfMidd )
### 使用中间件
#### 应用程序中间件
const express = require(‘express’);
const app = express();
//应用中间件
// app.use(‘*’, function (req, res, next) {
// console.log(‘method:’, req.method);
// console.log(‘middleware:’, req.params)
// next();
// });
app.use(‘*’, function (req, res, next) {
console.log(1)
next();
}, function (req, res, next) {
console.log(2)
next();
});
app.get(‘/user/:id/books/:bookid’, function (req, res) {
console.log(‘get:’, req.params)
res.send(‘hello world’);//d:直接返回
})
app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})
#### 路由中间件
##### app.js
const express = require(‘express’);
const bodyParser = require(‘body-parser’);
const userRouter = require(‘./user’);//d:导入user模块
const app = express();
app.use(‘/static’, express.static(‘files’))
app.use(function (req, res, next) {
console.log(‘application middleware …’)
next();
})
//extended: false 表示是否使用系统模块 querystring ,官方推荐
//extended: true 使用第三方qs来处理
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())//d:最终输出的数据都是以json输出的
//d:中间件是有前后顺序的,使用body-parser需要放在路由的user模块之前,当使用路由中间件的时候才会成功使用body-parser
app.use(‘/user’, userRouter)//d:使用user模块,添加了一个 /user 的前缀
//错误优先的原则
app.use(function (err, req, res, next) {
console.log(err.stack);
res.status(200).send(‘somting is wrong!’)
})
app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})
##### user.js(用户的路由中间件的模块)
const express = require(‘express’);
var router = express.Router();
//针对user下所有的路由接口
router.use(function (req, res, next) {
//获取传过来的用户信息
//let username = req.body.username;
//从数据库查询
//let rs = db.getUserinfo(uername)
// if(rs){next()}
// else {
// res.send(‘用户不存在’)
// }
console.log(‘权限验证’)
next();
})
//针对user下 /:id 的接口做权限验证
router.use(‘/:id’, function (req, res, next) {
console.log(‘id 权限验证’)
next();
})
//http://localhost:3000/user/10
// router.get(“/:id”, function (req, res) {
// console.log(req.params.id)
// res.send(req.params.id)
// })
//d:获取名字的接口
router.get(‘/getname’, function (req, res) {
// res.setHeader(‘Content-Type’,‘’)
console.log(“get name …”)
//d:可以直接使用json返回
res.json({
name: ‘肖战’,
age: 20
})
})
//crud: create read update delete
//数据的添加,消息体在body上
//建议全部更新
router.post(‘/add’, function (req, res) {
//用req.body获取post数据,需要装body-parser中间件
console.log(req.body);
res.send(req.body)
})
//获取数据,请求的参数在url地址上,在不同的浏览器上有长度的限制
//长度的限制是浏览器限制的,不是http协议限制的
//http://localhost:3000/user/getinfo?username=hanye&age=20
router.get(‘/getinfo’, function (req, res) {
//req.query 不需要装任何中间件,或者配置
console.log(req.query)
res.send(req.query)
})
//数据的更新,消息体在body 上
//建议全部更新
router.put(‘/r1’, function (req, res) {
res.send(‘r1’)
});
//数据的更新,消息体在body 上
//建议部分更新 {name:‘zhangsan’,age:20,address:“beijing”}
router.patch(‘/r2’, function (req, res) {
res.send(‘r2’)
})
//数据的删除,消息体在body上
router.delete(‘/r3’, function (req, res) {
res.send(‘r3’)
})
//数据的协商,测试服务端的一些功能
router.options(‘/r4’, function (req, res) {
res.send(‘r4’)
})
// head
// 类似于get请求,返回的响应中没有类容,用于获取报头
router.get(‘/r5’, function (req, res) {
throw new Error(‘error message’)
})
module.exports = router;
#### 异常处理中间件
通常写在最后面,参数必须是四个
router.get(‘/r5’, function (req, res) {
throw new Error(‘error message’)//抛出异常
})
//错误优先的原则
app.use(function (err, req, res, next) {
console.log(err.stack);
res.status(200).send(‘somting is wrong!’)
})
#### 内置中间件
express.static //静态资源的设置,html,图片,。。.
express.json //解析传入的的数据请求,为json格式
express.urlencoded parses incoming requests with URL-encoded payloads. NOTE: Available with Express 4.16.0+
#### 第三方中间件
官方推荐:<https://www.expressjs.com.cn/resources/middleware.html>
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
#### 练习
get: http://localhost:3000/user/42
http://localhost:3000/users/34/books/8989
http://localhost:3000/flights/LAX-SFO
埋点:http://localhost:3000/user/hm.gif?id=1&keyword=
Post: http://localhost:3000/user/add {username:‘xiaoming’,age:20}
const express = require(‘express’);
var router = express.Router();
//http://localhost:3000/user/42
// router.get(‘/:id’, (req, res) => {
// res.send(req.params.id)
// })
//http://localhost:3000/user/66/books/88
router.get(‘/:id/books/:bookid’, (req, res) => {
res.json({
id: req.params.id,
bookid: req.params.bookid
})
})
// http://localhost:3000/user/flights/LAX-SFO
router.get(‘/flights/:from-:to’, (req, res) => {
res.send({
from: req.params.from,
to: req.params.to,
})
})
//http://localhost:3000/user/hm.gif?id=1&keyword=china
router.get(‘/hm.gif’, (req, res) => {
res.send(req.query)
})
//http://localhost:3000/user/add
router.post(‘/add’, (req, res) => {
res.send({
code: 1,
message: ‘数据获取成功’,
data: req.body //需要装第三方中间件,body-parser
})
})
module.exports = router;
### express generator
搭建框架
`express --view==ejs ./`
安装依赖
`npm install -g express-generator`
//异常处理
var createError = require(‘http-errors’);
var express = require(‘express’);
var path = require(‘path’);
var cookieParser = require(‘cookie-parser’);
//日志处理模块
var logger = require(‘morgan’);
var indexRouter = require(‘./routes/index’);
var usersRouter = require(‘./routes/users’);
var app = express();
// view engine setup
//指定模板存储的位置
app.set(‘views’, path.join(__dirname, ‘views’));
app.set(‘view engine’, ‘ejs’);
app.use(logger(‘dev’));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, ‘public’)));
app.use(‘/’, indexRouter);
app.use(‘/users’, usersRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404, ‘file not found!’));
});
// 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(500);
//参数是模板的名字
res.render(‘error’);
});
module.exports = app;
## Ejs
### 什么是EJS
EJS是一个简单高效的模板语言,通过数据和模板,可以生成HTML标记文本。可以说EJS是一个JavaScript库,EJS可以同时运行在客户端和服务器端,客户端安装直接引入文件即可,服务器端用npm包安装。
#### EJS的特点
* 快速编译和渲染
* 简单的模板标签
* 自定义标记分隔符
* 支持文本包含
* 支持浏览器端和服务器端
* 模板静态缓存
* 支持express视图系统
#### EJS的成员函数
Render(str,data,[option]):直接渲染字符串并生成html
str:需要解析的字符串模板
data:数据
option:配置选项
#### EJS的常用标签
<% %>流程控制标签
<%= %>输出标签(原文输出HTML标签)
<%- %>输出标签(HTML会被浏览器解析)
<%# %>注释标签
% 对标记进行转义
#### Includes
## MongoDB
<https://www.mongodb.com/download-center/community>
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
它的特点:高性能、易部署、易使用,存储数据非常方便。
### 在Windows系统上安装
为了从命令提示符下运行MongoDB服务器,你必须从MongoDB目录的bin目录中执行mongod.exe文件。
或者将bin配置到环境变量path中。
>
> mongod --dbpath d:\data\db
>
>
>
安装不成功的原因:
1:操作系统版本较低,dll缺失,建议装3.6版本
2:闪退 (cmd : 进入到安装目录 的bin目录,执行 mongod.exe ,看详细的错误信息 )
### 在Mac系统上安装
在Mac OS上面安装MongoDB,你可以通过编译源代码来安装 ,也可以在Mac OS上使用Homebrew安装。
使用Homebrew安装MongoDB:
方法一:$ brew install mongodb ( brew install mongodb-community@4.0 )
方法二:https://github.com/mongodb/homebrew-brew
启动:
mongod --config /usr/local/etc/mongod.conf
### MongoDB术语/概念
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200724194003144.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200724193953637.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)
一个mongodb中可以建立多个数据库。
MongoDB的默认数据库为"db",该数据库存储在data目录中。
MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。
### MongoDB 集合
集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。
集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。
### MongoDB 文档
文档是一个键值(key-value)对(即BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。
一个简单的文档例子如下:
{“genres”: [“犯罪”,“剧情” ],“title”: “肖申克的救赎”}
### MongoDB 数据类型
* Object ID :Documents 自生成的 \_id
* String: 字符串,必须是utf-8
* Boolean:布尔值,true 或者false
* Integer:整数 (Int32 Int64 你们就知道有个Int就行了,一般我们用Int32)
* Double:浮点数 (没有float类型,所有小数都是Double)
* Arrays:数组或者列表,多个值存储到一个键
* Object:如果你学过Python的话,那么这个概念特别好理解,就是Python中的字典,这个数据类型就是字典
* Null:空数据类型 , 一个特殊的概念,None Null
* Timestamp:时间戳
* Date:存储当前日期或时间unix时间格式 (我们一般不用这个Date类型,时间戳可以秒杀一切时间类型)
### 数据库常用命令
1. (1)Help查看命令提示
2. help
3. db.help()
4. db.test.help()
5. db.test.find().help()
6. (2)创建/切换数据库
7. use music
8. (3)查询数据库
9. show dbs
10. (4)查看当前使用的数据库db/db.getName()
11. (5)显示当前DB状态
12. db.stats()
13. (6)查看当前DB版本
14. db.version()
15. (7)查看当前DB的链接机器地址
16. db.getMongo()
17. (8)删除数据库
18. db.dropDatabase()
### Collection集合操作
1. (1)创建一个集合
2. db.createCollection(“collName”, {size: 20, capped: true, max: 100});
3. db.collName.isCapped(); //判断集合是否为定容量
4. (2)得到指定名称的集合
5. db.getCollection(“account”);
6. (3)得到当前db的所有集合
7. db.getCollectionNames();
8. (4)显示当前db所有集合的状态
9. db.printCollectionStats();
### 添加、修改与删除集合数据
(1)添加
db.users.save({name:‘zhangsan’,age:25,sex:true})
db.users.save({name:‘lisi’,age:20,sex:true,address:‘beijing’})
(2)修改
//1:查询条件
//2:更新字段
//3: 是否需要将参数2插入到集合当中,如果没有查询到记录,配置为false,否则为true
//4:更新一条,还是多条, true:多条记录,false:单条记录
db.users.update({age:25},{$set:{name:‘changeName’}},false,true)
(3)删除
db.users.remove({age:23})
### 集合数据查询(一)
(1)查询所有记录
db.users.find()
(2)查询去重后数据
db.users.distinct(‘name’)
(3)查询age = 20的记录
db.users.find({age:20})
(4)查询age > 22的记录
db.users.find({age:{$gt:22}})
(5)查询age < 22的记录
db.users.find({age:{$lt:22}})
(6)查询age >= 23的记录
db.users.find({age:{$gte:23}})
(7)查询age <= 23的记录
db.users.find({age:{$lte:23}})
(8)查询age >= 23 并且 age <= 25
db.users.find({age:{
g
t
e
:
23
,
gte:23,
gte:23,lte:25}})
(9)查询name中包含 change的数据
db.users.find({name:/change/})
mysql:select * from users where name ‘%change%’
(10)查询name中以ch开头的
db.users.find({name:/^ch/})
### 集合数据查询(二)
(11)查询指定列name、age数据
db.users.find({},{name:1,age:1,_id:0})
(12)查询指定列name、age数据, age > 23
db.users.find({age:{$gt:23}},{name:1,age:1,_id:0}
(13)按照年龄排序
升序:db.users.find({},{name:1,age:1,_id:0}).sort({age:1})
降序:db.users.find({},{name:1,age:1,_id:0}).sort({age:-1})
(14)查询name = lisi, age = 20的数据
db.users.find({name:‘lisi’,age:20},{name:1,age:1,_id:0})
(15)查询前3条数据
db.users.find().limit(3)
### 集合数据查询(三)
(16)查询5条以后的数据
db.users.find(),skip(5)
(17)查询在3-5之间的数据
db.users.find().limit(3).skip(2)
(18)or与 查询
db.users.find({$or:[{age:25},{age:23}]})
(19)查询第一条数据
db.users.findOne()
(20)查询某个结果集的记录条数
db.users.find({age:20}).count()
### 案例练习
导入数据:
db.movies.insertMany([{},{}])
//查询所有数据
db.movies.find()
//查询电影列
db.movies.find({},{title:1,_id:0})
//查询电影名称、年份 , 评分
db.movies.find({},{title:1,year:1,_id:0,‘rating.average’:1})
//按照评分排序
db.movies.find({},{title:1,year:1,_id:0,‘rating.average’:1}).sort({‘rating.average’:-1})
//按照年份排序
db.movies.find({},{title:1,year:1,_id:0,‘rating.average’:1}).sort({year:-1})
//模糊查询
db.movies.find({title:/人/},{title:1,_id:0})
//获取总条数
db.movies.find({title:/人/},{title:1,_id:0}).count()
//根据翻页获取指定页面的数据
db.movies.find({},{title:1,_id:0}).skip(5).limit(5)
### Node连接mongoDB
db.js
const mongoose = require(‘mongoose’);
mongoose.connect(‘mongodb://127.0.0.1:27017/games’, {
useNewUrlParser: true,
useUnifiedTopology: true
})
var db = mongoose.connection;
db.on(‘error’, console.error.bind(console, ‘connection error:’));
db.once(‘open’, function () {
console.log(‘open…’)
})
module.exports = mongoose;
Index.js
const db = require(‘./db’);
var UserModel = db.model(‘users’, {
name: String,
age: Number,
sex: Boolean,
address: String
})
async function find() {
let rs = await UserModel.find({});
console.log(rs);
}
find();
function add() {
UserModel.insertMany([{ name: ‘user5’, age: 20 }, { name: ‘user6’, age: 21 }], function (err, docs) {
console.log(docs)
})
}
// add();
// async function update() {
// let rs = await UserModel.update({ name: ‘user6’ }, { $set: { age: 31 } })
// console.log(rs);
// }
// update();
// async function del() {
// let rs = await UserModel.remove({ name: “user6” })
// console.log(rs);
// }
// del()
## webpack
官网<https://www.webpackjs.com/concepts/>
### 核心概念
Entry :入口
output:出口
Plugins: 插件,执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量
Loader:翻译官,把浏览器不识别的内容做转换
### 研发环境
yarn add webpack webpack-cli //基础依赖
yarn add webpack-dev-server -D //热更新
yarn add mini-css-extract-plugin -D//将css文件提取为独立的文件的插件
yarn add html-webpack-plugin -D // 将模板文件和js文件整合到一块
yarn add sass-loader node-sass -D
##### webpack常用的插件和常用的 loader有哪些
**插件:**
mini-css-extract-plugin
html-webpack-plugin
**loader**
babel-loader
style-loader
css-loader
sass-loader
#### 自定义配置文件
创建webpack.config.dev.js 配置开发环境
添加快捷指令
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020072419573893.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)
webpack.config.dev.js
const path = require(‘path’)
const htmlWebpackPlugin = require(‘html-webpack-plugin’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
module.exports = {
//开发模式:development,代码调试, 生产模式:production ,代码压缩,优化
//如果mode不配置,会有警告提示信息
mode: “development”,
//代码调试,可以看到源代码
devtool: ‘inline-source-map’,
//入口文件,如果不配置,默然找根目录下 /src/index.js
// entry:“./src/js/index.js”,
entry: {//多页面,两个入口
‘main’: “./src/js/index.js”,
‘detail’: “./src/js/detai.js”
},
//打包完成,输出文件的位置(不能写相对路径),可以不配置,默认输出到dist目录
output: {
path: path.resolve(__dirname, ‘./dev’),
filename: ‘[name]-[hash].js’
},
//d:热更新
devServer: {
port: 9099,
//打开浏览器
open: true
},
// d:将模板文件和js文件整合到一块
plugins: [
new htmlWebpackPlugin({
title: ‘webpack demo home’,
//模板文件路径
template: “./src/views/index.html”,
//自动存储到output 配置的目录
filename: ‘index.html’,
chunks: [‘main’]//指定模块,让index.html的页面的内容只加载该页面对应的js的内容,如果不加的话也会同时加载detail页面的内容
}),
//d:多页面配置
new htmlWebpackPlugin({
title: ‘webpack demo home’,
//模板文件路径
template: “./src/views/detail.html”,
//自动存储到output 配置的目录
filename: ‘detail.html’,
chunks: [‘detail’]
}),
//d:将css文件提取为独立的文件的插件
new MiniCssExtractPlugin({
//页面引用的样式文件名
filename: ‘[name]-[hash].css’,
// chunkFilename: ‘common.css’,
})
],
module: {
rules: [
{
test: /.s[ac]ss$/,
//执行顺序:从右向左
use: [
// 将 JS 字符串生成为 style 节点
‘style-loader’,
// MiniCssExtractPlugin.loader, //这个和style-loader二者选其一,都是使用css的方式
//将 CSS 转化成 CommonJS 模块
‘css-loader’,
//把.scss文件文件转换为.css文件
‘sass-loader’
]
}
]
}
}
### 生产环境
## 项目实战
### 架构设计
#### 最后
-------------------------------------------------------------
**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**
大厂面试问深度,小厂面试问广度,如果有同学想进大厂深造一定要有一个方向精通的惊艳到面试官,还要平时遇到问题后思考一下问题的本质,找方法解决是一个方面,看到问题本质是另一个方面。还有大家一定要有目标,我在很久之前就想着以后一定要去大厂,然后默默努力,每天看一些大佬们的文章,总是觉得只有再学深入一点才有机会,所以才有恒心一直学下去。
![](https://img-blog.csdnimg.cn/img_convert/718310d106ab948d6f467d78e08b1aed.png)