Простой скрипт для создания оглавления или содержания статьи на сайте

июнь 24 , 2016

У меня давно была мысль сделать что-то вроде оглавления или содержания статьи на webdevkin-e. Многие посты объёмны и ориентироваться по ним не очень удобно. Идея была в том, чтобы в начало каждой статьи поставить из названий подразделов, клик на которые отправлял бы на соответствующее место страницы. Все это элементарно делается через якоря, атрибут id или name (устарел) тега a, но создавать врукопашную такие списки для каждой страницы было очень лениво. Поэтому я написал небольшой скрипт, если хотите - плагин или виджет, который автоматически создает оглавление для каждой статьи, прикрутил его к своему блогу и хочу поделиться реализацией с общественностью.


Что именно нам нужно от скрипта?

На входе имеем набор разделов статьи, которые как-то выделены, например, тегами h или отдельным классом. Мы задаем контейнер, в котором будет размещаться наше оглавление, в этом контейнере строится полный список из означенных разделов. Клик на них отправляет читателя на, собственно, сам раздел.

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

Пример того, как это работает, Вы видите в самом начале страницы - "Содержание статьи". Кликните и увидите список разделов для быстрого перехода к ним. Все перечисленные выше возможности я сам же использовал и проверил на webdevkin-е.


Как подключить оглавление?

Нужно выполнить 4 пункта:

  • Создать на странице статьи пустой контейнер для оглавления, например, div с id="content-post"
  • Подключить на странице скрипт с модулем оглавления
  • Создать объект оглавления с нужными настройками
  • Поправить стили под дизайн Вашего сайта
Ах да, требуется наличие jQuery на сайте - работа плагина подразумевает, что он уже подключен. А теперь подробности.


Подключаем javascript-модуль оглавления и создаем объект с настройками

Подключаем js-файл скрипта обычным способом через тег script. Вот ссылка на файл. Ниже разберем его код подробнее.

После этого будет доступен глобальный класс WbdContentPost, экземпляр которого мы и создадим после загрузки документа.

    jQuery(document).ready(function() {
		new WbdContentPost({
			selectorContent: '#content-post',
			selectorSubtitles: '#content article h3',
			title: 'Содержание статьи',
			minCountSubtitles: 3,
			hidden: true
		});
    });

Идем по списку параметров:

  • selectorContent - пустой контейнер, в который будет добавляться оглавление. себя я добавил в начало статьи div с id="content-post"
  • selectorSubtitles - самое важное - элементы, которые мы считаем заголовками. В моем случае это теги h3, но не все, а только внутри тега article.
  • title - заголовок. Как Вы хотите назвать: Оглавление, Содержание, Краткая сводка, как угодно. По умолчанию "Содержание статьи"
  • minCountSubtitles - минимальное количество заголовков, при котором строится оглавление. Например, если у меня меньше трех заголовков, то считаю статью небольшой и не вижу смысла показывать оглавление. По умолчанию - 1000. То есть показывать практически всегда.
  • hidden - показывать содержание раскрытым или скрывать под спойлер. Если установлено в true, то на клик на заголовке title навешивается событие, которое раскрывает или сворачивает оглавление. Пригодится для экономии места на экране. У меня сделано именно так. Но по умолчанию поставил false.


Смотрим на разметку и правим стили под себя

Напоминаю, что нужно создать пустой контейнер под оглавление, с тем селектором, который задается в selectorContent.

    

id=content-post я задаю в настройках плагина, класс content-post прописал для стилей. Когда оглавление загрузится, в контейнере будет примерно следующее

    

Содержание статьи

"Содержание статьи" между тегами p, в списке ul-li будут наши разделы. К каждой ссылке добавляем хэш вида #subtitleN, чтобы знать, к какому разделу сайта относится ссылка. Дальше привожу стили, которые использовал на webdevkine, Вам нужно будет поправить их под свой сайт.

    .content-post {
    	padding: 20px 0;
    }
    
    .content-post p {
        display: inline;
    	font-weight: 700;
        font-size: 1.1em;
        color: steelblue;
        margin-bottom: 5px;
        border-bottom: dotted 1px;
        cursor: pointer;
    }
    
    .content-post ul {
    	margin-top: 20px;
    }
    
    .content-post li {
    	list-style: none;
    	padding: 1px 0;
    }
    
    .content-post li a {
    	border-bottom: dotted 1px;
        text-decoration: none;
    }

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


Написание javascript-кода

Идея генерации оглавления проста. Ищем все разделы, перед каждым из них вставляем пустую ссылку-якорь вида a id="subtitleN". И добавляем в список оглавления li со ссылкой вида (адрес статьи)#subtitleN. И все! Попутно предусматриваем несколько условий, задаваемых в опциях.

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

    // Модуль оглавления статьи
    var WbdContentPost = (function($) {
    	
    	// Объявляем функцию-конструктор
    	var Content = function(options) {
    		this.ui = {
    			$content: $(options.selectorContent),
    			$subtitles: $(options.selectorSubtitles)
    		}
    		this.title = options.title || 'Содержание статьи';
    		this.minCount = options.minCountSubtitles || 1000;
    		this.hidden = options.hidden || false;
    
    		this.init();
    	}
    
    	// Инициализация
    	Content.prototype.init = function() {
    		if (!this.ui.$content.length || this.ui.$subtitles.length < this.minCount) {
    			this.ui.$content.remove();
    			return false;
    		}
    
    		var contentHtml = '',
    			url = document.location.href.split('#')[0],		
    			display = this.hidden ? 'none' : 'block';
    		
    		this.ui.$subtitles.each(function(n, item) {
    			var anchor = '',
    				$item = $(item),
    				subtitle = '
  • ' + $item.text() + '
  • '; $item.before(anchor); contentHtml += subtitle; }); this.ui.$content.html('
      ' + contentHtml + '
    '); this.ui.$content.prepend('

    ' + this.title + '

    '); // Навешиваем событие if (this.hidden) { this.ui.$content.find('p').on('click', function() { $(this).next().slideToggle(300); }); } } return Content; })(jQuery);

    В блоке "Объявляем функцию-конструктор" ничего интересного не происходит. Мы лишь принимаем значения из настроек options и сохраняем их в объекте.

    Весь интерес заключается в "Инициализация Content.prototype.init". Сначала мы проверяем, есть у нас вообще контейнер под оглавление (мало ли, забыли задать или он недоступен). Затем проверяем, не слишком ли мало у нас заголовков, не меньше ли указанного нами в настройках. Если хотя бы один из случаев срабатывает, то выходим из функции, предварительно удалив контейнер. Для чего удаляем контейнер, его же все равно не видно? Да, но на него могут быть навешены стили, например, padding-и, которые при отсутствующем оглавлении создадут лишний пробел на странице.

    Дальше инициализируем 3 переменные.
    contentHtml - пустая строка, в нее будут складываться ссылки с заголовками.
    url - полный адрес статьи. Манипуляции со сплитом - split('#')[0] - делаем для тех случаев, когда в адресной строке уже есть какие-то хэши. Они нам не нужны.
    display - определяем из настроек, показывать ли все оглавление и навешивать ли событие на скрытие/раскрытие.

    Дальше в цикле each перебираем все разделы, создаем якори и тексты, следя за совпадениями номеров n, и втыкаем якоря перед разделами, а ссылки добавляем в переменную contentHtml. После перебора содержимое contentHtml помещаем в контейнер, точнее в список ul, и также добавляем заголовок "Содержание статьи".

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

    Это минимальный набор опций для создания оглавления. Мне пока он показался достаточным, разве что не реализовал плавную прокрутку до соответствующего раздела, а не просто быстрый переход по клику. Вы можете использовать этот скрипт у себя на сайтах и дорабатывать его как угодно. И предлагайте свои идеи по улучшению в комментариях!

    Заходите в группу в контакте - https://vk.com/webdevkin
    Анонсы статей, обсуждения интернет-магазинов, vue, фронтенда, php, гита.
    Истории из жизни айти и обсуждение кода.
    Как Вам статья? Оцените!