.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 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('#contact-section');
const checkboxSelector = '[type="checkbox"][name="service[]"]';
const minChecked = 1;
const countChecked = checkboxes =>
Array.prototype.reduce.call(checkboxes, (acc, n) => acc + n.checked, 0);
const checkboxes = container.querySelectorAll(checkboxSelector);
const onChange = () => {
const minCheckedNotExceeded = countChecked(checkboxes) <= minChecked;
checkboxes.forEach(n => n.disabled = minCheckedNotExceeded && n.checked);
};
checkboxes.forEach(n => n.addEventListener('change', onChange));
container.addEventListener('change', function({ target: t }) {
if (t.matches(checkboxSelector)) {
t.checked ||= countChecked(this.querySelectorAll(checkboxSelector)) < minChecked;
}
});
[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 (let i = 0; i < arr.length; i++) {
const n = arr[i];
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);
const li = Array.prototype.filter.call(
document.querySelector('ul').children,
function(n) {
return this.every(([ k, v ]) => v === n.querySelector(`.${k}`).innerText);
},
Object.entries(items)
);
const li = [];
COLLECT_LI:
for (const n of document.querySelectorAll('li')) {
for (const k in items) {
if (Object.hasOwn(items, k) && items[k] !== n.querySelector('.' + k).textContent) {
continue COLLECT_LI;
}
}
li.push(n);
}
tags = Array.from(new Set(data.flatMap(n => n.tags)));
tags.splice(0, tags.length, ...new Set(data.flatMap(n => n.tags)));
async function getFirstLoadedImage(urls) {
for (const url of urls) {
try {
return await loadImage(url);
} catch (e) {}
}
throw 'ничего загрузить не удалось';
}
getFirstLoadedImage(resolutions.map(n => `https://i.ytimg.com/vi/${videoId}/${n}.jpg`))
.then(img => document.body.append(img))
.catch(console.error);
const getFirstLoadedImage = urls =>
new Promise((resolve, reject) => {
(function next(i) {
if (i === urls.length) {
reject('ничего загрузить не удалось');
} else {
loadImage(urls[i]).then(resolve, () => next(i + 1));
}
})(0);
});
function groupValues(arr, defaultValue = null) {
const keys = [...new Set(arr.flatMap(Object.keys))];
return arr.reduce((acc, n) => {
keys.forEach(k => acc[k].push(Object.hasOwn(n, k) ? n[k] : defaultValue));
return acc;
}, Object.fromEntries(keys.map(k => [ k, [] ])));
}
const result = groupValues(arr);
const groupValues = (arr, defaultValue = null) =>
arr.reduce((acc, n, i, a) => (
Object
.keys(n)
.forEach(k => (acc[k] ??= Array(a.length).fill(defaultValue))[i] = n[k]),
acc
), {});
const classContainer = 'selectboxss';
const classOption = 'selectoption';
const getClasses = el => [...el.classList].filter(n => n !== classOption);
//const getClass = el => el.className.match(RegExp(`${classOption}-\\d+`))[0];
document.addEventListener('click', ({ target: t }) => {
if (t.classList.contains(classOption)) {
const container = t.closest(`.${classContainer}`);
const { classList } = container;
classList.remove(...[...container.querySelectorAll(`.${classOption}`)].flatMap(getClasses));
classList.add(...getClasses(t));
//classList.remove(...Array.from(container.querySelectorAll(`.${classOption}`), getClass));
//classList.add(getClass(t));
}
});
tableValues(element);
element.children
/element.childNodes
.document.querySelector('form').childNodes
children
вместо childNodes
. Ну и погуглите, в чём между ними разница.if (element.nodeType == 1 && element.nodeName == 'INPUT' || element.nodeName == 'SELECT') {
nodeType
лишняя. Кроме того, вам не помешает разобраться с приоритетом выполнения операторов - nodeType
вы тут проверяете только для input'а.let result = [];
const getValues = el =>
el instanceof Element
? [ 'INPUT', 'SELECT' ].includes(el.tagName)
? [ el.value ]
: [...el.children].flatMap(getValues)
: [];
// или
const getValues = el =>
[ 'INPUT', 'SELECT' ].includes(el?.tagName)
? [ el.value ]
: [].flatMap.call(el.children ?? [], getValues);
const values = getValues(document.querySelector('form'));
const values = Array.from(document.querySelector('form').elements, n => n.value);
const getFromDOMNodes = (node, test, getVal) =>
node instanceof Node
? Array.prototype.reduce.call(
node.childNodes,
(acc, n) => (acc.push(...getFromDOMNodes(n, test, getVal)), acc),
test(node) ? [ getVal(node) ] : []
)
: [];
const values = getFromDOMNodes(
document.querySelector('form'),
node => [ 'INPUT', 'SELECT' ].includes(node.nodeName),
node => node.value
);
const values = {
RUS: [ 'раз значение', 'два значение', 'три' ],
US: [ '...', '...', '...' ],
// ...
};
const items = document.querySelectorAll('li');
const buttons = document.querySelectorAll('button');
buttons.forEach(n => n.addEventListener('click', onClick));
function onClick({ target: { innerText: key } }) {
items.forEach(function(n, i) {
n.innerText = this[i] ?? `ЗНАЧЕНИЕ #${i} ДЛЯ ${key} НЕ ЗАДАНО`;
}, values[key] ?? []);
}
вместо "Happy New Year!", я вижу это: "[object Object]appy New Year!"
reduce
. Особое внимание следует обратить на то, какие параметры он принимает, и что происходит, если указать не все.+
. Что бывает, если складываемые значения имеют различные типы.const str = strArr.reduce((acc, n) => (acc[n.index] = n.char, acc), []).join('');