简体   繁体   English

ejs模板的客户端和服务器端渲染

[英]Client side and Server side rendering of ejs template

I always wanted to learn NodeJS to be able to run the same code on server and client side.我一直想学习 NodeJS 以便能够在服务器端和客户端运行相同的代码。 I am using NodeJS with Express and EJS.我将 NodeJS 与 Express 和 EJS 一起使用。 So.所以。 I have a .ejs page with lot's of HTML, JS, CSS and a small bit with template.我有一个 .ejs 页面,其中包含大量 HTML、JS、CSS 和少量模板。 For the sake of justice let it be like this:为了正义,让它变成这样:

the_list-->some.ejs the_list-->some.ejs

<ul> 
<% for(i=0;i>the_list.length;i++) { %>
    <li>the_list[i]</li>
<% } %>
</ul>    

After some rendering on the server we have a perfect list.在服务器上进行一些渲染后,我们有一个完美的列表。

So.所以。 Now I want to rerender it on the client.现在我想在客户端重新渲染它。 I made some ajax request and now I have new items in the_list.我提出了一些 ajax 请求,现在我在 the_list 中有新项目。 What is the right way?什么是正确的方法?

As per ejs templates documentation根据 ejs 模板文档

var template = new EJS({
  text: `
    <ul>
      <% for(i = 0; i < the_list.length; i++) { %>
        <li>the_list[i]</li>
      <% } %>
    </ul>
  `
});
var html = template.render({ the_list: data });
document.getElementById('list-wrapper').innerHTML = html;
<div id="output"></div>
<script src="/assets/js/ejs.js"></script>
<script>
  let blogPosts = [
    {
        title: 'Perk is for real!',
        body: '...',
        author: 'Aaron Larner',
        publishedAt: new Date('2016-03-19'),
        createdAt: new Date('2016-03-19')
    },
    {
        title: 'Development continues...',
        body: '...',
        author: 'Aaron Larner',
        publishedAt: new Date('2016-03-18'),
        createdAt: new Date('2016-03-18')
    },
    {
        title: 'Welcome to Perk!',
        body: '...',
        author: 'Aaron Larner',
        publishedAt: new Date('2016-03-17'),
        createdAt: new Date('2016-03-17')
    }
];
      var html = ejs.render(`<% for(let i = 0; i < posts.length; i++) { %>
    <article>
        <h2><%= posts[i].title %></h1>
        <p><%= posts[i].body %></p>
    </article>
<% } %>`, {posts: blogPosts});
  // Vanilla JS:
  document.getElementById('output').innerHTML = html;
</script>

download ejs.js or ejs.min.js from latest version从最新版本下载 ejs.js 或 ejs.min.js

Sure, EJS works on the client.当然,EJS 在客户端上工作。 You can trivially keep the template in a string variable or apply EJS to user-provided input, but more likely, you'll want to store a template in a script (which can be in an external file) or use fetch to grab your template from another file on demand.您可以将模板简单地保存在字符串变量中或将 EJS 应用于用户提供的输入,但更有可能的是,您希望将模板存储在脚本中(可以在外部文件中)或使用fetch来获取您的模板按需从另一个文件中获取。

Using a template in a <script> is straightforward:<script>中使用模板很简单:

 const people = ["geddy", "neil", "alex"]; const template = document .querySelector("#template") .innerText; document.querySelector("#output") .innerHTML = ejs.render(template, {people});
 <!-- could be an external file --> <script id="template" type="text/template"> <%= people.join(", "); %> </script> <div id="output"></div> <script src="https://unpkg.com/ejs@3.1.6/ejs.min.js"></script>

For fetch , I'll mock the response so it'll be runnable in a snippet:对于fetch ,我将模拟响应,以便它可以在片段中运行:

 // mock fetch for illustrative purposes; // its response content would be another file fetch = async url => ({text: async () => '<%= people.join(", "); %>'}); fetch("/your-template") .then(res => res.text()) .then(template => { const people = ["geddy", "neil", "alex"]; document.querySelector("#output").innerHTML = ejs.render(template, {people}); });
 <script src="https://unpkg.com/ejs@3.1.6/ejs.min.js"></script> <div id="output"></div>

If this seems like too much heavy lifting, you can bury the fetch in a helper function, or go a step further and pick an attribute for each URL, then plug everything in with a call to a library function you can abstract away from the main code.如果这看起来繁重,您可以将fetch在辅助函数中,或者更进一步,为每个 URL 选择一个属性,然后通过调用一个库函数插入所有内容,您可以从主函数中抽象出来代码。 A simple example:一个简单的例子:

 // mock fetch for illustrative purposes; // its response content would be in other files const responses = { "/template.ejs": "<%= 42 %>", "/other-template.ejs": "<%= 43 %>", }; fetch = async url => ({text: async () => responses[url]}); [...document.querySelectorAll("[data-template]")] .forEach(e => { fetch(e.getAttribute("data-template")) .then(res => res.text()) .then(template => { e.innerHTML = ejs.render(template); }); });
 <script src="https://unpkg.com/ejs@3.1.6/ejs.min.js"></script> <div data-template="/template.ejs"></div> <div data-template="/other-template.ejs"></div>

Either way, keep in mind that JS will run after the static HTML is parsed and the DOM loads.无论哪种方式,请记住 JS 将在解析静态 HTML 并加载 DOM 之后运行。 This means the data won't appear all in one fully-formed piece as when using EJS on the server.这意味着数据不会像在服务器上使用 EJS 时那样全部出现在一个完整的片段中。 Network errors are possible.网络错误是可能的。

See also using ejs partials from express client side .另请参阅使用来自 express 客户端的 ejs partials If you want to mock the include function, the problem is that the fetch call is asynchronous but the include function isn't.如果你想模拟include函数,问题是fetch调用是异步的,但include函数不是。 EJS offers an include callback that seems like it offers an opportunity to pull in an external file, but it's purely synchronous and won't await any promises you return. EJS 提供了一个包含回调,看起来它提供了一个拉入外部文件的机会,但它纯粹是同步的,不会等待您返回的任何承诺。 How to work around this best depends on your use case.如何最好地解决这个问题取决于您的用例。

This should work, looks like your problem was the relational operator '>' because it will never output something.这应该可以工作,看起来你的问题是关系运算符'>',因为它永远不会输出一些东西。

<ul>
    <% for(var i=0; i<the_list.length; i++) { %>
        <li>
            <a>
                <%= the_list[i]%>
            </a>
        </li>
    <% } %>
</ul>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM