Объект менять не нужно.
const SERIES = [
{
comment: '1 сезон',
folder: [
{ comment: '1 серия' },
{ comment: '2 серия' },
],
},
{
comment: '2 сезон',
folder: [
{ comment: '1 серия' },
{ comment: '2 серия' },
{ comment: '3 серия' },
],
},
];
const ItemsList = ({ header, items, active, onChange }) => (
<div>
<h3>{header}</h3>
<ul className="items">
{items.map(({ comment }, i) => (
<li
className={`item ${active === i ? 'active' : ''}`}
onClick={() => onChange?.(i !== active ? i : -1)}
>
{comment}
</li>
))}
</ul>
</div>
);
function App() {
const [ iSeason, setActiveSeason ] = useState(-1);
const [ iEpisode, setActiveEpisode ] = useState(-1);
const season = SERIES[iSeason];
const episode = season?.folder[iEpisode];
useEffect(() => {
setActiveEpisode(-1);
}, [ iSeason ]);
return (
<div>
<ItemsList
header="сезоны"
items={SERIES}
active={iSeason}
onChange={setActiveSeason}
/>
{season && <ItemsList
header="серии"
active={iEpisode}
onChange={setActiveEpisode}
items={season.folder}
/>}
{episode && <div>Выбрали: {season.comment}, {episode.comment}</div>}
</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 grouped = productData.reduce((acc, n) => (
(acc[n.coordinates] ??= []).push(n),
acc
), {});
for (const [ coord, data ] of Object.entries(grouped)) {
const placemark = new ymaps.Placemark(
coord.split(',').map(parseFloat),
{
balloonContent: data
.map(n => `
<div>
${n.address}
<br>
<a href="${n.productURL}">Подробнее</a>
</div>`)
.join(''),
},
{
preset: 'islands#blueDotIcon',
maxWidth: 300,
}
);
map.geoObjects.add(placemark);
}
const placemarks = productData.map((n, i) => new ymaps.Placemark(
n.coordinates.split(',').map(parseFloat),
{
balloonContent: `${n.address}<br><a href="${n.productURL}">Подробнее</a>`,
clusterCaption: `Адрес №${i + 1}`,
},
{
preset: 'islands#blueDotIcon',
maxWidth: 300,
}
));
const clusterer = new ymaps.Clusterer({
clusterDisableClickZoom: true,
});
clusterer.add(placemarks);
map.geoObjects.add(clusterer);
decoded = ''.join(data_crypt.get(n, n) for n in text)
print(decoded)
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);
const arrs = [
[ 1, 2, 3, 4 ],
[ 5, 6, 7, 8 ],
[ 9, 10, 11 ],
];
const result = [];
const max = Math.max(...arrs.map(n => n.length));
const index = Array(arrs.length).fill(0);
for (let i = 0; i < max; i++) {
for (let j = 0; j < index.length; j++) {
if (index[j] < arrs[j].length) {
result[result.length] = arrs[j][index[j]++];
}
}
}
const result = arrs
.reduce((acc, arr) => (
arr.forEach((n, i) => (acc[i] ??= []).push(n)),
acc
), [])
.flat();
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);
}
- <script src="https://unpkg.com/vue-router@3/dist/vue-router.js"></script>
+ <script src="https://unpkg.com/vue-router@4/dist/vue-router.global.js"></script>
import VueRouter from 'vue-router'
<yandex-map
ref="map"
@map-was-initialized="onBoundsChange"
@boundschange="onBoundsChange"
...
>
<ymap-marker
v-for="n in markersData"
...
>
methods: {
onBoundsChange() {
const bounds = this.$refs.map.myMap.getBounds();
this.markersData.forEach(n => {
if (
bounds[0][0] < n.coords[0] && n.coords[0] < bounds[1][0] &&
bounds[0][1] < n.coords[1] && n.coords[1] < bounds[1][1]
) {
// ...
}
});
},
...
$extract = fn($keys, $item) => array_combine($keys, array_map(fn($k) => $item[$k], $keys));
$grouped = [];
$productKeys = [ 'product_id', 'sku', 'quantity' ];
$orderKeys = array_diff(array_keys($arr[0] ?? []), $productKeys);
foreach ($arr as $n) {
$id = $n['order_id'];
$grouped[$id] ??= $extract($orderKeys, $n);
$grouped[$id]['products'][] = $extract($productKeys, $n);
}
метод testemit компонента question не отрабатывает
$emit('testemit')
есть, а вот @testemit="testemit"
отсутствует. site:qna.habr.com <имя-пользователя> <тег> <чего ищем>
tags = Array.from(new Set(data.flatMap(n => n.tags)));
tags.splice(0, tags.length, ...new Set(data.flatMap(n => n.tags)));
const lastEdited = Vue.observable({ instance: null });
props: [ 'value' ],
methods: {
onInput(e) {
this.$emit('input', e.target.value);
lastEdited.instance = this;
},
},
created() {
this.$watch(() => lastEdited.instance, val => {
if (val && val !== this) {
this.$emit('input', '');
}
});
},
beforeDestroy() {
if (lastEdited.instance === this) {
lastEdited.instance = null;
}
},
<input :value="value" @input="onInput">
const eventBus = new Vue();
props: [ 'value' ],
methods: {
onInput(e) {
this.$emit('input', e.target.value);
eventBus.$emit('clear-other-inputs', this);
},
},
created() {
const clear = e => e !== this && this.$emit('input', '');
eventBus.$on('clear-other-inputs', clear);
this.$on('hook:beforeDestroy', () => eventBus.$off('clear-other-inputs', clear));
},
<input :value="value" @input="onInput">