Pull to refresh

Практическое применение Backbone.View

JavaScript *

В своем прошлом топике, я описал базовые принципы работы с фреймворком backbone.js, теперь предлагаю перейти к практике и сделать что-нибудь полезное.

Задача


Предположим, что на нашем сайте часто используются разного вида попапы. Все они обладают схожими чертами, их можно открывать в большом количестве, перетаскивать, закрывать. Кроме того различаются активные и неактивные попапы, причем активный расположен поверх остальных и не затенен (хм… я бы сказал, что это уже больше напоминает window-manager).
Вобщем как-то так:


В соответствии с заветами ООП, попробуем разработать класс для попапа, от которого мы сможем наследоваться и создавать попапы на свой вкус с общим для всех поведением.

Скачиваем backbone.js, jquery, jquery ui, underscore.js и

index.html


Для начала создадим индексный файл с подключенными библиотеками, файлами нашего (еще не написанного) приложения и шаблонами.

<!doctype html>
<html>
<head>
  <title>Popup demo</title>
  
  <link rel="stylesheet" href="css/main.css" />
  
  <!-- libs -->
  <script type="text/javascript" src="js/lib/jquery.js"></script>
  <script type="text/javascript" src="js/lib/jquery-ui.js"></script>
  <script type="text/javascript" src="js/lib/underscore.js"></script>
  <script type="text/javascript" src="js/lib/backbone.js"></script>
  
  <!-- app -->
  <script type="text/javascript" src="js/app/app.js"></script>
  <script type="text/javascript" src="js/app/views/PopupView.js"></script>
  <script type="text/javascript" src="js/app/views/ChildPopupView.js"></script>
  
  <!-- templates -->
  <script id="popup-template" type="text/template">
    <div class="title">
      <h1><%= title %></h1>
    </div>
    <div class="content">
      <%= content %>
    </div>
    <div class="popup-close">
    </div>
  </script>
  
  <script id="child-popup-template" type="text/template">
    <div class="title">
      <h1><%= title %></h1>
      <h3>i am a child</h3>
    </div>
    <div class="content">
      <%= content %>
    </div>
    <div class="popup-close">
    </div>
  </script>
  
</head>
<body>
  <button id="popup-button">popup</button>
  <button id="child-popup-button">child popup</button>
</body>
</html>


В «body» у нас только 2 кнопки с помощью которых мы будем создавать попапы.

app.js


В этом файлике на клики по кнопкам навешивается код, создающий попапы, и добавляющий их в наш DOM.
function getRandomInt(min, max) {
	return Math.floor(Math.random() * (max - min + 1)) + min;
}

$(function () {
  $('#popup-button').click(function () {
    var popup = new PopupView();  
    $('body').append(popup.render().el);
  });
  
  $('#child-popup-button').click(function () {
    var popup = new ChildPopupView();  
    $('body').append(popup.render().el);
  });
});

Так же я сюда запихнул функцию для получения случайного целого числа, она нам потом пригодится.

И теперь самое интересное!

PopupView.js


var PopupView = Backbone.View.extend({
  className: 'popup',

  events: {
    'click .popup-close': 'close',
    'mousedown': 'raise'
  },
  
  initialize: function () {
    this.template = $('#popup-template').html();
    
    this.width = '400px';
    this.height = '350px';
    this.top = getRandomInt(100, 400) + 'px';
    this.left = getRandomInt(200, 500) + 'px';
    
    this.context = {
      title: 'Default Title',
      content: 'Lorem ipsum dolor sit amet.'
    }
    
    $(this.el).css({
      'width': this.width,
      'height': this.height,
      'top': this.top,
      'left': this.left,
      'position': 'absolute'
    });
    
    $(this.el).draggable();
  },
  
  /**
   * Рендерит попап и располагает его поверх остальных.
   */
  render: function () {
    $(this.el).html(_.template(this.template, this.context));
    
    // Делаем декущий попап активным
    $('.popup-active').removeClass('popup-active');
    $(this.el).addClass('popup-active');
    
    // Начальный z-index, минимальное значение которое может получить попап
    var max_z = 100;
    
    $('.popup').each(function () {
      var curr_z = parseInt($(this).css('z-index'));
      if (curr_z > max_z) {
        max_z = curr_z;
      }
    });
    
    $(this.el).css({ 'z-index': max_z + 10 });
    
    return this;
  },
  
  /**
   * Поднимает попап наверх и делает его активным
   * по нажатию кнопки мыши.
   */
  raise: function (e) {
    if (!$(this.el).hasClass('popup-active')) {
      var max_z = 0;
      
      $('.popup-active').removeClass('popup-active');
      
      $('.popup').each(function () {   
        var curr_z = parseInt($(this).css('z-index'));
        if (curr_z > max_z) {
          max_z = curr_z;
        }
      });
      
      $(this.el).css({ 'z-index': max_z + 10 });
      $(this.el).addClass('popup-active')
    }
  },
  
  /**
   * Удаляет попап из DOM.
   */
  close: function () {
    $(this.el).remove();
    
    var max_z = 0;
    var top = null;
    
    
    // Выбираем самый верхний их оставшихся попапов
    $('.popup').each(function () {
      var curr_z = parseInt($(this).css('z-index'));
      if (curr_z > max_z) {
        max_z = curr_z;
        top = this;
      }
    });
    
    // Делаем его активным
    if (top) {
      $(top).addClass('popup-active');
    }
  }
});


Здесь у нас описан попап, который станет родителем для всех остальных попапов, в нем реализован весь типичный функционал.

Теперь, для того чтобы создать новый попап, реализующий какое-то новое поведение, или использующий другой шаблон нам потребуется всего несколько строк кода.

ChildPopupView.js


var ChildPopupView = PopupView.extend({
  initialize: function () {
    ChildPopupView.__super__.initialize.call(this);
    
    this.template = $('#child-popup-template').html();
    
    this.context = {
      title: 'Child Title',
      content: 'Lorem ipsum dolor sit amet.'
    }
  }
});


В этом потомке мы подключили другой шаблон и поменяли заголовок попапа. Вот так вот все просто!

Код демки
Tags:
Hubs:
Total votes 41: ↑35 and ↓6 +29
Views 28K
Comments Comments 36