vue3 tab切换函数回调刷新跳转页面

需求背景

页面miTab引用了两个组件A和B, 以tab切换方式显示,在tab页面A提交表单保存成功后跳转到tab页面B,并且tab页面B自动刷新表格列表能显示刚才保存成功的数据

出现的问题

跳转成功了,但是列表没刷新,排查后发现是没有在跳转后调用 tab B 的数据获取函数

解决方案

在页面miTab调用tab B组件的 getData 方法,前提是用 B页面提供注入功能来让父组件能够访问子组件的方法。
主要还得是在父组件中把逻辑处理好

关键代码

  • miTab.vue
<template>
  <div>
    <el-tabs :model-value="activeName" @tab-click="handleClick">
      <el-tab-pane label="CAD-BOM" name="CAD-BOM">
        <CADBOMComponent @a-reuse-success="switchToaTab" />
      </el-tab-pane>
      <el-tab-pane label="a" name="a" >
        <aComponent ref="aComponent"/>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
import { ref } from 'vue';
import CADBOMComponent from './CADBOMComponent.vue'; // 导入 CAD-BOM 组件
import aComponent from './aComponent.vue'; // 导入 a 组件

export default {
  name: 'part',
  components: {
    CADBOMComponent,
    aComponent
  },
  setup() {
    const activeName = ref('CAD-BOM');
    const aComponent = ref(null); // 用于引用 aComponent 实例



    const handleClick = (tab, event) => {
      activeName.value = tab.props.name;
    };

    const switchToaTab = () => {
      // 当收到子组件的 a-reuse-success 事件时,切换到 a tab
      activeName.value = 'a';
      if (aComponent.value) {
        aComponent.value.getData(); // 直接调用 aComponent 的 getData 方法
      }
    };


    return {
      activeName,
      handleClick,
      switchToaTab,
      aComponent
    };
  }
};
</script>
  • aTab
    表格表单代码以及其他逻辑处理太多,此处省略一万字…

export default {
    name: 'aTab',
    setup(_,context) {
    }
    const emit = context.emit;
       const MBOMaddEdit = () => {
            const data = {
                partNo: MBOMForm.partNo,
                partRev: MBOMForm.partRev,
                name: MBOMForm.name,
                cName: MBOMForm.cName,
                material: MBOMForm.material,
                gauge: MBOMForm.gauge,
                massqty: MBOMForm.massqty,
                partType: MBOMForm.partType
            }
            addMBom(data).then(res => {
                if (res.code !== 500) {
                    ElMessage.success('恭喜您,添加成功!')
                    //通知父组件切换到 MBOM tab
                    emit('mbom-reuse-success');
                } else {
                    ElMessage.error(res.msg)
                }
            })
 }
  
  • bTab
<template>
    <div class="part">
        <div class="common-query">
            <div class="common-query-demo">
                <span>零部件名称</span>
                <el-input placeholder="请输入零部件名称" v-model="query.name"></el-input>
            </div>
            <div class="common-query-demo">
                <el-button icon="el-icon-search" @click="handleQuery">查询</el-button>
                <el-button icon="el-icon-refresh" @click="resetQuery"
                    style="margin-left: 20px !important;">重置</el-button>
            </div>
        </div>
        <div class="line-body">
            <el-button type="primary" class="handle-btn" icon="el-icon-circle-plus-outline"
                @click="addEdit">新建</el-button>
            <el-button type="primary" class="handle-btn" icon="el-icon-delete" @click="deleteBatch">批量删除</el-button>

            <el-table :data="tableData" :max-height="tableHeight" @selection-change="handleSelectionChange" stripe
                border>
                <el-table-column type="selection" width="55" fixed></el-table-column>
                <el-table-column type="index" label="序号" width="50"></el-table-column>
                <el-table-column prop="name" label="名称" sortable min-width="100"></el-table-column>
                <el-table-column prop="cName" label="中文名称" min-width="100"></el-table-column>
                <el-table-column prop="partNo" label="数模号 " min-width="100"></el-table-column>
                <el-table-column prop="partRev" label="版本号" min-width="100"></el-table-column>
                <el-table-column prop="material" label="材料" min-width="100"></el-table-column>
                <el-table-column prop="gauge" label="规格" min-width="100"></el-table-column>
                <el-table-column prop="massqty" label="重量" min-width="100"></el-table-column>
                <el-table-column prop="partType" label="数据类型" min-width="100"></el-table-column>
                <el-table-column prop="status" label="状态" min-width="100">
                    <template #default="scope">
                        {{ scope.row.isLock == 0 ? '未锁定' : '已锁定' }}
                    </template>
                </el-table-column>

                <el-table-column fixed="right" label="操作" width="400">
                    <template #default="scope">
                        <el-button type="primary" icon="el-icon-view" @click="showTree(scope.row)">树形结构</el-button>
                        <el-button type="primary" icon="el-icon-view" @click="MBOMMux(scope.row)">MBOM复用</el-button>
                        <!-- 下载 -->
                        <el-button type="primary" icon="el-icon-download" @click="download(scope.row)">下载文件</el-button>
                        <i class="el-icon-delete" @click="deletePart(scope.row)"></i>
                    </template>
                </el-table-column>
            </el-table>

            <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
                :current-page="query.pageNum" :page-sizes="[10, 15, 20, 25, 30]" :page-size="query.pageSize"
                layout="total, sizes, prev, pager, next, jumper" :total="total">
            </el-pagination>

            <el-dialog :title="title" v-model="drawer" width="600px">
                <el-form :model="partForm" :rules="rules" ref="partFormsss" label-width="120px" class="demo-partForm">
                    <el-form-item label="数模号:" prop="partNo">
                        <el-input v-model="partForm.partNo" clearable></el-input>
                    </el-form-item>
                    <el-form-item label="版本号:" prop="partRev">
                        <el-input v-model="partForm.partRev" clearable></el-input>
                    </el-form-item>
                    <el-form-item label="名称:" prop="name">
                        <el-input v-model="partForm.name" clearable></el-input>
                    </el-form-item>
                    <el-form-item label="上级节点:" v-if="partForm.parentName">
                        <el-input v-model="partForm.parentName" disabled></el-input>
                    </el-form-item>
                    <el-form-item label="中文名称:" prop="cName">
                        <el-input v-model="partForm.cName" clearable></el-input>
                    </el-form-item>
                    <el-form-item label="材料:" prop="material">
                        <el-input v-model="partForm.material" clearable></el-input>
                    </el-form-item>
                    <el-form-item label="规格:" prop="gauge">
                        <el-input v-model="partForm.gauge" clearable></el-input>
                    </el-form-item>
                    <el-form-item label="重量:" prop="massqty">
                        <el-input v-model="partForm.massqty" clearable></el-input>
                    </el-form-item>
                    <el-form-item label="数据类型:" prop="partType">
                        <el-input v-model="partForm.partType" clearable></el-input>
                    </el-form-item>
                </el-form>
                <template #footer>
                    <span class="dialog-footer">
                        <el-button @click="cancelEdit">取 消</el-button>
                        <el-button type="primary" @click="saveEdit">确 定</el-button>
                    </span>
                </template>
            </el-dialog>
        </div>

    </div>
</template>

<script>
import { reactive, ref, toRefs, unref, onMounted, nextTick, onUnmounted } from 'vue'
import { add, remove, listByPage, listAll, downloadFile } from '@api/pdm/part'
import { addMBom, getMBomDdata } from '@api/pdm/mbom'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useRouter } from 'vue-router'
import axios from 'axios';


export default {
    name: 'bTab',
    setup() {
        // 定义的变量
        const state = reactive({
            query: {
                pageNum: 1,
                pageSize: 10,
                name: ''
            },
            statusList: [],
            title: '',
            drawer: false,  // 新建对话框
            handleId: '',  // 编辑id
            // 表数据
            tableData: [],
            total: 0,
            selectList: [],
            multipleSelection: []
        })
        const router = useRouter()

        // 通过计算表格距离页面底部的距离来实现表格高自适应
        const tableHeight = ref(window.innerHeight - 342)


        const partForm = reactive({
            partNo: '',
            partRev: '',
            name: '',
            cName: '',
            material: '',
            gauge: '',
            massqty: '',
            partType: '',
            parentId: '',
            parentName: ''
        })

        const partFormsss = ref(null)

        const rules = {
            name: [{ required: true, message: "此处为必填项" }],
            partNo: [{ required: true, message: "此处为必填项" }],
            partRev: [{ required: true, message: "此处为必填项" }]
        }



        //零部件表格
        function getData() {
            getMBomDdata(state.query).then(res => {
                state.total = res.data.total
                state.tableData = res.data.list
            })
        }



        // 新建零部件
        const addEdit = () => {
            state.drawer = true
            partForm.parentName = ''
            state.title = '添加零部件'
            partForm.parentId = ''
            partForm.partNo = ''
            partForm.partRev = ''
            partForm.name = ''
            partForm.cName = ''
            partForm.material = ''
            partForm.gauge = ''
            partForm.massqty = ''
            partForm.partType = ''
        }

        //展示零部件
        const showTree = (row) => {
            // state.title = '编辑零部件'
            // state.drawer = true
            // state.btnShow = true

            // state.handleId = row.id
            // partForm.partNo = row.partNo
            // partForm.partRev = row.partRev
            // partForm.name = row.name
            // partForm.cName = row.cName
            // partForm.material = row.cName
            // partForm.gauge = row.gauge
            // partForm.massqty = row.massqty
            // partForm.partType = row.partType

            // router.push({path: '/pdm/property?partId='+row.id})

            router.push({
                path: '/pdm/property',
                query: {
                    id: row.id
                }
            })
        }


        //断点续传
        // const download = async (row) => {
        //     const fileName = '11.png'; // 文件名
        //     const chunkSize = 1024 * 1024; // 分块大小,例如1MB
        //     let startByte = localStorage.getItem(`${fileName}-downloaded`) || 0;

        //     const config = {
        //         responseType: 'blob',
        //         headers: {
        //             'Range': `bytes=${startByte}-${startByte + chunkSize - 1}`,
        //         },
        //     };
        //     try {
        //         const response = await axios.get('/mes/file/download', config);
        //         // 直接处理响应,不再依赖于状态码检查
        //         const url = window.URL.createObjectURL(new Blob([response]));
        //         const link = document.createElement('a');
        //         link.href = url;
        //         link.download = fileName;
        //         document.body.appendChild(link);
        //         link.click();
        //         document.body.removeChild(link);

        //         // 更新已下载的字节数
        //         startByte += chunkSize;
        //         if (startByte < response.size) {
        //             localStorage.setItem(`${fileName}-downloaded`, startByte);
        //         } else {
        //             localStorage.removeItem(`${fileName}-downloaded`);
        //         }
        //     } catch (error) {
        //         console.error('Download error:', error);
        //     }
        // };




        const download = async (row) => {
            try {
                const data = {
                    id: row.id
                }
                downloadFile(data).then(response => {
                    if (response.code && response.code == 500) {
                        ElMessage.error(response.msg)
                    } else {
                        // 创建一个URL表示Blob对象
                        // const url = window.URL.createObjectURL(new Blob([response]));
                        const url = '/mes/pdm/cadDownloadPart?id=' + row.id;
                        // let fileName = response.headers['Content-Disposition'].split('filename=')[1];

                        // 创建隐藏的可下载链接
                        const link = document.createElement('a');
                        link.href = url
                        link.style.display = 'none';
                        // 将链接添加到DOM中,然后模拟点击下载
                        document.body.appendChild(link);
                        link.click();
                        // 清理工作,释放URL对象
                        window.URL.revokeObjectURL(url);
                        link.remove();
                    }
                })
            } catch (error) {
                // console.error('下载失败:', error);
                // alert('文件不存在或下载过程中出现问题!');
                ElMessage.error('下载失败')
            }
        };




        // 新建/编辑零部件
        const saveEdit = async () => {
            const form = unref(partFormsss)
            if (!form) return
            try {
                await form.validate()
                if (state.title == '添加零部件') {
                    addSavePart()
                }
                if (state.title == '编辑零部件') {
                    updateSavePart()
                }
                state.drawer = false
            } catch (error) {
                console.error(error)
                ElMessage.error('抱歉,您有必填项未填!')
            }
        }


        const addSavePart = () => {
            const data = {
                partNo: partForm.partNo,
                partRev: partForm.partRev,
                name: partForm.name,
                cName: partForm.cName,
                material: partForm.material,
                gauge: partForm.gauge,
                massqty: partForm.massqty,
                partType: partForm.partType,
            }
            add(data).then(res => {
                state.drawer = false
                ElMessage.success('恭喜您,添加成功!')
                getData()
            })
        }

        const updateSavePart = () => {
            const data = {
                id: state.handleId,
                partNo: partForm.partNo,
                partRev: partForm.partRev,
                name: partForm.name,
                cName: partForm.cName,
                material: partForm.material,
                gauge: partForm.gauge,
                massqty: partForm.massqty,
                partType: partForm.partType
            }
            update(data).then(res => {
                state.drawer = false
                getData()
                ElMessage.success('恭喜您,保存成功!')
            })
        }

        // 删除零部件
        const deletePart = (row) => {
            const ids = []
            ids.push(row.id)
            deleteProData(ids)
        }

        // 调用删除零部件接口
        const deleteProData = (data) => {
            remove(data).then(res => {
                getData(state.query)
                ElMessage.success('恭喜您,删除成功!')
            })
        }

        //批量删除零部件
        function deleteBatch() {
            const sels = state.multipleSelection
            if (sels.length != 0) {
                // 获取所有选中行的id组成的字符串,以逗号分隔
                const strIds = sels.map((item) => item.id).join()
                // split() 方法用于把一个字符串分割成字符串数组。
                const ids = strIds.split(',')
                deleteProData(ids)
                // ElMessage.success('您刪除了' + ids + '!')
            } else {
                ElMessage.error('您当前未选中!')
            }
        }

        // 新建取消
        const cancelEdit = () => {
            state.drawer = false
            setTimeout(() => {
                const form = unref(partFormsss)
                form.resetFields()
            }, 100)
        }

        const statusFormat = (row) => {
            for (let i = 0; i < state.statusList.length; i++) {
                if (row == state.statusList[i].dictValue) {
                    return state.statusList[i].dictLabel
                }
            }
        }

        // 批量删除选中
        function handleSelectionChange(val) {
            state.multipleSelection = val
        }


        function handleQuery() {
            queryEdit(state.query)
        }

        function resetQuery() {
            state.query.name = ''
        }

        // 查询
        function queryEdit(query) {
            getData(query)
            ElMessage.success('恭喜您,查询成功!')
        }




        // 分页页数
        function handleSizeChange(val) {
            state.query.pageSize = val
            queryEdit(state.query)
        }

        function handleCurrentChange(val) {
            state.query.pageNum = val
            queryEdit(state.query)
        }

        function getHeight() {
            tableHeight.value = window.innerHeight - 342
        }




        // 页面加载时调用函数
        onMounted(() => {
            // 注册监听器
            window.addEventListener('resize', getHeight)
            // 调用函数
            getHeight()
            getData()
        })

        onUnmounted(() => {
            // 注销监听器
            window.removeEventListener('resize', getHeight)
        })

    

        return {
            ...toRefs(state),
            tableHeight,
            rules,
            partFormsss,
            partForm,
            cancelEdit,
            saveEdit,
            handleSelectionChange,
            handleQuery,
            resetQuery,
            handleSizeChange,
            handleCurrentChange,
            showTree,
            addEdit,
            deletePart,
            deleteBatch,
            statusFormat,
            download,
            getData
        }
    }
}
</script>

<style lang="scss">
.part {
    width: 100%;
    height: 100%;

    .line-body {
        height: calc(100% - 120px);
        margin-top: 20px;
        box-shadow: $box-shadow;
        background: #fff;
        padding: 20px;

        .handle-btn {
            min-height: 32px;
            height: 32px;
            padding: 0 10px;
            margin-right: 10px;
        }

        .el-table {
            margin-top: 20px;

            td:last-child {
                .cell {
                    display: flex;
                    justify-content: space-between;
                    padding: 0 10px;
                }
            }

            .cell {
                padding: 0;

                .head-url {
                    height: 36px;
                    position: relative;

                    .el-image {
                        position: absolute;
                        top: 0;
                        right: 0;
                        bottom: 0;
                        left: 0;
                        margin: auto;
                        border-radius: 5px;
                    }
                }

                .el-tag {
                    height: 25px;
                    line-height: 25px;
                    padding: 0 7px;
                }
            }

            .el-icon-delete {
                cursor: pointer;
                color: #EB7A40;
                font-size: 22px;
            }

            .el-icon-delete:hover {
                opacity: 0.9;
            }
        }


    }
}
</style>

希望我的解决方案能帮助到遇到同样问题的同学,奥利给!

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迪霸戈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值