在 <% 标签内交织 EJS 和 JavaScript 变量

20

我需要在一些EJS代码中使用一个Javascript变量(在前端定义),如下所示:

var selected = 1;
<% for (var i=0; i < supplies.length; i++) { %>
    if (i == selected) {
        console.log(supplies);    
    }
<% } %>

我正在使用EJS、Express.js和socket.io。我可以通过向我的Node.js服务器实例发送消息将Javascript变量转换为EJS变量,但这有点傻...是否有一种方法可以在EJS中使用Javascript变量?

编辑: 我想在用户从下拉菜单中选择一个项目后访问supplies(一个Javascript数组)。当他选择这个项目时,上述代码中的一个Javascript函数需要访问一些EJS。这就是为什么我需要在EJS中使用普通的Javascript变量的原因。


在这种方式中使用EJS的目的是什么?我的理解是,EJS用于通过嵌入JavaScript来模板化HTML文件。看起来你正在将某些东西嵌入到默认情况下已经嵌入的地方。考虑使用问题下面的[编辑]链接添加更多关于为什么必须在这里使用EJS的细节。我认为这将为社区提供更多上下文信息以便解决问题。祝好运 :) - jamesmortensen
1
嗨durplr,EJS是客户端JavaScript,对吧?还是说它是服务器端的?;) - jamesmortensen
1个回答

53

我可以将JavaScript变量传递到模板中吗?:

可能会有更多的数据进入模板并重新呈现它,但不是您想象的方式,并且不需要向服务器发出另一个请求(除非是为了获取更多数据而不是获取更多HTML)。

解决方案:

没有更多细节的情况下回答这个问题可能会很困难,因此我将对您希望将选定的值传递到EJS模板中的原因做出一些假设。 我将尽力以有限的信息回答这个问题。

看起来您的用户正在页面上执行某些操作,例如选择清洁用品,您希望根据用户选择的元素以不同的方式呈现数据。 为此,您可以重新呈现模板并传递标识哪个元素已被选中的数据,使用视图助手将特定类应用于所选元素:

这是修改后的cleaning.ejs模板,使用视图助手添加类:

cleaning.ejs:

<script>
// NOTE: even if uncommented, JavaScript inside a template will not run.
//    var selected = 1;
</script>
<h1><%= title %></h1>
<ul>
    <% for(var i=0; i<supplies.length; i++) { %>

        <li>
            <!-- apply a class to the selected element -->
            <a class='<%= supplies[i].selected %>' href='supplies/<%= supplies[i].value %>'>
                <%= supplies[i].value %>
            </a>
        </li>
    <% } %>
</ul>    

呈现的HTML如下:

<script>
    /** NOTE: Script blocks will not fire in rendered templates. They are ignored
    //    var selected = 1;
</script>
<h1>Cleaning Supplies</h1>
<ul>


        <li>
            <a class="" href="supplies/Broom">
                Broom
            </a>
        </li>


        <li>
            <!-- Note the selected element -->
            <a class="selected" href="supplies/mop">
                mop
            </a>
        </li>


        <li>
            <a class="" href="supplies/Hammer">
                Hammer
            </a>
        </li>

</ul>

这个视图是使用以下JavaScript代码呈现的:

// modified data structure so that array of supplies contains objects
 // with the name of the item and whether or not it's selected.
data = {
    "title":"Cleaning Supplies",
    "supplies":[
        {
            "value":"Broom",
            "selected":""
        },
        {
            "value":"mop",
            "selected":"selected"
        },
        {
            "value":"Hammer",
            "selected":""
        }
    ]
};

// pass data into template and render
var html = new EJS({url: 'cleaning.ejs'}).render(data);

// add HTML to the DOM using a <div id="container"></div> wrapper.
document.getElementById("container").innerHTML = html;

正如您所看到的,supplies[i].selected将选择的类应用于在数据结构中标记为选定的元素。我修改了href值,使其访问第i个数组项中的对象,而不是数组本身的值。

现在,当选择的项被修改时,我们只需修改数据变量,重新呈现EJS模板并将其添加到DOM中。

使用此CSS代码放置在HTML文档的头部,您将看到类似于以下显示的内容:

<style>
    .selected { color:red; }
</style>

选定元素的演示,以红色显示


为什么模板中的JavaScript不运行:

您试图使用的方法来操纵JavaScript值或在EJS模板内使用JavaScript值将无法工作。这主要与JavaScript执行的时间上下文有关。

您认为EJS模板是在客户端编译的是正确的。但是,视图助手中的JavaScript是独立于全局上下文中的JavaScript执行的。从查看ejs.js源代码得知,似乎使用了eval。

此外,EJS会将渲染后的HTML作为字符串返回,EJS文档要求我们使用innerHTML将渲染的模板字符串注入到DOM中:

document.getElementById("container").innerHTML = html;

无论您使用哪种视图技术,关于JavaScript,某些浏览器的一个基本真理是:一些浏览器可能不会评估使用innerHTML添加到DOM中的<script>块。

换句话说,在我的测试模板中,当我尝试添加一个脚本标记以将所选值输出到控制台时,我可以看到脚本块已添加,但由于innerHTML的工作方式,它没有被执行:

示例模板演示了使用innerHTML添加的JavaScript代码不会运行:

 <h1><%= title %></h1>
<ul>
    <% for(var i=0; i<supplies.length; i++) {  %>
       <span id="selected"></span><script>console.info('test <%= i %> = <%= supplies[i] %>');</script>            
        <li>
            <a href='supplies/<%= supplies[i] %>'>
                <%= supplies[i] %>
            </a>
        </li>
    <% } %>
</ul>

渲染的HTML:

如下所示,控制台日志语句出现在HTML中。然而,当使用innerHTML添加时,它们不会触发。

对于视图技术的处理方法是将其限制在仅用于渲染视图方面,并保持您的逻辑在“常规JavaScript”中。

<h1>Cleaning Supplies</h1>
<ul>

       <span id="selected"></span><script>console.info('test 0 = Brrom');</script>            
        <li>
            <a href='supplies/Brrom'>
                Brrom
            </a>
        </li>

       <span id="selected"></span><script>console.info('test 1 = mop');</script>            
        <li>
            <a href='supplies/mop'>
                mop
            </a>
        </li>

       <span id="selected"></span><script>console.info('test 2 = Hammer');</script>            
        <li>
            <a href='supplies/Hammer'>
                Hammer
            </a>
        </li>

</ul>

关于EJS模板的更多示例和文档可以在Google Code Embedded JavaScript网站上找到。


4
哇...太棒了!谢谢你的回答,这使事情变得更加清晰明了!你的解决方案把我带上了正确的道路,我想我应该让 EJS 少一些逻辑。 :) - philipDS
很高兴这能帮到你!祝你好运 ;) - jamesmortensen
截至2021年6月1日,这个有变化吗?我在我的ejs模板(或文件,更确切地说 - 也许我没有使用模板?)中使用javascript。ejs模板必须包含{{}}吗?进一步查看 - 我正在使用模板。 - richardwhitney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接