str.replace(/(\d{2})(\d{2})/, '$1.$2.')
// или
str.replace(/(?=\d{4}$|\d{6}$)/g, '.')
// или
str.match(/(..)(..)(.+)/).slice(1).join('.')
// или
[ 0, 2, 4 ].map((n, i, a) => str.slice(n, a[i + 1])).join`.`
// или
[...str].reduce((acc, n, i) => acc + n + ([ ,'.',,'.' ][i] || ''))
// или
''.concat(...Array.from(str, (n, i) => '24'.includes(i) ? `.${n}` : n))
on: {
breakpoint() {
this.el.classList.toggle('класс', this.slides.length < this.params.slidesPerView);
},
},
ref={ref}
элементу, который собираетесь скрывать.Не могу закрыть поп-ап
dialog: [],
dialog[index]= false
При нажатии на кнопку, при выборе 3 изображения на превью открывается всегда первое.
data: () => ({
slide: null,
dialog: false,
...
}),
methods: {
openDialog(slideIndex) {
this.slide = slideIndex;
this.dialog = true;
},
...
},
v-row
v-col(v-for="(n, i) in pictures")
v-item
v-img(height="100", width="100", :src="n", @click="openDialog(i)")
v-col(hidden="")
v-dialog(v-model="dialog")
v-carousel(v-model="slide")
v-carousel-item(v-for="n in pictures")
v-img(:src="n")
v-btn(@click="dialog = false") close dialog
<div className="mainWindow">
{this.props.children}
</div>
<posts :posts="$store.state.posts" />
<router-link :to="{ name: 'home', params: { posts } }">home</router-link>
this.$router.push({
name: 'home',
params: {
posts: this.posts,
},
});
router-link
или вызова $router.push
. При этом, если переход осуществляется не из корневого компонента, то, чтобы дотянуться до posts, придётся ещё и $root
использовать. В случае же, когда пользователь решит осуществить переход посредством адресной строки браузера, то ничего передать не получится.router-view
, тогда они будут переданы как параметры в компонент текущего маршрута: <router-view :posts="post" />
.$attrs
). Чтобы передавать что надо только куда надо, можно оформить параметры, передаваемые в router-view
, как вычисляемое свойство, значение которого будет зависеть от текущего маршрута:computed: {
routeParams() {
return что-то, в зависимости от this.$route;
},
},
<router-view v-bind="routeParams" />
function Modal(props) {
const root = useRef();
useEffect(() => {
const onClick = e => root.current.contains(e.target) || закрытьОкно();
document.addEventListener('click', onClick);
return () => document.removeEventListener('click', onClick);
}, []);
return (
<div ref={root}>
...
</div>
);
}
function Modal(props) {
return (
<div
className="modal-overlay"
onClick={e => (e.currentTarget === e.target) && закрытьОкно()}
>
...
</div>
);
}
.modal-overlay {
position: absolute;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
}
document.querySelector('table').addEventListener('click', ({ target: t }) => {
if (t.classList.contains('save_order')) {
const tr = t.closest('tr'); // всё, идентифицировали
}
});
arr.pop();
// или
arr.length -= !!arr.length;
// или
arr.splice(-1);
const count = сколько надо удалить;
):for (let i = count; --i >= 0 && arr.length; arr.pop()) ;
// или
arr.length -= Math.max(0, Math.min(arr.length, count));
// или
count > 0 && arr.splice(-count);
echo implode('', array_map(function($author, $book) {
return '<p>Книга '.$book['nameBook'].', ее написал '.$author['fio'].', '.$author['email'].'</p>';
}, $arr['authors'], $arr['books']));
document.addEventListener('input', ({ target: t }) => {
if (t.classList.contains('rating__value')) {
const value = +t.value;
t.closest('.item-rating').querySelector('.rating__dynamic').innerHTML = Array
.from({ length: 5 }, (n, i) => `<span class="char">${'☆★'[+(value > i)]}</span>`)
.join('');
}
});
document.querySelectorAll('.rating__value').forEach(n => {
n.dispatchEvent(new Event('input', { bubbles: true }));
});
for (const n of document.getElementsByClassName('rating__value')) {
n.previousElementSibling.innerHTML = '<span class="char"></span>'.repeat(5);
n.addEventListener('input', onRatingInput);
onRatingInput.call(n);
}
function onRatingInput() {
const value = this.value | 0;
const stars = this.previousElementSibling.children;
for (let i = 0; i < stars.length; i++) {
stars[i].innerText = value > i ? '★' : '☆';
}
}
tbody
для каждой пары строк. Переносите tbody
из компонента таблицы в компонент строки - будет там корневым элементом:<tbody>
<tr>... </tr>
<tr v-if="...">...</tr>
</tbody>
tr
сразу в компоненте таблицы:<tbody>
<template v-for="...">
<tr>... </tr>
<tr v-if="...">...</tr>
</template>
</body>
data: () => ({
formData: {},
formMeta: [
{ name: 'phone', title: 'Телефон', type: 'text', placeholder: 'Телефон' },
{ name: 'email', title: 'E-mail', type: 'text', placeholder: 'E-mail' },
{ name: 'address', title: 'Адрес', type: 'text', placeholder: 'Адрес' },
...
],
}),
this.$emit('save-contact', this.formData);
<div v-for="n in formMeta">
<span class="form__other-title">{{ n.title }}</span>
<div class="form__other-data">
<input
v-model="formData[n.name]"
:type="n.type"
:placeholder="n.placeholder"
>
</div>
</div>
работать с dom напрямую плохая практика
props: [ 'items', 'value' ],
data: () => ({
sliderStyles: null,
}),
<ul class="tabs">
<li
v-for="n in items"
:key="n.value"
@click="$emit('input', n.value)"
class="tabs-item"
>{{ n.text }}</li>
</ul>
<div
class="tabs-slider"
:style="sliderStyles"
></div>
.tabs-slider
) зададим абсолютное позиционирование и transition.mounted() {
this.$watch(
'value',
value => {
const index = this.items.findIndex(n => n.value === value);
const el = this.$el.querySelectorAll('.tabs-item')[index];
this.sliderStyles = el
? {
left: `${el.offsetLeft}px`,
width: `${el.offsetWidth}px`,
}
: null;
},
{
immediate: true,
}
);
},
const sortedArr = arr
.map(n => [ n, new Date(n.date.replace(/(\d+)\.(\d+)\.(\d+)/, '$3-$2-$1')) ])
.sort((a, b) => a[1] - b[1])
.map(n => n[0]);