在Pug(Jade)模板中动态添加HTML的正确方法是什么?[已关闭]

问题描述 投票:0回答:1

假设我们想使用Pug和NodeJS创建一个网页,显示一个基于外部数据源的项目列表,例如:。

doctype html
  ...
  body
    p Welcome to #{siteName}
    each item in variableWithExternalData
        ul
          li= item

当前的方法:

  1. 用户访问页面
  2. 服务器向外部API发送请求
  3. 服务器处理外部数据并将其存储在 data
  4. 渲染页面使用 res.render('index', {siteName: 'MyName', variableWithExternalData: data});

虽然这样做很好,但它并不是特别迅速的客户端体验,因为服务器首先要处理外部数据,然后再渲染页面。更为可取的是像下面这样。

  1. 用户访问页面
  2. 服务器渲染页面
  3. 服务器向外部API发送请求
  4. 服务器处理外部数据
  5. 客户端从服务器获取数据,并动态添加到页面中。

这将是有益的,因为在检索和处理外部数据之前,页面可以呈现,特别是由于该 ul 在页面加载时,并不直接可见。我知道可以通过使用Ajax从客户端发出请求,然后使用JavaScript将项目添加到列表中,从而实现类似上述的功能。然而,我想知道是否有一种Pug允许的更基于服务器端的方法,例如在 pug.render()?

javascript html node.js pug
1个回答
1
投票

你可以发送部分页面(HTML标记),使用分块响应,然后在后端处理更多的数据后,再发送另一个页面的分块。不过这种方式有一定的局限性,你不能在已经发送的数据中间插入内容。

至于Pug,它是模板库,与发送数据回客户端无关。你可以用Pug来创建整个页面的HTML,或者只创建其中的一部分。然后根据你的意愿从Pug中发送输出。

例子#1

下面我写了简单的NodeJS演示,展示了分块发送HTML。每秒钟都会有新的分块发送。10个chunks之后,将发送结束标签。每一个分块都应该在到达后立即在浏览器中呈现。

const http = require('http')
const port = 3000
const hostname = 'localhost'
const server = http.createServer(main)

function main (req, res) {
    res.setHeader('Content-Type', 'text/html; charset=UTF-8')
    res.setHeader('Transfer-Encoding', 'chunked')

    let chunksLeft = 10

    res.write('<DOCTYPE html><html><head><title>Chunked response demo</title></head><body>')
    res.write(`<h1>Hello chunks!</h1><p>I will be sending ${chunksLeft} entries.</p><ol>`)

    function sendChunk () {
        chunksLeft -= 1
        res.write(`<li>Entry</li>`)
        if (chunksLeft > 0) {
            setTimeout(sendChunk, 1000)
        } else {
            res.end('</ol></html>')
        }
    }

    sendChunk()
}

function message () {
    console.log(`Listening on ${hostname}:${port}...`)
}

server.listen(port, hostname, message)

示例#2

下面的代码展示了使用 axios 和 pug 库从外部 API 获取和渲染数据,使用了前面例子中的概念。

const http = require('http')
const axios = require('axios')
const pug = require('pug')
const port = 3000
const hostname = 'localhost'
const server = http.createServer(main)

const template =
`doctype html
html
    head
        title Chunked response with pug and axios
    body
        h1 Hello chunks!
        p Below is example data downloaded from <a href="https://jsonplaceholder.typicode.com/todos">jsonplaceholder</a> and transformed to HTML.`

const list =
`ol
    each t in todos
        li= t.title`

function main (req, res) {
    res.setHeader('Content-Type', 'text/html; charset=UTF-8')
    res.setHeader('Transfer-Encoding', 'chunked')

    res.write(pug.render(template))

    axios.get('https://jsonplaceholder.typicode.com/todos').then(reply => {
        res.end(pug.render(list, { todos: reply.data }))
    }).catch(() => {
        res.end(pug.render('p Error: could not download todos!'))
    })
}

function message () {
    console.log(`Listening on ${hostname}:${port}...`)
}

server.listen(port, hostname, message)

更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.