Окно прокрутки контроллер


Я вообще думаю, что шаблон я использую для развития не так-то. Я начну с простой функциональностью, тогда, когда я понимаю, что некоторые части могут быть повторно использованы, я обычно начинаю писать "корневой уровень" функций для того, чтобы быть более сухой. Я обычно разместить эти функции в нижней части моего "сфера". Бы эти функции (changeColumn, в данном случае) лучше быть методы основным объектом? Бы этот сценарий лучше быть организованы в более объектно-ориентированным способом? Существуют ли серьезные проблемы с моим стилем кодирования?

К сожалению, я работаю напрямую с бэкэнд-программистов, которым не наплевать на JS и так я остался сам с собой на этом. Я пытаюсь посмотреть на “рок-звезды”, но они в основном пишу инструментов, а не простые функции взаимодействия, поэтому для такого рода скриптов я редко вижу примеры очень хорошо учиться.

/** Depends on: 
 *  - jQuery (tested with 1.5.1) 
 *    http://jquery.com/
 *  - jQuery scrolTo (tested with 1.4.2)
 *    http://flesler.blogspot.com/2009/05/jqueryscrollto-142-released.html
 **/

// Main obj
omami = {
  init: function() {
        // scrollable area
    var content = $('#content').css('overflow-x', 'scroll'),
        // flag identifying scroll event
        didScroll,
        // flag identifying if scroll event 
        // is caused by mouse / trackpad etc.
        // i.e. user action
        userScroll,
        // flag identifying if scroll event 
        // is caused by script action
        scriptScroll,
        // content sections
        cols = content.find('.column'),
        // hash table to store initial columns x-axis positions
        positionsMap = {},
        currentColHash,
        // Checks if first argument is bigger than second 
        // and smaller than third
        isInRange = function(num, a, b) {
          return (num > a && num < b);
        };

    // store initial columns positions
    cols.each(function() {
      var col = $(this);
      positionsMap[col.attr('id')] = col.position().left;
    });

    // don't bind complex logic directly on scroll –
    // http://ejohn.org/blog/learning-from-twitter/
    content.bind('scroll', function(e) {
      didScroll = true;
    })

    // for each user initiated scroll event 
    // poll current section
    setInterval(function() {
      if ( didScroll && !scriptScroll ) {
        didScroll = false;

        var curScroll = content.scrollLeft(), colID;

        // find what column is selected
        for ( colID in positionsMap ) {
          // safe sex
          if ( {}.hasOwnProperty.call(positionsMap, colID) ) {
            // we compare current left scroll of container element
            // with initial positions of columns
            if ( isInRange(curScroll, positionsMap[colID] - 150, positionsMap[colID] + 410) ) {
              // cut "col-" from column ID
              currentColHash = colID.substring(4);

              // if current col isn't already selected
              if (location.hash.indexOf(currentColHash) == '-1') {
                // indicate user action
                userScroll = true;
                // highlight current column in the address bar
                location.hash = currentColHash;
              }
            }
          }
        }
      }
    }, 250);

    // Controller
    $(window).bind('hashchange', function() {
      var hash = location.hash;

      if (hash != '' && hash != '#') {
        // cut '#' off
        hash = hash.substring(1);

        // don't override user action
        if (!userScroll) {
          // indicate that scroll happens programmatically
          scriptScroll = true;

          // do the scrolling
          content.scrollTo(
            ( content.scrollLeft() + $('#col-' + hash).position().left ) - 20
          , 500, {
            onAfter: function() {
              // done with JavaScript scrolling
              // start polling current section again
              scriptScroll = false;
            }
          });
        }
        userScroll = false;
      } else {
        // support back-button up to empty-hash state
        content.scrollTo(0);
      }
    // on page load, scroll to the proper section
    }).trigger('hashchange');

    // scroll to the next/previous column controls
    // just updating location.hash 
    // controller will take care of taking appropriate action
    $('.column .scroll').bind('click', function(e) {
      e.preventDefault();

      var arrow = $(this);

      // change the column
      changeColumn({
        direction : arrow.hasClass('right') ? 'right' : 'left', 
        currentColumn : arrow.closest('.column')
      });

    });// .scroll bind('click) fn


    // handle left and right arrows
    $(window).bind('keyup', function(e) {
      // 37 – left arrow
      // 39 - right arrow
      if (e.keyCode == 37 || e.keyCode == 39) {
        e.preventDefault();
        changeColumn({
          direction: (e.keyCode == 39) ? 'right' : 'left'
        });
      }
    });// window bind('keyup') fn

    // updates location.hash with slug of the column
    // user wants to view, either by scrolling to it, 
    // either by navigating to it with arrows/header nav
    //
    // @param {Object} options object
    //   @option {String} direction – determens change direction
    //   @option {jQuery} currentColumn – currently selected column
    function changeColumn(opts) {

      // defaults
      var settings = {
        direction : 'right',
        currentColumn : (function(){
          // calculate current column from hash if it's selected
          var colHash = location.hash.substring(1);
          // if it's not, we suppose we are at first column
          return (colHash.length != 0) ? $('#col-' + colHash) : cols.first();
        })()
      };

      // merge options and defaults
      $.extend(settings, opts);

      // what's the next column?
      var nextColumn = 
      (settings.direction == 'right')
      // scroll right
      ? (settings.currentColumn.next().length != 0) 
        // scroll to the next column
        ? settings.currentColumn.next()
        // scroll to the first column
        : settings.currentColumn.siblings().first()
      // scroll left
      : (settings.currentColumn.prev().length != 0) 
        // scroll to the previous column
        ?  settings.currentColumn.prev()
        // scroll to the last column
        : settings.currentColumn.siblings().last();

      // update the hash 
      location.hash = nextColumn.attr('id').substring(4);
    }// fn changeColumn
  } // fn omami.init
};// obj omami


Комментарии
2 ответа

Это немного, чтобы много кода для меня, чтобы пройти на одном дыхании, но я возьму удар на одну часть:

// for each user initiated scroll event 
// poll current section
setInterval(function() {
if ( didScroll && !scriptScroll ) {
didScroll = false;

var curScroll = content.scrollLeft(), colID;

// find what column is selected
for ( colID in positionsMap ) {
// safe sex
if ( {}.hasOwnProperty.call(positionsMap, colID) ) {
// we compare current left scroll of container element
// with initial positions of columns
if ( isInRange(curScroll, positionsMap[colID] - 150, positionsMap[colID] + 410) ) {
// cut "col-" from column ID
currentColHash = colID.substring(4);

// if current col isn't already selected
if (location.hash.indexOf(currentColHash) == '-1') {
// indicate user action
userScroll = true;
// highlight current column in the address bar
location.hash = currentColHash;
}
}
}
}
}
}, 250);

Я бы написал так:

// for each user initiated scroll event 
// poll current section
setInterval(function() {
if ( !didScroll || scriptScroll ) return;
didScroll = false;
var curScroll = content.scrollLeft(), colID;

// find what column is selected
for ( colID in positionsMap ) {
// safe sex
if ( !{}.hasOwnProperty.call(positionsMap, colID) ) continue;
// we compare current left scroll of container element
// with initial positions of columns
if ( !isInRange(curScroll, positionsMap[colID] - 150, positionsMap[colID] + 410) )
continue;
// cut "col-" from column ID
currentColHash = colID.substring(4);

// if current col isn't already selected
if (location.hash.indexOf(currentColHash) !== -1) continue;
// indicate user action
userScroll = true;
// highlight current column in the address bar
location.hash = currentColHash;
}
}
}, 250);

Я надеюсь, что это немного помогло. :)

4
ответ дан 12 марта 2011 в 11:03 Источник Поделиться

У меня нет времени для полноценного ответа.

Вот лишь несколько советов:


  • Вместо того, чтобы комментировать все, оставить только полезное.

    Иногда (как в вашем первом вызова setInterval), это лучше назвать толково функции, а не комментировать то, что он делает.


  • Префикс jQuerified имена переменных с $. Очень полезно

  • Не используйте больше чем одну троичную (?:) оператор одновременно. Это просто ужасно.

    Переписать это как:

    var current = settings.currentColumn,
    next = current[{ right: next, left: prev }[settings.direction]]();
    if (!next.length) {
    next = current.siblings()[{right: first, left: last}[settings.direction]]
    }

    Или лучше: добавить метод, чтобы сделать рядом с логикой цикла.


Я мог бы добавить больше, если я получаю время, чтобы сделать так

2
ответ дан 12 марта 2011 в 11:03 Источник Поделиться