// такого у вас сейчас нет, сами догадайтесь, кому надо класс добавить
const containerSelector = '.container';
const buttonsSelector = `${containerSelector} .filter__navigation`;
const buttonSelector = `${buttonsSelector} [data-filter]`;
const buttonActiveClass = '_active';
const itemsSelector = `${containerSelector} .search__body`;
const itemSelector = `${itemsSelector} .filter-column`;
const itemHiddenClass = '_hide';
const itemFilterClassPrefix = 'filter__column_';
document.querySelectorAll(buttonSelector).forEach(n => {
n.addEventListener('click', onFilterButtonClick);
});
function onFilterButtonClick({ currentTarget: { dataset: { filter } } }) {
const activeItemClass = itemFilterClassPrefix + filter;
this.closest(buttonsSelector).querySelectorAll(buttonSelector).forEach(n => {
n.classList.toggle(buttonActiveClass, n === this);
});
this.closest(containerSelector).querySelectorAll(itemSelector).forEach(({ classList: cl }) => {
cl.toggle(itemHiddenClass, filter !== 'all' && !cl.contains(activeItemClass));
})
}
document.addEventListener('click', e => {
const button = e.target.closest(buttonSelector);
if (button) {
const { filter } = button.dataset;
const activeItemSelector = filter === 'all' ? '*' : `.${itemFilterClassPrefix}${filter}`;
for (const n of button.closest(buttonsSelector).children) {
n.classList.toggle(buttonActiveClass, n === button);
}
for (const n of button.closest(containerSelector).querySelector(itemsSelector).children) {
n.classList.toggle(itemHiddenClass, !n.matches(activeItemSelector));
}
}
});
{ 'старый ключ': 'новый ключ' }
:const keys = {
x: 'a',
y: 'b',
z: 'c',
};
const renameKeys = (obj, keys) =>
Object.fromEntries(Object
.entries(obj)
.map(([ k, v ]) => [ Object.hasOwn(keys, k) ? keys[k] : k, v ])
);
// или
const renameKeys = (obj, keys) =>
Object.keys(obj).reduce((acc, k) => (
acc[keys[k] ?? k] = obj[k],
acc
), {});
const newArr = arr.map(n => renameKeys(n, keys));
function renameKeys(keys, obj) {
for (const k in keys) {
if (obj.hasOwnProperty(k)) {
obj[keys[k]] = obj[k];
delete obj[k];
}
}
}
arr.forEach(renameKeys.bind(null, keys));
элемент.insertAdjacentHTML('afterend', разметка);
элемент.remove();
// или
элемент.outerHTML = разметка;
colors: markerColors, // Устанавливаем цвета маркеров в зависимости от результата
discrete
, позволяющим индивидуально настраивать внешний вид каждого маркера. Всплывающую подсказку это никак не затрагивает, так что её придётся кастомизировать отдельно. function bindRootContext(obj, context = obj) {
return new Proxy(obj, {
get(target, key) {
const val = target[key];
return (
val instanceof Function ? val.bind(Object.hasOwn(target, key) ? context : target) :
val instanceof Object ? bindRootContext(val, context) :
val
);
},
});
}
const obj = bindRootContext({
name: 'Root',
a: {
name: 'A',
logName() { console.log(this.name); },
b: {
name: 'B',
logName() { console.log(this.name); },
arr: [
{
name: '666',
logName() { console.log(this.name); },
},
function() { console.log(this.name); },
],
c: {
name: 'C',
logName() { console.log(this.name); },
},
},
},
});
obj.a.b.c.logName(); // Root
obj.a.b.logName(); // Root
obj.a.logName(); // Root
obj.a.b.arr[0].logName(); // Root
obj.a.b.arr[1](); // Root
кнопка.addEventListener('click', () => {
const [ li ] = шаблон.content.cloneNode(true).children;
li.querySelector('.card__image').src = инпут_с_ссылкой.value;
li.querySelector('.card__title').textContent = инпут_с_подписью.value;
список.insertAdjacentElement('afterbegin', li);
// или
список.prepend(document.importNode(шаблон.content, true));
список.querySelector('img').setAttribute('src', инпут_с_ссылкой.value);
список.querySelector('h2').innerText = инпут_с_подписью.value;
});
// если гарантируется отсутствие thead и tfoot, или их содержимое также должно учитываться
const { rows } = table;
// если tbody один
const [ { rows } ] = table.tBodies;
// если tbody несколько
const rows = Array.prototype.flatMap.call(table.tBodies, n => [...n.rows]);
// или
const rows = [].concat(...Array.from(table.tBodies, n => [...n.children]));
// или
const rows = table.querySelectorAll('tbody tr');
const middle = arr => arr[arr.length >> 1];
// или
const middle = arr => arr[Math.floor(arr.length / 2)];
// или
const middle = arr => arr[Math.round(~-arr.length / 2)];
// или
const middle = arr => arr[(arr.length - arr.length % 2) / 2];
const cell = middle(middle(rows).cells);
// или
const cell = middle([].reduce.call(rows, (acc, n) => (acc.push(...n.children), acc), []));
// или, без получения строк
const cell = middle(table.querySelectorAll('tbody td'));
const el = document.querySelector('p');
const strings = [ 'hello, world!!', 'fuck the world', 'fuck everything' ];
const delay = 100;
function Typewriter(el, strings, delay) {
let i = 0;
let length = 0;
return setInterval(() => {
if (++length > strings[i].length) {
i = -~i % strings.length;
length = 0;
}
el.textContent = strings[i].slice(0, length);
}, delay);
}
const intervalId = Typewriter(el, strings, delay);
// хотим остановить, делаем так: clearInterval(intervalId);
function Typewriter(el, strings, delay) {
let timeoutId = null;
(function step(i, length) {
length = -~length % -~strings[i].length;
i = (i + !length) % strings.length;
el.innerText = strings[i].substring(0, length);
timeoutId = setTimeout(step, delay, i, length);
})(0, 0);
return () => clearTimeout(timeoutId);
}
const stop = Typewriter(el, strings, delay);
// хотим остановить, делаем так: stop();
При повторном нажатии на кнопку максимальным числом выскакивает число удалённого li.
remove
приведёт к исчезновению элемента из lis
? Искать максимальный элемент следует среди тех, что всё ещё присутствуют на странице, а не тех, что были изначально - то есть, или надо получать элементы непосредственно перед поиском, или коллекция элементов должна быть динамической.function max(data, key = n => n) {
const getVal = key instanceof Function ? key : n => n[key];
let result = null;
for (const n of data) {
const val = getVal(n);
if (!result || result[1] < val) {
result = [ n, val ];
}
}
return result?.[0];
}
document.querySelector('button').addEventListener('click', function(e) {
max(this, n => +n.textContent)?.remove();
e.target.disabled = !this.length;
}.bind(document.querySelector('ul').children));
getMaxQuestionsLeft(question, depth) {
return Math.max(
depth,
...question.nextQuestions.map(n => {
return this.getMaxQuestionsLeft(this.questions[n], depth + 1);
})
);
},
get progress() {
const ac = this.answersCount;
return Math.floor(ac / (ac + this.getMaxQuestionsLeft(this.question, 0)) * 100);
},
get maxQuestionsLeft() {
let result = 0;
for (const stack = [ [ this.question, 0 ] ]; stack.length;) {
const [ q, d ] = stack.pop();
result = Math.max(result, d);
stack.push(...q.nextQuestions.map(n => [ this.questions[n], -~d ]));
}
return result;
},
get progress() {
const { answersCount: ac } = this;
return ac / (ac + this.maxQuestionsLeft) * 100 | 0;
},
const getWeekdaysOfMonth = (year, month) =>
Array.from(
{ length: new Date(year, month, 0).getDate() },
function() {
this[0].setDate(-~this[0].getDate());
this[1] += this[0].getDay() === 1 || !this[1];
return `неделя ${this[1]}, ` + this[0].toLocaleString('ru-RU', {
day: 'numeric',
weekday: 'short',
});
},
[ new Date(year, ~-month, 0), 0 ]
);
const may2024 = getWeekdaysOfMonth(2024, 5);
const sep2023 = getWeekdaysOfMonth(2024, -3);
const jun2021 = getWeekdaysOfMonth(2020, 18);
.then( (x) => x + 1, (x) => x + 3 ) //promise rejected, value = 14
.then((x) => x * 20)
. every
для пустого массива?||
? const months = Object.fromEntries(Array.from(
{ length: 12 },
(_, i) => [ new Date(0, i).toLocaleString('ru-RU', { month: 'long' }), i ]
));
function parseDate(str) {
const [ , month, day, year, hour, minute ] = str.match(/(\S+) (\d+), (\d+) (\d+):(\d+)/);
return +new Date(year, months[month.toLowerCase()], day, hour, minute);
}
const checkboxContainer = document.querySelector('.options');
const itemsContainer = document.querySelector('.box');
const hiddenClass = 'hidden';
:not
):function getCheckedSelector(container) {
const [ not, has ] = Array.prototype.reduce.call(
container.querySelectorAll('input'),
(acc, n) => (acc[+n.checked].push(`.${n.value}`), acc),
[ [], [] ]
);
return has.join('') + (not.length ? `:not(${not.join(',')})` : '');
}
checkboxContainer.addEventListener('change', function() {
const selector = getCheckedSelector(this);
for (const n of itemsContainer.children) {
n.classList.toggle(hiddenClass, !n.matches(selector));
}
});
const toggleHidden = (selector, state) => itemsContainer
.querySelectorAll(selector)
.forEach(n => n.classList.toggle(hiddenClass, state));
checkboxContainer.addEventListener('change', e => {
toggleHidden(':scope > *', true);
toggleHidden(getCheckedSelector(e.currentTarget), false);
});
const checkboxes = [...checkboxContainer.querySelectorAll('input')];
const onChange = function() {
this.forEach(({ classList: cl }) => {
cl.toggle(hiddenClass, checkboxes.some(n => n.checked !== cl.contains(n.value)));
});
}.bind([...itemsContainer.children]);
checkboxes.forEach(n => n.addEventListener('change', onChange));