我使用的是 [email protected]
和 [email protected]
我有一个名为 index.vue
和一个子组件来列出所有客户。customerModal.vue
以控制 v-modal
对于 Edit
和 Create
Cusotmer形式。
我使用的是 v-table
用按钮动作列出客户的详细信息
<!-- {{-- CREATE CUSTOMER --}} -->
<b-button @click="$root.$emit('bv::show::modal', 'customerModal' , $event.target)" variant="success" title="Create New Customer">
<i class="fas fa-plus-circle" id="action-icon" style="right:3%"></i>
</b-button>
<!-- Modal Customer -->
<customer-modal :customers="customers" modalType="create" @create-customer="customers.push($event)"></customer-modal>
<b-table
show-empty
:filter="filter"
@filtered="on_filtered"
id="customers-table"
:sort-by.sync="sort_by"
:sort-desc.sync="sort_desc"
:items="customers"
:fields="fields"
:per-page="per_page"
:current-page="current_page"
responsive
hover
head-variant="light"
class="text-center mt-4"
>
<template v-slot:cell(actions)="data">
<div class="btn-group" role="group">
<!-- {{-- EDIT CUSTOMER --}} -->
<b-button @click="$root.$emit('bv::show::modal', data.item.first_name.replace(/\s/g, '')+data.item.id, $event.target)" variant="primary" title="Edit Customer">
<i class="fas fa-edit"></i>
</b-button>
<!-- Customer Modal-->
<customer-modal modalType="edit" :selectedCustomer="data.item" :customers="customers" @update-customer="data.item = $event"></customer-modal>
</div>
</template>
<b-pagination
class=" m-auto justify-content-center"
pills
:per-page="per_page"
:total-rows="rows"
v-model="current_page"
aria-controls="#customers-table"
>
</b-pagination>
<b-modal
:id="this.customer.first_name.replace(/\s/g, '')+this.customer.id || 'customerModal'"
title="Customer Modal"
@hidden="resetModal"
hide-footer
>
当我使用 b-pagination
btn edit
不显示相应的v-modal。而在第一页中,所有的 edit
每个客户的btns都能正常工作。
问题是Vue试图在第1页重用你的模式,以节省重新渲染的费用。
问题的根源是在模态组件中,你设置了 this.customer
到 this.selectedCustomer
在 create
钩,而不是其他地方。由于 create
在第2页又不运行了,它不会更新了 this.customer
意味着ID仍然会与第1页的行相匹配。
从长远来看,你可能需要重新考虑这个逻辑。
但是你应该可以通过添加以下内容来解决这个问题。:key="data.item.id"
至 customer-modal
的时候,迫使Vue重新渲染模式。id
更新。所以它不能尝试在各个页面中重用模式。
<customer-modal modalType="edit" :selectedCustomer="data.item" :customers="customers" @update-customer="data.item = $event" :key="data.item.id"></customer-modal>
工作片段(基于这个网站的codepen) Github问题.
Vue.use(window.vuelidate.default);
const { required, email, numeric, minLength, maxLength } = window.validators;
let OMDModal = {
props: ["selectedCustomer", "modalType", "customers"],
template: '#customer-modal',
validations: {
customer: {
first_name: {
required,
minLen: minLength(3),
maxLen: maxLength(12)
},
last_name: {
required,
minLen: minLength(3),
maxLen: maxLength(12)
},
email: {
required,
email,
isUnique: function (val) {
if (val === "") return true;
else if (val === this.currentEmail) return true;
return axios.get(`api/validateEmail/${val}`).then((res) => {
return res.data.unique;
});
}
}
}
},
data() {
return {
currentEmail: "",
alert_sec: 0,
alert_duration: 5,
alert_message: "",
alert_color: "",
customer: {
id: "",
first_name: "",
last_name: "",
email: ""
},
customer_default: {
first_name: [],
last_name: [],
email: []
}
};
},
watch: {
"customer.first_name"(newVal, oldVal) {
if (this.modalType === "edit") {
this.customer_default.first_name.push(oldVal);
}
},
"customer.last_name"(newVal, oldVal) {
if (this.modalType === "edit") {
this.customer_default.last_name.push(oldVal);
}
},
"customer.email"(newVal, oldVal) {
if (this.modalType === "edit") {
this.customer_default.email.push(oldVal);
}
}
},
computed: {
ModalID() {
if (this.modalType === "create") {
return "customerModal";
} else {
return this.customer.first_name.replace(/\s/g, "") + this.customer.id;
}
},
now() {
const monthNames = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
const today = new Date();
let day = today.getDate().toString();
let month = (today.getMonth() + 1).toString();
let year = today.getFullYear().toString();
return year + "-" + month + "-" + day;
},
first_nameValidate() {
if (this.$v.customer.first_name.$dirty) {
return !this.$v.customer.first_name.$anyError;
} else return null;
},
last_nameValidate() {
if (this.$v.customer.last_name.$dirty) {
return !this.$v.customer.last_name.$anyError;
} else return null;
},
emailValidate() {
if (this.$v.customer.email.$dirty) {
return !this.$v.customer.email.$anyError;
} else return null;
}
},
methods: {
setFirstName(e) {
this.customer.first_name = e;
this.$v.customer.first_name.$touch();
},
setLastName(e) {
this.customer.last_name = e;
this.$v.customer.last_name.$touch();
},
setEmail(e) {
this.customer.email = e;
this.$v.customer.email.$touch();
},
resetModal() {
this.$nextTick(() => {
this.$v.$reset();
});
if (this.modalType === "create") {
this.customer = {
id: "",
first_name: "",
last_name: "",
email: ""
};
}
if (this.alert_color != "success") {
if (this.customer_default.first_name[1] != undefined) {
this.customer.first_name = this.customer_default.first_name[1];
}
if (this.customer_default.last_name[1] != undefined) {
this.customer.last_name = this.customer_default.last_name[1];
}
if (this.customer_default.email[1] != undefined) {
this.customer.email = this.customer_default.email[1];
}
}
},
onSubmit(v, e) {
v.customer.$touch();
if (this.$v.customer.$anyError) {
this.alert_message = "Correct the inputs Please";
this.alert_color = "danger";
this.show_alert();
} else {
this.customer.first_name =
this.customer.first_name.charAt(0).toUpperCase() +
this.customer.first_name.slice(1);
// CREATE CUSTOMER
if (this.modalType === "create") {
this.customer.created_at = this.now;
let last_index = this.customers.length - 1;
let last_customer = this.customers[last_index];
this.customer.id = last_customer.id + 1;
fetch(`api/customers`, {
method: "POST",
body: JSON.stringify(this.customer),
headers: { "content-type": "application/json" }
})
.then((res) => res.json())
.then((res) => {
this.$nextTick(() => {
this.$v.$reset();
});
this.$bvModal.hide(
this.customer.first_name.replace(/\s/g, "") +
this.customer.id || "customerModal"
);
this.$emit("create-customer", this.customer);
this.customer = {
id: "",
first_name: "",
last_name: "",
email: ""
};
})
.catch((e) => console.log(e));
} else {
// UPDATE CUSTOMER
this.customer.updated_at = this.now;
fetch(`api/customers/${this.customer.id}`, {
method: "put",
body: JSON.stringify(this.customer),
headers: {
"content-type": "application/json"
}
})
.then((res) => res.json())
.then((data) => {
this.$nextTick(() => {
this.$v.$reset();
this.$bvModal.hide(
this.customer.first_name.replace(/\s/g, "") +
this.customer.id || "customerModal"
);
});
this.$emit("update-customer", this.selectedCustomer);
this.alert_color = "success";
this.alert_message = "Customer Updated Successfully";
})
.catch((error) => console.log(error));
}
}
},
show_alert() {
this.alert_sec = this.alert_duration;
},
countDown(alert_sec) {
this.alert_sec = alert_sec;
}
},
created() {
if (this.modalType === "edit") {
this.customer = this.selectedCustomer;
this.currentEmail = this.selectedCustomer.email;
}
}
};
window.onload = () => {
new Vue({
el: "#app",
data() {
return {
per_page: 3,
current_page: 1,
fields: [
{ key: "#", sortable: false },
{ key: "id", sortable: true },
{ key: "first_name", label: "Name", sortable: true, class: "w-25" },
{ key: "email", sortable: true },
{ key: "actions", sortable: false }
],
sort_by: "email",
sort_desc: false,
filter: null,
filter_on: [],
customers: [],
customer: {
id: "",
first_name: "",
last_name: "",
email: ""
}
};
},
computed: {
now() {
const monthNames = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
const today = new Date();
let day = today.getDate().toString();
let month = (today.getMonth() + 1).toString();
let year = today.getFullYear().toString();
return year + "-" + month + "-" + day;
},
rows() {
return this.customers.length;
}
},
methods: {
fetchCustomers() {
fetch("https://reqres.in/api/users")
.then((res) => res.json())
.then((res) => {
this.customers = res.data;
})
.catch((err) => console.log(err));
},
on_filtered(filtered_items) {
this.rows;
},
openModal(id) {
this.$root.$emit('bv::show::modal', id)
}
},
created() {
this.fetchCustomers();
},
components: {
"omd-modal": OMDModal
}
});
};
<link href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/[email protected]/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/[email protected]/dist/bootstrap-vue.js"></script>
<div id="app">
<div class="card">
<div class="card-body">
<!-- Card Header (Title & Create btn) -->
<div class="row ">
<div class="col-sm-4">
<h4 class="card-title font-weight-bold">
User Management
</h4>
</div>
<div class="col-sm-4 offset-sm-4">
<div class="btn-toolbar float-right">
<!-- {{-- CREATE CUSTOMER --}} -->
<b-button @click="$root.$emit('bv::show::modal', 'customerModal', $event.target)" variant="success" title="Create New Customer">
CREATE
</b-button>
</div>
</div>
</div>
<!-- Modal Customer Create -->
<omd-modal :customers="customers" modal-type="create" @create-customer="customers.push($event)"></omd-modal>
<!-- Search Bar -->
<div class="row">
<div class="col-12">
<b-input-group class="w-50 m-auto">
<b-form-input placeholder="Search for Customers" v-model="filter" class="rounded-pill searchbar">
</b-form-input>
</b-input-group>
</div>
</div>
<!-- Customer List (Card Content) -->
<div class="row ">
<div class="col">
<b-table ref="table" :key="customer.id" show-empty :filter="filter" @filtered="on_filtered" id="customers-table" :sort-by.sync="sort_by" :sort-desc.sync="sort_desc" :items="customers" :fields="fields" :per-page="per_page" :current-page="current_page" responsive hover head-variant="light" class="text-center mt-4">
<template v-slot:cell(#)="data">
{{data.index+1}}
</template>
<template v-slot:cell(first_name)="data">
{{data.item.first_name}} {{data.item.last_name}}
</template>
<template v-slot:cell(actions)="data">
<div class="btn-group" role="group">
<!-- {{-- EDIT CUSTOMER --}} -->
<b-button @click="$root.$emit('bv::show::modal', data.item.first_name.replace(/\s/g, '')+data.item.id)" variant="primary" title="Edit Customer">
Edit
</b-button>
</div>
<!--Edit Customer Modal-->
<omd-modal modal-type="edit" :selected-customer="data.item" :customers="customers" @update-customer="data.item = $event" :key="data.item.id"></omd-modal>
</template>
</b-table>
</div>
</div>
<hr>
<!-- {{-- Card Footer --}} -->
<div class="row">
<div class="col-sm-4">
<small class="text-muted"> Total Customers {{rows}} </small>
</div>
<div class="col-sm-4">
<b-pagination class=" m-auto justify-content-center" pills :per-page="per_page" :total-rows="rows" v-model="current_page" aria-controls="#customers-table">
</b-pagination>
</div>
</div>
</div>
</div>
</div>
<template id="customer-modal">
<b-modal :id="customer.first_name.replace(/\s/g, '')+customer.id || 'customerModal'" title="Customer Modal" @hidden="resetModal" hide-footer>
<b-alert id="alert" style="width: 100%;" :show="alert_sec" dismissible :variant="alert_color" @dismissed="alert_sec=0" @dismiss-count-down="countDown">
{{alert_message}}
</b-alert>
<b-form @submit.prevent="onSubmit($v, $event)">
<!-- first_name -->
<b-form-group id="first-name-group" label="First Name" label-for="first-name">
<b-form-input id="first-name" type="text" :value="customer.first_name" :state="first_nameValidate" @change="setFirstName($event)" required></b-form-input>
<b-form-invalid-feedback :state="first_nameValidate">First Name is required and must be 3-5 character long.</b-form-invalid-feedback>
</b-form-group>
<!-- Last_name -->
<b-form-group id="last-name-group" label="Last Name" label-for="last-name">
<b-form-input id="last_name" :value="customer.last_name" :state="last_nameValidate" @change="setLastName($event)" type="text" required>
</b-form-input>
<b-form-invalid-feedback :state="last_nameValidate">Last Name is required and must be 3-5 character long.</b-form-invalid-feedback>
</b-form-group>
<!-- Email -->
<b-form-group id="email-group" label="Email" label-for="email">
<b-form-input id="email" :state="emailValidate" :value="customer.email" @change="setEmail($event)" type="email" required>
</b-form-input>
<b-form-invalid-feedback :state="emailValidate">Invalid Email.</b-form-invalid-feedback>
</b-form-group>
<hr style="margin-top: 2rem; margin-bottom: 1rem;">
<div class="row justify-content-center">
<b-button variant="success" class="mr-1" type="submit">Save Changes</b-button>
<b-button variant="danger" class="ml-1" @click="$bvModal.hide(customer.first_name.replace(/\s/g, '')+customer.id || 'customerModal')">Cancel</b-button>
</div>
</b-form>
</b-modal>
</template>
<script src="https://unpkg.com/[email protected]/dist/validators.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vuelidate.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>