一个页面多次复用相同组件
要求
- 表格中每行都需要一个,即一个页面多次复用
- 多个相同组件之间数据不能乱串
- 对多个组件进行操作,多选
问题
- 表格换页或者发请求,更换表格数据时,可能会造成混乱
- 组件内的值是否需要响应式,组件内是否都需要重置
- 对某一组件操作时,会影响到其他组件的内容
实现
1. 组件
-
组件列是封装的组件,简单的el-descriptions,蓝色+控制内部infoValue++
- id是通过props的传值,只要都传都接收,不会混乱
- infoValue noneValue 内部响应式变量,有混乱的可能
<div class="container"> <el-descriptions :column="4" size="small" direction="vertical" border > <!--id是通过props的传值--> <el-descriptions-item label="id">{{ props.id }}</el-descriptions-item> <!--infoValue noneValue 是经计算的值 --> <el-descriptions-item label="infoValue">{{ infoValue }}</el-descriptions-item> <el-descriptions-item label="noneValue">{{ noneValue }}</el-descriptions-item> <el-descriptions-item label="加"> <el-button type="primary" @click="plus" icon="plus"></el-button> </el-descriptions-item> </el-descriptions> </div>const plus = () => { infoValue.value = infoValue.value + 1; }; defineExpose({plus, noneValue, infoValue}) -
组件初始值
const props = defineProps(["row", "id"]); const infoValue = ref(0); const personValue = ref(); const noneValue = ref(-1); watch( () => props.row, (newvalue, oldvalue) => { noneValue.value = 0 // 注意点二:要重置noneValue infoValue.value = newvalue.initValue; personValue.value = newvalue.list if(personValue.value.length > 2){ noneValue.value += personValue.value.length } }, { immediate: true, deep: true } // 注意点一:对象里面的属性值发生改变时,深度监听 );
1. 表格
-
姓名列、组件列、操作列(红色+通过组件暴露的函数控制组件内infoValue++)
<el-table :data="personList" ref="tableRef" table-layout="auto" @selection-change="handleSelectionChange" v-if="personList" > <el-table-column type="selection" width="55" /> <el-table-column label="姓名" prop="name"> </el-table-column> <el-table-column label="组件"> <template #default="scope"> <!--注意点三:key 属性 唯一标识组件--> <!--注意点四:多个相同组件的ref--> <InfoLine :row="scope.row" :id="scope.row.id" :key="scope.row.id" :ref=" (el) => { slideRefs[scope.row.id] = el; } " /> </template> </el-table-column> <el-table-column label="操作"> <template #default="scope"> <el-button type="danger" icon="plus" @click="plusRef(scope.row.id)" ></el-button> </template> </el-table-column> </el-table>import InfoLine from "./info.vue"; const slideRefs = ref([]); const plusRef = (id) => { slideRefs.value[id].plus(); // 调用组件暴露出的方法 }; -
表格分页:模拟分两页
/* 表格数据 */ const personList = ref([]); // 若表格外还有切换的话,需要personList=[] const tableRef = ref(); personList.value = [ { id: 1, name: "人员一", initValue: 2, list: [1], }, { id: 2, name: "人员二", initValue: 2, list: [2, 2], }, ]; const getTableData = (pageNum) => { showdata.value = null; // 注意点五:重置数据 if (pageNum === 1) { personList.value = [ { id: 1, name: "人员一", initValue: 1, list: [1], }, { id: 2, name: "人员二", initValue: 2, list: [2, 2], }, ]; } else { personList.value = [ { id: 3, name: "人员三", initValue: 3, list: [3, 3, 3], }, { id: 4, name: "人员四", initValue: 4, list: [4, 4, 4, 4], }, ]; } }; const pageConfig = reactive({ pageNum: 1, pageSize: 2, total: 4, }); const handleCurrentChange = (pageNum) => { pageConfig.pageNum = pageNum; getTableData(pageNum); };<el-pagination background layout="prev, pager, next, total" class="pagination" @current-change="handleCurrentChange" :page-size="pageConfig.pageSize" :total="pageConfig.total" :current-page="pageConfig.pageNum" /> -
展示:按钮【多选数据】
<div class="show"> <el-button type="primary" @click="multipleShow">多选数据</el-button> {{ showdata }} </div>
3. 注意点
-
注意点一:watch深度监听对象属性值改变(初始由空变有值)
-
注意点二:要重置noneValue
对如下这种情况,nonevalue没有重新设置,就会造成该值在组件间混乱。这种情况可通过key避免(注意点三)。
if(personValue.value.length > 2){ noneValue.value += personValue.value.length } -
注意点三:设置key 属性,唯一标识组件。切记设置的key是唯一的,包括根据别的情况切换表格的情况,都要唯一。
-
注意点四:多个相同组件的ref,通过唯一标识索引。可通过slideRefs.value[id]获取组件,可获取组件暴露出的变量,调用方法。
// :ref="(el) => { slideRefs[scope.row.id] = el;}" const slideRefs = ref([]); // slideRefs.value[id]
4. 表格批量操作
- 可通过slideRefs获取选中的组件,从而进行数据处理或请求等。
- 本例通过showdata展示批量选择的表格数据。
const showdata = ref();
const multipleSelection = ref([]);
const handleSelectionChange = (val) => {
multipleSelection.value = val;
};
const multipleShow = () => {
try {
// 判断是否选中数据
if (multipleSelection.value.length === 0) {
ElMessage.info("未选中修改数据!");
// 显示提示
showdata.value = "未选中数据";
} else {
// 取出将选中人员的数据
let mdata = [];
multipleSelection.value.forEach((element) => {
mdata.push({
id: element.id,
name: element.name,
noneValue: slideRefs.value[element.id].noneValue,
infoValue: slideRefs.value[element.id].infoValue,
});
});
// 显示数据
showdata.value = mdata;
}
} catch (error) {}
};
5. 其他
-
组件内部按钮操作组件的方法,更加方便安全。父组件调用暴露方法也可实现,但如果该方法中有数据请求、对父组件的更新等复杂交互逻辑时一定要注意各个函数、请求的顺序、请求是否异步等。
-
完善测试,测试各种情况,包括脏数据,尽可能接近生产数据的测试,以保证代码正确。