Сайт вебмастера

Работа с куками в Alpine.js

12-01-2021Время чтения ~ 5 мин.Alpine.js 3870

Работать с куками в Alpine.js в общем-то можно как и с любым другим js-кодом. Вопрос здесь скорее в плоскости того, как мы используем куки и где это можно применить. Я покажу несколько примеров на Alpine.js, где используются куки. Это сообщение «Наш сайт использует куки бла-бла-бла...» и табы с памятью.

Перед началом определимся с функциями для работы с куками. Работать с ними через нативный js-код не очень удобно, поэтому мы воспользуемся уже готовыми функциями, например с learn.javascript.ru/cookie (прямой линк на их файл).

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

Пусть будет просто три кнопки:

<div x-data="{val: '-', cname: 'myCookie'}">
	<button @click="val = Date.now(); setCookie(cname, val, {'max-age': 60})">set Cookie</button>
	<button @click="val = getCookie(cname)">get Cookie</button>
	<button @click="deleteCookie(cname)">delete Cookie</button>
	
	<div x-text="val"></div>
</div>

В компоненте мы задаём переменные: val — текущее значение куки. Имя куки храним в cname.

Первая кнопка по onclick через функцию setCookie() устанавливает значение куки. В данном случае это текущее время в Unix-формате. В куку мы передаём параметр max-age, который задаёт время жизни куки в секундах.

Вторая кнопка просто получает значение куки через getCookie().

И последняя кнопка — удаляет куку с помощью deleteCookie().

Текущее значение куки выводится в последнем блоке. Поскольку здесь используется «реактивность» Альпины, то всё обходится одной инструкцией x-text.

При обновлении страницы в течение 60 секунд, кнопкой get Cookie можно получить значение куки. Если прошло больше времени, то кука будет удалена браузером. Это обычный жизненный цикл куки.

Сообщение об использовании кук на сайте

Более практичный пример. Обычно для такого блока используется PHP, но с Альпиной он реализуется намного проще. Вначале полный код.

<div x-data="{open: false, time: 300, cname: 'myMessage'}" 
	x-init="() => {open = (getCookie(cname) !== 'close') ? true : false}" 
	x-show.transition="open" 
	x-cloak 
	class="b-shadow-var pad20 bg-indigo100 t-gray800 pos-fixed pos10-b pos10-l pos10-r">
 
	<div class="mar20-b">Сообщение о куках</div>
		
	<button @click="setCookie(cname, 'close', {'max-age': time}); open = false" class="button button1">Ok</button>
</div>

Алгоритм работы такой. В момент инициализации компонента мы получаем значение куки. Если она не равна close, то показываем сообщение, иначе скрываем. В само же блоке размещается кнопка «OK», которая выставляет куку со значением close.

В компоненте используются переменные

  • open - флаг для отображения блока
  • time — время жизни куки в секундах
  • cname — имя куки

В директиве x-init мы прописываем колбэк функцию (так нужно для Alpine). В ней мы считываем куку и на её значении выставляем переменную open.

Показ блока определяется директивой x-show, которая зависит от open. Для анимации используем transition, но это уже на любителя.

Директива x-cloak нужна для того, чтобы скрыть блок до загрузки и инициализации Альпины. Я об этом уже писал, повторяться не буду.

Дальше обычные классы Berry CSS для позиционирования и дизайна. Тоже на любителя.

Клик на кнопке создаёт куку с помощью setCookie() и сразу прячем блок через open = false. Этот же код можно использовать не только для кнопки, но и например на «Х» в верхнем углу. То есть это вопрос дизайна самого блока.

Код получился небольшой, но при желании его можно вынести в отдельную функцию и использовать в x-spread. Но я думаю, вы согласитесь, что это намного проще, чем городить что-то подобное на PHP. :-)

Табы с памятью

Это обычные табы, которые я уже раньше показывал, но теперь сделаем так, чтобы запоминалась выбранная вкладка, даже после закрытия страницы.

Вначале полный код.

<div x-data="{tab: 't1', time: 30, cname: 'myTab1', startInit: false}" 
	x-show="startInit" 
	x-cloak
	x-init="() => {
		let t = getCookie(cname);
		if (t) tab = t;
		$watch('tab', value => setCookie(cname, value, {'max-age': time}));
		startInit = true;
	}">
	
    <button :class="{'bg-blue': tab == 't1'}" @click="tab = 't1'" class="button">Foo</button>
    <button :class="{'bg-blue': tab == 't2'}" @click="tab = 't2'" class="button">Bar</button>
    
	<div class="pad20 bordered">
    	<div x-show="tab == 't1'">Вкладка Foo</div>
    	<div x-show="tab == 't2'">Вкладка Bar</div>
    </div>
</div>
Вкладка Foo
Вкладка Bar

В целом это обычные табы: та же разметка и та же логика работы. Для куки мы задаём переменные для времени и имени, как и в прошлом примере.

Переменная startInit изначально скрывает отображение всего блока. Но, как только мы получили куку и табы переключились startInit становится true и блок отображается. Если её не использовать, то посетитель будет видеть вначале дефолтное отображение табов (обычно первой вкладки), а только потом произойдёт переключение — это будет видно и создаёт неприятный эффект. А так мы отображаем блок только после полной инициализации компонента.

В x-init у нас опять же колбэк-функция, в которой мы получаем значение куки, которая указывает на имя открытой вкладки, которое присваивается tab.

Директива $watch отслеживает изменения переменной tab и как только она изменилась, срабатывает код с функцией setCookie(), то есть мы сразу меняем значение куки. Здесь также используется «реактивность» Альпины: мы можем изменить tab, кликнув на кнопку вкладки, в этот момент сработает $watch и задаст нужную куку.

Всего пара строчек кода для такой функциональности, это круто! :-)

В заключении хочу отметить, что с Alpine работать с куками оказалось достаточно приятным занятием. Обычно я использую PHP, который работает на «приём» куки и от её значения отдаётся разный html-код. Если же куки нет, то отдаём html-код с вкраплением JS-кода, который и выставляет куку. Конечно, можно всё сделать на чистом JavaScript, но там опять же завязка на ID блоков, или их классы, потом навешивается слушатель на события,.. в общем возни прилично. С Альпиной же процесс сильно упрощается и позволяет вообще отказаться как от PHP, так и от нативного JS-кода.

Похожие записи