.dropdown.show {
display: block;
}
const accordionItemSelector = '.data-accordion--summary-container';
const contentSelector = '.dropdown';
const activeClass = 'show';
document.body.addEventListener('click', ({ target: t }) => {
if (t.matches(accordionItemSelector)) {
document.querySelectorAll(contentSelector).forEach(n => {
if (!n.contains(t) && !t.contains(n)) {
n.classList.remove(activeClass);
};
});
t.querySelector(contentSelector).classList.toggle(activeClass);
}
});
- acc[key] = [value];
+ (acc[key] ??= []).push(value);
const convertQueryStringToObject = str => Array
.from(new URLSearchParams(str))
.reduce((acc, n) => ((acc[n[0]] ??= []).push(n[1]), acc), {});
const convertQueryStringToObject = str => Array
.from(str.matchAll(/([^&]+)=([^&]+)/g))
.reduce((acc, [ , k, v ]) => (
Object.hasOwn(acc, k) || (acc[k] = []),
acc[k][acc[k].length] = v,
acc
), {});
работает, но кажется, что достаточно криво
let lvl = 0;
for (let i = LVLS.length; i--;) {
if (LVLS[i].exp <= EXP) {
lvl = LVLS[i].lv;
break;
}
}
переделать это во что-то более красивое
const lvl = LVLS.findLast(n => n.exp <= EXP)?.lv ?? 0;
const LVLS = [ 10, 25, 45, 70, 100 ];
const lvl = 1 + LVLS.findLastIndex(n => n <= EXP);
<button data-country="">Показать всё</button>
<button data-country="France">Франция</button>
<button data-country="Germany">Германия</button>
<button data-country="England">Англия</button>
const catalogEl = document.querySelector('#catalog-box');
let catalogArr = [];
const buttons = document.querySelectorAll('button[data-country]');
buttons.forEach(n => n.addEventListener('click', onClick));
function onClick({ target: t }) {
buttons.forEach(n => n.classList.toggle('active', n === t));
renderCatalog(t.dataset.country);
}
function renderCatalog(country) {
const toRender = country
? catalogArr.filter(n => n.tag === country)
: catalogArr;
catalogEl.innerHTML = toRender
.map(n => `
<div class="catalog__card" id="${n.id}">
<img src="${n.img}" alt="${n.alt}" class="catalog__card_img">
<p class="catalog__card_author">${n.author}</p>
<p class="catalog__card_name">${n.name}</p>
<p class="catalog__card_note">${n.note}</p>
<p class="catalog__card_price">${n.price}</p>
<button class="catalog__card_btn">${n.btn}</button>
</div>`)
.join('');
}
fetch('catalogBox.json')
.then(r => r.json())
.then(r => {
catalogArr = r;
buttons[0].click();
});
const obj1 = Object.fromEntries(arr1.map(n => [ n.name, n ]));
// или
const obj1 = arr1.reduce((acc, n) => (acc[n.name] = n, acc), {});
const newArr2 = arr2.map(n => ({ ...obj1[n.name], ...n }));
// или
const newArr2 = [];
for (let i = 0; i < arr2.length; i++) {
newArr2.push(Object.assign({}, obj1[arr2[i].name], arr2[i]));
}
arr2.forEach(n => Object
.entries(obj1[n.name] ?? {})
.forEach(([ k, v ]) => Object.hasOwn(n, k) || (n[k] = v))
);
// или
for (const n of arr2) {
const obj = obj1[n.name];
for (const k in obj) {
if (!n.hasOwnProperty(k)) {
n[k] = obj[k];
}
}
}
можно ли исключить объекты у которых не изменился value? То есть что бы этих объектов не было в итоговом массиве.
const newArr2 = arr2.reduce((acc, n) => (
obj1[n.name]?.value !== n.value && acc.push({ ...obj1[n.name], ...n }),
acc
), []);
function restrictChecked({
container,
selector = 'input[type="checkbox"]',
min = 0,
max = Infinity,
enableOnCancel = true,
}) {
const checkboxes = [...container.querySelectorAll(selector)];
const onChange = () => {
const countChecked = checkboxes.reduce((acc, n) => acc + n.checked, 0);
const minReached = countChecked <= min;
const maxReached = countChecked >= max;
checkboxes.forEach(n => n.disabled = minReached && n.checked || maxReached && !n.checked);
};
checkboxes.forEach(n => n.addEventListener('change', onChange));
onChange();
return () => checkboxes.forEach(n => {
n.disabled &&= !enableOnCancel;
n.removeEventListener('change', onChange);
});
}
function restrictChecked({
container,
selector = 'input[type="checkbox"]',
min = 0,
max = Infinity,
}) {
function onChange({ target: t }) {
if (t.matches(selector)) {
const countChecked = this.querySelectorAll(`${selector}:checked`).length;
t.checked ||= countChecked < min;
t.checked &&= countChecked <= max;
}
}
container.addEventListener('change', onChange);
return () => container.removeEventListener('change', onChange);
}
const addDepth = (val, depth = 0) =>
val instanceof Object
? Object.entries(val).reduce((acc, n) => (
acc[n[0]] = addDepth(n[1], depth + 1),
acc
), { depth })
: val;
const toString = (val, keys = []) =>
val instanceof Object
? Object.entries(val).map(([ k, v ]) => {
keys.push(k);
const result = toString(v, keys);
keys.pop();
return result;
}).join('&')
: `${keys.join('.')}=${val}`;
function toString(val) {
const result = [];
for (const stack = [ [ val, [] ] ]; stack.length;) {
const [ n, keys ] = stack.pop();
if (n instanceof Object) {
stack.push(...Object.entries(n).map(([ k, v ]) => [ v, [ ...keys, k ] ]).reverse());
} else {
result.push(`${keys.join('.')}=${n}`);
}
}
return result.join('&');
}
const units = [
[ 'де?н', 24 * 60 * 60 ],
[ 'час', 60 * 60 ],
[ 'мин', 60 ],
[ 'сек', 1 ],
].map(n => [ RegExp(`\\d+(?=\\s+${n[0]})`), n[1] ]);
const getSeconds = str =>
units.reduce((acc, n) => acc + n[0].exec(str) * n[1], 0);
getSeconds('2 часа 22 секунды') // 7222
getSeconds('99 минут') // 5940
getSeconds('1 час 1 минута 1 секунда') // 3661
getSeconds('1 день 23 часа 59 минут 60 секунд') // 172800
getSeconds('2 дня') // 172800
getSeconds('546 секунд и ещё 2 минуты') // 666
RegExp(`\\d+(?=\\s+${n[0]})`, 'g')
, а функция подсчёта секунд примет следующий вид:const getSeconds = str =>
units.reduce((seconds, [ reg, multiplier ]) => {
return [...str.matchAll(reg)].reduce((acc, n) => acc + n * multiplier, seconds);
}, 0);
// или
const getSeconds = str => units
.flatMap(n => (str.match(n[0]) ?? []).map(m => m * n[1]))
.reduce((acc, n) => acc + n, 0);
// или
const getSeconds = str => eval(units
.map(n => `${n[1]} * (${str.match(n[0])?.join('+') ?? 0})`)
.join('+')
);
getSeconds('1 секунда плюс 3 секунды плюс 5 секунд') // 9
getSeconds('21 день, 7 дней, да ещё 3 дня - всего секунд в мае месяце будет') // 2678400
.panel {
padding: 0 15px;
transition: all 0.4s;
height: 0;
overflow: hidden;
}
.faq-item.active .panel {
padding: 15px 15px 20px;
}
.faq-item.active .cross {
transform: rotate(45deg);
}
const containerSelector = '.faq-list';
const itemSelector = '.faq-item';
const headerSelector = '.accordion';
const contentSelector = '.panel';
const activeClass = 'active';
const toggle = item => item
?.closest(containerSelector)
?.querySelectorAll(itemSelector).forEach(n => {
const state = n === item && !n.classList.contains(activeClass);
const content = n.querySelector(contentSelector);
n.classList.toggle(activeClass, state);
content.style.height = `${state ? content.scrollHeight : 0}px`;
});
document.addEventListener('click', e => {
toggle(e.target.closest(headerSelector)?.closest(itemSelector));
});
// или
document.querySelectorAll(headerSelector).forEach(n => {
n.addEventListener('click', toggle.bind(null, n.closest(itemSelector)));
});
translate
элементу. А чтобы не делать отдельные обработчики клика всем кнопкам, можно записать им в data-атрибут информацию о том, на сколько какие координаты должна изменить данная кнопка.<button data-steps="1,0">right</button>
<button data-steps="-1,0">left</button>
<button data-steps="0,1">down</button>
<button data-steps="0,-1">up</button>
<button data-steps="1,1">right down</button>
<button data-steps="0,-2">double up</button>
const coord = [ 0, 0 ];
const stepSize = 30;
const box = document.querySelector('#box');
const buttons = document.querySelectorAll('[data-steps]');
buttons.forEach(n => n.addEventListener('click', onClick));
function onClick() {
this.dataset.steps.split(',').forEach((n, i) => coord[i] += n * stepSize);
box.style.transform = `translate(${coord.map(n => `${n}px`).join(',')})`;
}
const arr = [
[ 'author', 'Author - ' ],
[ 'name', 'Name' ],
[ 'currentTime', '00:00' ],
[ 'duration', '00:00' ],
];
for (const [ className, text ] of arr) {
titleElement.appendChild(create({
el: 'span',
className,
text,
}));
}
// или
titleElement.append(...arr.map(n => create({
el: 'span',
className: n[0],
text: n[1],
})));
// или, без всех этих ваших странных функций
document.querySelector('#root').innerHTML = `
<div id="title">${arr.map(n => `
<span class="${n[0]}">${n[1]}</span>`).join('')}
</div>
`;
const questionEl = document.querySelector('ul');
const resultsEl = document.querySelector('p span');
questionEl.addEventListener('change', showResults);
function showResults() {
resultsEl.innerText = Array.prototype.reduce.call(
questionEl.querySelectorAll('input[type="radio"]:checked'),
(acc, n) => acc + +n.value,
0
);
}
const getNestedData = (data, test) => Object
.values(data instanceof Object ? data : {})
.reduce((acc, n) => (
acc.push(...getNestedData(n, test)),
acc
), test(data) ? [ data ] : []);
const result = getNestedData(arr, n => n?.workControl?.includes?.('intermediate'));
function getNestedData(data, test) {
const result = [];
for (const stack = [ data ]; stack.length;) {
const n = stack.pop();
if (n instanceof Object) {
stack.push(...Object.values(n).reverse());
}
if (test(n)) {
result.push(n);
}
}
return result;
}
// или
function getNestedData(data, test) {
const result = [];
const stack = [];
for (let i = 0, arr = [ data ]; i < arr.length || stack.length; i++) {
if (i === arr.length) {
[ i, arr ] = stack.pop();
} else {
if (test(arr[i])) {
result.push(arr[i]);
}
if (arr[i] instanceof Object) {
stack.push([ i, arr ]);
[ i, arr ] = [ -1, Object.values(arr[i]) ];
}
}
}
return result;
}
const container = document.querySelector('селектор общего предка чекбоксов');
const checkboxSelector = 'селектор чекбоксов';
const minChecked = 1;
const maxChecked = Infinity;
const countChecked = checkboxes =>
Array.prototype.reduce.call(checkboxes, (acc, n) => acc + n.checked, 0);
const checkboxes = container.querySelectorAll(checkboxSelector);
const onChange = () => {
const count = countChecked(checkboxes);
const minReached = count <= minChecked;
const maxReached = count >= maxChecked;
checkboxes.forEach(n => n.disabled = minReached && n.checked || maxReached && !n.checked);
};
checkboxes.forEach(n => n.addEventListener('change', onChange));
container.addEventListener('change', function({ target: t }) {
if (t.matches(checkboxSelector)) {
const count = countChecked(this.querySelectorAll(checkboxSelector));
t.checked ||= count < minChecked;
t.checked &&= count <= maxChecked;
}
});
[Symbol.iterator]() { return this; }
и без:const iter = new Range(1, 5)[Symbol.iterator]();
console.log(iter.next().value);
console.log(iter.next().value);
console.log([...iter]);
Пытаюсь так:
let currentIndex = $(".js-practice_button.current").index();
Но значение всегда 0, у какой бы кнопки классcurrent
не присутствовал.
index
по умолчанию определяет индекс элемента среди соседей, а так как у каждой кнопки есть отдельный родитель... Ну да, получаете то, что получаете.const index = $('.js-practice_button.current').closest('li').index();
index
в качестве параметра селектор, то индекс будет определятся не среди соседей, а среди элементов, соответствующих селектору:const index = $('.js-practice_button.current').index('.js-practice_button');
const index = Array.prototype.findIndex.call(
document.querySelectorAll('.js-practice_button'),
n => n.classList.contains('current')
);
// или
const el = document.querySelector('.js-practice_button.current')?.parentNode;
const index = el ? [...el.parentNode.children].indexOf(el) : -1;
// или
let index = -1;
for (
let el = document.querySelector('.js-practice_button.current')?.closest('li');
el;
el = el.previousElementSibling, index++
) ;
const noRepeatingDigits = num => !/(\d).*\1/.test(num);
// или
const noRepeatingDigits = num => -~Math.log10(num) === new Set(`${num}`).size;
// или
const noRepeatingDigits = num => [...'' + num].every((n, i, a) => i === a.indexOf(n));
// или
const noRepeatingDigits = num => String(num)
.split('')
.reduce((acc, n) => (acc[n]++, acc), Array(10).fill(0))
.every(n => n < 2);
// или
const noRepeatingDigits = num =>
!''.match.call(num, /./g).some(function(n) {
return this[n] = Object.hasOwn(this, n);
}, {});
// или
const noRepeatingDigits = num =>
!Array.from(num.toString()).sort().find((n, i, a) => n === a[i + 1]);
arr.splice(0, arr.length, ...arr.filter(noRepeatingDigits));
// или
let numDeleted = 0;
for (const [ i, n ] of arr.entries()) {
arr[i - numDeleted] = n;
numDeleted += !noRepeatingDigits(n);
}
arr.length -= numDeleted;
// или
for (let i = arr.length; i--;) {
if (!noRepeatingDigits(arr[i])) {
arr.splice(i, 1);
}
}
const newArr = arr.filter(noRepeatingDigits);
// или
const newArr = [];
for (const n of arr) {
if (noRepeatingDigits(n)) {
newArr.push(n);
}
}
// или
const newArr = [];
for (let i = 0; i < arr.length; i++) {
if (noRepeatingDigits(arr[i])) {
newArr[newArr.length] = arr[i];
}
}
// или
const newArr = (function xxx(arr, i = 0) {
return i < arr.length
? (noRepeatingDigits(arr[i]) ? [ arr[i] ] : []).concat(xxx(arr, i + 1))
: [];
})(arr);