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 变量?

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

4

1 回答 1

51

我可以将 JavaScript 变量传递给模板吗?

可以在模板中获取更多数据并重新呈现它,但不是以您想的方式,并且无需向服务器发出另一个请求(除非它是获取更多数据,而不是获取更多 HTML)。

解决方案:

如果没有更多细节,这个问题将很难回答,所以我将对为什么要将选定的值传递到 EJS 模板做一些假设。我会尽我所能用关于你目标的有限信息来回答这个问题。

您的用户似乎正在页面上执行一些操作,例如选择清洁用品,并且您希望根据用户选择的元素以不同的方式呈现数据。为此,您可以重新渲染模板并传入标识选定元素的数据,使用视图助手将特定类应用于选定元素:

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

清洁.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。

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

<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 评估<script>添加到 DOM 的块。

换句话说,在我的测试模板中,当我尝试添加脚本标签以将所选值输出到控制台时,我可以看到添加了脚本块,但由于 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:

正如您在下面看到的,console.log 语句存在于 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>

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

于 2012-05-27T23:56:17.073 回答