Vue3+TS+Vant3——增删改input和通过双页面进行增删改操作
两种方案:
-
第一种点击添加按钮添加一项,缺点:页面过于臃肿,用户体验较差
-
第二种:分成两种页面进行添加等操作
先说一下第一种,我这里用到了vant3Ui组件库
直接上代码:
<!-- aaa -->
<template>
<van-sticky>
<header-slot>
<template #denglu>
<van-nav-bar title="aaa" left-arrow @click-left="()=>{router.back();}">
</van-nav-bar>
</template>
</header-slot>
</van-sticky>
<van-form @submit="onSubmit">
<van-cell-group inset>
<div v-for="(item,index) in formData.arr" :key="index" class="box1">
<div class="borders"></div>
<van-button type="danger" v-if="index!=0" size="mini" class="delete" @click="deleteRow(index)">删除</van-button>
<div class="">
<van-field v-model="item.aaa" :name="'aaa'+index" placeholder="aaa" />
<van-field v-model="item.bbb" :name="'bbb'+index" placeholder="bbb" />
<van-field v-model="item.ccc" :name="'ccc'+index" placeholder="ccc" />
</div>
</div>
<div class="borders"></div>
<van-button type="primary" size="small" class="button" @click="butclick2">添加一项</van-button>
<div style="margin: 16px;" class="submit">
<van-button round block type="primary" native-type="submit" color="#FCD39F" :loading="status.submit">
提交
</van-button>
</div>
</van-form>
</template>
<script lang='ts' setup>
import { ref, onMounted, reactive, toRefs, computed } from "vue";
import { useRouter } from "vue-router";
import { Notify, Toast, Button } from 'vant';
const defaultData = {
arr: [
{
appellation: "",
getName: "",
workplace: "",
office_code: "",
},
],
count: 0,
};
const butclick = () => {
let obj={
appellation: "",
getName: "",
workplace: "",
office_code: "",
}
formData.value.arr.push(obj);
/* 方法二 */
/* let arrs: any = [];
arrs.push({
appellation: "",
getName: "",
workplace: "",
office_code: "",
});
formData.value.arr.push(arrs);
console.log(formData.value);
formData.value.count++;
console.log(formData.value.count); */
};
/* 删除 */
const deleteRow = (index: any) => {
console.log(index);
formData.value.arr.splice(index, 1);
};
const onConfirm = (value: any) => {
formData.value.highest = value;
showPicker.value = false;
};
const formData = ref<typeof defaultData>(Object.assign({}, defaultData));
const status = reactive({
loading: true,
submit: false,
});
onMounted(() => {
let sub: any = window.localStorage.getItem("onSubmit");
if (sub !== null) {
console.log( formData.value.explain=JSON.parse(sub).explain);
console.log( formData.value.arr=JSON.parse(sub).arr);
}
});
const onSubmit = (values: any) => {
console.log("submit", values = formData.value);
window.localStorage.setItem("onSubmit", JSON.stringify(values));
};
const router = useRouter();
</script>
<style scoped lang='less'>
</style>
新增节点
const butclick = () => {
let obj={
appellation: "",
getName: "",
workplace: "",
office_code: "",
}
formData.value.arr.push(obj);
/* 方法二 */
/* let arrs: any = [];
arrs.push({
appellation: "",
getName: "",
workplace: "",
office_code: "",
});
formData.value.arr.push(arrs);
console.log(formData.value);
formData.value.count++;
console.log(formData.value.count); */
};
其中obj里的对象名称要跟reactive中创建这个的数组里的名称一样
Vue3是通过v-model生成新的节点,无需用克隆节点生成新的Dom
这里因为不需要进入页面,所以直接引入接口就可以了,无需写编辑事件
删除:获取对应选中的div盒子,之后对盒子进行删除操作
const deleteRow = (index: any) => {
console.log(index);
formData.value.arr.splice(index, 1);
};
第二种方法
<!-- 教育背景 -->
<template>
<van-sticky>
<header-slot>
<template #denglu>
<van-nav-bar title="教育背景" left-arrow @click-left="()=>{router.back();}">
</van-nav-bar>
</template>
</header-slot>
</van-sticky>
<van-form @submit="onSubmit" input-align="right">
<van-cell-group inset>
<h1>教育背景(高中起填)</h1>
<van-cell-group>
<div v-if="jiaoyu instanceof Array || formData.educational.length ==0">
<van-cell value="尚未填写" />
</div>
<div v-if="jiaoyu.educational">
<!-- formData.educational -->
<div v-for="(item,index) in jiaoyu.educational" :key="index">
<van-swipe-cell>
<van-cell :title="item.school" @click="editoriaClick(index)" is-link :value="item.time" :label="item.major" />
<template #right>
<van-button square type="danger" text="删除" @click="delectClick(index)" />
</template>
</van-swipe-cell>
</div>
</div>
</van-cell-group>
<!-- <van-divider :style="{ color: '#B0A8B9', borderColor: '#B0A8B9'}"/> -->
<van-button type="primary" size="small" class="button" @click="btbclickAdd()">{{jiaoyu instanceof Array?'点我进行添加':'添加'}}</van-button>
<van-divider :style="{ color: '#B0A8B9', borderColor: '#B0A8B9'}" />
<!-- 最高学历绩点 -->
<van-field v-model="formData.harp" name="harp" label="最高学历绩点" placeholder="最高学历绩点" />
<!-- 成绩排名 -->
<van-field v-model="formData.classRank" is-link readonly name="classRank" label="成绩排名" placeholder="点击选择成绩排名" @click="status.showPicker3 = true;" />
<van-popup v-model:show="status.showPicker3" position="bottom">
<van-picker :columns="columns3" @confirm="onConfirm4" @cancel="status.showPicker3 = false" />
</van-popup>
<!-- 证明人/联系方式 -->
<van-field v-model="formData.references" name="references" label="证明人/联系方式" placeholder="证明人/联系方式" />
<!-- 次高学历绩点 -->
<van-divider :style="{ color: '#B0A8B9', borderColor: '#B0A8B9'}" />
<!-- 次高学历绩点 -->
<van-field v-model="formData.mostHarp" name="mostHarp" label="次高学历绩点" placeholder="次高学历绩点" />
<!-- 成绩排名 -->
<van-field v-model="formData.mostClassRank" is-link readonly name="mostClassRank" label="成绩排名" placeholder="点击选择成绩排名" @click="status.showPicker4 = true;" />
<van-popup v-model:show="status.showPicker4" position="bottom">
<van-picker :columns="columns4" @confirm="onConfirm5" @cancel="status.showPicker4 = false" />
</van-popup>
<!-- 证明人/联系方式 -->
<van-field v-model="formData.mostReferences" name="mostReferences" label="证明人/联系方式" placeholder="证明人/联系方式" />
</van-cell-group>
<div style="margin: 16px;" class="submit">
<van-button round block type="primary" color="#FCD39F" native-type="submit">
提交
</van-button>
</div>
</van-form>
</template>
<script lang='ts' setup>
import { ref, onMounted, reactive, toRefs, computed } from "vue";
import { useRouter } from "vue-router";
import { Notify, Toast } from "vant";
import { type } from "os";
import path from "path/posix";
const defaultData = {
educational: [],
// 最高学历绩点
harp: "",
// 最高成绩排名
classRank: "",
// 最高证明人/联系方式
references: "",
// 次高学历绩点
mostHarp: "",
// 次高成绩排名
mostClassRank: "",
// 次高证明人/联系方式
mostReferences: "",
};
const currIndex = ref("0");
const num = ref(0);
const num2 = ref(0);
const num3 = ref(0);
const columns = ["高中", "大专", "本科", "硕士", "博士"];
const columns2 = ["全日制", "非全日制"];
const columns3 = ["前10%", "前30%", "平均水平", "平均水平以下"];
const columns4 = ["前10%", "前30%", "平均水平", "平均水平以下"];
const formData = ref<typeof defaultData>(Object.assign({}, defaultData));
const status = reactive({
loading: true,
submit: false,
showCalendar: false,
showPicker: false,
showPicker2: false,
showPicker3: false,
showPicker4: false,
});
/* 自定义区间 */
/* 成绩排名 */
const onConfirm4 = (value: any) => {
formData.value.classRank = value;
status.showPicker3 = false;
};
const onConfirm5 = (value: any) => {
formData.value.mostClassRank = value;
status.showPicker4 = false;
};
const propertiesClick = (index: any) => {
status.showPicker2 = true;
num3.value = index;
};
if (window.localStorage.getItem("jiaoyubeijing") != null) {
}
// @ts-ignore
let jiaoyu: any =
// @ts-ignore
JSON.parse(window.localStorage.getItem("jiaoyubeijing")) || [];
onMounted(() => {
console.log("jiaoyu", jiaoyu);
if (jiaoyu instanceof Array) {
console.log("我现在是个数组");
console.log(jiaoyu instanceof Array);
jiaoyu = formData.value;
window.localStorage.setItem("jiaoyubeijing", JSON.stringify(jiaoyu));
} else {
formData.value = jiaoyu;
console.log(formData.value);
}
/* let tem = formData.value as any;
for (let i in formData.value) {
if (res.data[i]) {
tem[i] = res.data[i];
}
}
formData.value = tem; */
});
// 编辑
const editoriaClick = (index: any) => {
// console.log( jiaoyu.educational[index]);
window.localStorage.setItem(
"indexValue",
JSON.stringify(jiaoyu.educational[index])
);
router.push({
path: "/index/Education/Educational",
query: { str: "编辑", index: index },
});
};
/* 删除 */
const delectClick = (index: any) => {
// jiaoyu.educational.splice(index, 1);
console.log(index);
console.log(formData.value.educational.splice(index, 1));
window.localStorage.setItem("jiaoyubeijing", JSON.stringify(jiaoyu));
console.log(formData.value);
};
/* 添加 */
const btbclickAdd = () => {
router.push({ path: "/index/Education/Educational", query: { str: "添加" } });
};
const deleteRow = (index: any) => {
formData.value.educational.splice(index, 1);
};
const onSubmit = (values: any) => {
values = formData.value;
console.log(values);
window.localStorage.setItem("jiaoyubeijing", JSON.stringify(values));
};
const router = useRouter();
</script>
<style scoped lang='less'>
.box1 {
position: relative;
}
:deep(.van-nav-bar) {
background-color: #fef0e3;
}
.submit :deep(.van-button__text) {
color: #7c4e36;
}
.button {
display: block;
// text-align: center;
// line-height: 26px;
background: #f60;
border: #f60;
color: #fff;
margin: 10px auto;
cursor: pointer;
font-size: 12px;
border-radius: 13px;
}
h1 {
font-size: 16px;
padding: 10px;
}
.borders {
width: 100%;
height: 1px;
transform: scaleY(0.5);
transform-origin: 50% 100%;
background: #000;
margin-top: -1px;
}
.delete {
position: absolute;
top: 0;
right: 0;
z-index: 2;
}
</style>
下面是详情页
<template>
<van-sticky>
<header-slot>
<template #denglu>
<van-nav-bar title="教育背景详情" left-arrow @click-left='()=>{router.back();}'></van-nav-bar>
</template>
</header-slot>
</van-sticky>
<van-form @submit="onSubmit" input-align="right">
<van-cell-group inset>
<van-divider :style="{ borderColor: '#B0A8B9'}" content-position="left">教育背景(高中起填)</van-divider>
<div class="box1" v-for="(item,index) in formData.educational" :key="index">
<!-- 时间 -->
<van-field v-model="item.time" is-link readonly name="time" label="时间" placeholder="点击选择日期" @click="times(index)" />
<van-calendar color="#1989fa" v-model:show="status.showCalendar" type="range" @confirm="onConfirm" />
<!-- 学历 -->
<van-field v-model="item.education" is-link readonly name="education" label="学历" placeholder="点击选择学历" @click="educationClick(index)" />
<van-popup v-model:show="status.showPicker" position="bottom">
<van-picker :columns="columns" @confirm="onConfirm2" :default-index="0" @cancel="status.showPicker = false" />
</van-popup>
<!-- 教学性质 -->
<van-field v-model="item.properties" is-link readonly name="properties" label="教育性质" placeholder="点击选择教育性质" @click="propertiesClick(index)" />
<van-popup v-model:show="status.showPicker2" position="bottom">
<van-picker :columns="columns2" @confirm="onConfirm3" :default-index="0" @cancel="status.showPicker2 = false" />
</van-popup>
<!-- 导师 -->
<van-field v-model="item.tutor" name="tutor" label="导师" placeholder="导师" />
<!-- 学校 -->
<van-field v-model="item.school" name="school" label="学校" placeholder="学校" />
<!-- 专业 -->
<van-field v-model="item.major" name="major" label="专业" placeholder="专业" />
</div>
</van-cell-group>
<div style="margin: 16px;" class="submit">
<van-button round block type="primary" color="#FCD39F" native-type="submit">
{{route.query.str == '编辑'?'编辑':"保存"}}
</van-button>
</div>
<div style="margin: 16px;" class="submit">
<van-button round block type="primary" color="#EC002B" @click="delectClick">
清空所有内容
</van-button>
</div>
</van-form>
</template>
<script lang='ts' setup>
import { ref, onMounted, reactive } from "vue";
import { useRouter, useRoute } from "vue-router";
import { Notify, Toast } from "vant";
const defaultData = {
educational: [
{
// 时间
time: "",
// 学历
education: "",
// 教学性质
properties: "",
// 导师
tutor: "",
// 学校
school: "",
// 专业
major: "",
},
],
// 最高学历绩点
harp: "",
// 最高成绩排名
classRank: "",
// 最高证明人/联系方式
references: "",
// 次高学历绩点
mostHarp: "",
// 次高成绩排名
mostClassRank: "",
// 次高证明人/联系方式
mostReferences: "",
};
const formData = ref<typeof defaultData>(Object.assign({}, defaultData));
const columns = ["高中", "大专", "本科", "硕士", "博士"];
const columns2 = ["全日制", "非全日制"];
const status = reactive({
loading: true,
submit: false,
showCalendar: false,
showPicker: false,
showPicker2: false,
showPicker3: false,
showPicker4: false,
});
const num = ref(0);
const num2 = ref(0);
const num3 = ref(0);
/* 自定义区间 */
const formatDate = (date: any) =>
`${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
/* 调用方法 */
const onConfirm = (date: any) => {
const [start, end] = date;
status.showCalendar = false;
formData.value.educational[num.value].time = `${formatDate(
start
)} - ${formatDate(end)}`;
console.log(date);
};
/* 时间 */
const times = (index: any) => {
status.showCalendar = true;
console.log(index);
num.value = index;
};
/* 学历 */
const onConfirm2 = (value: any) => {
formData.value.educational[num2.value].education = value;
status.showPicker = false;
};
/* 学历 */
const educationClick = (index: any) => {
status.showPicker = true;
console.log(index);
num2.value = index;
};
/* 教学性质 */
const onConfirm3 = (value: any) => {
formData.value.educational[num3.value].properties = value;
status.showPicker2 = false;
};
const propertiesClick = (index: any) => {
status.showPicker2 = true;
num3.value = index;
};
/* const btbclickAdd = () => {
let obj = {
time: "",
education: "",
properties: "",
tutor: "",
school: "",
major: "",
};
formData.value.educational.push(obj);
console.log(formData.value.educational);
}; */
let jybg: any = window.localStorage.getItem("JYBG");
let jiaoyubeijing: any = window.localStorage.getItem("jiaoyubeijing");
jybg = JSON.parse(jybg);
jiaoyubeijing = JSON.parse(jiaoyubeijing);
onMounted(() => {
console.log();
if (route.query.str == "编辑") {
let indexValue = window.localStorage.getItem("indexValue") || [];
console.log(indexValue);
if (indexValue instanceof Array) {
return;
} else {
formData.value.educational[0] = JSON.parse(indexValue);
}
} else {
}
});
/* 删除 */
const delectClick = () => {
let tem = formData.value.educational[0] as any;
for (let i in formData.value.educational[0]) {
tem[i] = "";
}
formData.value.educational[0] = tem;
};
/* 提交 */
const onSubmit = (values: any) => {
console.log(values);
if (route.query.str == "编辑") {
Toast("编辑成功!");
router.back();
// => item.id === obj.id ? obj : item
jiaoyubeijing.educational[Number(route.query.index)] = values;
window.localStorage.setItem("jiaoyubeijing", JSON.stringify(jiaoyubeijing));
window.localStorage.removeItem("indexValue");
} else {
Toast("添加成功!");
router.back();
window.localStorage.removeItem("indexValue");
if (window.localStorage.getItem("indexValue") == null) {
if (jiaoyubeijing == null) {
jiaoyubeijing = {};
}
jiaoyubeijing.educational.push(values);
console.log(jiaoyubeijing);
window.localStorage.setItem(
"jiaoyubeijing",
JSON.stringify(jiaoyubeijing)
);
window.localStorage.setItem("JYBG", JSON.stringify(values));
}
}
// router.back();
};
const router = useRouter();
const route = useRoute();
</script>
<style scoped lang='less'>
h1 {
font-size: 18px;
padding: 10px;
}
</style>
这个是把数据存到本地上了,真实项目需要通过接口去传递数据,原理是一样的