2012-11-27 36 views
6

對於有幾年Web開發經驗的人來說,這是一個有點小問題,但是在程序員堆棧交換Google找不到答案後,我決定在這裏問一下。如何從Express/Node.js中動態生成的內容中分離內聯javascript?

我使用的Node.js快遞 web框架,但這個問題是不特定於任何Web框架或編程語言。

這裏是正在從數據庫中查詢遊戲列表。每個遊戲實體是一個錶行,使用for循環生成:

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

enter image description here

每個評分塊,以及每個購買按鈕/模態對話框是由產生帶有與遊戲匹配的id的for循環。例如,對於刺客信條的購買按鈕將有ID =「價格殺手 - 信條」#{}可變 - 是你如何引用翡翠的變量,從服務器中通過。

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

乘上游戲的數量,這就是我多少內嵌腳本有一個頁面上。

更糟糕的是,我必須考慮以下情況:

  • 用戶未登陸:以只讀模式顯示上述評級的腳本。
  • 用戶登錄,但尚未投票:

...在這種情況下,使用下面的腳本:

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); 
          } 
         }); 
         } 
        }); 
  • 用戶登錄,但從評級暫停:複製並粘貼到另一個只讀腳本這個特定的if-else條件。

長話短說,它已成爲一個維護的噩夢試圖保持這個所有的JavaScript在我.jade模板文件,和我的標記看起來不可接受髒。

什麼是一個解決方案?對於CRUD應用程序來說,這似乎是一種常見的情況。理想情況下,我想將所有javascript都移至單獨的。js文件。但是如果我可以刪除一些代碼重複,那也會很棒。

的問題是,如果我移動內嵌的JavaScript到單獨的文件我怎麼知道哪個遊戲am我的評價?我如何知道用戶點擊了哪個購買按鈕?

現在沒有歧義,因爲ň比賽,我有N個購買按鈕,ñ模態對話框和ñ評級腳本。不管任何人對這種編程風格的看法,這是維護代碼的一種可怕的方式。

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

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

大牆文字,但一個很好的問題+1 – Ben

回答

3

這是太長的方式閱讀。不管怎麼說,我想我明白你說的話的要點,並會使用這樣的格式:

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

而且你的腳本將一些與代表團(以儘量減少綁定大大的號碼):

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

至於模態的東西,你既可以創建一個<div>有什麼可以顯示任何一個「模板」。然後,當你點擊任何按鈕時,使用類似上面的邏輯(獲取第一個父項.item-container以獲取有關該項目的詳細信息,然後用該信息填寫模板中的「模板」,然後按「確定」按鈕並不需要一百萬硬編碼的東西 - 只有一個 - 從模板中獲取信息並進行任何調用或提交表單。

+1

謝謝,我結束了使用盡管我不能提供太多的信息,比如所有在特定遊戲上投票的用戶名(隱私問題),所以我最終在我的模板中做了一些邏輯,它將會導致一個布爾變量True/False,它將在data-*屬性中傳遞給客戶端。 –