понедельник, 28 октября 2013 г.

Event-Focused JS and CSS

medium.com/objects-in-space/9b8a9dd7bfe3

The Rules

1. Use the data-behavior HTML attribute to designate what an element does when clicked, touched or interacted with in some way.

2. Visual changes happen via CSS only — size, color, opacity, and especially animation. Visual changes come about by adding or removing CSS classes via Javascript.

4. Use class names with semantic meaning for your document (.title, .actions, .error), not literal meaning (.big, .hide, .red).

5. Standard DOM events (click, change) are attached via .on() and in turn fire of meaningful custom events (open, save) via .trigger().

5. Responding to custom events is what adds and removes CSS class names to control visual changes.

6. When possible, events should be attached to the outer-most container of a “module”, not the actual item being interacted with.

Using data-behavior makes easy to add the behavior to new elements. If you have a dialog box that closes with a “Close” button and later decide to also add a big “X” up the top corner, give the “X” the same data-behavior attribute and it starts working the same as the “Close” button with no additional work—no need to add another class to a jQuery selector.

The standard syntax for this is $(‘[data-behavior~=open]’). This attaches to any HTML element that contains a data-behavior=”open” attribute. The ~= syntax means that “open” only needs to be somewhere in the data-behavior attribute. This means you can have multiple behaviors on one element.

If you attached two open events via a call to on() and later wanted to remove one with off(‘open’) you would be stuck: all open events are now gone. But calling off(‘open.task’) removes only that single event.

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <style type="text/css">
   
        body {
            background-color: #eeeeee;
        }
       
        h2 {
            margin: 0;
            font-size: 16px;
            font-weight: bold;
        }
       
        p {
            margin: 0;
        }
       
        ul {
            margin: 0;
            padding: 0;
            list-style: none;
        }
       
        form {
            text-align: center;
            overflow: hidden;
            height: 0;
            transition: height .5s;
        }
       
        /* Task default */
       
        ul#tasks li.task {
            overflow: auto;
            background-color: #ffffff;
            padding: 10px;
            transition: all 1s;
        }
       
        ul#tasks li.task a.open-task {
            display: block;
            float: right;
        }
       
        ul#tasks li.task a.close-task {
           display: none;
            float: right;
        }
       
        /* Task complete */
       
        ul#tasks li.task.complete {
            background-color: #dddddd;
            color: #999999;
        }
       
        ul#tasks li.task.complete a.open-task {
            display: none;
        }
       
        /* Task open */
       
        ul#tasks li.task.open form {
            height: 2em;
        }
       
        ul#tasks li.task.open a.close-task {
            display: block;
        }
       
        ul#tasks li.task.open a.open-task {
            display: none;
        }
       
    </style>
    <script data-main="js/index.js" src="js/lib/require/require.js"></script>
<title>Behavior</title>
</head>
<body>
    <ul id="tasks">
      <li class="task">
        <h2>Task name</h2>
        <p>Task description</h2>
        <a href="#" class="open-task" data-behavior="open">Open</a>
        <a href="#" class="close-task" data-behavior="close">Close</a>
        <form action="/echo/json/">
          <input type="text" name="name">
          <a href="#" class="save" data-behavior="save">Save</a>
        </form>
      </li>
    </ul>
</body>
</html>

index.js

require.config({
      paths: {
          jquery: 'lib/jquery/jquery'
      }
});

require(
    [
          'jquery'
    ]
    , function(
          $
    ) {

        // DOM Events - Стандартные события браузера

        // Разрешен клик только по элементу <a> с  data-behavior="open", находящемуся внутри <li class="task">
        $('ul#tasks li.task').on('click', '[data-behavior~=open]', function() {
           // Найти ближайший родительский тэг <li class="task"> и активировать приязанное ниже к нему событие 'open.task'
            $(this).closest('.task').trigger('open.task');
            return false; // Отменить стандартное поведение элемента <a> при клике по нему
        });

        // Разрешен клик только по элементу <a> с  data-behavior="close", находящемуся внутри <li class="task">
        $('ul#tasks li.task').on('click', '[data-behavior~=close]', function() {
            // Найти ближайший родительский тэг <li class="task"> и активировать приязанное ниже к нему событие 'close.task'
            $(this).closest('li.task').trigger('close.task');
            return false; // Отменить стандартное поведение элемента <a> при клике по нему
        });

        // Разрешен клик только по элементу <a> с  data-behavior="save", находящемуся внутри <li class="task">
        $('ul#tasks li.task').on('click', '[data-behavior~=save]', function() {
            // Найти ближайший родительский тэг <li class="task"> и активировать приязанное ниже к нему событие 'save.task'
            $(this).closest('li.task').trigger('save.task');
            return false; // Отменить стандартное поведение элемента <a> при клике по нему
        });

        // Custom Events - Новые собственные логические события, на которые теперь будут реагировать элементы,
        // созданные разработчиком и искуственно добавленные в систему

        // При возникновении события 'open.task'
        $('ul#tasks li.task').on('open.task', function() {
            $(this).addClass('open');
        });

        // При возникновении события 'close.task'
        $('ul#tasks li.task').on('close.task', function() {
            $(this).removeClass('open');
        });

        // При возникновении события 'save.task'
        $('ul#tasks li.task').on('save.task', function() {
            var $this = $(this);
            $.post('/echo/json').success(function(data) {
                $this.trigger('saved.task', data); // Активировать приязанное к тэгу <li class="task"> событие 'saved.task'
            });
        });

        // При возникновении события 'saved.task'
        $('ul#tasks li.task').on('saved.task', function(e, data) {
            $(this).trigger('complete.task'); // Активировать приязанное к тэгу <li class="task"> событие 'complete.task'
        });

        // При возникновении события 'complete.task'
        $('.task').on('complete.task', function() {
            $(this).trigger('close.task'); // Активировать приязанное к тэгу <li class="task"> событие 'close.task'
            $(this).addClass('complete');
        });
   
    }
);

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

Отправить комментарий