我是 Vue 的新手,正在使用 Vue 3 组合 api。我也在使用 Vuetify,所以对话框是从他们的示例中复制的代码。希望我没有通过将其混合到我的学习中而使它变得更复杂。我有一个当前由 javascript 数组填充的主要用户列表。这个想法是一个相当常见的设置,它列出数组中的每个用户,用户的链接打开一个对话框来编辑用户信息。还有一个添加用户链接可以打开添加用户的对话框。
在我的代码中,到目前为止,我可以在单击名称时打开对话框。单击“添加用户”链接时我无法打开它。它们都调用相同的方法,但添加用户链接只是将 null 传递给用户值。单击用户的链接时,虽然对话框打开,但它不会设置用户的属性来填充表单。所以,我有几个问题。如何从添加用户链接打开对话框,以及如何从用户链接填充用户。基本代码如下。
商店.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()
用户列表.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>
用户窗体.vue
<script setup>
import {ref} from 'vue'
const dialog = ref(false)
const save = () => {
console.log('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>
<table>
<thead>
<tr>
<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>
</table>
<v-btn
rounded="lg"
color="primary"
@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 = {
id: store.state.users.length + 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"
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"
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>