<div>
<input id="password">
</div>
<div>
<div>Сложность пароля: <span id="strength_percent">0</span>%</div>
<progress id="strength_progress" max="100" value="0"></progress>
</div>
<div id="errors"></div>
const validations = [
{
test: val => val.length >= 8,
message: 'пароль должен содержать хотя бы 8 символов',
},
{
test: val => /[A-ZА-ЯЁ]/.test(val),
message: 'пароль должен содержать хотя бы 1 большую букву',
},
{
test: val => /[a-zа-яё]/.test(val),
message: 'пароль должен содержать хотя бы 1 маленькую букву',
},
{
test: val => /[^\s\da-zа-яё]/i.test(val),
message: 'пароль должен содержать хотя бы 1 специальный символ (не пробел, букву или цифру)',
},
{
test: val => /\d/.test(val),
message: 'пароль должен содержать хотя бы 1 цифру',
},
];
document.querySelector('#password').addEventListener('input', ({ target: { value } }) => {
const errors = validations.reduce((acc, n) => (
n.test(value) || acc.push(n.message),
acc
), []);
const strength = (validations.length - errors.length) / validations.length * 100;
document.querySelector('#strength_progress').value = strength;
document.querySelector('#strength_percent').innerText = strength | 0;
document.querySelector('#errors').innerHTML = errors
.map(n => `<p>${n}</p>`)
.join('');
});
оборачивается не полностью
childNodes
представляет собой динамическую коллекцию, т.е., при добавлении или удалении узлов она обновляется без каких-либо действий с вашей стороны. Поэтому, когда вы добавляете в wrapper
нулевой узел, он тут же пропадает из item.childNodes
, а у оставшихся узлов позиция уменьшается на единицу - тот, что был первым, становится нулевым, второй первым и так далее. Так что когда for...of
переходит к следующему узлу, им оказывается не тот, что изначально имел индекс 1
, а расположенный за ним. Бывший первый, а теперь нулевой, оказывается пропущен. Аналогичным образом будут пропущены и все последующие узлы, изначально имевшие нечётные индексы.while (item.childNodes.length) {
wrapper.appendChild(item.childNodes[0]);
}
childNodes
от конца к началу:for (let i = item.childNodes.length; i--;) {
wrapper.prepend(item.childNodes[i]);
}
childNodes
, а массив:for (const n of [...item.childNodes]) {
wrapper.append(n);
}
append
может принимать несколько параметров, так что переносим сразу всё:document.querySelectorAll('.www').forEach(n => {
const wrapper = document.createElement('div');
wrapper.classList.add('red');
wrapper.append(...n.childNodes);
n.append(wrapper);
});
for (const n of document.getElementsByClassName('www')) {
n.innerHTML = `<div class="red">${n.innerHTML}</div>`;
}
computed: {
summary() {
return (this.choosenSize?.cost ?? 0) + this.choosenTopping.reduce((acc, n) => acc + n.cost, 0);
},
},
from random import choice
chars = '0123456789abcdefghijklmnopqrstuvwxyz'
section_size = 4
sections_num = 5
string = '-'.join(''.join(choice(chars) for j in range(section_size)) for i in range(sections_num))
const sorted = arr
.map(n => [
n,
+new URLSearchParams(n.querySelector('a').href.split('?').pop()).get('value') || Infinity,
])
.sort((a, b) => a[1] - b[1])
.map(n => n[0]);
parentEl.append(...Array
.from(parentEl.querySelectorAll('a'), n => [
n.parentNode,
Number(n.getAttribute('href').match(/(?<=value=)\d+/)) || Infinity,
])
.sort((a, b) => a[1] - b[1])
.map(n => n[0])
);
const Figure = ({ type, ...props }) => <div className={type} {...props}></div>;
class App extends React.Component {
state = {
types: [ 'circle', 'square', 'triangle' ],
figures: [],
}
add(type) {
this.setState(({ figures }) => ({
figures: [ ...figures, type ],
}));
}
render() {
const { types, figures } = this.state;
return (
<div>
<div>
{types.map(n => <Figure type={n} onClick={() => this.add(n)} />)}
</div>
<div>
{figures.map(n => <Figure type={n} />)}
</div>
</div>
);
}
}
function Preloader({ Tag = 'h1', children }) {
return (
<Tag className={s.wrapper}>
<div className={s.preloader}></div>
{children}
</Tag>
);
}
<div className="App">
<Preloader>hello, world!!</Preloader>
<Preloader Tag="h2">fuck the world</Preloader>
</div>
const updateValue = input =>
input.previousElementSibling.querySelector('.p_value').innerText = input.value;
class="xxx"
.document.addEventListener('input', ({ target: t }) => {
if (t.classList.contains('xxx')) {
updateValue(t);
}
});
document.querySelectorAll('.xxx').forEach(function(n) {
n.addEventListener('input', this);
}, e => updateValue(e.target));
watch: { cloneItems(old, cur) { this.prevItems = old; },
computed: { cloneItems: () => this.items.slice(),
prev items: <div v-for="item in items" :key="item">
this.items = [...this.items, Date.now()];
const cols = document.querySelectorAll('.col');
cols.forEach(n => {
n.addEventListener('mouseover', onHover);
n.addEventListener('mouseout', onHover);
});
function onHover(e) {
const index = [...this.children].findIndex(n => n.contains(e.target));
if (index !== -1) {
const t = e.type === 'mouseover';
cols.forEach(n => n.children[index].classList.toggle('hovered', t));
}
}
document.querySelectorAll('.nav-about a').forEach((n, i) => n.attributes.href.value += i + 1);
$('button').click(() => $('select').prop('selectedIndex', 0));
document.querySelector('button').addEventListener('click', () => {
document.querySelectorAll('select').forEach(n => {
// Какие тут есть варианты:
// 1. Установить индекс выбранного option'а
n.selectedIndex = 0;
// 2. Установить select'у значение option'а, который должен быть выбран
// (чтобы заработало, надо будет добавить value="" option'ам)
n.value = '';
// 3. Назначить true свойству selected того option'а, на который надо переключиться
n[0].selected = true;
// или
// n.options[0].selected = true;
// n.children[0].selected = true;
// n.firstElementChild.selected = true;
// n.querySelector('option').selected = true;
});
});
const arrs = [ arr1, arr2 ];
), дальше есть варианты:const result = arrs[0].map((_, i) => arrs.flatMap(arr => arr[i]));
const result = arrs.reduce((acc, arr) => (
arr.forEach((n, i) => (acc[i] ??= []).push(...n)),
acc
), []);
const result = [];
for (const arr of arrs) {
for (const [ i, n ] of arr.entries()) {
if (!result[i]) {
result[i] = [];
}
for (const m of n) {
result[i][result[i].length] = m;
}
}
}
watch: {
'product.qty'(val) {
this.product.qty = Math.max(1, Math.min(99, val | 0));
},
},
v-for
и это элемент массива, то можно установить глубокое наблюдение за всем массивом:watch: {
products: {
deep: true,
handler: val => val.forEach(n => n.qty = Math.max(1, Math.min(99, n.qty | 0))),
},
},
methods: {
onInput(e) {
if (e.isTrusted) {
e.target.value = Math.max(1, Math.min(99, e.target.value | 0));
e.target.dispatchEvent(new Event('input'));
}
},
},
<input
@input="onInput"
...
function onInput({ isTrusted, target: t }) {
if (isTrusted) {
t.value = Math.max(t.min, Math.min(t.max, t.value | 0));
t.dispatchEvent(new Event('input'));
}
}
const minmaxDirective = {
mounted: el => el.addEventListener('input', onInput),
unbind: el => el.removeEventListener('input', onInput),
};
app.directive('minmax', minmaxDirective);
<input
v-minmax
min="1"
max="99"
...
document.querySelectorAll('.item').forEach((n, i) => n.dataset.priority = ++i);
// или
for (const [ i, n ] of document.querySelectorAll('.item').entries()) {
n.setAttribute('data-priority', i + 1);
}
// или
const items = document.getElementsByClassName('item');
for (let i = 0; i < items.length; i++) {
items[i].attributes['data-priority'].value = -~i;
}