Я новичок в Vue и работаю с API композиции Vue 3. Я также использую Vuetify, поэтому код диалога скопирован из их примера. Надеюсь, я не усложнил это, смешав это со своим обучением. У меня есть основной список пользователей, в настоящее время заполненный массивом javascript. Идея представляет собой довольно распространенную настройку, в которой перечислены все пользователи в массиве, а ссылка пользователя открывает диалоговое окно для редактирования информации о пользователе. Также есть ссылка «Добавить пользователя», чтобы открыть диалоговое окно для добавления пользователя.
Пока что в моем коде я могу открыть диалоговое окно, когда я щелкаю имя. Я не могу заставить его открыться при нажатии на ссылку «Добавить пользователя». Оба они вызывают один и тот же метод, но ссылка «Добавить пользователя» просто передает значение null вместо значения пользователя. При нажатии на ссылку для пользователя, хотя диалоговое окно открывается, оно не устанавливает свойство пользователя для заполнения формы. Итак, у меня есть пара вопросов. Как открыть диалоговое окно по ссылке «Добавить пользователя» и как ввести пользователя по ссылке пользователя. Основной код ниже.
store.js
import { reactive } from 'vue'
class Store{
constructor() {
this.state = reactive({
users: [
{ id: 1, firstName: "John", lastName: "Smithers" },
{ id: 2, firstName: "Mary", lastName: "Smithers"}
],
currentUserId: null
})
}
addUser(){
this.state.currentUserId = null;
}
}
export const store = new Store()
UserList.vue
<script setup>
import { ref } from 'vue'
import {store} from '../services/store.js'
import UserForm from './UserForm.vue'
const userform = ref(null)
const openDialog = (user) => {
userform.user = user
userform.value.openDialog()
}
</script>
<template>
<table>
<thead>
<tr>
<th>Users</th>
</tr>
</thead>
<tbody>
<tr v-for = "user in store.state.users" :key = "user.id">
<td><a href = "javascript:;" @click = "openDialog(user)">{{ user.firstName }} {{ user.lastName }}</a></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan = "2" class = "text-center" style = "padding:20px 0">
<a href = "javascript:;" @onclick = "openDialog(null)">Add User</a>
<UserForm user = "null" ref = "userform"></UserForm>
</td>
</tr>
</tfoot>
</table>
</template>
UserForm.vue
<script setup>
import {ref} from 'vue'
const dialog = ref(false)
const save = () => {
console.info('saving')
}
const openDialog =() => {
dialog.value = true;
}
const props = defineProps({
user: {
type: Object,
required: true,
firstName: String,
lastName: String
},
openDialog: {
type: Boolean
}
})
const emits = defineEmits(['save'])
defineExpose({
openDialog
});
</script>
<template>
<form>
<v-row justify = "center">
<v-dialog
v-model = "dialog"
persistent
width = "1024"
>
<template v-slot:activator = "{ props }">
</template>
<v-card>
<v-card-title>
<span class = "text-h5">Add a User</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col cols = "12" lg = "4" sm = "4" xs = "12">
<v-text-field
label = "First name*"
required
v-model = "props.user.firstName"
></v-text-field>
</v-col>
<v-col cols = "12" lg = "4" sm = "4" xs = "12">
<v-text-field
label = "Middle name"
hint = "example of helper text only on focus"
></v-text-field>
</v-col>
<v-col cols = "12" lg = "4" sm = "4" xs = "12">
<v-text-field
label = "Last name"
hint = "example of helper text only on focus"
v-model = "props.user.lastName"
></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols = "12" lg = "6" sm = "6" xs = "12">
<v-text-field
label = "Email*"
required
></v-text-field>
</v-col>
<v-col cols = "12" lg = "6" sm = "6" xs = "12">
<v-text-field
label = "Password*"
type = "password"
required
></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col
cols = "12"
sm = "6"
>
<v-select
:items = "['0-17', '18-29', '30-54', '54+']"
label = "Age*"
required
></v-select>
</v-col>
<v-col
cols = "12"
sm = "6"
>
<v-autocomplete
:items = "['Skiing', 'Ice hockey', 'Soccer', 'Basketball', 'Hockey', 'Reading', 'Writing', 'Coding', 'Basejump']"
label = "Interests"
multiple
></v-autocomplete>
</v-col>
</v-row>
</v-container>
<small>*indicates required field</small>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color = "blue-darken-1"
variant = "text"
@click = "dialog = false"
>
Close
</v-btn>
<v-btn
class = "ma-2"
color = "primary"
@click = "save"
>
<v-icon
start
icon = "mdi-checkbox-marked-circle"
></v-icon>
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-row>
</form>
</template>





Я не уверен, что вы имеете в виду под этой строкой:
userform.user = user
так как userform является ref, и поэтому userform.user не анализирует для меня.
Одним из возможных решений является передача пустого фиктивного пользователя в диалоговый компонент, например,
const selectedUser = ref(null);
const dialog = ref(false);
const openDialog = (user) => {
if (user) {
selectedUser.value = user;
} else {
selectedUser.value = {
id: store.state.users.length + 1,
firstName: "",
lastName: ""
}
}
dialog.value = true;
}
Все это может выглядеть так:
<template>
<v-app>
<v-main>
<v-card width = "800" class = "ml-4 mt-4">
<v-card-title>
Users
</v-card-title>
<v-card-text>
<v-table class = "w-auto">
<thead>
<tr class = "bg-grey-lighten-3">
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody>
<tr v-for = "user in store.state.users" :key=user.id>
<td><a href = "#" @click.prevent = "openDialog(user)">{{ user.firstName }}</a></td>
<td><a href = "#" @click.prevent = "openDialog(user)">{{ user.lastName }}</a></td>
</tr>
</tbody>
</v-table>
</v-card-text>
</v-card>
<v-btn
rounded = "lg"
color = "primary"
class = "mt-4 ml-4"
@click = "openDialog(null)">Add User</v-btn>
<my-dialog v-model:dialog = "dialog" :user = "selectedUser" @save = "saveUser"/>
</v-main>
</v-app>
</template>
<script setup>
import { ref } from 'vue';
import {store} from './store.js'
import MyDialog from './MyDialog.vue';
const selectedUser = ref(null);
const dialog = ref(false);
const openDialog = (user) => {
if (user) {
selectedUser.value = user;
} else {
selectedUser.value = {
// get max user id and add 1
id: Math.max(...store.state.users.map(o => o.id)) + 1,
firstName: "",
lastName: ""
}
}
dialog.value = true;
}
const saveUser = (user) => {
let existingUser = store.state.users.find((u) => u.id === user.id);
if (existingUser) {
existingUser.lastName = user.lastName;
existingUser.firstName = user.firstName;
} else {
store.state.users.push(user);
}
}
</script>
<template>
<v-row justify = "center">
<v-dialog
:model-value = "dialog"
persistent
>
<v-card>
<v-card-title>
<span class = "text-h5">User Profile</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col
cols = "4"
>
<v-text-field
label = "Legal first name*"
v-model = "first"
@keyup.enter = "saveUser"
required
></v-text-field>
</v-col>
<v-col
cols = "4"
>
<v-text-field
label = "Legal last name*"
hint = "example of persistent helper text"
v-model = "last"
@keyup.enter = "saveUser"
persistent-hint
required
></v-text-field>
</v-col>
</v-row>
</v-container>
<small>*indicates required field</small>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color = "blue-darken-1"
variant = "text"
@click = "closeDialog"
>
Close
</v-btn>
<v-btn
color = "blue-darken-1"
variant = "text"
@click = "saveUser"
>
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-row>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue';
const props = defineProps(['user', 'dialog']);
const emit = defineEmits(['update:dialog', 'save']);
const first = ref("");
const last = ref("");
const closeDialog = () => {
emit("update:dialog", false);
}
const saveUser = () => {
let user = {
id: props.user.id,
firstName: first.value,
lastName: last.value,
}
emit("save", user);
emit("update:dialog", false);
}
watch(() => props.dialog,
(newValue) => {
if (newValue) {
first.value = props.user.firstName;
last.value = props.user.lastName;
}
});
</script>
import { reactive } from 'vue'
class Store{
constructor() {
this.state = reactive({
users: [
{ id: 1, firstName: "John", lastName: "Smithers" },
{ id: 2, firstName: "Mary", lastName: "Smithers"}
],
currentUserId: null
})
}
addUser(){
this.state.currentUserId = null;
}
}
export const store = new Store()
Код можно найти на Vuetify Playground
Опция - разрешить диалогу принимать нулевого пользователя и работать с ним.
Чтобы приведенный выше код работал с этим, я проверяю истинность props.user при открытии диалогового окна, когда props.dialog становится истинным:
watch(() => props.dialog,
(newValue) => {
if (newValue) {
if (props.user) {
first.value = props.user.firstName;
last.value = props.user.lastName;
} else {
first.value = "";
last.value = "";
}
}
});
Vuetify Playground для «нулевого» варианта
@geoffswartz: я уверен, что есть другие способы решить эту проблему, но это то, что я придумал. Обратите внимание на только что сделанные изменения.
@geoffswartz: Кроме того, приведенный выше код можно найти на игровой площадке Vuetify. Это то, что мне пришлось использовать, чтобы попытаться что-то придумать, так как я не использую Vuetify (до сих пор).
Спасибо. Теперь мне просто нужно проработать это и убедиться, что я понимаю, как это работает.