当前位置: 首页 > news >正文

Vue2函数式组件实战:手写可调用的动态组件,适用于toast轻提示、tip提示、dialog弹窗等

Vue2函数式组件实战:手写可调用的动态组件

一、需求场景分析

在开发中常遇到需要动态调用的组件场景:

  • 全局弹窗提示
  • 即时消息通知
  • 动态表单验证
  • 需要脱离当前DOM树的悬浮组件

传统组件调用方式的痛点:

<template>
  <!-- 必须预先写入模板 -->
  <MyComponent v-if="show" :content="text"/>
</template>

二、函数式组件实现方案

//myComponent.js
import MyComponent from './MyComponent.vue';
import Vue from 'vue';

let instance;

//实例初始化
function initInstance(){
    //先销毁已有实例,单例模式
    if(instance){
        instance.$destroy();
        // 显式移除DOM
        instance.$el.parentNode.removeChild(instance.$el) 

    }
    instance = new (Vue.extend(MyComponent))({
        el: document.createElement('div')
    });

    //自定义事件,控制组件显隐
    instance.$on('show',value=>{
        instance.value = value
    })
}

//函数式组件调用
function myComponent(options){
    if(!instance){
        initInstance();
    }
    //复制传参并控制显示组件
    Vue.nextTick(() => {
        Object.keys(options).forEach(key => {
            instance[key] = options[key]
        })
        instance.value = true
    })
}

myComponent.Component = MyComponent;
export default myComponent;
<template>
  <transition name="fade">
    <div v-show="value" class="component-wrapper">
      <div class="header">
        <slot name="header">{{ title }}</slot>
      </div>
      <div class="content">
        {{ content }}
      </div>
      <div class="footer">
        <button @click="handleClose">关闭</button>
      </div>
    </div>
  </transition>
</template>

<script>
export default {
  props: {
    content: String,
    title: {
      type: String,
      default: '提示'
    }
  },
  mounted() {
    // 智能挂载到最近的dialog-container
    const container = document.querySelector('.dialog-container') || document.body
    container.appendChild(this.$el)
  },
  methods: {
    handleClose() {
            this.$emit('show',false);
    }
  },
  beforeDestroy() {
    // 安全移除DOM
    if (this.$el.parentNode) {
      this.$el.parentNode.removeChild(this.$el)
    }
  }
}
</script>

<style scoped>
.fade-enter-active, .fade-leave-active {
  transition: opacity 0.3s;
}
.fade-enter, .fade-leave-to {
  opacity: 0;
}
</style>

三、使用方式对比

传统组件调用

<template>
  <button @click="show = true">打开</button>
  <MyComponent v-if="show" @close="show = false"/>
</template>

<script>
export default {
  data: () => ({
    show: false
  })
}
</script>

函数式组件调用

import { myComponent} from '@/utils/myComponent'

// 任意位置调用
showComponent({
  content: '操作成功',
  title: '系统提示',
})

四、弹窗需要考虑的问题

  1. 当页面滚动时,弹窗是否需要滚动?是否会被其他元素遮挡
  2. 移动端如何避免点击穿透问题
  3. 当频繁触发弹窗时,如何确保弹窗的内容/显隐时间正常

五、进阶优化建议

  1. 多实例支持
function createInstance() {
  return new (Vue.extend(MyComponent))({
    el: document.createElement('div')
  })
}

export function showComponent(options) {
  const instance = createInstance()
  // 单独管理实例
}
  1. 如果是vue3定制函数式组件,可以使用teleport将组件传送至最外层

函数式组件是Vue2中实现命令式调用的利器,但需要特别注意实例管理和DOM操作。建议仅在确实需要动态调用的场景使用,常规需求优先使用标准组件化方案。

相关文章:

  • 掌握AI营销:移动营销的新动力
  • c++:哈希表
  • GPT-4o推出的原生图像生成功能升级后有点东西!
  • 世界通信大会、嵌入式展及慕尼黑上海光博会亮点回顾
  • 手绘风格流程图工具:简单高效的在线流程图绘制工具
  • C语言复习笔记--指针(1)
  • echarts+HTML 绘制3d地图,加载散点+散点点击事件
  • 2025年SCI1区(TAC) ——语义和情感双重通道用于文本对话情感识别
  • 基于vue框架的智能服务旅游管理系统54kd3(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • Python学习第二十八天
  • 游戏引擎学习第195天
  • 8.集成模板引擎
  • 【1-1】ICT=IT+CT
  • MySQL GROUP BY分组获取非聚合列值方法
  • [Android汉化] DuckStation of Android:安卓端 Playstation 模拟器(PSX / PSOne)汉化版
  • Open GL ES ->纹理贴图,顶点坐标和纹理坐标组合到同一个顶点缓冲对象中进行解析
  • 视频推拉流EasyDSS互联网直播点播平台技术特点及应用场景剖析
  • C+++题
  • 解锁全方位健康生活,构筑身心防护网
  • vue前端项目技术架构(第二版)
  • 李强签署国务院令,公布修订后的《中华人民共和国植物新品种保护条例》
  • 俄罗斯纪念卫国战争胜利80周年阅兵式首次彩排在莫斯科举行
  • “乐购浦东”消费券明起发放,多个商家同期推出折扣促销活动
  • 美财长称关税战升级的责任在中方,外交部:关税战、贸易战没有赢家
  • 王毅会见泰国外长玛里:坚决有力打击电诈等跨境犯罪
  • 新质观察|重塑低空经济的系统安全观