В моем приложении есть приличное количество форм, в которых пользователь может редактировать, возвращать или сохранять изменения объекта, которые в конечном итоге сохраняются в серверной части.
Очень похоже на это: (код найден в другом вопросе)
https://jsfiddle.net/k5j6zj9t/22/
var app = new Vue({
el: '#app',
data: {
isEditing: false,
user: {
firstName: 'John',
lastName: 'Smith',
}
},
mounted() {
this.cachedUser = Object.assign({}, this.user);
},
methods: {
save() {
this.cachedUser = Object.assign({}, this.user);
this.isEditing = false;
},
cancel() {
this.user = Object.assign({}, this.cachedUser);
this.isEditing = false;
}
}
})
Поскольку привязка v-model немедленно изменяет базовый объект, я должен сначала создать клон объекта. Также мне нужно сохранить элемент данных, находится ли объект в состоянии редактирования.
Умножьте этот код, чтобы получить больше форм и полей, и я получу слишком много членов данных и много шаблонного кода.
В серверных фреймворках, таких как django, модель находится во «временном состоянии» до тех пор, пока не будет сохранена, поэтому я могу редактировать вот так
user.first_name = 'aa' # temporary object in memory
user.save() # saved to the db
Мой вопрос, есть ли компонент / шаблон модели для vue, чтобы лучше справиться с этой задачей?
Что-то, что будет содержать состояние модели, например, isEditing, автоматически клонировать объект для редактирования формы, отменить изменения и т. д.
Значит, мне не придется писать такой код для такого количества объектов?
@Brissy Можете уточнить? Я ищу часами и не нашел решения
Решает ли это вашу проблему?
Не совсем, у меня есть экземпляр vue, привязанный к нескольким формам.
И почему мы не можем переместить каждую форму в отдельный компонент и расширить его с помощью миксина? Боюсь, потому что все у вас разные формы, вы не можете их объединить :(
Я хочу создать компонент формы. но как я могу передать объект компоненту формы, чтобы он обрабатывал клонирование объекта и установку v моделей? Вот как я думал, что это должно быть сделано, но я не могу придумать реализацию
Существует простой компонент формы для объектов только строковых полей jsfiddle, вам нужно что-то вроде этого? Или вы хотите встроить редактировать объекты без модальных окон / всплывающих окон?




Использование Слоты с ограниченным доступом может соответствовать вашим требованиям.
Мое решение:
Создайте один компонент с одним слотом
Затем этот слот свяжет значения с clonedValues (если closeMode ложно, clondedValues = values)
наконец, в родительском компоненте сгенерируйте свой шаблон со свойствами слота с заданной областью действия, а затем передайте его в слот.
Как показано ниже, демо:
Vue.component('child', {
template: `
<div>
<div>
<slot v-bind:values = "clonedValues"></slot>
</div>
<p>
<button @click = "saveAction(clonedValues)">Save</button>
<button @click = "resetAction()">Reset</button>
</p>
</div>`,
props: {
'cloneMode': {
type: Boolean,
default: true
},
'values': {
type: Object,
default: () => { return new Object() }
},
'saveAction': {
type: Function,
default: function (newValues) {
this.$emit('save', newValues)
}
},
'resetAction': {
type: Function,
default: function () {
this.syncValues(this.values)
}
}
},
data() {
return {
clonedValues: {}
}
},
created: function () {
this.syncValues(this.values)
},
watch: {
values: {
handler: function (newVal) {
this.syncValues(newVal)
},
deep: true
},
cloneMode: function () {
this.syncValues(this.values)
}
},
methods: {
syncValues: function (newVal) {
this.clonedValues = this.cloneMode ? Object.assign({}, newVal) : newVal // if you'd like to support nested object, you have to deep clone
}
}
})
Vue.config.productionTip = false
app = new Vue({
el: "#app",
data: {
mode: true,
labels: ['id', 'name'],
childForm: {
'id': 1,
'name': 'test'
}
},
methods: {
saveForm: function (ev) {
Object.keys(this.childForm).forEach((item) => {
this.childForm[item] = ev[item]
})
// call backend to update the data
},
changeCurrentValue: function () {
this.childForm.id += '#'
this.childForm.name += '@'
}
}
})<script src = "https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id = "app">
<p><button @click = "mode=!mode">Mode: {{mode}}</button></p>
<p>Current: {{childForm}} --<button @click = "changeCurrentValue()">Change Current</button></p>
<child :values = "childForm" @save = "saveForm($event)" :clone-mode = "mode">
<template slot-scope = "slotProps">
<p>ID: <input v-model = "slotProps.values['id']"/></p>
<p>Name: <input v-model = "slotProps.values['name']"/></p>
</template>
</child>
</div>Запрошено изменение для OP:
измените слот по умолчанию на именованный slot = редактировать, затем создайте один слот = Посмотреть
добавлено свойство данных = редактирование, если true, показать слот «Edit», если false, показать слот «View».
в родительском компоненте создайте шаблон для slot = Посмотреть.
Как показано ниже, демо:
Vue.component('child', {
template: `
<div>
<div v-show = "editing">
<slot name = "edit" v-bind:values = "clonedValues"></slot>
<button @click = "saveForm(clonedValues)">Save</button>
<button @click = "resetAction()">Reset</button>
</div>
<div v-show = "!editing">
<slot name = "view"></slot>
<button @click = "editing = true">Edit</button>
</div>
</div>`,
props: {
'values': {
type: Object,
default: () => { return new Object() }
},
'saveAction': {
type: Function,
default: function (newValues) {
this.$emit('save', newValues)
}
},
'resetAction': {
type: Function,
default: function () {
this.syncValues(this.values)
}
}
},
data() {
return {
editing: false,
clonedValues: {}
}
},
created: function () {
this.syncValues(this.values)
},
watch: {
editing: function (newVal) {
if (newVal) this.syncValues(this.values)
},
values: {
handler: function (newVal) {
if (this.editing) this.syncValues(newVal) //comment out this if don't want to sync latest props=values
},
deep:true
}
},
methods: {
syncValues: function (newVal) {
this.clonedValues = Object.assign({}, newVal) // if you'd like to support nested object, you have to deep clone
},
saveForm: function (values) {
this.saveAction(values)
this.editing = false
}
}
})
Vue.config.productionTip = false
app = new Vue({
el: "#app",
data: {
childForm: {
'id': 1,
'name': 'test'
}
},
methods: {
saveForm: function (ev) {
Object.keys(this.childForm).forEach((item) => {
this.childForm[item] = ev[item]
})
// call backend to update the data
},
changeCurrentValue: function () {
this.childForm.id += '#'
this.childForm.name += '@'
}
}
})<script src = "https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id = "app">
<p>Current: {{childForm}} --<button @click = "changeCurrentValue()">Change Current</button></p>
<child :values = "childForm" @save = "saveForm($event)">
<template slot-scope = "slotProps" slot = "edit">
<h3>---Edit---</h3>
<p>ID: <input v-model = "slotProps.values['id']"/></p>
<p>Name: <input v-model = "slotProps.values['name']"/></p>
</template>
<template slot = "view">
<h3>---View---</h3>
<p>ID: <span>{{childForm['id']}}</span></p>
<p>Name: <span>{{childForm['name']}}</span></p>
</template>
</child>
</div>Спасибо. Возможно ли иметь слот-область на корневом компонентном элементе (<form>)? вместо обертки div. Кроме того, является ли срезанная область видимости единственным способом для компонента экспортировать методы? И я не вижу здесь опции редактирования, я думал, что клонирую объект только при редактировании, а не при инициализации, возможно ли реализовать это в этом компоненте? Также мне не нужен cloneMode, мне всегда нужно клонировать при редактировании
@ user3599803 обновил ответ (добавлено свойство данных = редактирование). Отвечая на ваш первый вопрос, вы имеете в виду изменить корневой элемент дочернего компонента с div на form?
Я собираюсь изменить корневой элемент на form, я имею в виду, можно ли пропустить элемент <template>, что кажется несколько странным. Таким образом, область видимости слота будет привязана к компоненту корневого элемента (<child>). Несмотря на то, что это решение выполняет свою работу, я думаю, можно ли его реализовать без слота с заданной областью действия, возможно, с миксином, который выполняет клонирование и добавляет логическое значение редактирования. Я буду признателен за любые указатели здесь
Я бы использовал для этого миксин. Таким образом, вы сможете написать всего 1 миксин и использовать его везде, где у вас есть такие формы.