почему при изменении даты передаваемой в пропс не обновляется значение в самом компоненте таймера?
targetDate
при изменении props.date
. Нет, можете себя не утруждать - ничего такого у вас нет.targetDate
, рассчитываем дни-часы-минуты-секунды сразу на основе props.date
- так при изменении props.date
не придётся предпринимать никаких дополнительных телодвижений, всё посчитается как надо при следующем вызове updateCountdown
. Вот как-то так. .no-overflow {
overflow: hidden;
}
mounted() {
this.$watch(
() => this.isModalAddVisible || this.activeId,
val => document.body.classList.toggle('no-overflow', val),
{ immediate: true }
);
},
transition-group
. Вот так всё просто. v-model
, кого показывать в модальном окне - отправляйте наверх эту информацию вместе с событием. Свойство, управляющее видимостью модального окна - пусть оно вместо логического значения хранит id или объект или что там у вас должно показываться в окне, если не null
, значит открываем окно. Вот так всё просто.v-model
, конечно только на уровне таблицы, в строках всё по-прежнему.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/`,
currentPriority: {
get() {
return this.filterPriorities;
},
set(val) {
this.$emit('update:filterPriorities', val);
},
},
currentStopsId: {
get() {
return this.filterStops;
},
set(val) {
this.$emit('update:filterStops', val);
},
},
v-for="(address, i) in form.addresses_to" :key="i"
всегда удаляется последний
Vue использует алгоритм, который минимизирует перемещение элементов
const formMeta = ref([
{
name: '...',
component: '...',
props: { ... },
},
...
]);
name
элементов formMeta
. Изначально можно сделать пустым: const formData = ref({});
. Можно явно задать начальные значения:const formData = ref({
имяПоля1: значение1,
имяПоля2: значение2,
...
});
const formData = ref(Object.fromEntries(formMeta.value.map(n => [
n.name,
n.defaultValue ?? null,
])));
formMeta
создаётся форма, через v-model
свойства formData
связываются с экземплярами компонентов:<form>
<div v-for="n in formMeta">
<component
:is="components[n.component]"
v-model="formData[n.name]"
v-bind="n.props"
/>
</div>
</form>
<template v-for
, ячейки с rowspan'ами создаются в зависимости от равенства индексов элементов вложенных массивов нулю, значения rowspan'ов - длины (суммы длин) вложенных массивов. Например:const rowspan = item => item.backlinks.reduce((acc, n) => acc + n.recipients.length, 0);
<tbody>
<template v-for="item in data">
<template v-for="(backlink, iBacklink) in item.backlinks">
<template v-for="(recipient, iRecipient) in backlink.recipients">
<tr>
<template v-if="!iBacklink && !iRecipient">
<td :rowspan="rowspan(item)">{{ item.name }}</td>
<td :rowspan="rowspan(item)">{{ item['domain score'] }}</td>
</template>
<template v-if="!iRecipient">
<td :rowspan="backlink.recipients.length">{{ backlink.donor }}</td>
<td :rowspan="backlink.recipients.length">{{ backlink['page score'] }}</td>
</template>
<td>{{ recipient.url }}</td>
<td>{{ recipient.image }}</td>
</tr>
</template>
</template>
</template>
</tbody>
const keys = ref([
'name', 'domain score', 'backlinks',
'donor', 'page score', 'recipients',
'url', 'image',
]);
function createTableData(arr, keys, iKey = 0) {
return arr.flatMap(n => {
const row = [];
const innerRows = [];
for (let i = iKey; i < keys.length; i++) {
const val = n[keys[i]];
if (Array.isArray(val)) {
innerRows.push(...createTableData(val, keys, i + 1));
row.forEach(cell => cell.rowspan = innerRows.length);
row.push(...innerRows.shift());
break;
} else {
row.push({ text: val });
}
}
return [ row, ...innerRows ];
});
}
const tableData = computed(() => {
return createTableData(props.data, props.keys);
});
<tbody>
<tr v-for="row in tableData">
<td
v-for="cell in row"
v-text="cell.text"
:rowspan="cell.rowspan"
></td>
</tr>
</tbody>
const coords = ref([ 50, 50 ]);
const circleStyles = computed(() => ({
left: `${coords.value[0]}px`,
top: `${coords.value[1]}px`,
}));
const updateCoords = e => coords.value = [ e.pageX, e.pageY ];
const updateCoordsOn = () => document.addEventListener('mousemove', updateCoords);
const updateCoordsOff = () => document.removeEventListener('mousemove', updateCoords);
<div
class="circle"
:style="circleStyles"
@mousedown="updateCoordsOn"
@mouseup="updateCoordsOff"
></div>
<div v-once>
<select ref="select" v-model="region"></select>
</div>
mounted() {
const choices = new Choices(this.$refs.select);
this.$watch(
'regions',
val => choices.setChoices(val, 'value', 'name', true),
{ immediate: true }
);
this.$on('hook:beforeDestroy', () => choices.destroy());
},
- <script src="https://unpkg.com/vue-router@3/dist/vue-router.js"></script>
+ <script src="https://unpkg.com/vue-router@4/dist/vue-router.global.js"></script>
import VueRouter from 'vue-router'