<div class="container">
<div class="one">1</div>
<div class="two">2</div>
<div class="third">3</div>
</div>
$('div').replaceWith(function(){
return $("<span />").append($(this).contents());
});
$('body').on('change', '.check:checked', function(){
$(this).parent().next('.copy').clone().appendTo('.modal');
$('.modal > p').replaceWith(function(){
return $('<span class="' + this.className + '"></span>').append($(this).contents());
});
});
.replace
возвращает не объект JQuery, и по-этому использовать в дальнейшем методы JQuery к измененному тексту нельзя. Через .replace
можно сделать так:$('body').on('change', '.check:checked', function(){
var replace = $(this).parent().next('.copy')[0].outerHTML.replace(/(<|<\/)p/g, '$1span');
$('.modal').append(replace);
});
(...)
- в скобках обозначается группа символов< | <\/
- означает, что ищем совпадение <
ИЛИ </
p
- дальше после того как нашли <
ИЛИ </
соответственно совпадение до символа p
$1
это как раз переменная первой группы, то, что мы указали в (...)
и это мы в итоге подставляем к span
, это будет <
или </
, то есть либо открывающий, либо закрывающий тэг p
- это тэг p
который мы ищемg
- это глобальный флаг, который говорит о том, что нужно искать все совпадения в указанном тексте, если его не указать, то заменится только первое совпадение, флаги идут в конце после слэша /
говорящего об окончании выражения<p>
, в котором input
, из выборки + вы забыли поставить точку в селекторе .copy-2
$('body').on('change', '.check:checked', function(){
var replace = '';
var elements = $(this).parent().siblings('.copy, .copy-2');
$(elements).each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
});
$('.modal').append(replace);
});
<p>
.....
var elements = $(this).parent().nextAll('p');
.....
$('body').on('change', '.check:checked', function(){
if ($(this).prop('checked')){
$(this).parent().siblings('.copy, .copy-2').clone().appendTo(".modal");
} else {
$('.modal').empty();
}
});
.replace
$('body').on('change', '.check', function(){
var replace = '';
var elements = $(this).parent().siblings('.copy, .copy-2');
$(elements).each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
});
var modal = $('.modal');
if ($(this).prop('checked')) {
modal.append(replace);
} else {
modal.html(modal.html().replace(replace, ''));
}
});
$('body').on('change', '.check', function(){
var replace = '';
var elements = $(this).parent().siblings('.copy, .copy-2');
$(elements).each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
// console.log(replace);
});
var modal = $('.modal');
if ($(this).prop('checked')) {
var wrapReplace = '<div class="item">' + replace + '</div>';
modal.append(wrapReplace);
} else {
modal.html(modal.html().replace(wrapReplace, ''));
}
});
var wrapReplace = '<div class="item">' + replace + '</div>';
нужно вынести за условие, иначе элемент не будет удаляться. А чтобы скрывать/показывать .modal
во-первых надо добавить display: none;
к блоку .modal
в CSS. И прописать условие в JS:$('body').on('change', '.check', function(){
var replace = '';
var elements = $(this).parent().siblings('.copy, .copy-2');
var modal = $('.modal');
$(elements).each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
});
var wrapReplace = '<div class="item">' + replace + '</div>';
if ($(this).prop('checked')) {
modal.append(wrapReplace);
} else {
modal.html(modal.html().replace(wrapReplace, ''));
}
if ($('input').is(':checked')) { /* если у нас есть хоть один элемент на котором стоит чек, то показываем .modal */
modal.show();
} else { /* иначе скрываем .modal */
modal.hide();
}
});
$('body').on('change', '.check', function(){
var replace = '';
var elements = $(this).parent().siblings('.copy, .copy-2');
var modal = $('.modal').html('');
$(elements).each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
});
var wrapReplace = '<div class="item">' + replace + '</div>';
if ($(this).prop('checked')) {
modal.append(wrapReplace);
} else {
modal.html(modal.html().replace(wrapReplace, ''));
}
if ($('input').is(':checked')) {
modal.addClass('modal-show');
} else {
modal.addClass('modal-hide').text('Здесь ничего нет');
}
});
.outerHTML
это нативный метод JS, не имеющий отношения к JQuery. С помощью .clone
вам предлагали решение в ответах насколько я помню, только почему-то сейчас ответ удален. Главная причина почему я предложил решение на .outerHTML
+ .replace
это потому что вам нужно было заменять тэги. Делать это на JQuery не совсем удобно, тем более если будет например такое, что у некоторых элементов будут отличаться атрибуты. С помощью .clone
можно реализовать добавление элементов легко, но вот с заменой тэгов, повторюсь, не совсем удобно. input
специальный уникальный идентификатор, к примеру атрибут data-id
:<p><input class="check" name="name" type="checkbox" data-id="1"></p>
.....
<p><input class="check" name="name" type="checkbox" data-id="2"></p>
.....
.clone
$('.check').on('change', function() {
var attrName = 'data-id'; /* имя уникального атрибута */
var cloneElements = $(this).parent().nextAll('p').clone().attr(attrName, $(this).attr(attrName));
var modal = $('.modal');
if ($(this).prop('checked')) {
modal.append(cloneElements);
} else {
modal.find('[' + attrName + '="' + $(this).attr(attrName) + '"]').remove();
}
if ($('input').is(':checked')) {
modal.show()
} else {
modal.hide();
}
});
.offset
вот например почти по первой же ссылке в гугле дает вот такой код - https://error-log.ru/blog/jquery-animirovannyij-po... $('body').on('change', '.check', function(){
var replace = '';
var elements = $(this).parent().siblings('.copy, .copy-2');
var modal = $('.modal');
$(elements).each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
});
var wrapReplace = '<div class="item">' + replace + '</div>';
if ($(this).prop('checked')) {
modal.append(wrapReplace);
} else {
modal.html(modal.html().replace(wrapReplace, ''));
}
if ($('input').is(':checked')) {
modal.show();
} else {
modal.addClass('modal-hide').text('Здесь ничего нет');
}
});
.modal
при этом это условие должно быть выше кода добавления элемента, чтобы не удалился сам добавляемый элемент:$('body').on('change', '.check', function(){
var replace = '';
var elements = $(this).parent().siblings('.copy, .copy-2');
var modal = $('.modal');
$(elements).each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
});
if ($('input').is(':checked')) {
if ($('input:checked').length === 1) modal.html(''); /* если ставится первый чек, то удаляем все содержимое .modal */
modal.show();
} else {
modal.addClass('modal-hide').text('Здесь ничего нет');
}
var wrapReplace = '<div class="item">' + replace + '</div>';
if ($(this).prop('checked')) {
modal.append(wrapReplace);
} else {
modal.html(modal.html().replace(wrapReplace, ''));
}
});
if ($('input:checked').length === 1) modal.html('');
написать условиеif (!modal.children().is('.item')) modal.html('');
.clone
соответственно без замены тэгов, не совсем понятно зачем вам вообще нужна замена тэгов:$(document).mouseup(function (e){
var modalShow = $(".modal-hide");
if (!modalShow.is(e.target) && modalShow.has(e.target).length === 0) {
$(".modal").removeClass("modal-hide");
}
});
$(document).mouseup
. Ошибка конечно не из-за этого, но так делать неправильно..mouseup
? Странное решение. Достаточно клика.$('body').on('change', '.check', function(){
.....
}
$(document).on('click', e => {
const target = $(e.target);
if (!target.hasClass('check') && !target.closest('.modal').length) {
$('.modal').removeClass("modal-show");
}
});
$('.modal').removeClass("modal-show");
.preview
:$(document).on('click', e => {
.....
if (!target.hasClass('check') && !target.closest('.modal, .preview').length) {
.....
});
$(function() {
Внутри этого кода, я добавил:
$('body').on('change', '.check', function(){
.....
});
$(document).on('click', e => {
});
});
$(function...
хоть нет, без разницы. В чем то другом проблема. <label>
то соответственно нужно опять добавить новое условие, чтобы клик по лейблу не закрывал модальное окно. Можно так:.....
if (!target.hasClass('check') && !target.is('label[for*="check-option"]') && !target.closest('.modal, .preview').length) {
.....
.....
if (!target.hasClass('check') && !target.prev('input').hasClass('check') && !target.closest('.modal, .preview').length) {
.....
.....
if (!target.is('.check, label[for*="check-option"]') && !target.closest('.modal, .preview').length) {
.....
localStorage
. Думаю это было бы удобнее в этом случае. А для работы с куками не обязательно подключать сторонние библиотеки. Куки довольно просто читаются и прописываются ванильным способом через document.cookie. Правда для удобства работы с ними можно немного допилить чтение/запись написав пользовательские функции. localStorage
таким образом:/* добавляем функцию обработки запроса к localStorage */
function actLocalStorage(data) {
const localName = 'local';
let current = localStorage.getItem(localName);
/* если значение в localStorage пустое, то возвращаем новое значение */
if (current === null) {
localStorage.setItem(localName, data);
return localStorage.getItem(localName);
}
/* если есть совпадение текущего чека, с тем, что уже есть в localStorage, то удаляем запись,
иначе просто добавляем новое значение к текущему */
if (current.match(data)) {
current = current.replace(data, '');
if (current) {
localStorage.setItem(localName, current)
} else {
localStorage.removeItem(localName);
}
} else {
current = current + data;
localStorage.setItem(localName, current);
}
current = localStorage.getItem(localName);
return (current === null) ? '' : current;
}
$('body').on('change', '.check', function(){
var replace = '';
var elements = $(this).parent().siblings('.copy, .copy-2');
var modal = $('.modal');
$(elements).each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
});
if ($('input').is(':checked')) {
if (!modal.children().is('.item')) modal.html('');
} else {
modal.removeClass('modal-show').text('Здесь ничего нет');
}
var wrapReplace = '<div class="item">' + replace + '</div>';
/* до этого момента оставляем все как есть */
/* дальше убираем все записи относящиеся к localStorage, поскольку мы с ним работаем внутри функции */
modal.html(actLocalStorage(wrapReplace)); /* записываем в .modal результат выполнения функции */
/* в проверке чека оставляем только открытие модального окна */
if ($(this).prop('checked')) modal.addClass('modal-show');
});
<p>
на <span>
, как вы хотели + все обращения и работу с localStorage
при таком подходе нужно полностью переписывать. Но это будет правильнее с точки зрения логики кода, но опять же это не значит, что вам нужно обязательно писать именно так. Можно и через HTML, если вас это устраивает и функционирует как нужно. При клике на последний параграф - в модальном окне ничего не отображается
localStorage
в этом коде сделан только при клике по чекбоксу. Если хотите, чтобы модальное окно заполнялось сразу же при загрузке страницы, нужно немного дописать код. Плюс вам по идее нужно отмечать записанные чекбоксы. И вот тут как раз появляется проблема проставления записанных в localStorage
чекбоксов. Как мы будет определять какие чекбоксы нужно отмечать, если им не присвоены никакие уникальные идентификаторы? По-этому в этом примере это сделать довольно сложно. Вот код, который пропишет данные из localStorage
в модальное окно при загрузке страницы, но чекбоксы он не проставит. Нужно переписывать весь код для этого.function actLocalStorage(data) {
const localName = 'local';
let current = localStorage.getItem(localName);
/* добавим условие, что если параметром data мы передает строку 'ready' то нужно
просто добавить данные из localStorage в модальное окно */
if (data === 'ready') {
if (current !== null) {
return $('.modal').html(current);
} else return;
}
if (current === null) {
localStorage.setItem(localName, data);
return localStorage.getItem(localName);
}
if (current.match(data)) {
current = current.replace(data, '');
if (current) {
localStorage.setItem(localName, current)
} else {
localStorage.removeItem(localName);
}
} else {
current = current + data;
localStorage.setItem(localName, current);
}
current = localStorage.getItem(localName);
return (current === null) ? '' : current;
}
$(function() { /* функция, которая выполнится при загрузке страницы */
actLocalStorage('ready');
});
.....
у меня все нормально отображается при клике на любой чекбокс
Плюс вам по идее нужно отмечать записанные чекбоксы. И вот тут как раз появляется проблема проставления записанных в localStorage чекбоксов. Как мы будет определять какие чекбоксы нужно отмечать, если им не присвоены никакие уникальные идентификаторы?
var checkBox = $('.check');
if (localStorage.getItem(isChecked) === 'true') {
checkBox.checked === true;
}
if ((checkBox).is(':checked')) {
localStorage.setItem(isChecked, true)
}
После перезагрузки страницы, если снова начать активировать чекбоксы, то у меня все элементы начинают удаляться
localStorage
Получается все таки нужно стремиться к данному варианту ?
И разве нельзя сделать проверку типа:
id="check-option-1"
. Пример с data-id
это был просто пример. Я просто привык отделять собственную идентификацию элементов от дефолтной HTML, по-этому и добавил дополнительный атрибут data-id
.....
/* добавляем функцию для установки и записи чекбоксов в localStorage */
function actChecked(id) {
const checkedName = 'checked';
let current = localStorage.getItem(checkedName);
if (id === 'ready') { /* это условие опять же для того, чтобы проставить чекбоксы при загрузке страницы */
if (current !== null) {
/* перебираем каждый записанный в localStorage элемент и проставляем на нем чекбокс */
JSON.parse(current).forEach(v => {
$('#' + v).prop('checked', true);
});
}
return;
}
if (current === null) { /* если чекбоксов еще нет в localStorage то делаем новую запись */
return localStorage.setItem(checkedName, JSON.stringify([id]));
}
let arrCurrent = JSON.parse(current);
const iof = arrCurrent.indexOf(id);
if (iof !== -1) { /* если в localStorage уже есть записанные чекбоксы */
arrCurrent.splice(iof, 1); /* удаляем его */
return (arrCurrent.length === 0) ? localStorage.removeItem(checkedName) : localStorage.setItem(checkedName, JSON.stringify(arrCurrent));
} else { /* иначе добавляем новый чекбокс в localStorage */
arrCurrent.push(id);
return localStorage.setItem(checkedName, JSON.stringify(arrCurrent));
}
}
$(function() {
actLocalStorage('ready');
actChecked('ready'); /* добавим новую функцию в выполнение при загрузке страницы */
});
$('body').on('change', '.check', function(){
var replace = '';
var elements = $(this).parent().siblings('.copy, .copy-2');
var modal = $('.modal');
$(elements).each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
});
if ($('input').is(':checked')) {
if (!modal.children().is('.item')) modal.html('');
} else {
modal.removeClass('modal-show').text('Здесь ничего нет');
}
var wrapReplace = '<div class="item">' + replace + '</div>';
actChecked($(this).attr('id')); /* выполняем новую функцию, параметром передаем атрибут id текущего чекбокса */
modal.html(actLocalStorage(wrapReplace));
if ($(this).prop('checked')) {
modal.addClass('modal-show');
}
});
localStorage
, чтобы все корректно работало.$(function() {
localStorage.removeItem('local');
localStorage.removeItem('checked');
});
+
. Их нужно экранировать. Стандартной функции экранирования в JS нет, но можно использовать свою функцию. Сделайте так:/* добавьте функцию экранирования */
function escapeRegExp(str){
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function actLocalStorage(data)
следующее:.....
if (current.match(escapeRegExp(data))) {
.....
'Здесь ничего нет'
, после удаления всех параграфов escapeRegExp
нужно выше всех функций добавить ?localStorage
и получается, что когда мы снимаем все чекбоксы localStorage
у нас пустой и пустое значение добавляется в модальное окно. Нужно просто задать условие, чтобы при пустом localStorage
результат функции не записывался в модальное окно.modal.html(actLocalStorage(wrapReplace));
const localStr = actLocalStorage(wrapReplace);
if (localStr) modal.html(localStr);
const
это константа, значение, которое не будет изменяться в дальнейшем. let
это переменная, которая будет изменяться в дальнейшем. Область видимости (локальная, глобальная) явным способом никак не задается и зависит от того в каком месте кода объявлена переменная. Можно везде записывать let
или var
(если имена переменных не пересекаются), не используя const
вообще. Просто указывать конкретное назначение переменной, изменяемое или нет, все-таки более правильно.localStorage
нет. Это вполне нормальная практика. id
мы и так уже сохраняем, только как бы отдельно для чекбоксов. Можно эти же сохраненные id
использовать и для других действий. Вообще в целом можно реализовать так:localStorage
только id
id
из localStorage
и на основе него подхватываем HTML-код непосредственно с самой страницыlocalStorage
. Но нужно понимать, что если на странице не будет нужного нам кода, то ничего в итоге не подхватится. Все зависит от самой задачи, что, как и где нужно. Просто на том примере, что мы разбираем, как видите почти с каждым новым вашим дополнением приходится что-то дописывать, потому что изначально все пишется на упрощенном примере. id
в localStorage
то при постоянном наличии нужного HTML-кода на странице можно реализовать так:/* добавляем функцию получения HTML-кода исходя из текущих id записанных в localStorage */
function getHTML() {
const checkedName = 'checked';
const current = localStorage.getItem(checkedName);
if (current !== null) {
const arrCurrent = JSON.parse(current);
let mHTML = '';
arrCurrent.forEach(id => {
let replace = '';
$('#' + id).parent().nextAll('p').each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
});
mHTML += '<div class="item">' + replace + '</div>';
})
return mHTML;
} else return;
}
/* убираем лишнее из обработчика события и оставляем так */
$('body').on('change', '.check', function(){
var modal = $('.modal');
if ($('input').is(':checked')) {
if (!modal.children().is('.item')) modal.html('');
} else {
modal.removeClass('modal-show').text('Здесь ничего нет');
}
if ($(this).prop('checked')) {
modal.addClass('modal-show');
}
actChecked($(this).attr('id'));
modal.html(getHTML()); /* в самом конце добавляем HTML-код в модальное окно */
});
/* так же прописываем, чтобы код добавлялся при загрузке страницы */
$('.modal').html(getHTML());
actChecked('ready');
arrCurrent.forEach(id => {
let replace = '';
$('#' + id).parent().siblings('.copy, .copy-2, .pic-art').each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
});
mHTML += '<div class="item">' + replace + '</div>';
})
var obj {
id: id,
name: name
image: img - у меня еще есть мини картинка
}
function actChecked(id) {
const checkedName = 'checked';
let current = localStorage.getItem(checkedName);
if (id === 'ready') {
if (current !== null) {
JSON.parse(current).forEach(v => {
$('#' + v).prop('checked', true);
});
}
return;
}
if (current === null) {
return localStorage.setItem(checkedName, JSON.stringify([id]));
}
let arrCurrent = JSON.parse(current);
const iof = arrCurrent.indexOf(id);
if (iof !== -1) {
arrCurrent.splice(iof, 1);
return (arrCurrent.length === 0) ? localStorage.removeItem(checkedName) : localStorage.setItem(checkedName, JSON.stringify(arrCurrent));
} else {
arrCurrent.push(id);
return localStorage.setItem(checkedName, JSON.stringify(arrCurrent));
}
}
function getHTML() {
const checkedName = 'checked';
const current = localStorage.getItem(checkedName);
if (current !== null) {
const arrCurrent = JSON.parse(current);
let mHTML = '';
arrCurrent.forEach(id => {
let replace = '';
$('#' + id).parent().nextAll('p').each(function() {
replace += this.outerHTML.replace(/(<|<\/)p/g, '$1span');
});
mHTML += '<div class="item">' + replace + '</div>';
})
return mHTML;
} else return;
}
$('body').on('change', '.check', function(){
var modal = $('.modal');
if ($('input').is(':checked')) {
if (!modal.children().is('.item')) modal.html('');
} else {
modal.removeClass('modal-show').text('Здесь ничего нет');
}
if ($(this).prop('checked')) {
modal.addClass('modal-show');
}
actChecked($(this).attr('id'));
modal.html(getHTML());
});
$(function() {
$('.modal').html(getHTML());
actChecked('ready');
});
$('.preview').click(function(){
$(".modal").toggleClass("modal-show");
});
const checkedName = 'local';
const current = localStorage.getItem(checkedName);
if (current !== null) {
let p = $('.copy');
let p2 = $('.copy-2');
current.push = ({
p: p,
p2: p2
});
localStorage.setItem(checkedName, JSON.stringify(current));
}
id
и затем на основе этих данных строить HTML-структуру внутри модального окна. Тут нужно почти полностью переписывать код, по-этому к сожалению пока у меня нет времени вам его написать. Почему вас не устраивать просто сохранение HTML-кода в localStorage
? В целом это ведь рабочая версия, просто не совсем верная с точки зрения правильности исполнения кода.
Тут нужно почти полностью переписывать код, по-этому к сожалению пока у меня нет времени вам его написать.
Почему вас не устраивать просто сохранение HTML-кода в localStorage? В целом это ведь рабочая версия, просто не совсем верная с точки зрения правильности исполнения кода.
localStorage
заносится объект с данными: id, картинка, название, цена. Потом уже на основе этих данных просто строятся элементы внутри модального окна. let cart = [];
function Item(id, p) {
this.id = id;
this.p = p;
}
function saveCart() {
localStorage.setItem("shoppingCart", JSON.stringify(cart));
}
function loadCart() {
cart = JSON.parse(localStorage.getItem("shoppingCart"));
if (cart === null) {
cart = []
}
}
loadCart();
var item = new Item(id, p);
cart.push(item);
saveCart();
};
$('body').on('change', '.check', function(){
var modal = $('.modal');
if ($('input').is(':checked')) {
if (!modal.children().is('.item')) modal.html('');
} else {
modal.removeClass('modal-show').text('Здесь ничего нет');
}
if ($(this).prop('checked')) {
modal.addClass('modal-show');
}
var id= $(this).attr("id");
var p = $(this).parent().siblings('.copy, .copy-2');
});
$('.moved-item').css({"display": "block", 'top' : offset.top-window.scrollY + 'px', 'left' : offset.left + 'px'}).animate({'top': icon.offset().top-window.scrollY-30, 'left': icon.offset().left + 20}, 700,
function(){ $('.moved-item').css({'top' : icon.offset().top-window.scrollY-30 + 'px', 'left' : icon.offset().left + 20 + 'px'}).animate({'top': icon.offset().top-window.scrollY, 'left': icon.offset().left + 20}, 500,
function(){ $(this).remove(); }) }
);
setTimeout(function(i){...}.bind(i+1), 200)
offset.top + (offset.top - (icon.offset().top-window.scrollY-30))*i/n