.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
), {});
.no-overflow {
overflow: hidden;
}
mounted() {
this.$watch(
() => this.isModalAddVisible || this.activeId,
val => document.body.classList.toggle('no-overflow', val),
{ immediate: true }
);
},
transition-group
. Вот так всё просто. const defaults = {
index: 0,
length: 0,
step: 1,
};
function Typewriter({ strings, delay }) {
const [ state, setState ] = useState(null);
useEffect(() => {
setState(() => ({...defaults}));
}, [ strings ]);
useEffect(() => {
const timeoutId = setTimeout(setState, delay, ({...state}) => {
state.length += state.step;
if (state.length === strings[state.index].length) {
state.step = -1;
} else if (state.length === 0) {
state.step = 1;
state.index = (state.index + 1) % strings.length;
}
return state;
});
return () => clearTimeout(timeoutId);
});
return <div>{strings?.[state?.index]?.slice(0, state?.length)}</div>;
}
работает, но кажется, что достаточно криво
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);
v-model
, кого показывать в модальном окне - отправляйте наверх эту информацию вместе с событием. Свойство, управляющее видимостью модального окна - пусть оно вместо логического значения хранит id или объект или что там у вас должно показываться в окне, если не null
, значит открываем окно. Вот так всё просто.v-model
, конечно только на уровне таблицы, в строках всё по-прежнему.<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 addCard = (cardName) => { cards.value.push({ id: Date.now(), component: cardName, order: cards.value.length + 1, isRequired: false }) }
const components = {
ShortTextCard,
LongTextCard,
SingleQuestionCard,
MultiQuestionCard,
};
- @click="addCard(ShortTextCard)"
+ @click="addCard('ShortTextCard')"
- :is="card.component"
+ :is="components[card.component]"
<el-menu mode="horizontal" router :default-active="$route.name">
<el-menu-item
v-for="n in $router.getRoutes()"
v-text="n.name"
:index="n.name"
:route="n"
/>
</el-menu>
<router-view />
computed: {
activeRouteName: {
get() {
return this.$route.name;
},
set(name) {
this.$router.push({ name });
},
},
},
<router-view>
, но рендерить будем его только в активной вкладке. Вот такой получается говнокод:<el-tabs v-model="activeRouteName">
<el-tab-pane v-for="{ name: n } in $router.getRoutes()" :label="n" :name="n">
<router-view v-if="activeRouteName === n" />
</el-tab-pane>
</el-tabs>
handleEdit(row){
@click="handleEdit(scope.$index, scope.row)"
path:'/protocol_information/:id/edit/', params:{ id:row.id }
path: `/protocol_information/${row.id}/edit/`,
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);
}
currentPriority: {
get() {
return this.filterPriorities;
},
set(val) {
this.$emit('update:filterPriorities', val);
},
},
currentStopsId: {
get() {
return this.filterStops;
},
set(val) {
this.$emit('update:filterStops', val);
},
},
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;