如何从Express / Node.js中动态生成的内容分离内嵌的JavaScript? [英] How to separate inline javascript from dynamically generated content in Express/Node.js?

查看:191
本文介绍了如何从Express / Node.js中动态生成的内容分离内嵌的JavaScript?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于具有几年网络开发经验的人来说,这是一个有点noob问题,但是在没有找到程序员堆栈交换或 Google 的答案之后,我已经决定在这里问问。



我正在使用 Express Web框架来 ,但这个问题不是特定于任何Web框架或编程语言。



以下是从数据库中查询的游戏列表。每个游戏实体是使用 for-loop 生成的单个表行:

  table.table 
tbody
游戏中的游戏
tr
td.span2
img.img-polaroid(src ='/ img / games /#{game.largeImage}' )
//继续进一步



每个评级块,以及每个购买按钮/模态对话框由具有与游戏匹配的id的for-loop生成。例如,刺客信条的购买按钮将具有 id =price-assassins-creed#{variable} - 是如何引用从服务器传入的Jade中的变量。

  button.btn.btn-primary.btn-mini(id ='price  - #{game.slug}',href ='#buyModal',role ='button',data-toggle ='modal')

  .modal.hide.fade(id ='modal  - #{game.slug}',tabindex =' -  1',role ='dialog',aria-labelledby ='myModalLabel',aria-hidden ='true') 
.modal-header
span.lead游戏结帐
img.pull-right(src ='/ img / new_visa_medium.gif')
.modal-body
标签
i.icon-user
|卡上的名字
input.input-medium(type ='text')
label
i.icon-barcode
|卡号
input.input-medium(type ='text',placeholder ='••••••••••••••••',maxlength = 16)

label
i.icon-time
|到期日期
input.input-mini(type ='text',placeholder ='MMYY',maxlength = 4)
label
i.icon-qrcode
|卡代码
input.input-mini(type ='text',placeholder ='CVC',maxlength = 4)
.modal-footer
button.btn(data-dismiss ='modal ',aria-hidden ='true')取消
button.btn.btn-primary(id ='#{game.slug}')购买

  script(type ='text / javascript')
$('#_#{game.slug}')。raty({
path:'/ img',
round:{down:.25,full:.6,up: .76},
得分:#{game.rating} /#{game.votes},
readOnly:true
});

乘以游戏数量,这是一页上有多少个内嵌脚本。 p>

更糟糕的是,我必须解决以下情况:




  • 用户未登录:以只读模式显示上述评级脚本。

  • 用户登录但尚未投票



...在这种情况下,请使用以下脚本:

  script(type ='text / javascript')
$('#_#{game.slug}')。raty({
path:'/ img' ,
round:{down:.25,full:.6,up:.76},
score:#{game.rating} /#{game.votes},
readOnly: false,
click:function(score,event){
var self = this;
$ .meow({
message:'谢谢投票,你的评级已被记录。',
图标:'http://png-3.findicons.com/files/icons/1577/danish_royalty_free/32/smiley.png'
});
$ .ajax({
type:'POST',
url:'/ games / rating',
data:{
slug:$(self) attr('id')。slice(1),
rating:score
},
success:function(){
console.log('setting to read-only' );
$(self).raty('readOnly',true);
}
});
}
});




  • 用户登录但暂停评级:复制并粘贴另一个只读脚本,用于此特定的 if-else 条件。



简单的说,它已经成为一个维护噩梦,试图在我的 .jade 模板文件中维护所有这些JavaScript,我的标记看起来是无法接受的。



这是什么解决方案?这似乎是CRUD应用程序的常见场景。理想情况下,我想将所有javascript移到单独的 .js 文件中。但是如果我可以删除一些代码重复,那也是太好了。



问题是如果我将内联JavaScript移动到单独的文件,我该如何知道我评分哪个游戏?如何知道用户点击了哪个购买按钮?



现在没有歧义,因为 N 游戏我有N个购买按钮, N 模态对话框和 N 评分脚本。不管任何人对这种风格的编程有什么想法,维护代码是一个很糟糕的方法。



请与noobie分享一些洞察力!



提前谢谢。



以下是我的games.jade文件的完整代码段:

 扩展布局

块内容
br
ul.nav.nav-pills
如果标题==='前25'
li.active
a(href ='/ games')前25
else
li
a(href = '/ games')Top 25

如果标题==='Action'
li.active
a(href ='/ games / genre / action')Action
else
li
a(href ='/ games / genre / action')Action

如果标题==='冒险'
li.active $ b $冒险


a(href ='/ games / genre / adventure')冒险

如果标题==='驾驶'
li.active
a(href ='/ games / genre / driving')驾驶
else
li
a(href ='/游戏/流派/驾驶')Driv

如果标题==='拼图'
li.active
a(href ='/ games / genre / puzzle')拼图
else
li
a(href ='/ games / genre / puzzle')拼图

如果标题==='角色扮演'
li.active
a(href = '/ games / genre / role-playing')角色扮演
else
li
a(href ='/ games / genre / role-playing')角色扮演

如果标题==='模拟'
li.active
a(href ='/ games / genre / simulation')模拟
else
li
a href ='/ games / genre / simulation')模拟

如果标题==='策略'
li.active
a(href ='/ games / genre / strategy' )策略
else
li
a(href ='/ games / genre / strategy')策略

如果标题==='运动'
li .active
a(href ='/ games / genre / sports')运动
else
li
a(href ='/ games / genre / sports')运动


如果games.length == 0
.alert.alert-warning
|数据库查询没有返回结果。
else
table.table
tbody
游戏中的游戏
.modal.hide.fade(id ='modal - #{game.slug}',tabindex =' - 1',角色='对话',aria-labelledby ='myModalLabel',aria-hidden ='true')
.modal-header
span.lead游戏结帐
img .pull-right(src ='/ img / new_visa_medium.gif')
.modal-body
label
i.icon-user
|卡上的名字
input.input-medium(type ='text')
label
i.icon-barcode
|卡号
input.input-medium(type ='text',placeholder ='••••••••••••••••',maxlength = 16)

label
i.icon-time
|到期日期
input.input-mini(type ='text',placeholder ='MMYY',maxlength = 4)
label
i.icon-qrcode
|卡代码
input.input-mini(type ='text',placeholder ='CVC',maxlength = 4)
.modal-footer
button.btn(data-dismiss ='modal ',aria-hidden ='true')取消
button.btn.btn-primary(id ='#{game.slug}')购买
tr
td.span2
img.img-polaroid(src ='/ img / games /#{game.largeImage}')
td
a(href ='/ games /#{game.slug}')
strong
= game.title
| &安培; NBSP;

如果user.userName
button.btn.btn-primary.btn-mini(id ='price - #{game.slug}',href ='#modal - #{game .slug}',role ='button',data-toggle ='modal')
i.icon-shopping-cart.icon-white
= game.price
如果user.purchasedGames &安培;&安培; user.purchasedGames.length> 0
forgame in user.purchasedGames
if mygame.game.slug == game.slug
script(type ='text / javascript')
$('#price- #{game.slug} ')removeAttr(' href属性);
$('#price - #{game.slug}')。html('< i class =icon-shopping-cart icon-white>< / i>已购买)

div
span(id ='_'+ game.slug)
span(id ='票',name ='票')
| (#{game.votes} votes)
div
small.muted
div#{game.releaseDate} | #{game.publisher}
div#{game.genre}
p
= game.description

//登录用户
如果用户。 userName
如果game.votedPeople.length> 0
为选民在game.votedPeople
如果选民== user.userName || user.suspendedRating
script(type ='text / javascript')
$('#_#{game.slug}')。raty({
path:'/ img',
round:{down:.25,full:.6,up:.76},
score:#{game.rating} /#{game.votes},
readOnly:true
});
else
脚本(type ='text / javascript')
$('#_#{game.slug}')。raty({
path:'/ img' ,
round:{down:.25,full:.6,up:.76},
score:#{game.rating} /#{game.votes},
readOnly: false,
click:function(score,event){
var self = this;
$ .meow({
message:'感谢您投票,您的评分已被记录。 ',
icon:'http://png-3.findicons.com/files/icons/1577/danish_royalty_free/32/smiley.png'
});
$ .ajax( {
type:'POST',
url:'/ games / rating',
data:{
slug:$(self).attr('id' ).slice(1),
rating:score
},
success:function(){
console.log('setting to read-only');
$(self).raty('readOnly',true);
}
});
}
});
else
if(user.suspendedRating)
script(type ='text / javascript')
$('#_#{game.slug}')。raty
路径:'/ img',
round:{down:.25,full:.6,up:.76},
score:#{game.rating} /#{game .votes},
readOnly:true
});
else
脚本(type ='text / javascript')
$('#_#{game.slug}')。raty({
path:'/ img / ',
round:{down:.25,full:.6,up:.76},
score:#{game.rating} /#{game.votes},
readOnly :false,
click:function(score,event){
var self = this;
$ .meow({
message:'感谢您的投票)您的评分已被记录',
图标:'http://png-3.findicons.com/files/icons/1577/danish_royalty_free/32/smiley.png'
});
$ .ajax ({
type:'POST',
url:'/ games / rating',
data:{
sl ug:$(self).attr('id')。slice(1),
rating:score
},
success:function(){
console.log '设置为只读');
$(self).raty('readOnly',true);
}
});
}
});
else
脚本(type ='text / javascript')
$('#_#{game.slug}')。raty({
path:'/ img' ,
round:{down:.25,full:.6,up:.76},
score:#{game.rating} /#{game.votes},
readOnly: true
});

脚本(type ='text / javascript')
$('## {game.slug}')点击(function(){
var game = this;
$ .ajax({
type:'post',
url:'/ buy',
data:{
slug:$(game).attr 'id')
}
})。success(function(){
$('#price - #{game.slug}')attr('disabled','true' );
$('#modal-'+ $(game).attr('id'))。modal('hide');
humane.log('你的订单已经提交! );
});
});


解决方案

这段时间太长了。无论如何,我想我得到你所说的要点,并使用这样的格式:

 < div id = some_container > 
<! - 以下div将在您所说的for循环的每次迭代中生成 - >
< div class =item-containerdata-game-name =你的游戏名称data-game-id =23>
< span class =button delete-button> X< / span>
< / div>
< / div>

您的脚本将是委托的东西(以最大限度地减少绑定的数量):

  $(document).ready(function(){
$(#some_container)。on(click .delete-button,function(){
var $ this = $(this);
var $ container = $ this.closest(。item-container);
var game_name = $ container.data(game-name);
var game_id = $ container.data(game-id);
//使用上述2个变量执行任何操作
});
});

对于模态的东西,你可以创建一个< div> 有一个模板为什么显示什么。然后,当您点击任何按钮时,您使用上述逻辑(获取第一个父 .item-container 以获取该项目的详细信息,他们填写模板在这个信息的模态,那么这样的OK按钮不需要一百万个硬编码的东西 - 只需一个 - 从模板中获取信息,并做任何调用或提交表单。


This is a somewhat noob-question for someone who had a few years of web development experience, but after not finding the answer on either Programmer Stack Exchange or Google, I have decided to ask it here.

I am using Express web framework for Node.js, but this question is not specific to any web framework or programming language.

Here's a list of games that are queried from the database. Each game entity is a single table row, generated using a for-loop:

    table.table
      tbody
        for game in games
          tr
            td.span2
              img.img-polaroid(src='/img/games/#{game.largeImage}')   
              // continues further  

Each Rating block, as well as each Buy button/modal dialog are generated by the for-loop with an id that matches the game. For example, the Buy button for Assassin's Creed will have id="price-assassins-creed". #{variable} - is how you reference a variable in Jade, passed in from the server.

button.btn.btn-primary.btn-mini(id='price-#{game.slug}', href='#buyModal', role='button', data-toggle='modal')

and

.modal.hide.fade(id='modal-#{game.slug}', tabindex='-1', role='dialog', aria-labelledby='myModalLabel', aria-hidden='true')
            .modal-header
              span.lead Game Checkout
                img.pull-right(src='/img/new_visa_medium.gif')
            .modal-body
              label
                i.icon-user
                |  Name on Card
              input.input-medium(type='text')
              label
                i.icon-barcode
                |  Card Number
              input.input-medium(type='text', placeholder='•••• •••• •••• ••••', maxlength=16)

              label
                i.icon-time
                |  Expiration Date
              input.input-mini(type='text', placeholder='MMYY', maxlength=4)
              label
                i.icon-qrcode
                |  Card Code
              input.input-mini(type='text', placeholder='CVC', maxlength=4)
            .modal-footer
              button.btn(data-dismiss='modal', aria-hidden='true') Cancel
              button.btn.btn-primary(id='#{game.slug}') Buy

and

script(type='text/javascript')
  $('#_#{game.slug}').raty({
    path: '/img',
    round : { down: .25, full: .6, up: .76 },
    score: #{game.rating}/#{game.votes},
    readOnly: true
  });

Multiply that by the number of games and that's how many inline scripts I have on one page.

Worse yet, I have to account for the following cases:

  • User's not logged-in: display above rating script in read-only mode.
  • User's logged-in, but hasn't voted yet:

...in that case, use the following script:

script(type='text/javascript')
                    $('#_#{game.slug}').raty({
                      path: '/img',
                      round : { down: .25, full: .6, up: .76 },
                      score: #{game.rating}/#{game.votes},
                      readOnly: false,
                      click: function (score, event) {
                        var self = this;
                        $.meow({
                          message: 'Thanks for voting. Your rating has been recorded.',
                          icon: 'http://png-3.findicons.com/files/icons/1577/danish_royalty_free/32/smiley.png'
                        });
                        $.ajax({
                          type: 'POST',
                          url: '/games/rating',
                          data: {
                            slug: $(self).attr('id').slice(1),
                            rating: score
                          },
                          success: function () {
                            console.log('setting to read-only');
                            $(self).raty('readOnly', true);
                          }
                        });
                      }
                    });

  • User's logged-in but suspended from rating: Copy and paste yet another read-only script for this particular if-else condition.

Long story short, it has become a maintenance nightmare trying to maintain all this JavaScript in my .jade template files, and my markup looks unacceptably dirty.

What's a solution for this? This seems like such a common scenario for CRUD applications. Ideally I would like to move all javascript to a separate .js file. But if I could remove some code duplication, that would be great too.

The problem is if I move inline javascript to a separate file how do I know which game am I rating? How do I know which Buy button has user clicked on?

Right now there is no ambiguity because for N games I have N buy buttons, N modal dialogs and N rating scripts. Regardless of what anyone thinks of this style of programming, it's an awful way to maintain the code.

Please share some insight with a noobie!

Thank you in advance.

Here's a complete code snippet of my games.jade file:

extends layout

block content
  br
  ul.nav.nav-pills
    if heading === 'Top 25'
      li.active
        a(href='/games') Top 25
    else
      li
        a(href='/games') Top 25

    if heading === 'Action'
      li.active
        a(href='/games/genre/action') Action
    else
      li
        a(href='/games/genre/action') Action

    if heading === 'Adventure'
      li.active
        a(href='/games/genre/adventure') Adventure
    else
      li
        a(href='/games/genre/adventure') Adventure

    if heading === 'Driving'
      li.active
        a(href='/games/genre/driving') Driving
    else
      li
        a(href='/games/genre/driving') Driving

    if heading === 'Puzzle'
      li.active
        a(href='/games/genre/puzzle') Puzzle
    else
      li
        a(href='/games/genre/puzzle') Puzzle

    if heading === 'Role-Playing'
      li.active
        a(href='/games/genre/role-playing') Role-Playing
    else
      li
        a(href='/games/genre/role-playing') Role-Playing

    if heading === 'Simulation'
      li.active
        a(href='/games/genre/simulation') Simulation
    else
      li
        a(href='/games/genre/simulation') Simulation

    if heading === 'Strategy'
      li.active
        a(href='/games/genre/strategy') Strategy
    else
      li
        a(href='/games/genre/strategy') Strategy

    if heading === 'Sports'
      li.active
        a(href='/games/genre/sports') Sports
    else
      li
        a(href='/games/genre/sports') Sports


  if games.length == 0
    .alert.alert-warning
      | Database query returned no results.
  else
    table.table
      tbody
        for game in games
          .modal.hide.fade(id='modal-#{game.slug}', tabindex='-1', role='dialog', aria-labelledby='myModalLabel', aria-hidden='true')
            .modal-header
              span.lead Game Checkout
                img.pull-right(src='/img/new_visa_medium.gif')
            .modal-body
              label
                i.icon-user
                |  Name on Card
              input.input-medium(type='text')
              label
                i.icon-barcode
                |  Card Number
              input.input-medium(type='text', placeholder='•••• •••• •••• ••••', maxlength=16)

              label
                i.icon-time
                |  Expiration Date
              input.input-mini(type='text', placeholder='MMYY', maxlength=4)
              label
                i.icon-qrcode
                |  Card Code
              input.input-mini(type='text', placeholder='CVC', maxlength=4)
            .modal-footer
              button.btn(data-dismiss='modal', aria-hidden='true') Cancel
              button.btn.btn-primary(id='#{game.slug}') Buy
          tr
            td.span2
              img.img-polaroid(src='/img/games/#{game.largeImage}')
            td
              a(href='/games/#{game.slug}')
                strong
                  = game.title
              | &nbsp;

              if user.userName
                button.btn.btn-primary.btn-mini(id='price-#{game.slug}', href='#modal-#{game.slug}', role='button', data-toggle='modal')
                  i.icon-shopping-cart.icon-white
                  =  game.price
                if user.purchasedGames && user.purchasedGames.length > 0
                  for mygame in user.purchasedGames
                    if mygame.game.slug == game.slug
                      script(type='text/javascript')
                        $('#price-#{game.slug}').removeAttr('href');
                        $('#price-#{game.slug}').html('<i class="icon-shopping-cart icon-white"></i> Purchased');

              div
                span(id='_' + game.slug)
                span(id='votes', name='votes')
                |  (#{game.votes} votes)
              div
                small.muted
                  div #{game.releaseDate} | #{game.publisher}
                  div #{game.genre}
              p
                =game.description

          // logged-in users
          if user.userName
            if game.votedPeople.length > 0
              for voter in game.votedPeople
                if voter == user.userName || user.suspendedRating
                  script(type='text/javascript')
                    $('#_#{game.slug}').raty({
                      path: '/img',
                      round : { down: .25, full: .6, up: .76 },
                      score: #{game.rating}/#{game.votes},
                      readOnly: true
                    });
                else
                  script(type='text/javascript')
                    $('#_#{game.slug}').raty({
                      path: '/img',
                      round : { down: .25, full: .6, up: .76 },
                      score: #{game.rating}/#{game.votes},
                      readOnly: false,
                      click: function (score, event) {
                        var self = this;
                        $.meow({
                          message: 'Thanks for voting. Your rating has been recorded.',
                          icon: 'http://png-3.findicons.com/files/icons/1577/danish_royalty_free/32/smiley.png'
                        });
                        $.ajax({
                          type: 'POST',
                          url: '/games/rating',
                          data: {
                            slug: $(self).attr('id').slice(1),
                            rating: score
                          },
                          success: function () {
                            console.log('setting to read-only');
                            $(self).raty('readOnly', true);
                          }
                        });
                      }
                    });
            else
              if (user.suspendedRating)
                script(type='text/javascript')
                  $('#_#{game.slug}').raty({
                    path: '/img',
                    round : { down: .25, full: .6, up: .76 },
                    score: #{game.rating}/#{game.votes},
                    readOnly: true
                  });
              else
                script(type='text/javascript')
                  $('#_#{game.slug}').raty({
                        path: '/img/',
                        round : { down: .25, full: .6, up: .76 },
                        score: #{game.rating}/#{game.votes},
                        readOnly: false,
                        click: function (score, event) {
                          var self = this;
                          $.meow({
                            message: 'Thanks for voting. Your rating has been recorded.',
                            icon: 'http://png-3.findicons.com/files/icons/1577/danish_royalty_free/32/smiley.png'
                          });
                          $.ajax({
                            type: 'POST',
                            url: '/games/rating',
                            data: {
                              slug: $(self).attr('id').slice(1),
                              rating: score
                            },
                            success: function () {
                              console.log('setting to read-only');
                              $(self).raty('readOnly', true);
                            }
                          });
                        }
                      });
          else
            script(type='text/javascript')
              $('#_#{game.slug}').raty({
                path: '/img',
                round : { down: .25, full: .6, up: .76 },
                score: #{game.rating}/#{game.votes},
                readOnly: true
              });

          script(type='text/javascript')
            $('##{game.slug}').click(function() {
              var game = this;
              $.ajax({
                type: 'post',
                url: '/buy',
                data:  {
                  slug: $(game).attr('id')
                }
              }).success(function () {
                $('#price-#{game.slug}').attr('disabled', 'true');
                $('#modal-' + $(game).attr('id')).modal('hide');
                humane.log('Your order has been submitted!');
              });
            });

解决方案

That was way too long to read. Anyways, I think I get the gist of what you're saying and would use a format like this:

<div id="some_container">
    <!-- The following div would be generated in each iteration of the for loop you speak of -->
    <div class="item-container" data-game-name="Your game name" data-game-id="23">
        <span class="button delete-button">X</span>
    </div>
</div>

And your script would be something with delegation (to minimize the number of bindings greatly):

$(document).ready(function () {
    $("#some_container").on("click", ".delete-button", function () {
        var $this = $(this);
        var $container = $this.closest(".item-container");
        var game_name = $container.data("game-name");
        var game_id = $container.data("game-id");
        // Do whatever with the above 2 variables
    });
});

As for the modal stuff, you could either create a <div> that has a "template" for what to display for whatever. Then, when you click on whatever button, you use logic like the above (get the first parent .item-container to get details on the item, them fill in the "template" in the modal with this information. Then that way, the "OK" button doesn't need a million hardcoded things - just one - grab the information from the template and make whatever call or submit the form.

这篇关于如何从Express / Node.js中动态生成的内容分离内嵌的JavaScript?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆