const getMonthNameInGenitiveCase = (date = new Date) =>
date.toLocaleString('ru', {
month: 'long',
day: 'numeric',
}).split(' ')[1];
const getMonthNameInGenitiveCase = (date = new Date) =>
[
'января', 'февраля', 'марта', 'апреля', 'мая', 'июня',
'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря',
][date.getMonth()];
props
, используете v-bind
для привязки функции к экземпляру дочернего компонента.<button @click="$emit('click')"
.<component @click="onClick"
.$listeners
, так что вместо $emit('click')
или (если надо передать родителю какие-то данные) $emit('click', аргумент)
можно (но не нужно) написать $listeners.click
или $listeners.click(аргумент)
. const openSelector = '[data-target]';
const closeSelector = '.modal__close';
const modalSelector = '.modal';
const activeClass = 'modal--active';
document.addEventListener('click', ({ target: t }) => {
const open = t.closest(openSelector);
if (open) {
document.querySelector(`#${open.dataset.target}`).classList.add(activeClass);
} else {
t.closest(closeSelector)?.closest(modalSelector).classList.remove(activeClass);
}
});
const onClick = (selector, handler) => document
.querySelectorAll(selector)
.forEach(n => n.addEventListener('click', handler));
onClick(openSelector, ({ currentTarget: { dataset: { target } } }) => {
document.querySelector(`#${target}`).classList.add(activeClass);
});
onClick(closeSelector, e => {
e.currentTarget.closest(modalSelector).classList.remove(activeClass);
});
const obj = {
val: 1,
valueOf() {
return this.val ^= 1;
},
};
// или
const obj = {
val: '1',
toString() {
return this.val = '1'.slice(this.val.length);
},
};
// или
const obj = {
val: true,
[Symbol.toPrimitive]() {
return this.val = !this.val;
},
};
console.log(obj == false, obj == true); // true true
console.log(...Array.from({ length: 5 }, () => +obj)); // 0 1 0 1 0
function mustStay(n) {
for (const m of arr2) {
if (m.content.insuranceType === n.value) {
return false;
}
}
return true;
}
// или
const mustStay = n => arr2.every(m => m.content.insuranceType !== n.value);
// или
const mustStay = function(n) {
return !this.has(n.value);
}.bind(new Set(arr2.map(n => n.content.insuranceType)));
// или
const mustStay = n =>
(function next(i) {
return i >= arr2.length
? true
: arr2[i].content.insuranceType !== n.value && next(-~i);
})(0);
for (let i = 0; i < arr1.length; i++) {
if (!mustStay(arr1[i])) {
for (let j = i--; ++j < arr1.length; arr1[j - 1] = arr1[j]) ;
arr1.pop();
}
}
// или
arr1.reduceRight((_, n, i, a) => mustStay(n) || a.splice(i, 1), null);
// или
arr1.splice(0, arr1.length, ...arr1.filter(mustStay));
// или
arr1.length -= arr1.reduce((acc, n, i, a) => (
a[i - acc] = n,
acc + !mustStay(n)
), 0);
const steps = [ /* ... */ ];
let iStep = 0;
const question = document.querySelector('.quiz__question');
const answers = document.querySelector('.quiz__answers');
const prev = document.querySelector('.quiz__button_prev');
const next = document.querySelector('.quiz__button_next');
prev.addEventListener('click', () => nextStep(-1));
next.addEventListener('click', () => nextStep(+1));
function nextStep(stepChange) {
iStep = Math.max(0, Math.min(steps.length - 1, iStep + stepChange));
prev.disabled = iStep === 0;
next.disabled = iStep === steps.length - 1;
question.innerHTML = steps[iStep].question;
answers.innerHTML = steps[iStep].answers.map(n => `<li>${n}</li>`).join('');
}
nextStep(0);
expanded-item
:<v-data-table
:headers="mainTableHeaders"
:items="mainTableItems"
item-key="mainTableItemKey"
show-expand
>
<template #expanded-item="{ headers, item }">
<td :colspan="headers.length">
<v-data-table
:headers="nestedTableHeaders"
:items="item.nestedTableItems"
></v-data-table>
</td>
</template>
</v-data-table>
при клике на строчку
show-expand
, добавляем обработчик клика, где отображение дополнительного контента будет переключаться вручную:methods: {
onRowClick(item, row) {
row.expand(!row.isExpanded);
},
...
<v-data-table
@click:row="onRowClick"
...
class DB {
info = null;
...
const Episodes = observer(() => {
useEffect(() => {
...
}, [ DB.info ]);
...
return <Episodes />;
на return DB.info && <Episodes />;
. <div data-filter="service">
<div class="sign">Streaming service</div>
<div class="item">Netflix</div>
<div class="item">HBO Max</div>
<div class="item">Hulu</div>
</div>
<div data-filter="genre">
<div class="sign">Movie genre</div>
<div class="item">Comedy</div>
<div class="item">Action</div>
<div class="item">Horror</div>
<div class="item">Drama</div>
<div class="item">Fantasy</div>
</div>
<li class="card" data-service="Netflix" data-genre="Comedy">
const cardSelector = '.card';
const hiddenCardClass = 'hidden';
const filterSelector = '[data-filter]';
const filterItemSelector = `${filterSelector} .item`;
const activeFilterItemClass = 'item_active';
document.querySelector('.filters').addEventListener('click', e => {
const item = e.target.closest(filterItemSelector);
if (!item) {
return;
}
item.closest(filterSelector).querySelectorAll(filterItemSelector).forEach(n => {
n.classList[n === item ? 'toggle' : 'remove'](activeFilterItemClass);
});
const values = Array.from(
e.currentTarget.querySelectorAll(`.${activeFilterItemClass}`),
n => [ n.closest(filterSelector).dataset.filter, n.innerText ]
);
document.querySelectorAll(cardSelector).forEach(n => {
n.classList.toggle(hiddenCardClass, values.some(m => n.dataset[m[0]] !== m[1]));
});
});
v-text-field
подобной возможности не предоставляет, так что придётся закостылить.<v-text-field @click.native="onClick">
methods: {
onClick({ target: t }) {
if (
t.classList.contains('v-messages__message') &&
t.closest('.v-messages.error--text')
) {
// ну да, кликнули по сообщению об ошибке
}
},
},
v-model
, обновил данные в компоненте; устанавливаете отформатированное значение. Для предотвращения рекурсивной обработки событий input проверяете isTrusted:function updateValue(el) {
el.value = el.value, из которого удалено всё, кроме цифр;
el.dispatchEvent(new Event('input'));
el.value = форматированное значение el.value;
}
function onInput(e) {
if (e.isTrusted) {
updateValue(e.target);
}
}
Vue.directive('number', {
bind(el) {
el.addEventListener('input', onInput);
updateValue(el);
},
update(el) {
updateValue(el);
},
unbind(el) {
el.removeEventListener('input', onInput);
},
});
с минимальным количеством действий
v-for="el in link"
на v-for="el in [].concat(link)"
. return getValue(objectValus[prop], property);
const getValue = (obj, key) => Object
.values(obj ?? {})
.reduce((found, n) => found ?? getValue(n, key), obj?.[key]);