elem.classList.add('check'); elem.querySelector('input[type="checkbox"]').remove();
data: () => ({
tasks: [],
taskId: 0,
newTaskText: '',
}),
methods: {
addTask() {
this.tasks.push({
id: ++this.taskId,
text: this.newTaskText,
done: false,
edit: false,
});
this.newTaskText = '';
},
},
<ul>
<li v-for="(n, i) in tasks" :key="n.id" :class="{ check: n.done }" @dblclick="n.edit = !n.done">
<input type="checkbox" v-if="!n.done" v-model="n.done">
<input type="text" v-if="!n.done && n.edit" v-model="n.text" @keyup.enter="n.edit = false">
<template v-else>{{ n.text }}</template>
<input type="button" class="del" value="+" @click="tasks.splice(i, 1)">
</li>
</ul>
<input type="text" v-model="newTaskText" @keyup.enter="addTask">
Не могу закрыть поп-ап
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
<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" />
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,
}
);
},
data: () => ({
opened: false,
}),
<div class="dropdown">
<div class="dropdown-header" @click="opened = !opened">
<slot name="header" :opened="opened">
{{ opened ? 'CLOSE' : 'OPEN' }}
</slot>
</div>
<div v-if="opened" class="dropdown-content">
<slot name="content"></slot>
</div>
</div>
options: {
scales: {
yAxes: [
{ id: 'y1', position: 'left' },
{ id: 'y2', position: 'right' },
],
},
},
приложение делается на vue
@click="$store.commit('setCoords', marker.coords)"
. data: () => ({
sortBy: '',
...
}),
<v-btn @click="sortBy = 'имя_свойства_по_которому_надо_выполнить_сортировку'">click me</v-btn>
<v-data-table :sort-by.sync="sortBy">...</v-data-table>
data: () => ({
sortBy: [],
sortDesc: [],
...
}),
methods: {
sort(colName) {
const sameCol = this.sortBy[0] === colName;
const sortDesc = this.sortDesc[0];
this.sortBy = sameCol && sortDesc ? [] : [ colName ];
this.sortDesc = sameCol && sortDesc ? [] : [ sameCol ];
},
...
},
<v-btn @click="sort('имя_свойства_по_которому_надо_выполнить_сортировку')">click me</v-btn>
<v-data-table :sort-by.sync="sortBy" :sort-desc.sync="sortDesc">...</v-data-table>
sort(colName) {
const index = this.sortBy.indexOf(colName);
if (index === -1) {
this.sortBy.push(colName);
this.sortDesc.push(false);
} else if (this.sortDesc[index]) {
this.sortBy.splice(index, 1);
this.sortDesc.splice(index, 1);
} else {
this.$set(this.sortDesc, index, true);
}
},
<v-btn @click="sort('имя_свойства_по_которому_надо_выполнить_сортировку')">click me</v-btn>
<v-data-table ref="table">...</v-data-table>
methods: {
sort(colName) {
const index = this.свойство_описывающее_столбцы_таблицы.findIndex(n => n.value === colName);
this.$refs.table.$el.querySelector('thead tr').cells[index].click();
},
...
},
import { yandexMap, ymapMarker, loadYmap } from 'vue-yandex-maps';
components: {
yandexMap,
ymapMarker,
},
data: () => ({
coords: null,
markers: [],
settings: { /* ... */ },
}),
methods: {
onClick(e) {
this.markers.push({
id: 1 + Math.max(0, ...this.markers.map(n => n.id)),
coords: e.get('coords'),
});
},
},
async mounted() {
await loadYmap({ ...this.settings, debug: true });
ymaps.geolocation.get().then(res => {
this.coords = res.geoObjects.position;
});
},
<yandex-map
v-if="coords"
:coords="coords"
@click="onClick"
>
<ymap-marker
v-for="n in markers"
:key="n.id"
:marker-id="n.id"
:coords="n.coords"
></ymap-marker>
</yandex-map>
data: () => ({
items: [ ... ],
active: null,
}),
<v-xxx
v-for="(n, i) in items"
:показыватьДополнительныйКонтент="active === i"
@переключитьОтображениеДополнительногоКонтента="active = active === i ? null : i"
...
const xxx = Vue.observable({ active: null });
computed: {
показыватьДополнительныйКонтент() {
return xxx.active === this.какоеТоСвойствоСУникальнымЗначением;
},
},
<div v-if="показыватьДополнительныйКонтент">
...
</div>
methods: {
переключитьОтображениеДополнительногоКонтента() {
xxx.active = this.показыватьДополнительныйКонтент
? null
: this.какоеТоСвойствоСУникальнымЗначением;
},
},
<button @click="переключитьОтображениеДополнительногоКонтента">
{{ показыватьДополнительныйКонтент ? 'hide' : 'show' }}
</button>
false
, тогда ничего не делаете, по умолчанию будет отрендерен чекбокс, если true
- передаёте в соответствующий слот что там вам надо:data: () => ({
событиеНаступило: false,
...
}),
@событие="событиеНаступило = true"
<v-data-table>
<template v-if="событиеНаступило" #item.data-table-select>
здесь размещаете контент, который должен отображаться вместо чекбоксов
</template>
...
<v-data-table>
<template #item.data-table-select="{ item, isSelected, select }">
<div v-if="item.событиеНаступило">hello, world!!</div>
<v-simple-checkbox
v-else
:value="isSelected"
@input="select($event)"
></v-simple-checkbox>
</template>
...
v-model="dialog_destroy"
), то при открытии любого из них открываются все и вы всегда видите только последний - он скрывает собой остальные.data: () => ({
showDialog: {},
...
}),
<v-dialog v-model="showDialog[item.свойствоИмеющееУникальныеЗначенияДляКаждогоItem]">
<v-btn @click="showDialog[item.свойствоИмеющееУникальныеЗначенияДляКаждогоItem] = false">Отменить
<v-dialog v-model="item.showDialog">
<v-btn @click="item.showDialog = false">Отменить
data: () => ({
dialogData: null,
...
}),
<v-data-table>
<template #item.action="{ item }">
<v-btn @click="dialogData = item">Удалить контакт</v-btn>
</template>
</v-data-table>
<v-dialog :value="!!dialogData" @input="dialogData = $event">
<span>Удалить контакт: @{{ dialogData?.contact_name }}</span>
<v-btn :href="dialogData?.destroy_link">Подтвердить</v-btn>
<v-btn @click="dialogData = null">Отменить</v-btn>
</v-dialog>
functional: true,
render(h, ctx) {
return h('div', {
class: 'col-12',
}, [
h('input', {
class: [ ctx.data.class, ctx.data.staticClass ],
}),
]);
},
mounted() {
this.$el.querySelectorAll('input').forEach(n => n.dispatchEvent(new Event('input')));
},
inheritAttrs: false,
model: {
prop: 'checked',
},
props: [ 'value', 'checked' ],
computed: {
innerChecked: {
get() {
return this.checked;
},
set(val) {
this.$emit('input', val);
},
},
},
<label>
<input
type="checkbox"
v-model="innerChecked"
v-bind="$attrs"
:value="value"
>
<slot></slot>
</label>
data: () => ({
items: [
{ label: 'hello, world!!', value: 69 },
{ label: 'fuck the world', value: 187 },
{ label: 'fuck everything', value: 666 },
],
checked: [ 187 ],
}),
watch: {
checked(val) {
if (val.length > 1) {
this.checked = val.slice(-1);
}
},
},
<v-checkbox
v-for="n in items"
v-model="checked"
:value="n.value"
name="items[]"
>
{{ n.label }}
</v-checkbox>