不能在客户端上呈现EJS模板

Can't Render EJS Template on Client

本文关键字:EJS 模板 客户端 不能      更新时间:2023-09-26

我正在编写express上的应用程序,并且我使用ejs作为视图/模板引擎。

在路径/artists,我渲染视图artists.ejs,其中有艺术家的封面。当点击一个封面,我想要一个AJAX调用来检索相应的数据,把它放在我的模板/视图的艺术家artist.ejs和显示这个模板在我的HTML下的封面。

我看到过这个相关的问题,但它并没有解决我的用例。

一切似乎都很清楚,但我不能用模板渲染数据。我想在服务器端编译模板,将其发送到客户端准备使用,然后在需要时使用从AJAX调用接收到的数据填充它。

我做了什么:

调用/artists时,在服务器端使用ejs.compile(str, opt)进行编译:

router.get('/artists', function(req, res) {
// Compile artist template
fs.readFile('views/artist.ejs', "utf-8", function(err, template) { // Convert template file to string
    artist_template = ejs.compile(template); // Compile template
    res.render('artists.ejs', {template: artist_template}); // render page with compiled template
});

我负责将文件转换为String,因为ejs编译器只适用于String(与Jade .compileFile相比)

然后在客户端,我抓取函数:

<script>
    var template = <%= template %>
</script>

然后在另一个脚本中,我使用AJAX调用检索数据:

$.get('/artists/'+artist_name, function(data) {
    var html = template({artist: data});
    $('#artist-page').html(html);
}

但是当我打电话时,我收到:

Uncaught ReferenceError: fn is not defined

当我调用模板fn时,我收到:

Uncaught ReferenceError: opts is not defined.

函数fn是硬编码的吗?我已经阅读了EJS和Jade文档,但是几乎没有关于我的问题的相关信息。

我是否也需要客户端模板?

我最终找到了一个解决我的问题的方法,我理解了你的回答,你可以用两种不同的方式进行:

1)我所做的:读取并保存模板为字符串,然后用ejs运行时脚本在客户端渲染它。

// In controller.js    
var templates = {};
templates.template1 = fs.readFileSync(filePath1, 'utf-8'); // Read template as a string
templates.template2 = fs.readFileSync(filePath2, 'utf-8');     
...
res.render('app.ejs', {templates: templates}); // Send templates in view
// In view app.ejs
<script type="text/javascript">
   var templates = <%- JSON.stringify(templates) %>; // Get templates object (object of strings) 
</script>
<script type="text/javascript" src="/JS/ejs.min.js"></script> <!-- Load ejs RunTime -->
// In site.js - javascript client/public file
$.get('/artists', function(data) {
     var html = ejs.render(templates.template1, data); // Render ejs client side with EJS script (template1 corresponds to the artists template)
     $('#artists-wrapper').html(html); // Sets HTML
});

因此,我在第一页加载时发送所有模板,然后在客户端呈现所请求的页面。根据我所读到的,有趣的是,您只通过AJAX调用发送JSON对象(您的数据),而不是整个页面,使您的请求变得轻松。只有第一次加载的所有模板都很重。

2)我想做什么根据@RyanZim回答:编译模板服务器端成函数,发送它们,然后在客户端调用它们:模板(数据)。如果我理解得好,在这种情况下不需要EJS客户端库,我的模板不再是字符串,而是函数:

// In controller.js    
var templates = {};
templates.template1 = ejs.compile(fs.readFileSync(filePath1, 'utf-8'), {client: true}); // Get template as a function
templates.template2 = ejs.compile(fs.readFileSync(filePath2, 'utf-8'), {client: true});     
...
res.render('app.ejs', {templates: templates}); // Send templates in view

然而,我不能得到他们在我的观点:

<script type="text/javascript">
   var templates = <%- JSON.stringify(templates) %>; // Get templates object (object of functions) 
</script>   

不能工作。它们是我发送之前服务器上的函数,但是我不知道如何恢复它们。你有什么主意吗?

我尝试了一个解决方法,在发送它们之前将它们更改为String:

templates.template1 = templates.template1.toString();

发送它们,然后在客户端,将它们转换回函数:

var template = new Function(templates.template1);
$.get('/artists', function(data) {
     var html = template(data);
     $('#artists-wrapper').html(html); // Sets HTML
});

但这也行不通。

你知道我错过了什么吗?最后,您是否同意在使用函数之前在服务器端编译它们比在客户端呈现每个模板在计算方面更好?

谢谢你的帮助,希望能帮助到其他人!

在为客户端编译时,需要在服务器端使用client选项。来自文档:

  • clienttrue,编译一个可以渲染的函数,而不需要加载EJS Runtime

https://github.com/mde/ejs选项

您的服务器端代码片段应该是:

// Compile artist template
fs.readFile('views/artist.ejs', "utf-8", function(err, template) {
  artist_template = ejs.compile(template, {client: true}); // Use client option
  res.render('artists.ejs', {template: artist_template});
});