vue2中teleport传送门实践

4,177 阅读1分钟

前言

最近的需求开发中,优惠券管理页面,在原有的header组件中新增了面包屑与导航栏,但其它页面并不需要,考虑到后期的拓展性,便想到了通过vue3中学习到的teleport传送门组件,来解决项目逻辑的耦合问题。

业务要求

正常页面

微信截图_20230420173917.png

优惠券管理页面

微信截图_20230420174012.png

项目实践

1.简单封装teleport组件

由于项目是基于vue2版本的,所以第一步需要先实现一个vue2版本的传送门组件,以下是一个简单实现。

<template>
    <div>
        <slot></slot>
    </div>
</template>

<script>
export default {
    name: 'teleport',
    props: {
        to: {
            type: String,
            required: true
        }
    },
    mounted() {
        const toEl = document.querySelector(this.to)
        if (toEl) {
            toEl.appendChild(this.$el)
        }
    },
    destroyed() {
        const toEl = document.querySelector(this.to)
        if (toEl) {
            toEl.removeChild(this.$el)
        }
    }
}
</script>

实现原理其实很简单,内部通过一个默认插槽,接收外部的ui,在组件挂载成功后,将当前组件元素挂载到目标元素当中,在组件卸载后,从目标元素中移除当前组件元素。

2.改造原来的header组件

只需要在原有的header组件中新增一个占位元素layout-nav,负责接收其它组件传送来的组件元素即可。

header组件部分代码

<div class="main">
    <!-- 新增了_layout-nav元素,用于外部扩展 -->
    <div id="_layout-nav"></div>
    <!---->
    <el-dropdown trigger="click" @command="handleCommand">
        <span class="el-dropdown-link">
            {{userName}}
            <i class="el-icon-arrow-down el-icon--right"></i></span>
        <el-dropdown-menu slot="dropdown">
            <el-dropdown-item command="out">登出</el-dropdown-item>
        </el-dropdown-menu>
    </el-dropdown>
</div>
3.页面使用

如下所示,只需要在管理页面利用teleport组件,将面包屑和导航栏动态插入到目标元素即可,管理页面负责ui的样式及业务逻辑。

<div class="layout">
    <!-- 传送门 -->
    <teleport to="#_layout-nav">
        <div class="header">
            <div class="breadcrumb">
                <el-breadcrumb separator="/">
                    <el-breadcrumb-item>首页</el-breadcrumb-item>
                    <el-breadcrumb-item>小程序管理</el-breadcrumb-item>
                    <el-breadcrumb-item>领券中心</el-breadcrumb-item>
                </el-breadcrumb>
            </div>
            <ul class="menu">
                <li v-for="item in menuList" :key="item.name">
                    <router-link
                        active-class="menu-item-active"
                        :to="{ name: item.name }">{{ item.title }}</router-link>
                </li>
            </ul>
        </div>
    </teleport>
    <div class="layout-body">
        <router-view></router-view>
    </div>
</div>