Статьи

Создайте Twitter-подобный виджет «Загрузить еще»

И Twitter, и Apple App Store используют блестящую технику для загрузки дополнительной информации; Вы нажимаете на ссылку, и свежие элементы волшебным образом появляются на экране. Это руководство научит вас использовать AJAX, CSS, Javascript, JSON, PHP и HTML для создания этой магии. В этом руководстве также будут представлены версии скрипта для jQuery и MooTools.


Есть несколько предположений и замечаний, которые мы собираемся использовать в этой системе:

  • На сервере должна быть запущена PHP5, чтобы мы могли использовать функции PHP5 JSON.
  • Мы будем извлекать записи базы данных из таблицы MySQL WordPress «posts». Что хорошего в предоставленном коде, так это то, что вы можете использовать его с любой системой баз данных; все, что вам нужно сделать, это изменить запрос MySQL и свойства JSON, используемые jQuery или MooTools.
  • Клиент должен поддерживать JavaScript.
  • Мы используем MooTools 1.2.3 Core и многое другое 1.2.3.1. Если jQuery является предпочтительным фреймворком, то jQuery 1.3.2 и плагин Ariel Flesler ScrollTo .

В этом руководстве будет дано объяснение JavaScript-кода MooTools. В то время как JQuery
синтаксис отличается от MooTools, красота современных фреймворков JavaScript заключается в том, что
они отличаются в основном по синтаксису, а не по логике. JQuery Javascript будет предоставлен ниже.

Вот последовательность событий, которые будут происходить в нашем скользком виджете:

  • Страница загружается нормально с начальным количеством сообщений, показывающих
  • Пользователь нажимает на элемент «Загрузить еще» внизу списка
  • Запрос AJAX / JSON сработает, получив указанное количество новых сообщений
  • Наш javascript jQuery / MooTools получит результат и создаст серию новых HTML-элементов, содержащих информацию JSON
  • Каждый элемент будет скользить в элемент контейнера виджета
  • После того, как все элементы загружены на страницу, окно прокручивается вниз до первого нового элемента.
  • Промыть и повторить.

Загрузить больше виджетов

Первый шаг — это решить, сколько сообщений нужно загрузить во время начальной загрузки страницы. Поскольку наш виджет будет помнить, сколько сообщений было загружено во время последней загрузки (в случае, если пользователь заходит на другую страницу и возвращается), нам нужно будет использовать сеанс.

1
2
3
4
/* settings */
session_start();
$number_of_posts = 5;
$_SESSION[‘posts_start’] = $_SESSION[‘posts_start’] ?

Приведенный выше фрагмент кода содержит все необходимое нам содержимое «настроек». Затем нам нужно создать функцию PHP, которая подключается к нашей базе данных, получает больше записей и возвращает их содержимое в формате JSON:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
/* grab stuff */
function get_posts($start = 0, $number_of_posts = 5) {
    /* connect to and select the db */
    $connection = mysql_connect(‘localhost’,’username’,’password’);
    mysql_select_db(‘davidwalsh83_blog’,$connection);
    /* create the posts array */
    $posts = array();
    /* get the posts */
    $query = «SELECT post_title, post_content, post_name, ID FROM wp_posts WHERE post_status = ‘publish’ ORDER BY post_date DESC LIMIT $start,$number_of_posts»;
    $result = mysql_query($query);
    /* for every post… */
    while($row = mysql_fetch_assoc($result)) {
        /* set the post content equal to the first paragraph…a «preview» regular expression */
        preg_match(«/<p>(.*)<\/p>/»,$row[‘post_content’],$matches);
        $row[‘post_content’] = strip_tags($matches[1]);
        /* add this record to the posts array */
        $posts[] = $row;
    }
    /* return the posts in the JSON format */
    return json_encode($posts);
}

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

Как только вышеуказанная функция будет готова, нам нужно создать наш AJAX-приемник запросов. Мы узнаем, что кто-то отправил запрос AJAX, если в URL-адресе запроса установлена ​​переменная $ _GET [‘start’].
Если запрос получен, мы получаем еще 5 постов с помощью нашей функции get_posts () и выводим их JSON. После вывода новых сообщений в формате JSON мы сохраняем количество элементов, запрошенных пользователем, и уничтожаем скрипт, как показано ниже.

1
2
3
4
5
6
7
8
9
/* loading of stuff */
if(isset($_GET[‘start’])) {
    /* spit out the posts within the desired range */
    echo get_posts($_GET[‘start’],$_GET[‘desiredPosts’]);
    /* save the user’s «spot», so to speak */
    $_SESSION[‘posts_start’]+= $_GET[‘desiredPosts’];
    /* kill the page */
    die();
}

На этом мы завершаем серверный код для нашего виджета. Просто нет?

Загрузить больше виджетов

Первоначально в этом виджете не так много необработанного HTML. Мы создадим один основной контейнер виджетов. Внутри контейнера виджета будет обертка постов и наш элемент «Загрузить еще», который будет виртуально похож на сервер для запуска загрузки большего количества контента.

1
2
3
4
5
6
7
8
<!— Widget HTML Starts Here —>
<div id=»posts-container»>
    <!— Posts go inside this DIV —>
    <div id=»posts»></div>
    <!— Load More «Link» —>
    <div id=»load-more»>Load More</div>
</div>
<!— Widget HTML Ends Here —>

Хотя мы пока не вставляем отдельные элементы post, важно знать структуру HTML элементов post DIV, которые будут вставлены в оболочку posts:

1
2
3
4
5
6
7
8
<div class=»post»>
    <a href=»{postURL}» class=»post-title»>{post_title}</a>
    <p class=»post-content»>
        {post_content}
        <br />
        <a href=»{postURL}» class=»post-more»>Read more…</a>
    </p>
</div>

Образец

Пришло время добавить блик нашему виджету. Не стесняйтесь форматировать элементы виджета так, как вам удобно. Я решил добавить свою карикатуру слева, а заголовок поста, контент и ссылку — справа. Нам нужно добавить CSS для статических элементов HTML и сгенерированных javascript элементов, как показано ниже.

1
2
3
4
5
6
7
8
9
#posts-container { width:400px;
.post { padding:5px 10px 5px 100px;
.post:hover { background-color:lightblue;
a.post-title { font-weight:bold;
a.post-title:hover { text-decoration:underline;
a.post-more { color:#900;
p.post-content { font-size:10px;
#load-more { background-color:#eee;
#load-more:hover { color:#666;

Один дополнительный CSS-класс, который мы создадим, называется «активировать», который мы будем показывать при каждом запуске AJAX-запроса и скрывать при его завершении.

1
.activate { background:url(/dw-content/loadmorespinner.gif) 140px 9px no-repeat #eee;

AJAX Spinner

Наш JavaScript MooTools сделает волшебство случиться. Мы будем использовать шаблон замыкания для содержания кода MooTools в качестве лучшей практики:

1
2
3
4
5
6
7
8
9
//safety closure
(function($) {
    //when the DOM is ready…
    window.addEvent(‘domready,function() {
         
        /* ALL JAVASCRIPT WILL BE IN HERE */
         
    });
})(document.id);

Как только DOM будет готов, мы предоставляем начальные настройки javascript. Обратите внимание, что один из этих параметров, initialPosts, содержит JSON для первого пакета сообщений, которые должны отображаться при загрузке страницы. Мы также определяем переменные для количества постов, которые мы загружаем изначально, и количества постов, которые нужно захватить во время каждого запроса AJAX.

1
2
3
4
5
//settings on top
var domain = ‘http://davidwalsh.name/’;
var initialPosts = <?php echo get_posts(0,$_SESSION[‘posts_start’]);
var start = <php echo $_SESSION[‘posts_start’];
var desiredPosts = <?php echo $number_of_posts;

Начальный JSON

Как только наши настройки будут выполнены, мы определим функцию для обработки JSON, который мы получаем при загрузке страницы, а также через будущие запросы AJAX. Для каждого поста в JSON мы …

  • Создайте почтовую переменную URL, которую мы будем использовать чуть позже в цикле
  • Создайте элемент DIV «post», который будет содержать заголовок, контент и ссылку (в формате, показанном выше)
  • Вставьте вновь созданный элемент «post» в оболочку сообщений
  • Создайте объект Fx.Slide для нового элемента «post», чтобы мы могли мгновенно скрыть элемент, а затем сдвинуть его в поле зрения
  • Прокрутите окно вниз до первого нового сообщения

Вот код JavaScript MooTools, который делает это.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//function that creates the posts
var postHandler = function(postsJSON) {
    postsJSON.each(function(post,i) {
        //post url
        var postURL = » + domain + post.post_name;
        //create the HTML «post» element
        var postDiv = new Element(‘div’,{
            ‘class’: ‘post’,
            events: {
                //click event that makes the entire DIV clickable
                click: function() {
                    window.location = postURL;
                }
            },
            id: ‘post-‘ + post.ID,
            html: ‘<a href=»‘ + postURL + ‘» class=»post-title»>’ + post.post_title + ‘</a><p class=»post-content»>’ + post.post_content + ‘<br /><a href=»‘ + postURL + ‘» class=»post-more»>Read more…</a></p>’
        });
        //inject into the container
        postDiv.inject($(‘posts’));
        //create the Fx Slider
        var fx = new Fx.Slide(postDiv).hide().slideIn();
        //scroll to first NEW item
        if(i == 0) {
            var scroll = function() {
                new Fx.Scroll(window).toElement($(‘post-‘ + post.ID));
            };
            scroll.delay(300);
        }
    });
};

Свитки

Теперь, когда наша функция postHandler определена, пришло время обрабатывать начальную строку элементов JSON.

1
2
//place the initial posts in the page
postHandler(initialPosts);

Затем мы создаем еще несколько переменных для хранения значения нашего AJAX-запроса и хранения значений начального значения сеанса PHP, количества постов, которые нужно получить за раз, и элемента «Загрузить еще».

1
2
3
var start = <?php echo $_SESSION[‘posts_start’];
var desiredPosts = <?php echo $number_of_posts;
var loadMore = $(‘load-more’);

Чтобы сократить использование памяти, мы создадим наш объект Request.JSON вне события click, которое мы скоро добавим. Объект Request.JSON выглядит долго, но на самом деле все довольно просто. Разбивая это …

Мы создаем объект запроса с основными настройками …

1
2
3
4
5
6
var request = new Request.JSON({
    url: ‘load-more.php’, //ajax script — same script
    method: ‘get’,
    link: ‘cancel’,
    noCache: true,
    //more settings coming…

Добавьте параметр onRequest, который добавляет наш CSS-класс «activ» к кликабельному элементу «Load More», и измените текст элемента «Load More» на «Loading …» ….

1
2
3
4
onRequest: function() {
    //add the activate class and change the message
    loadMore.addClass(‘activate’).set(‘text’,’Loading…’);
},

Добавьте параметр onSuccess, который сбрасывает текст элемента «Загрузить еще», отслеживает текущую начальную точку для захвата будущих элементов и обрабатывает ответ JSON так же, как мы делали с начальными публикациями …

1
2
3
4
5
6
7
8
onSuccess: function(responseJSON) {
    //reset the message
    loadMore.set(‘text’,’Load More’);
    //increment the current status
    start += desiredPosts;
    //add in the new posts
    postHandler(responseJSON);
},

Добавьте функцию onFailure для обновления текста «LoadMore» при ошибке …

1
2
3
4
onFailure: function() {
    //reset the message
    loadMore.set(‘text’,’Oops! Try Again.’);
},

Наконец, добавьте функцию onComplete, которая удаляет счетчик после завершения запроса, независимо от успеха или неудачи.

1
2
3
4
onComplete: function() {
    //remove the spinner
    loadMore.removeClass(‘activate’);
}

Последний шаг — добавление события click к элементу «Load More». При нажатии мы делаем запрос AJAX, и вся вышеуказанная работа запускается. Успех!

01
02
03
04
05
06
07
08
09
10
//add the «Load More» click event
loadMore.addEvent(‘click’,function(){
    //begin the ajax attempt
    request.send({
        data: {
            ‘start’: start,
            ‘desiredPosts’: desiredPosts
        },
    });
});

AJAX JSON
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//safety closure
(function($) {
    //domready event
    window.addEvent(‘domready’,function() {
        //settings on top
        var domain = ‘http://davidwalsh.name/’;
        var initialPosts = <?php echo get_posts(0,$_SESSION[‘posts_start’]);
 
        //function that creates the posts
        var postHandler = function(postsJSON) {
            postsJSON.each(function(post,i) {
                //post url
                var postURL = » + domain + post.post_name;
                //create the HTML
                var postDiv = new Element(‘div’,{
                    ‘class’: ‘post’,
                    events: {
                        click: function() {
                            window.location = postURL;
                        }
                    },
                    id: ‘post-‘ + post.ID,
                    html: ‘<a href=»‘ + postURL + ‘» class=»post-title»>’ + post.post_title + ‘</a><p class=»post-content»>’ + post.post_content + ‘<br /><a href=»‘ + postURL + ‘» class=»post-more»>Read more…</a></p>’
                });
                //inject into the container
                postDiv.inject($(‘posts’));
                //create the Fx Slider
                var fx = new Fx.Slide(postDiv).hide().slideIn();
                //scroll to first NEW item
                if(i == 0) {
                    var scroll = function() {
                        new Fx.Scroll(window).toElement($(‘post-‘ + post.ID));
                    };
                    scroll.delay(300);
                }
            });
        };
 
        //place the initial posts in the page
        postHandler(initialPosts);
 
        //a few more variables
        var start = <?php echo $_SESSION[‘posts_start’];
        var desiredPosts = <?php echo $number_of_posts;
        var loadMore = $(‘load-more’);
        var request = new Request.JSON({
            url: ‘load-more.php’, //ajax script — same page
            method: ‘get’,
            link: ‘cancel’,
            noCache: true,
            onRequest: function() {
                //add the activate class and change the message
                loadMore.addClass(‘activate’).set(‘text’,’Loading…’);
            },
            onSuccess: function(responseJSON) {
                //reset the message
                loadMore.set(‘text’,’Load More’);
                //increment the current status
                start += desiredPosts;
                //add in the new posts
                postHandler(responseJSON);
            },
            onFailure: function() {
                //reset the message
                loadMore.set(‘text’,’Oops! Try Again.’);
            },
            onComplete: function() {
                //remove the spinner
                loadMore.removeClass(‘activate’);
            }
        });
        //add the «Load More» click event
        loadMore.addEvent(‘click’,function(){
            //begin the ajax attempt
            request.send({
                data: {
                    ‘start’: start,
                    ‘desiredPosts’: desiredPosts
                },
            });
        });
    });
})(document.id);

Если вы предпочитаете JQuery Javascript Framework, это ваш счастливый день; вот версия jQuery:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//when the DOM is ready
$(document).ready(function(){
    //settings on top
    var domain = ‘http://davidwalsh.name/’;
    var initialPosts = <?php echo get_posts(0,$_SESSION[‘posts_start’]);
    //function that creates posts
    var postHandler = function(postsJSON) {
        $.each(postsJSON,function(i,post) {
            //post url
            var postURL = » + domain + post.post_name;
            var id = ‘post-‘ + post.ID;
            //create the HTML
            $(‘<div></div>’)
            .addClass(‘post’)
            .attr(‘id’,id)
            //generate the HTML
            .html(‘<a href=»‘ + postURL + ‘» class=»post-title»>’ + post.post_title + ‘</a><p class=»post-content»>’ + post.post_content + ‘<br /><a href=»‘ + postURL + ‘» class=»post-more»>Read more…</a></p>’)
            .click(function() {
                window.location = postURL;
            })
            //inject into the container
            .appendTo($(‘#posts’))
            .hide()
            .slideDown(250,function() {
                if(i == 0) {
                    $.scrollTo($(‘div#’ + id));
                }
            });
        });
    };
    //place the initial posts in the page
    postHandler(initialPosts);
    //first, take care of the «load more»
    //when someone clicks on the «load more» DIV
    var start = <?php echo $_SESSION[‘posts_start’];
    var desiredPosts = <?php echo $number_of_posts;
    var loadMore = $(‘#load-more’);
    //load event / ajax
    loadMore.click(function(){
        //add the activate class and change the message
        loadMore.addClass(‘activate’).text(‘Loading…’);
        //begin the ajax attempt
        $.ajax({
            url: ‘load-more.php’,
            data: {
                ‘start’: start,
                ‘desiredPosts’: desiredPosts
            },
            type: ‘get’,
            dataType: ‘json’,
            cache: false,
            success: function(responseJSON) {
                //reset the message
                loadMore.text(‘Load More’);
                //increment the current status
                start += desiredPosts;
                //add in the new posts
                postHandler(responseJSON);
            },
            //failure class
            error: function() {
                //reset the message
                loadMore.text(‘Oops! Try Again.’);
            },
            //complete event
            complete: function() {
                //remove the spinner
                loadMore.removeClass(‘activate’);
            }
        });
    });
});

Версии MooTools и jQuery — это в точности одна и та же логика с разным синтаксисом!

Реализация этого виджета на вашем сайте — отличный способ добавить динамичности и креативности вашему сайту. Я с нетерпением жду встречи с вашим виджетом! Есть вопросы, предложения по улучшению? Опубликуйте их ниже!