node.js(1)

1. Node.js是什么

1.1 概述

官网:https://nodejs.org

  • Node 不适合从来没有接触过服务端的人学习
  • 如果想要真正的学好服务端,还是老牌的 Java、PHP 这些平台
  • Node 不是特别适合入门服务端,但不代表 Node 不强大
  • Node 很厉害,具有经验的人可以玩儿的非常的牛
  • 不适合新手的原因就在于比较偏底层、而且太灵活
  • Java、PHP 好入门的原因就在于:这些平台屏蔽了一些底层
Node.js®是基于Chrome的V8 JavaScript引擎构建的JavaScript运行时(官方)
  • Node.js是JavaScript 运行时
  • 通俗易懂的讲,Node.js是JavaScript的运行平台(运行环境)
  • Node.js既不是语言,也不是框架,它是一个平台

1.2 特征:

1>构建于Chrome的V8引擎之上

  • 代码只是具有特定格式的字符串
  • 引擎可以认识它,帮你解析和执行
  • Google Chrome的V8引擎是目前公认的解析执行JavaScript代码最快的
  • Node.js的作者把Google Chrome中的V8引擎移植出来,开发了一个独立的JavaScript运行时环境

2>Node.js uses an envent-driven,non-blocking I/O mode that makes it lightweight and efficent.

  • envent-driven 事件驱动
  • non-blocking I/O mode 非阻塞I/O模型(异步)
  • ightweight and efficent. 轻量和高效

3>Node.js package ecosystem,npm,is the larget scosystem of open sourcr libraries in the world

  • npm 是世界上最大的开源生态系统
  • 绝大多数JavaScript相关的包都存放在npm上,这样做的目的是为了让开发人员更方便的去下载使用
  • npm install jquery

1.3 浏览器中的JavaScript

  • EcmaScript
    • 基本语法
    • if
    • var
    • function
    • Object
    • Array
  • Bom
  • Dom

1.4 Node.js中的JavaScript

  • 没有Bom,Dom
//报错
console.log(window)
console.log(document)
  • EcmaScript
    • 变量
    • 方法
    • 数据类型
    • 内置对象
    • Array
    • Object
    • Date
    • Math
    • 模块系统
      • 在 Node 中没有全局作用域的概念
      • 在 Node 中,只能通过 require 方法来加载执行多个 JavaScript 脚本文件
      • require 加载只能是执行其中的代码,文件与文件之间由于是模块作用域,所以不会有污染的问题
        • 模块完全是封闭的
        • 外部无法访问内部
        • 内部也无法访问外部
      • 模块作用域固然带来了一些好处,可以加载执行多个文件,可以完全避免变量命名冲突污染的问题
      • 但是某些情况下,模块与模块是需要进行通信的
      • 在每个模块中,都提供了一个对象:exports
      • 该对象默认是一个空对象
      • 你要做的就是把需要被外部访问使用的成员手动的挂载到 exports 接口对象中
      • 然后谁来 require 这个模块,谁就可以得到模块内部的 exports 接口对象
      • 还有其它的一些规则,具体后面讲,以及如何在项目中去使用这种编程方式,会通过后面的案例来处理
    • 核心模块
      • 核心模块是由 Node 提供的一个个的具名的模块,它们都有自己特殊的名称标识,例如
        • fs 文件操作模块
        • http 网络服务构建模块
        • os 操作系统信息模块
        • path 路径处理模块
        • 。。。。
      • 所有核心模块在使用的时候都必须手动的先使用 require 方法来加载,然后才可以使用,例如:
        • var fs = require('fs')

2. 安装Node环境

  • 查看Node环境的版本号
  • 下载:https://nodejs.org/en/
  • 安装:
    • 傻瓜式安装,一路next
    • 安装过再次安装会升级
  • 确认Node环境是否安装成功
    • 查看node的版本号:node --version
    • 或者node -v
  • 配置环境变量

3. 解析执行JavaScript

  1. 创建编写JavaScript脚本文件
  2. 打开终端,定位脚本文件的所属目录
  3. 输入node 文件名执行对应的文件

注意:文件名不要用node.js来命名,也就是说除了node这个名字随便起,最好不要使用中文。

例如 node helloworld.js执行该文件

4. 文件的读写

文件读取:

  • 浏览器中的JavaScript是没有文件操作能力的
  • 但是Node中的JavaScript具有文件操作能力

fs核心模块(所有文件操作API都在该模块):

  • fs是file-system的简写,就是文件系统的意思

  • 在fs这个核心模块中,就提供了所有文件操作相关的API

    • 例如 fs.readFile就是用来读取文件的
    • fs.writeFile 用来写文件
//  1.使用fs核心模块
var fs = require('fs');
// 2.读取文件
//    第一个参数就是要读取的文件路径
//    第二个参数是一个回调函数
fs.readFile('./data/a.txt',function(err,data){
   if(err){
        console.log('文件读取失败');
       // console.log(error)
       // 在这里就可以通过判断 error 来确认是否有错误发生
   }
    else{
         console.log(data.toString()); //data为文件二进制数据
    }
    // console.log(data);
})

  // <Buffer 68 65 6c 6c 6f 20 6e 6f 64 65 6a 73 0d 0a>
  // 文件中存储的其实都是二进制数据 0 1
  // 这里为什么看到的不是 0 和 1 呢?原因是二进制转为 16 进制了
  // 但是无论是二进制01还是16进制,人类都不认识
  // 所以我们可以通过 toString 方法把其转为我们能认识的字符

  
//  success :
//              data    数据
//              error   null
//  error :
//              data    null
//              error   就是错误对象

文件写入:

var fs = require('fs')

// $.ajax({
//   ...
//   success: function (data) {
    
//   }
// })

// 第一个参数:文件路径
// 第二个参数:文件内容
// 第三个参数:回调函数

//    成功:
//      文件写入成功
//      error 是 null
//    失败:
//      文件写入失败
//      error 就是错误对象
fs.writeFile('./data/你好.md', '大家好,给大家介绍一下,我是Node.js', function (error) {
  // console.log('文件写入成功')
  // console.log(error)
  if (error) {
    console.log('写入失败')
  } else {
    console.log('写入成功了')
  }
})

5. http

最简单的http服务:

  • 你可以使用 Node 非常轻松的构建一个 Web 服务器
  • 在 Node 中专门提供了一个核心模块:http
  • http 这个模块的职责就是帮你创建编写服务器的
// 1. 加载 http 核心模块
var http = require('http')

// 2. 使用 http.createServer() 方法创建一个 Web 服务器
//    返回一个 Server 实例
var server = http.createServer()

// 3. 服务器要干嘛?
//    提供服务:对 数据的服务
//    发请求
//    接收请求
//    处理请求
//    给个反馈(发送响应)
//    注册 request 请求事件
//    当客户端请求过来,就会自动触发服务器的 request 请求事件,然后执行第二个参数:回调处理函数
server.on('request', function () {
  console.log('收到客户端的请求了')
})

// 4. 绑定端口号,启动服务器
server.listen(3000, function () {
  console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
})

发送响应

var http = require('http')

var server = http.createServer()

// request 请求事件处理函数,需要接收两个参数:
//    Request 请求对象
//        请求对象可以用来获取客户端的一些请求信息,例如请求路径
//    Response 响应对象
//        响应对象可以用来给客户端发送响应消息
server.on('request', function (request, response) {
  // http://127.0.0.1:3000/ /
  // http://127.0.0.1:3000/a /a
  // http://127.0.0.1:3000/foo/b /foo/b
  console.log('收到客户端的请求了,请求路径是:' + request.url)

  // response 对象有一个方法:write 可以用来给客户端发送响应数据
  // write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待
  response.write('hello')
  response.write(' nodejs')

  // 告诉客户端,我的话说完了,你可以呈递给用户了
  response.end()
})

server.listen(3000, function () {
  console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
})

根据不同请求路径,返回不同数据

var http = require('http')

// 1. 创建 Server
var server = http.createServer()

// 2. 监听 request 请求事件,设置请求处理函数
server.on('request', function (req, res) {
  console.log('收到请求了,请求路径是:' + req.url)
  console.log('请求我的客户端的地址是:', req.socket.remoteAddress, req.socket.remotePort)

  // res.write('hello')
  // res.write(' world')
  // res.end()

  // 上面的方式比较麻烦,推荐使用更简单的方式,直接 end 的同时发送响应数据
  // res.end('hello nodejs')

  // 根据不同的请求路径发送不同的响应结果
  // 1. 获取请求路径
  //    req.url 获取到的是端口号之后的那一部分路径
  //    也就是说所有的 url 都是以 / 开头的
  // 2. 判断路径处理响应

  var url = req.url

  if (url === '/') {
    res.end('index page')
  } else if (url === '/login') {
    res.end('login page')
  } else if (url === '/products') {
    var products = [{
        name: '苹果 X',
        price: 8888
      },
      {
        name: '菠萝 X',
        price: 5000
      },
      {
        name: '小辣椒 X',
        price: 1999
      }
    ]

    // 响应内容只能是二进制数据或者字符串           数字  对象  数组  布尔值
    res.end(JSON.stringify(products))
  } else {
    res.end('404 Not Found.')
  }
})

// 3. 绑定端口号,启动服务
server.listen(3000, function () {
  console.log('服务器启动成功,可以访问了。。。')
})

6. node中js核心模块

开发时参考官方API ,

// 用来获取机器信息的
var os = require('os')

// 用来操作路径的
var path = require('path')

// 获取当前机器的 CPU 信息
console.log(os.cpus())

// memory 内存
console.log(os.totalmem())

// 获取一个路径中的扩展名部分
// extname extension name
console.log(path.extname('c:/a/b/c/d/hello.txt'))

7. IP地址和端口号

  • ip 地址用来定位计算机
  • 端口号用来定位具体的应用程序
  • 所有需要联网通信的应用程序都会占用一个端口号
var http = require('http')

var server = http.createServer()

// 2. 监听 request 请求事件,设置请求处理函数
server.on('request', function (req, res) {
  console.log('收到请求了,请求路径是:' + req.url)
  console.log('请求我的客户端的地址是:', req.socket.remoteAddress, req.socket.remotePort)

  res.end('hello nodejs')
})

server.listen(5000, function () {
  console.log('服务器启动成功,可以访问了。。。')
})

// require
// 端口号

var http = require('http')

var server = http.createServer()

server.on('request', function (req, res) {
  // 在服务端默认发送的数据,其实是 utf8 编码的内容
  // 但是浏览器不知道你是 utf8 编码的内容
  // 浏览器在不知道服务器响应内容的编码的情况下会按照当前操作系统的默认编码去解析
  // 中文操作系统默认是 gbk
  // 解决方法就是正确的告诉浏览器我给你发送的内容是什么编码的
  // 在 http 协议中,Content-Type 就是用来告知对方我给你发送的数据内容是什么类型
  // res.setHeader('Content-Type', 'text/plain; charset=utf-8')
  // res.end('hello 世界')

  var url = req.url

  if (url === '/plain') {
    // text/plain 就是普通文本
    res.setHeader('Content-Type', 'text/plain; charset=utf-8')
    res.end('hello 世界')
  } else if (url === '/html') {
    // 如果你发送的是 html 格式的字符串,则也要告诉浏览器我给你发送是 text/html 格式的内容
    res.setHeader('Content-Type', 'text/html; charset=utf-8')
    res.end('<p>hello html <a href="">点我</a></p>')
  }
})

server.listen(3000, function () {
  console.log('Server is running...')
})

8. Content-Type (响应内容类型)

解决node中乱码问题 HTTP Content-type对照表

  • 在服务端默认发送的数据,其实是 utf8 编码的内容,但是浏览器不知道你是 utf8 编码的内容
  • 浏览器在不知道服务器响应内容的编码的情况下会按照当前操作系统的默认编码去解析, 中文操作系统默认是 gbk
  • 解决方法就是正确的告诉浏览器我给你发送的内容是什么编码的
  • 在 http 协议中,Content-Type 就是用来告知对方我给你发送的数据内容是什么类型
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
res.end('hello 世界')
  • Content-Type
    • 服务器最好把每次响应的数据是什么内容类型都告诉客户端,而且要正确的告诉
    • 不同的资源对应的 Content-Type 是不一样,具体参照:http://tool.oschina.net/commons
    • 对于文本类型的数据,最好都加上编码,目的是为了防止中文解析乱码问题
    • 通过网络发送文件
      • 发送的并不是文件,本质上来讲发送是文件的内容
      • 当浏览器收到服务器响应内容之后,就会根据你的 Content-Type 进行对应的解析处理
// 1. 结合 fs 发送文件中的数据
// 2. Content-Type
//    http://tool.oschina.net/commons
//    不同的资源对应的 Content-Type 是不一样的
//    图片不需要指定编码
//    一般只为字符数据才指定编码

var http = require('http')
var fs = require('fs')

var server = http.createServer()

server.on('request', function (req, res) {
  // / index.html
  var url = req.url

  if (url === '/') {
    // 肯定不这么干
    // res.end('<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title></head><body><h1>首页</h1></body>/html>')

    // 我们要发送的还是在文件中的内容
    fs.readFile('./resource/index.html', function (err, data) {
      if (err) {
        res.setHeader('Content-Type', 'text/plain; charset=utf-8')
        res.end('文件读取失败,请稍后重试!')
      } else {
        // data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串
        // res.end() 支持两种数据类型,一种是二进制,一种是字符串
        res.setHeader('Content-Type', 'text/html; charset=utf-8')
        res.end(data)
      }
    })
  } else if (url === '/xiaoming') {
    // url:统一资源定位符
    // 一个 url 最终其实是要对应到一个资源的
    fs.readFile('./resource/ab2.jpg', function (err, data) {
      if (err) {
        res.setHeader('Content-Type', 'text/plain; charset=utf-8')
        res.end('文件读取失败,请稍后重试!')
      } else {
        // data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串
        // res.end() 支持两种数据类型,一种是二进制,一种是字符串
        // 图片就不需要指定编码了,因为我们常说的编码一般指的是:字符编码
        res.setHeader('Content-Type', 'image/jpeg')
        res.end(data)
      }
    })
  }
})

server.listen(3000, function () {
  console.log('Server is running...')
})

8. Node中的模块系统

使用Node编写应用程序主要就是在使用:

在 Node 中,模块有三种:

  • 1 核心模块

    • 文件操作的fs
    • http服务操作的http
    • url路径操作模块
    • path路径处理模块
    • os操作系统信息
  • 2 第三方模块

    • art-template
    • 必须通过npm来下载才可以使用
  • 3 用户自己编写的文件模块

    • 自己创建的文件

    • 相对路径必须加 ./ ,可以省略后缀名

      相对路径中的 ./ 不能省略,否则报错

什么是模块化

  • 文件作用域(模块是独立的,在不同的文件使用必须要重新引用)【在node中没有全局作用域,它是文件模块作用域】
  • 也就是说不引用,作用域只在文件内生效,外部访问不到内部,内部也访问不了外部
  • 通信规则
    • 加载require
    • 导出exports

CommonJS模块规范

在Node中的JavaScript还有一个重要的概念,模块系统。

  • 模块作用域

  • 使用require方法来加载模块

  • 使用exports接口对象来导出模板中的成员

加载require

语法:

  var 自定义变量名 = require('模块')
require 方法有两个作用:
  1. 加载文件模块并执行里面的代码
  2. 拿到被加载文件模块中的exports导出的接口对象
//假装同一目录下有  a.js  b.js   c.js  三个文件
//a.js
console.log('a start')
console.log('./b.js')
console.log('a end')
//======================
//b.js
console.log('b start')
console.log('./c.js')
console.log('b end')
//======================
//c.js
console.log('ccc')

执行

//执行a.js
a start
b start
ccc
b end
a end
//执行b.js
b start
ccc
b end

导出exports

  • Node中是模块作用域,默认文件中所有的成员只在当前模块有效

  • 对于希望可以被其他模块访问到的成员,我们需要把这些公开的成员都挂载到exports接口对象中就可以了

  • exports 默认是一个空对象

导出多个成员(必须在对象中):

exports.a = 123;
exports.b = function(){
    console.log('bbb')
};
exports.c = {
    foo:"bar"
};
exports.d = 'hello';

导出单个成员(拿到的就是函数,字符串):

 module.exports = 'hello';

以下情况会覆盖:

module.exports = 'hello';
//后者会覆盖前者
module.exports = function add(x,y) {
    return x+y;
}

也可以通过以下方法来导出多个成员:

module.exports = {
    foo = 'hello',
    add:function(){
        return x+y;
    }
};
var ret = require('./b')
console.log(ret)   

console.log(export) //{}

export.foo = 'hello'
console.log(export)
// require 方法有两个作用:
//    1. 加载文件模块并执行里面的代码
//    2. 拿到被加载文件模块导出的接口对象
//    
//    在每个文件模块中都提供了一个对象:exports
//    exports 默认是一个空对象
//    你要做的就是把所有需要被外部访问的成员挂载到这个 exports 对象中
var bExports = require('./b')
var fs = require('fs')

console.log(bExports.foo)  //hello
console.log(bExports.add(10, 30))  //40
console.log(bExports.age)   //18

bExports.readFile('./a.js')  //

fs.readFile('./a.js', function (err, data) {
  if (err) {
    console.log('读取文件失败')
  } else {
    console.log(data.toString())
  }
})

var foo = 'bbb'
// console.log(exports)

exports.foo = 'hello'

exports.add = function (x, y) {
  return x + y
}

exports.readFile = function (path, callback) {
  console.log('文件路径:', path)
}

var age = 18
exports.age = age

function add(x, y) {
  return x - y
}

模块原理

exports和module.exports的一个引用:

console.log(exports === module.exports);    //true

exports.foo = 'bar';

//等价于
module.exports.foo = 'bar';

//当给exports重新赋值后,exports!= module.exports.
//最终return的是module.exports,无论exports中的成员是什么都没用。
//真正去使用的时候:
//  导出单个成员:exports.xxx = xxx;
//  导出多个成员:module.exports 或者 modeule.exports = {};
  1. jQuery中的each 和 原生JavaScript方法forEach的区别:
    提供源头:
    原生js是es5提供的(不兼容IE8),
    jQuery的each是jQuery第三方库提供的(如果要使用需要用2以下的版本也就是1.版本),它的each方法主要用来遍历jQuery实例对象(伪数组),同时也可以做低版本forEach的替代品,jQuery的实例对象不能使用forEach方法,如果想要使用必须转为数组([].slice.call(jQuery实例对象))才能使用
  2. exports和module.exports的区别:
    每个模块中都有一个module对象, module对象中有一个exports对象
    我们可以把需要导出的成员都挂载到module.exports接口对象中,也就是module.exports.xxx = xxx的方式
    但是每次写太多了就很麻烦,所以Node为了简化代码,就在每一个模块中都提供了一个成员叫exports
    exports === module.exports结果为true,所以完全可以exports.xxx = xxx 当一个模块需要导出单个成员的时候必须使用module.exports = xxx的方式,=,使用exports = xxx不管用,因为每个模块最终return的是module.exports,而exports只是module.exports的一个引用,所以exports即使重新赋值,也不会影响module.exports
    有一种赋值方式比较特殊:exports = module.exports这个用来新建立引用关系的。

9. http 路径跳转改写

var http = require('http')
var fs = require('fs')

// 1. 创建 Server
var server = http.createServer()

// 2. 监听 Server 的 request 请求事件,设置请求处理函数
//    请求
//      处理
//    响应
//    一个请求对应一个响应,如果在一个请求的过程中,已经结束响应了,则不能重复发送响应。
//    没有请求就没有响应。
// 
// 咱们以前使用过 Apache 服务器软件,这个软件默认有一个 www 目录,所有存放在 www 目录中的资源都可以通过网址来浏览
// 127.0.0.1:80/a.txt
// 127.0.0.1:80/index.html
// 127.0.0.1:80/apple/login.html

//    假装这里有一个目录
//      D:/Movie/www
//          index.html
//          a.txt
//          apple
//              login.html

var wwwDir = 'D:/Movie/www'

server.on('request', function (req, res) {
  var url = req.url
  // / index.html
  // /a.txt wwwDir + /a.txt
  // /apple/login.html wwwDir + /apple/login.html
  // /img/ab1.jpg wwwDir + /img/ab1.jpg
  if (url === '/') {
    fs.readFile(wwwDir + '/index.html', function (err, data) {
      // if (err) {
      //   res.end('404 Not Found.')
      // } else {
      // }

      if (err) {
        // return 有两个作用:
        //  1. 方法返回值
        //  2. 阻止代码继续往后执行
        return res.end('404 Not Found.')
      }
      res.end(data)
    })
  } else if (url === '/a.txt') {
    fs.readFile(wwwDir + '/a.txt', function (err, data) {
      if (err) {
        return res.end('404 Not Found.')
      }
      res.end(data)
    })
  } else if (url === '/index.html') {
    fs.readFile(wwwDir + '/index.html', function (err, data) {
      if (err) {
        return res.end('404 Not Found.')
      }
      res.end(data)
    })
  } else if (url === '/apple/login.html') {
    fs.readFile(wwwDir + '/apple/login.html', function (err, data) {
      if (err) {
        return res.end('404 Not Found.')
      }
      res.end(data)
    })
  }
})

// 3. 绑定端口号,启动服务
server.listen(3000, function () {
  console.log('running...')
})

url 固定部分替换

var http = require('http')
var fs = require('fs')

var server = http.createServer()

var wwwDir = 'D:/Movie/www'

server.on('request', function (req, res) {
  var url = req.url
  // / index.html
  // /a.txt wwwDir + /a.txt
  // /apple/login.html wwwDir + /apple/login.html
  // /img/ab1.jpg wwwDir + /img/ab1.jpg
  
  var filePath = '/index.html'
  if (url !== '/') {
    filePath = url
  }

  fs.readFile(wwwDir + filePath, function (err, data) {
    if (err) {
      return res.end('404 Not Found.')
    }
    res.end(data)
  })
})

// 3. 绑定端口号,启动服务
server.listen(3000, function () {
  console.log('running...')
})

10. 案例之简易目录列表

[图片上传失败...(image-d64eb-1603337864181)]

var http = require('http')
var fs = require('fs')

var server = http.createServer()

var wwwDir = 'D:/Movie/www'

server.on('request', function (req, res) {
  var url = req.url
  fs.readFile('./template.html', function (err, data) {
    if (err) {
      return res.end('404 Not Found.')
    }
    // 1. 如何得到 wwwDir 目录列表中的文件名和目录名
    //    fs.readdir
    // 2. 如何将得到的文件名和目录名替换到 template.html 中
    //    2.1 在 template.html 中需要替换的位置预留一个特殊的标记(就像以前使用模板引擎的标记一样)
    //    2.2 根据 files 生成需要的 HTML 内容
    // 只要你做了这两件事儿,那这个问题就解决了
    fs.readdir(wwwDir, function (err, files) {
      if (err) {
        return res.end('Can not find www dir.')
      }

      // 2.1 生成需要替换的内容
      var content = ''
      files.forEach(function (item) {
        // 在 EcmaScript 6 的 ` 字符串中,可以使用 ${} 来引用变量
        content += `
          <tr>
            <td data-value="apple/">
              <a class="icon dir" href="/D:/Movie/www/apple/">${item}/</a>
           </td>
            <td class="detailsColumn" data-value="0">1024kb</td>
            <td class="detailsColumn" data-value="1509589967">2017/11/2 上午10:32:47</td>
          </tr>
        `
      })

      // 2.3 替换
      data = data.toString()
      data = data.replace('^_^', content)

      // 3. 发送解析替换过后的响应数据
      res.end(data)
    })
  })
})
server.listen(3000, function () {
  console.log('running...')
})

template.html

<html dir="ltr" lang="zh" i18n-processed="">
<head>
  <meta charset="utf-8">
  <meta name="google" value="notranslate">
  <title id="title">D:\Movie\www\ 的索引</title>
  <style>假装这里有样式</style>
</head>

<body>
  <div id="listingParsingErrorBox">
      糟糕!Google Chrome无法解读服务器所发送的数据。请
      <a href="http://code.google.com/p/chromium/issues/entry">报告错误</a>
      ,并附上
      <a href="LOCATION">原始列表</a>。
  </div>
  <h1 id="header">D:\Movie\www\ 的索引</h1>
  <div id="parentDirLinkBox" style="display:none">
    <a id="parentDirLink" class="icon up">
    <span id="parentDirText">[上级目录]</span>
  </a>
  </div>
  <table>
    <thead>
      <tr class="header" id="theader">
        <th onclick="javascript:sortTable(0);">名称</th>
        <th class="detailsColumn" onclick="javascript:sortTable(1);">
          大小
        </th>
        <th class="detailsColumn" onclick="javascript:sortTable(2);">
          修改日期
        </th>
      </tr>
    </thead>
    <tbody id="tbody">^_^</tbody>
  </table>
</body>

</html>

11. 读取目录 readdir

格式:

readdir(‘读取文件的文件目录路径’,function(err,files){})读取目录
var fs = require('fs')

fs.readdir('D:/Movie/www', function (err, files) {
  if (err) {
    return console.log('目录不存在')
  }
  console.log(files)
})
//得到一个数组例如  ['a.txt','apple','img']

12. 在浏览器中使用art-template

  • 导入后使用即可
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>在浏览器中使用art-template</title>
</head>
<body>
  <!-- 
    注意:在浏览器中需要引用 lib/template-web.js 文件

    强调:模板引擎不关心你的字符串内容,只关心自己能认识的模板标记语法,例如 {{}}
    {{}} 语法被称之为 mustache 语法,八字胡啊。
   -->
  <script src="node_modules/art-template/lib/template-web.js"></script>
  
  <script type="text/template" id="tpl">
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
    </head>
    <body>
      <p>大家好,我叫:{{ name }}</p>
      <p>我今年 {{ age }} 岁了</p>
      <h1>我来自 {{ province }}</h1>
      <p>我喜欢:{{each hobbies}} {{ $value }} {{/each}}</p>
    </body>
    </html>
  </script>
  
  <script>
    var ret = template('tpl', {
      name: 'Jack',
      age: 18,
      province: '北京市',
      hobbies: [
        '写代码',
        '唱歌',
        '打游戏'
      ]
    })

    console.log(ret)
  </script>
</body>
</html>

13. 在node中使用模板引擎

在 Node 中使用 art-template模板引擎
模板引起最早就是诞生于服务器领域,后来才发展到了前端。

art-template 不仅可以在浏览器使用,也可以在 node 中使用

  • 1、安装:
    • npm install art-template
    • 该命令在哪执行就会把包下载到哪里。默认会下载到 node_modules 目录中
    • node_modules 不要改,也不支持改。
  • 2、使用:
    • 在需要使用的文件模块中加载 art-template
    • 只需要使用 require 方法加载就可以了:require('art-template')
    • 参数中的 art-template 就是你下载的包的名字
    • 也就是说你 install 的名字是什么,则你 require 中的就是什么
  • 3、查文档,使用模板引擎的 API

tel.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{ title }}</title>
</head>
<body>
  <p>大家好,我叫:{{ name }}</p>
  <p>我今年 {{ age }} 岁了</p>
  <h1>我来自 {{ province }}</h1>
  <p>我喜欢:{{each hobbies}} {{ $value }} {{/each}}</p>
  <script>
    var foo = '{{ title }}'
  </script>
</body>
</html>

使用


var template = require('art-template')
var fs = require('fs')

// 这里不是浏览器
// template('script 标签 id', {对象})

// var tplStr = `
// <!DOCTYPE html>
// <html lang="en">
// <head>
//   <meta charset="UTF-8">
//   <title>Document</title>
// </head>
// <body>
//   <p>大家好,我叫:{{ name }}</p>
//   <p>我今年 {{ age }} 岁了</p>
//   <h1>我来自 {{ province }}</h1>
//   <p>我喜欢:{{each hobbies}} {{ $value }} {{/each}}</p>
// </body>
// </html>
// `

fs.readFile('./tpl.html', function (err, data) {
  if (err) {
    return console.log('读取文件失败了')
  }
  // 默认读取到的 data 是二进制数据
  // 而模板引擎的 render 方法需要接收的是字符串
  // 所以我们在这里需要把 data 二进制数据转为 字符串 才可以给模板引擎使用
  var ret = template.render(data.toString(), {
    name: 'Jack',
    age: 18,
    province: '北京市',
    hobbies: [
      '写代码',
      '唱歌',
      '打游戏'
    ],
    title: '个人信息'
  })

  console.log(ret)
})

14. http案例加入art-template

var http = require('http')
var fs = require('fs')
var template = require('art-template')

var server = http.createServer()

var wwwDir = 'D:/Movie/www'

server.on('request', function (req, res) {
  var url = req.url
  fs.readFile('./template-apache.html', function (err, data) {
    if (err) {
      return res.end('404 Not Found.')
    }
    // 1. 如何得到 wwwDir 目录列表中的文件名和目录名
    //    fs.readdir
    // 2. 如何将得到的文件名和目录名替换到 template.html 中
    //    2.1 在 template.html 中需要替换的位置预留一个特殊的标记(就像以前使用模板引擎的标记一样)
    //    2.2 根据 files 生成需要的 HTML 内容
    // 只要你做了这两件事儿,那这个问题就解决了
    fs.readdir(wwwDir, function (err, files) {
      if (err) {
        return res.end('Can not find www dir.')
      }

      // 这里只需要使用模板引擎解析替换 data 中的模板字符串就可以了
      // 数据就是 files
      // 然后去你的 template.html 文件中编写你的模板语法就可以了
      var htmlStr = template.render(data.toString(), {
        title: '哈哈',
        files: files
      })

      // 3. 发送解析替换过后的响应数据
      res.end(htmlStr)
    })
  })
})
server.listen(3000, function () {
  console.log('running...')
})

template-apache.html

<html dir="ltr" lang="zh" i18n-processed="">

<head>
  <meta charset="utf-8">
  <meta name="google" value="notranslate">
  
  <style>假装这里有样式</style>
  <title id="title">{{ title }}</title>
</head>

<body>
  <div id="listingParsingErrorBox">
      糟糕!Google Chrome无法解读服务器所发送的数据。请
      <a href="http://code.google.com/p/chromium/issues/entry">报告错误</a>
      ,并附上<a href="LOCATION">原始列表</a>。
  </div>
  <h1 id="header">D:\Movie\www\ 的索引</h1>
  <div id="parentDirLinkBox" style="display:none">
    <a id="parentDirLink" class="icon up">
    <span id="parentDirText">[上级目录]</span>
  </a>
  </div>
  <table>
    <thead>
      <tr class="header" id="theader">
        <th onclick="javascript:sortTable(0);">名称</th>
        <th class="detailsColumn" onclick="javascript:sortTable(1);">
          大小
        </th>
        <th class="detailsColumn" onclick="javascript:sortTable(2);">
          修改日期
        </th>
      </tr>
    </thead>
    <tbody id="tbody">
      {{each files}}
      <tr>
        <td data-value="apple/">
            <a class="icon dir" href="/D:/Movie/www/apple/">{{$value}}/</a>
        </td>
        <td class="detailsColumn" data-value="0"></td>
        <td class="detailsColumn" data-value="1509589967">2017/11/2 上午10:32:47</td>
      </tr>
      {{/each}}
    </tbody>
  </table>
</body>

</html>

15. 客户端渲染和移动端渲染

  • 服务端渲染

    • 说白了就是在服务端使用模板引擎
    • 模板引擎最早诞生于服务端,后来才发展到了前端
  • 服务端渲染和客户端渲染的区别

    • 客户端渲染不利于 SEO 搜索引擎优化

    • 服务端渲染是可以被爬虫抓取到的,客户端异步渲染是很难被爬虫抓取到的

    • 所以你会发现真正的网站既不是纯异步也不是纯服务端渲染出来的

    • 而是两者结合来做的

    • 例如京东的商品列表就采用的是服务端渲染,目的了为了 SEO 搜索引擎优化

    • 而它的商品评论列表为了用户体验,而且也不需要 SEO 优化,所以采用是客户端渲染

16. parse 和query

cmd终端输入:node + 回车可进入node控制台

var url = require('url')

var obj = url.parse('/pinglun?name=的撒的撒&message=的撒的撒的撒', true)

console.log(obj)
console.log(obj.query)

下一章node.js(2)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。