如何从Express / Node.js中的dynamic生成的内容分离内联的JavaScript?

对于那些有几年Web开发经验的人来说,这是一个稍微低级的问题,但是在Programmer Stack ExchangeGoogle上找不到答案之后,我决定在这里问一下。

我为Node.js使用Express web框架,但这个问题并不是特定于任何web框架或编程语言。

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

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

在这里输入图像描述

每个评级块,以及每个买入button/模式对话框都是由for循环生成的,并且与游戏相匹配。 例如,“刺客信条”的“ 购买”button将具有id =“价格刺客信条”#{variable} – 是如何引用Jade中的variables,从服务器传入的。

 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 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 

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

乘以游戏的数量,这就是我在一页上有多less内联脚本。

更糟糕的是,我必须考虑以下情况:

  • 用户未login :以只读模式显示以上评级脚本。
  • 用户已login,但还没有投票

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

 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); } }); } }); 
  • 用户已login但暂停评分 :复制并粘贴另一个只读脚本,用于此特定的if-else条件。

长话短说,它已经成为一个维护噩梦,试图维护我的.jade模板文件中的所有这些JavaScript,我的标记看起来不可接受的脏。

这是什么解决scheme? 对于CRUD应用程序来说,这似乎是一个常见的情况。 理想情况下,我想将所有的JavaScript移动到一个单独的.js文件。 但是,如果我可以删除一些代码重复,那也会很好。

问题是,如果我把内联的JavaScript移动到一个单独的文件,我怎么知道我评价哪个游戏? 如何知道用户点击了哪个购买button?

现在不存在歧义,因为对于N个游戏,我有N个购买button, N个模式对话框和N个评级脚本。 不pipe人们如何看待这种编程风格,维护代码是一种可怕的方式。

请与noobie分享一些见解!

先谢谢你。

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

 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!'); }); }); 

这太长了,看不懂。 无论如何,我想我得到你说的要点,并使用这样的格式:

 <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> 

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

 $(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 }); }); 

至于模式的东西,你可以创build一个具有“模板”的<div>以显示什么。 然后,当你点击任何button时,你使用上面的逻辑(获得第一个父项.item-container来获得项目的细节,然后用这个信息填充模板中的“模板”。 “确定”button不需要一百万硬编码的东西 – 只有一个 – 从模板中获取信息并进行任何调用或提交表单。