Node.js基础(三)

1.路由基础

  • 最低配版路由

server.js

//常规的书写框架
// const http = require('http')

// const app = http.createServer((req, res) => {

// })

// app.listen(8080, () => {
//     console.log('server at http://localhost:8080')
// })
//简写
const fs = require('fs')

require('http')
    .createServer((req, res) => {

    const urlStr = req.url
    console.log(urlStr)
    //简单的路由,理论上就是对每一个请求进行拦截并且判断

    switch (urlStr) {
        case '/':
            res.end('hello')
            break
        case '/home':
            fs.readFile('./home.html', (err, content) => {
                res.end(content)
            })
            break
        case '/app.js':
            res.end('app.js')
            break
        case '/p1.png':
            fs.readFile('../p1.png', (err, content) => {
                res.end(content)
            })
            break
        default:
            res.end('error')
    }


}).listen(8080, () => {
    console.log('server at http://localhost:8080')
})

home.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    home.html
    <img src="../p1.png" alt="">
    <script src="../app.js"></script>

</body>

</html>

app.js

console.log('hello')

  • 每次书写过于冗杂,所以进行批量路由管理

server.js


const fs = require('fs')

require('http')
    .createServer((req, res) => {
        const urlStr = req.url
        console.log(urlStr)
        const file = fs.readFileSync(`.${urlStr}`)
        res.end(file)

    }).listen(8080, () => {
        console.log('server at http://localhost:8080')
    })

  • 为了对后缀不同的文件进行管理,防止浏览器解析问题,我们引入第三方插件:mime ( npm i mime )
const mime = require('mime')
const fs = require('fs')

require('http')
    .createServer((req, res) => {

        const urlStr = req.url
        //使用mime的方法
        const type = mime.getType(urlStr.split('.'[1]))
        console.log(type)
        //书写请求头 
        res.writeHead(200, {
            'content-type': type
        })
        const file = fs.readFileSync(`.${urlStr}`)
        res.end(file)

    }).listen(8080, () => {
        console.log('server at http://localhost:8080')
    })

2.静态资源目录搭建

  • 目录结构

server.js

const http = require('http')
const readStaticFile = require('./readStaticFile')
const path = require('path')

//这里必须使用异步
const server = http.createServer(async (req, res) => {
    let urlStr = req.url
    //__dirname表示当前代码所在的物理路径,从根目录开始,然后追加后面的路径
    let filePathName = path.join(__dirname, '/public', urlStr)
    console.log(filePathName)
    //必须等待异步函数传值
    let { data, mimeType } = await readStaticFile(filePathName)

    res.writeHead(200, {
        'content-type': `${mimeType};charset=utf-8`
    })

    res.write(data)
    res.end()
})

server.listen(8080, () => {
    console.log('server at http://localhost:8080...')
})

readStaticFile.js

const path = require('path')
const mime = require('mime')
const fs = require('fs')

//封装一个读取文件的方法
function myReadFile(fileName) {
    console.log(fileName)
    //防止异步出错,这里自己封装一个Promise函数,如果成功就会自己调用里面的回调函数
    return new Promise((resolve, reject) => {
        fs.readFile(fileName, (err, data) => {
            //如果读取错误,返回提示
            if (err) {
                // reject('您访问的是是一个文件夹')
                resolve('您访问的是一个文件夹')
            } else {
                resolve(data)
            }
        })
    })

}

async function readStaticFile(filePathName) {
    //获取拓展名
    let ext = path.parse(filePathName).ext
    //获取文件类型
    let mimeType = mime.getType(ext) || 'text/html'

    let data

    //判断某个文件或者文件夹是否存在
    if (fs.existsSync(filePathName)) {

        if (ext) {
            // await myReadFile(filePathName)
            //     .then(result => data = result)
            //     .catch(err => data = err)

            data = await myReadFile(filePathName)


        } else {
            // await myReadFile(filePathName)
            //     .then(result => data = result)
            //     .catch(err => data = err)
            data = await myReadFile(path.join(filePathName, '/index.html'))

            //这里有数据说明获取到了
            // console.log(data)
        }



    } else {
        console.log('file not found')
    }

    return { mimeType, data }

}

module.exports = readStaticFile

3.Yarn

Yarn 对你的代码来说是一个包管理器。它可以让你使用并分享全世界开发者的(例如 JavaScript)代码。 Yarn 能够快速、安全、并可靠地完成这些工作,所以你不用有任何担心。

通过Yarn你可以使用其他开发者针对不同问题的解决方案,使自己的开发过程更简单。

代码通过包(package) (或者称为 模块(module)) 的方式来共享。 一个包里包含所有需要共享的代码,以及描述包信息的文件,称为 package.json。

  • 安装
    • 中文网:https://yarn.bootcss.com/docs/install/#mac-stable
  • 使用方法:
    • 文档:https://yarn.bootcss.com/docs/usage

1.安装

npm i -g yarn

yarn --version

2.Yarn使用方法

2.1初始化一个项目

yarn init -y

2.2添加依赖包

yarn add [package]

yarn add [package]@[version]

yarn add[package]@[tag]

2.3将依赖项添加到不同的依赖项类别中

分别添加到 devDependencies、peerDependencies 和 optionalDependencies 类别中:

yarn add [package] --dev
yarn add [package] --peer
yarn add [package] --optional

devDependencies、peerDependencies 和 optionalDependencies区别

在一个Node.js项目中,package.json几乎是一个必须的文件,它的主要作用就是管理项目中所使用到的外部依赖包,同时它也是npm命令的入口文件。

npm 目前支持以下几类依赖包管理:

  • dependencies
  • devDependencies
  • peerDependencies
  • optionalDependencies
  • bundledDependencies / bundleDependencies

dependencies

应用依赖,或者叫做业务依赖,这是我们最常用的依赖包管理对象!它用于指定应用依赖的外部包,这些依赖是应用发布后正常执行时所需要的,但不包含测试时或者本地打包时所使用的包。

devDependencies

开发环境依赖,仅次于dependencies的使用频率!它的对象定义和dependencies一样,只不过它里面的包只用于开发环境,不用于生产环境,这些包通常是单元测试或者打包工具等,例如gulp, grunt, webpack, moca, coffee等。

peerDependencies

同等依赖,或者叫同伴依赖,用于指定当前包(也就是你写的包)兼容的宿主版本。如何理解呢? 试想一下,我们编写一个gulp的插件,而gulp却有多个主版本,我们只想兼容最新的版本,此时就可以用同等依赖(peerDependencies)来指定。

{
  "name": "gulp-my-plugin",
  "version": "0.0.1",
  "peerDependencies": {
    "gulp": "3.x"
  }
}

optionalDependencies

可选依赖,如果有一些依赖包即使安装失败,项目仍然能够运行或者希望npm继续运行,就可以使用optionalDependencies。另外optionalDependencies会覆盖dependencies中的同名依赖包,所以不要在两个地方都写。

bundledDependencies / bundleDependencies

打包依赖,bundledDependencies是一个包含依赖包名的数组对象,在发布时会将这个对象中的包打包到最终的发布包里。

2.4 升级依赖包

yarn upgrade [package]
yarn upgrade [package]@[version]
yarn upgrade [package]@[tag]

2.5 移除依赖包

yarn remove [package]

2.6 安装项目的全部依赖

yarn

或者

yarn install

2.7切换源

yarn config get registry

  • 此外和npm nrm切换源相同

4.Express

在这里插入图片描述

  • 官网:https://www.expressjs.com.cn/

1.中间件

const express = require('express')

//express框架的基本使用
const app = express()

//使用use解析是从上到下,如果之前匹配了就不会往下匹配
//回调函数又被称之为中间件,中间件可以挂载多个,但是多个中间件需要前面的中间件使用next函数
//上面有关中间件的描述被称之为中间件栈
app.use('/api', (req, res, next) => {
    res.send('world')
    next()
}, (req, res) => {
    console.log(1)
})

//中间件栈
const middlewares = [
    (req, res, next) => {
        console.log(0)
        next()
    }, (req, res, next) => {
        console.log(1)
        next()
    }
]
//使用中间件栈
app.use('/list', middlewares)

app.use('/', (req, res) => {
    console.log(0)
    //send取代了write和end函数
    res.send('hello')
})


app.listen(8080, () => {
    console.log('server at http://localhost:8080...')
})

2.路由

server.js

const express = require('express')
const router = require('./router/index')
var bodyParser = require('body-parser')

const app = express()


// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json
app.use(bodyParser.json())


//app.use如果不写路径而直接使用中间件,表示接受所有路径?
app.use('/', router)

app.listen(8080, () => {
    console.log('server at http://localhost:8080...')
})

router/index.js

const express = require('express')

//express路由中间件
const router = express.Router()

//注意这个不是从上往下解析,而是按照规则解析
router.get('/', (req, res, next) => {
    res.send('hello')
})
router.get('/index', (req, res, next) => {
    //获取前端数据--GET--query对象,是以json类型
    const query = req.query
    console.log(query)
    // res.send(query)
    //表示返回json数据类型
    res.json(query)

})

router.post('/index', (req, res, next) => {
    //获取前端数据--POST--body
    //为了解析POST方式请求的数据,我们使用一个第三方插件--body-parser
    //yarn add body-parser -S
    const data = req.body
    console.log(data)
    res.send(data)

})

//除了get和put,还有其他几种重要的语义化请求
//解析这些方式主要还是req.body
//get--请求数据,put--覆盖式修改,post--添加数据,patch--增量式修改,delete--删除
router.put('/index', (req, res, next) => {

})
router.patch('/index', (req, res, next) => {

})
router.delete('/index', (req, res, next) => {

})


module.exports = router

3.抽离controler

controller/index.js

const list = (req, res, next) => {
    res.send('hello')
}
//暴露方法
exports.list = list

router/index.js

const express = require('express')
const { list } = require('../controller')
const router = express.Router()

router.get('/', list)

module.exports = router

server.js

const express = require('express')
const router = require('./router/index')
var bodyParser = require('body-parser')

const app = express()


// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json
app.use(bodyParser.json())


//app.use如果不写路径而直接使用中间件,表示接受所有路径?
app.use('/', router)

app.listen(8080, () => {
    console.log('server at http://localhost:8080...')
})

5.express template

  • ejs
  • pug
  • jade
  • art-template

页面渲染(render)

  • SSR(Server Side Render)
  • CSR(Client Side Render)

项目准备,使用express中间件托管静态资源:

server.js

const express = require('express')
const router = require('./router/index')
var bodyParser = require('body-parser')

const app = express()


// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json
app.use(bodyParser.json())

//利用 Express 托管静态文件
app.use(express.static('./public'))

//app.use如果不写路径而直接使用中间件,表示接受所有路径?
app.use('/', router)

app.listen(8080, () => {
    console.log('server at http://localhost:8080...')
})
  • 服务端渲染:
const list = (req, res, next) => {

    //渲染数据相当于服务端渲染
    let data = '<ul>'
    for (var i = 0; i < 100; i++) {
        data += `<li> ${i}</li>`
    }
    data += '</ul>'
    res.send(data)
}
//暴露方法
exports.list = list
  • 客户端渲染:

common.js

$.ajax({
    url: 'api/list',
    success(result) {
        //相当于在前端渲染
        let html = '<ul>'
        $.each(result.data, (index, value) => {
            html += '<li>' + value + '</li>'
        })
        html += "</ul>"

        $('#list').html(html)
    }
})

list.js

const list = (req, res, next) => {

    //服务端提供数据
    // let data = '{"ret":true,"data":'
    let dataObj = {
        ret: true,
        data: []
    }
    for (var i = 0; i < 100; i++) {
        dataObj.data.push('line' + i)
    }

    res.send(dataObj)
}
//暴露方法
exports.list = list

art-template

  • 官网:http://aui.github.io/art-template/zh-cn/index.html

  • 文档:http://aui.github.io/art-template/zh-cn/docs/

1.安装

npm i art-template express-art-template -S

2.使用

server.js

const express = require('express')
const router = require('./router/index')
var bodyParser = require('body-parser')
const path = require('path')

const app = express()


// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json
app.use(bodyParser.json())

//利用 Express 托管静态文件
app.use(express.static('./public'))

// view engine setup
app.engine('art', require('express-art-template'));
app.set('view options', {
    debug: process.env.NODE_ENV !== 'production',
    // 是否开启对模板输出语句自动编码功能。为 false 则关闭编码输出功能
    // escape 可以防范 XSS 攻击
    escape: true,
});
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'art');

//app.use如果不写路径而直接使用中间件,表示接受所有路径
app.use('/', router)

app.listen(8080, () => {
    console.log('server at http://localhost:8080...')
})

views/list.art

{
    "ret":true,
    "data":{{dataArray}}
}

controller/index.js

const list = (req, res, next) => {

    let dataArray = []
    for (var i = 0; i < 100; i++) {
        dataArray.push('line' + i)
    }

    //使用art-template渲染,注意不要去写.art
    res.render('list', {
        //下面两种写法都可以解构
        // data: dataArray
        dataArray
    })
}
//暴露方法
exports.list = list
  • 在浏览器中实时编译

①html需要引入这个实时编译

    <!-- <script src="https://unpkg.com/art-template@4.13.2/lib/template-web.js"></script> -->
    <script src="./js/template-web.js"></script>

③server.js要做简单修改

app.set('view options', {
    debug: process.env.NODE_ENV !== 'production',
    // 是否开启对模板输出语句自动编码功能。为 false 则关闭编码输出功能
    // escape 可以防范 XSS 攻击
    escape: false,//这里是一个坑
});

④修改list.art

{
    "ret":true,
    "data":{{data}}
}

⑤controller/index.js

const list = (req, res, next) => {

    let dataArray = []
    for (var i = 0; i < 100; i++) {
        dataArray.push('line' + i)
    }

    //使用art-template渲染,注意不要去写.art
    res.set('content-type', 'application/json;charset=utf-8')
    res.render('list', {
        data: JSON.stringify(dataArray)
    })
}
//暴露方法
exports.list = list

common.js



$.ajax({
    url: 'api/list',
    success(result) {

        //这里用到art-template语法
        let templateStr =
            `
        <ul>
            {{each data}}
                <li>
                {{ $value }}
                </li> 
            {{/each}}
        </ul>
        <div>{{x}}</div>
        `
        //在浏览器端实时渲染
        let str = template.render(templateStr, { data: result.data, x: 'hello' })

        $('#list').html(str)
    }
})
  • 这一章要好好理解,对于后面学的Vue的底层理解有很大帮助

3.案例

controller/index.js

var template = require('art-template');
const fs = require('fs');
const path = require('path')


const list = (req, res, next) => {

    let dataArray = []
    for (var i = 0; i < 100; i++) {
        dataArray.push('line' + i)
    }

    var html = template(path.join(__dirname, '../views/list-html.art'), {
        data: dataArray
    });
    // console.log(html)
    fs.writeFile(path.join(__dirname, '../public/list.html'), html, (err) => { })

    res.send('pages has been compiled')
}
//暴露方法
exports.list = list

list-html.art

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>
        {{each data}}
        <li>{{$value}}</li>
        {{/each}}
    </ul>
</body>

</html>
  • 还可以把M层进行封装

list.js

let dataArray = []
for (var i = 0; i < 100; i++) {
    dataArray.push('line' + i)
}

module.exports = {
    dataArray
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值