Задача:
Реализовать кнопку отката последнего действия.
Как работает:
Текущие данные записываются в массив history, по нажатию на кнопку apply, на кнопке undo откатывается, при этом значения в input меняются на предыдущие - всё отлично, хоть до 100500 шагов так, но это только если не нажимать кнопку undo.
history: [ { "0": "", "1": "test" },
{ "0": "test", "1": "test" },
{ "0": "test", "1": "test", "2": "test"}
]
Если хотя бы раз нажать кнопку undo, то при следующей записи новых данных в массив он пишет и v-model (ключи name, surname и т.д.) и input.value (индексы), а дальше снова нормально - только input.value
history: [
{ "0": "", "1": "test"},
{ "0": "test", "1": "test", "2": "", "3": "", "4": "", "5": "asd", "6": "", "surname": "test", "name": "test", "secondName": "", "phone": "", "phone2": "", "mail": "", "address": "" } ]
Почему добавляются и эти значения ["surname": "test", "name": "test", "....], если нажать undo и потом добавить новые значения?
Ниже код компонента:
<template>
<div class="wrapper">
<form>
<div
v-for="(n, index) in meta"
:key="(index += 1)"
class="form__other-data"
>
<span class="form__other-title">
{{ n.title }}
</span>
<input
v-model="contact[n.name]"
:type="n.type"
:value="contact[n.name]"
:disabled="disabled"
/>
</div>
</form>
<div>
<button @click="edit">Edit</button>
<button @click="apply">Подтвердить</button>
<button @click="saveChanges">Сохранить</button>
</div>
<button v-if="this.history.length > 0" @click="undo">Кнопка назад</button>
<div>history: {{ history }}</div>
<br />
<br />
<div>temp: {{ temp }}</div>
<br />
<br />
<div>newData: {{ newData }}</div>
<br />
<br />
<div>contact: {{ contact }}</div>
</div>
</template>
<script>
export default {
props: ["contact"],
data() {
return {
oneStepMode: true, //режим для регулирования
onUndoMode: false, //режим возврата активирован
disabled: true, //режим disabled для input
initData: [], //массив для сохранения первоначальных данных
history: [], //массив истории действий
newData: [], //массив новых данных, в котором хранятся данные из объекта temp и которые будут передаваться в книгу контактов как конечный результат для текущего контакта
temp: {}, //объект для хранения данных введенных на каждой итерации до нажатия кнопки "Подтвердить изменения"
meta: [
{ name: "surname", title: "Фамилия", type: "text" },
{ name: "name", title: "Имя", type: "text" },
{ name: "secondName", title: "Отчество", type: "text" },
{ name: "phone", title: "Телефон", type: "text" },
{ name: "phone2", title: "Телефон", type: "text" },
{ name: "mail", title: "E-mail", type: "text" },
{ name: "address", title: "Адрес", type: "text" },
],
};
},
mounted() {
let key = document.querySelectorAll("input");
//при загрузке изначальные значения помещаем в промежуточный массив
for (let i = 0; i < key.length; i++) {
this.initData.push(key[i].value);
}
//преобразуем полученный массив в объект и помещаем первым в массив истории действий, для возможности отката к нему
this.history.push({ ...this.initData });
},
methods: {
apply() { //кнопка подтверждения изменений
if (!this.onUndoMode) {
let input = document.querySelectorAll("input");
for (let i = 0; i < this.meta.length; i++) { //длина массива meta взята, чтобы при откате изменений на начальные значения, не было undefined
this.temp[i] = input[i].value;
}
this.history.push(this.temp);
this.temp = {};
this.disabled = !this.disabled;
this.oneStepMode = false
}
},
//кнопка отката на предыдущий шаг (назад)
undo() {
let input = document.querySelectorAll("input");
let history = this.history;
let meta = this.meta;
let newData = this.newData;
let temp = this.temp;
let last;
if (history.length > 1) { //если длина history больше 1, то откатывать на предыдущий шаг, который записан в history
if (this.oneStepMode == false) { //этот блок для чтения предпоследнего элемента массива и вставить это значение в input
history.splice(history.length - 1, 1);
last = history.pop();
this.oneStepMode = true;
} else { //если history длина 1, то данные в input будут равны тем, что при загрузке страницы были
last = history.pop();
}
} else {
last = this.initData;
}
this.onUndoMode = true;
this.$nextTick(() => {
this.onUndoMode = false;
}, 0);
//считываем данные из массива history для отображения в input предыдущих введенных данных (предыдущий шаг)
for (let i = 0; i < meta.length; i++) {
temp[meta[i].name] = last[i];
newData = temp;
input[i].value = newData[meta[i].name];
this.contact[meta[i].name] = input[i].value;
}
},
//кнопка доступа в режим редактирования
edit() {
this.oneStepMode = true;
this.disabled = !this.disabled;
},
},
};
</script>