Javascript 快速-在单个请求中向浏览器发送页面和自定义数据?

Javascript 快速-在单个请求中向浏览器发送页面和自定义数据?,javascript,html,node.js,http,express,Javascript,Html,Node.js,Http,Express,如何同时呈现页面并将自定义数据传输到浏览器。据我所知,它需要发送两层:第一层是模板,第二层是JSON数据。我想通过主干网来处理这些数据 正如我从教程express和bb-app中了解到的,互动如下: res.render将页面发送到浏览器 当document.ready触发jQuery.get到app.get('/post') app.get('/post',post.allPosts)send data to page 这是三个步骤,如何一步一步完成 var visitCard = { n

如何同时呈现页面并将自定义数据传输到浏览器。据我所知,它需要发送两层:第一层是模板,第二层是JSON数据。我想通过主干网来处理这些数据

正如我从教程
express
bb-app
中了解到的,互动如下:

  • res.render
    将页面发送到浏览器
  • document.ready
    触发jQuery.get到
    app.get('/post')
  • app.get('/post',post.allPosts)
    send data to page
  • 这是三个步骤,如何一步一步完成

    var visitCard = {
      name: 'John Smit',
      phone: '+78503569987'
    };
    
    exports.index = function(req, res, next){
      res.render('index');
      res.send({data: visitCard}); 
    };
    

    以及如何在页面上捕获此变量-
    document.card

    使用
    res.send
    而不是
    res.render
    。它接受任何形式的原始数据:字符串、数组、普通旧对象等。如果是对象或对象数组,它将为您将其序列化为JSON

    var visitCard = {
      name: 'John Smit',
      phone: '+78503569987'
    };
    
    exports.index = function(req, res, next){
      res.send(visitCard}; 
    };
    

    我创建了自己的小中间件函数,它向
    res
    对象添加了一个名为
    renderWithData
    的助手方法

    app.use(function (req, res, next) {
        res.renderWithData = function (view, model, data) {
            res.render(view, model, function (err, viewString) {
                data.view = viewString;
                res.json(data);
            }); 
        };
        next();
    });
    
    它接收视图名称、视图模型以及要发送到浏览器的自定义数据。它调用
    res.render
    ,但传入回调函数。这指示express将编译后的视图标记作为字符串传递给回调,而不是立即将其传递到响应中。获得视图字符串后,我将其作为
    data.view
    添加到数据对象中。然后我使用
    res.json
    将数据对象发送到浏览器,并完成编译视图:)

    编辑: 上面的一个警告是,请求需要使用javascript进行,因此不能是整页请求。您需要一个初始请求来下拉包含将发出ajax请求的javascript的主页面

    当用户通过AJAX导航到一个新页面时,如果您试图更改浏览器URL和标题,这非常适合。您可以将新页面的部分视图与页面标题的一些数据一起发送回浏览器。然后,客户端脚本可以将部分视图放在页面上它所属的位置,更新页面标题栏,并根据需要更新URL

    如果希望将完整的HTML文档和一些初始JavaScript数据一起发送到浏览器,则需要将该JavaScript代码编译到视图本身中。这是绝对可能做到的,但我从来没有找到一种方法,不涉及一些字符串魔术

    例如:

    // controller.js
    var someData = { message: 'hi' };
    res.render('someView', { data: JSON.stringify(someData) });
    
    // someView.jade
    script.
        var someData = !{data};
    
    注意:
    !使用{data}
    代替#{data},因为jade默认情况下会转义HTML,这会将所有引号转换为“占位符

    一开始它看起来很奇怪,但它可以工作。基本上,您在服务器上获取一个JS对象,将其转换为字符串,将该字符串呈现到编译视图中,然后将其发送到浏览器。当文档最终到达浏览器时,它应该是这样的:

    // someSite.com/someView
    <script type="text/javascript">
        var someData = { "message": "hi" };
    </script>
    
    app.use(function (req, res, next) {
        res.renderWithData = function (view, model, data) {
            model.data = JSON.stringify(data);
            res.render(view, model);
        };
        next();
    });
    
    它所做的一切就是获取自定义数据对象,为您对其进行字符串化,将其添加到视图的模型中,然后以正常方式呈现视图。现在您可以调用
    res.renderWithData('someView',{},{message:'hi'})
    ;您只需确保在视图中的某个位置获取该数据字符串并将其呈现为变量赋值语句

    html
        head
            title Some Page
            script.
                var data = !{data};
    
    我不想撒谎,这整件事感觉有点恶心,但如果它能为你节省一次额外的服务器访问,而这正是你所追求的,那么这就是你需要做的。也许有人能想出一些更聪明的方法,但我只是不知道你还能如何让数据出现在一个完整的HTML文档中,该文档正在为第一次

    编辑2: 以下是一个工作示例:

    您需要有一个(免费)Cloud9帐户才能运行该项目。登录,打开app.js,然后单击顶部的绿色运行按钮


    查看Steamer,这是一个专门为此而设计的小型模块


    我的方法是发送一个包含信息的cookie,然后从客户端使用它

    server.js

    const visitCard = {
      name: 'John Smit',
      phone: '+78503569987'
    };
    
    router.get('/route', (req, res) => {
      res.cookie('data', JSON.stringify(pollsObj));
      res.render('index');
    });
    
    const getCookie = (name) => {
      const value = "; " + document.cookie;
      const parts = value.split("; " + name + "=");
      if (parts.length === 2) return parts.pop().split(";").shift();
    };
    
    const deleteCookie = (name) => {
      document.cookie = name + '=; max-age=0;';
    };
    
    const parseObjectFromCookie = (cookie) => {
      const decodedCookie = decodeURIComponent(cookie);
      return JSON.parse(decodedCookie);
    };
    
    window.onload = () => {
      let dataCookie = getCookie('data');
      deleteCookie('data');
    
      if (dataCookie) {
        const data = parseObjectFromCookie(dataCookie);
        // work with data. `data` is equal to `visitCard` from the server
    
      } else {
        // handle data not found
      }
    
    client.js

    const visitCard = {
      name: 'John Smit',
      phone: '+78503569987'
    };
    
    router.get('/route', (req, res) => {
      res.cookie('data', JSON.stringify(pollsObj));
      res.render('index');
    });
    
    const getCookie = (name) => {
      const value = "; " + document.cookie;
      const parts = value.split("; " + name + "=");
      if (parts.length === 2) return parts.pop().split(";").shift();
    };
    
    const deleteCookie = (name) => {
      document.cookie = name + '=; max-age=0;';
    };
    
    const parseObjectFromCookie = (cookie) => {
      const decodedCookie = decodeURIComponent(cookie);
      return JSON.parse(decodedCookie);
    };
    
    window.onload = () => {
      let dataCookie = getCookie('data');
      deleteCookie('data');
    
      if (dataCookie) {
        const data = parseObjectFromCookie(dataCookie);
        // work with data. `data` is equal to `visitCard` from the server
    
      } else {
        // handle data not found
      }
    

    演练 在呈现页面之前,您可以从服务器发送cookie,以便加载页面时cookie可用

    然后,从客户端获取cookie和我找到的解决方案,并将其删除。cookie的内容存储在我们的常量中。如果cookie存在,则将其解析为对象并使用它。请注意,在
    parseObjectFromCookie
    中,首先必须解码内容,然后将JSON解析为对象

    注释

    • 如果以异步方式获取数据,请小心在渲染之前发送cookie。否则,您将收到错误,因为
      res.render()错误
      结束响应。如果数据提取时间太长,您可以使用另一种解决方案,该解决方案不会保留渲染时间太长。另一种方法是从客户端打开套接字,并发送您在服务器中保留的信息。对于这种方法

    • 可能
      data
      不是cookie的最佳名称,因为您可能会覆盖某些内容。请使用对您的目的更有意义的名称

    • 我在其他任何地方都没有找到此解决方案。我不知道是否出于某种原因不建议使用Cookie。我只是认为它可以工作,并检查了它,但我没有在生产中使用它


    最优雅、最简单的方法是使用渲染引擎(至少对于关注的页面)。例如,使用ejs引擎

    node install ejs -s
    
    在server.js上:

    let ejs = require('ejs');    
    app.set('view engine', 'ejs');
    
    然后将所需的index.html页面重命名为index.ejs,并将其移动到/views目录。之后,您可以为该页面创建API endpoit(使用mysql模块):

    在前端,您需要发出GET请求,例如使用Axios