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

vue2和vue3函数式调用组件学习记录

🚀 对比说明

功能Vue 2 版本Vue 3 改写
动态创建Vue.extend + $mount()createVNode + render()
控制显示data.showref(show) + v-model:show
销毁组件$destroy()render(null, container)
暴露方法直接访问实例defineExpose()
语法风格Options API<script setup> + Composition API

一、vue2

使用 Vue.extend 将定义对象转为一个可实例化的构造函数,然后挂载到一个独立 DOM 节点。

我们以一个假期弹窗作为示例


<template><van-popup v-model="show" @close="$emit('close')" :close-on-popstate="true" :close-on-click-overlay="true"><div class="popup-box"><div class="title">温馨提示</div><div class="popup-text" v-html="content"></div><van-button round block color="linear-gradient(to right, #F0D19A, #DEAA62)" @click="$emit('close')">{{ buttonText || '知道了'}}</van-button></div></van-popup>
</template>
<script>
import Vue from 'vue'
const HolidayPopup = {name: 'HolidayPopup',props: {content: String,buttonText: String},data() {return {show: false}},methods: {close() {this.show = false},onConfirm() {this.$emit('confirm', true)}}
}
export default HolidayPopupexport const holidayInst = function (props) {return new Promise(resolve => {const constructor = Vue.extend(HolidayPopup)const inst = new constructor({ propsData: props }).$mount()inst.$on('confirm', val => {inst.close()resolve(val)})inst.$on('close', () => {setTimeout(() => {inst.$destroy()document.body.removeChild(inst.$el)resolve(true)}, 300)})document.body.appendChild(inst.$el)inst.show = true})
}
</script><style scoped lang="scss">
.....省略</style>

使用方式

holidayInst({content: '放假通知:10月1日至10月7日休假!',buttonText: '我知道了'
}).then(() => {console.log('用户关闭了弹窗')
})

二、vue3

这是函数式调用封装(Vue 3 推荐使用 createVNode + render

HolidayPopup.vue

<template><van-popupv-model:show="show"@close="handleClose"close-on-popstateclose-on-click-overlay><div class="popup-box"><div class="title">温馨提示</div><div class="popup-text" v-html="content"></div><van-buttonroundblockcolor="linear-gradient(to right, #F0D19A, #DEAA62)"@click="handleClose">{{ buttonText || '知道了' }}</van-button></div></van-popup>
</template><script setup>
import { ref, defineExpose } from 'vue'const props = defineProps({content: String,buttonText: String
})const show = ref(false)const emit = defineEmits(['confirm', 'close'])const handleClose = () => {show.value = falseemit('close')
}const open = () => {show.value = true
}defineExpose({open,close: handleClose
})
</script><style scoped lang="scss">
......省略
</style>

holidayInst.js

import { createVNode, render } from 'vue'
import HolidayPopup from './HolidayPopup.vue'export function holidayInst(props) {return new Promise((resolve) => {const container = document.createElement('div')document.body.appendChild(container)const vnode = createVNode(HolidayPopup, {...props,onClose: () => {// 弹窗关闭时销毁实例render(null, container)document.body.removeChild(container)resolve(true)}})render(vnode, container)// 等待组件实例挂载后再显示const inst = vnode.component?.exposedif (inst && inst.open) {inst.open()}})
}

使用方式:

import { holidayInst } from '@/components/HolidayPopup/holidayInst'async function showHolidayNotice() {await holidayInst({content: '放假通知:10月1日至10月7日放假,祝大家假期愉快!',buttonText: '我知道了'})console.log('弹窗已关闭')
}

🟢 三、适用场景(什么时候适合这种调用方式)

这种组件调用方式适合「临时出现 / 全局生效 / 与组件树无强关联」的交互场景。

✅ 常见使用场景:

场景示例原因
1️⃣ 全局弹窗 / 消息提示Toast.success('保存成功')轻量、无需模板,逻辑触发后直接弹出
2️⃣ 确认框、警告框Dialog.confirm({ message: '确定删除?' })操作前确认提示,不依赖父组件
3️⃣ 系统公告 / 节日弹窗holidayInst({ content: '国庆放假通知' })在 App 启动或全局逻辑里触发
4️⃣ 登录过期提示全局拦截器里调用弹窗无法在模板里声明,只能用函数创建
5️⃣ 图片预览 / 全屏展示类组件ImagePreview.open(list)全局层级高,独立于业务组件树

⚙️ 四、使用这种方式的优势

优点说明
调用简单不需要在模板中声明 <Dialog />,直接一行代码调用
全局可用可以在任意地方调用,比如接口拦截器、store、router 等
使用体验好像调用函数一样方便,搭配 Promise 异步处理结果很自然
无状态干扰不依赖父组件的数据或生命周期,逻辑隔离清晰
动态数量灵活可以随时创建多个实例(比如多个 Toast)

🔴 五、潜在弊端(使用时要注意的坑)

弊端说明对策
⚠️ 不受 Vue 组件树管理不在正常的组件层级中,Vue 不会自动销毁手动执行 render(null) / $destroy() 清理
⚠️ 可能造成内存泄漏多次创建实例但未销毁,会堆积在内存中调用完后一定要清理 DOM 和实例
⚠️ 难以调试 / 跟踪组件不在模板里,不容易定位给组件添加唯一标识或日志
⚠️ 状态不可共享与其他组件的 reactive 状态不共享仅用于“独立展示型组件”
⚠️ SSR 不兼容涉及 document.body 操作,无法在服务端渲染执行SSR 环境中需禁用或判断执行环境
⚠️ 动画/过渡控制复杂因为是动态挂载,过渡钩子要自己处理可监听 @closed 后再销毁

💎 函数式调用组件(Programmatic Component)的优势

也就是像这样用的组件:

holidayInst({ content: '放假通知' })
Toast.success('保存成功')
Dialog.confirm({ message: '确认删除?' })

这类组件不写在模板里,而是直接用代码弹出。
它的优势主要体现在 开发灵活性、调用便捷性、全局可用性 三个方面 👇


🟢 一、调用更灵活(脱离模板约束)

  • 不需要在 <template> 中声明组件。

  • 可以在任意 JS 逻辑中调用,比如:

    • Vuex / Pinia 的 action 中;

    • Axios 拦截器里;

    • 路由守卫(router.beforeEach);

    • 甚至纯 JS 模块(无 Vue 上下文)。

示例:

axios.interceptors.response.use(res => res,err => {if (err.response.status === 401) {Dialog.alert({ message: '登录已过期,请重新登录' })}return Promise.reject(err)}
)

普通组件做不到,因为它必须依附在模板或页面中。


⚡ 二、使用方式简单直观

  • 调用形式类似“工具函数”,逻辑清晰;

  • 无需维护 v-ifv-show 状态;

  • 通过 Promise 直接拿到用户行为结果。

示例:

Dialog.confirm({ message: '确定删除?' }).then(() => deleteItem()).catch(() => console.log('取消'))

相比:

<MyDialog v-model="visible" @confirm="deleteItem" />

→ 不需要手动管理 visible,逻辑更纯粹。


🌍 三、可在全局任意地方调用

  • 因为它是动态挂载到 document.body 的;

  • 所以不依赖父组件或上下文;

  • 常用于 全局统一提示 / 系统级弹窗

✅ 常见应用:

  • 登录过期提示

  • 全局公告弹窗

  • Loading、Toast、Notify

  • 图片预览、全屏播放器


🧱 四、实例隔离、互不干扰

每次调用都会创建新的组件实例,不会污染其他页面的状态。
适合:

  • 多个同时存在的 Toast;

  • 并发消息提示;

  • 独立逻辑的确认框。


🎨 五、便于封装统一的 UI 行为

可以把 UI 弹窗逻辑和业务逻辑完全分离,
团队中可统一封装如:

// useDialog.js 
export const useDialog = (message) => { return Dialog.confirm({ message, title: '系统提示' 
}) }

这样业务方只需调用:

await useDialog('确定删除?')

无需关心组件实现,方便维护和替换。


🚀 六、减少模板污染 & 提升可维护性

声明式组件:

<MyDialog v-model="showDialog" :title="title" @confirm="confirmFn" />

函数式调用:

MyDialog({ title, message }).then(confirmFn)
  • 模板更干净;

  • 状态逻辑转为函数逻辑;

  • 对复用组件库开发非常友好。


✅ 总结对比表

优势说明
💬 使用简单像函数一样调用,无需 v-if/v-show
🌍 全局可用任意位置可调用(即使无 Vue 上下文)
🧩 逻辑解耦UI 与业务逻辑分离
🧱 实例独立每次调用独立创建,不干扰其他实例
🎨 模板干净不占用模板结构,适合全局弹窗类组件
⚙️ Promise 接口自然可以方便地使用异步/等待用户操作

一句话总结:

函数式调用组件最大的优势是——
不受模板限制、调用灵活、使用简单,非常适合「全局弹出类 UI」场景。

http://www.dtcms.com/a/495782.html

相关文章:

  • 廊坊市固安县建设局网站中小企业网络设计论文
  • 3D打印技术在金属材料上的应用现状
  • 网站数据库丢失注册公司网站需要什么资料
  • 重生之我在大学自学鸿蒙开发第九天-《分布式流转》
  • 做手机网站公司wordpress萌主题下载
  • 【Android15快速自定义与集成音效实战课】:正式上线了(二百六十二)
  • 数字化时代,企业应该如何看待商业智能BI
  • 算法---队列+宽搜
  • 解锁分布式唯一 ID:技术、实践与最佳方案
  • 检察院门户网站建设方案网站建设a2345
  • GB200 NVL72超节点深度解析:架构、生态与产业格局
  • 课程网站的设计做网站被骗去哪投诉
  • YOLO家族进化史:从V1到V3的跨越
  • Lipschitz连续及其常量
  • 个人做网站公司宁波趋势信息科技有限公司
  • 安装好采集侠网站地图后在哪里查看网站地图精准粉丝引流推广
  • 外贸soho怎么建网站网站的分辨率
  • 子序列问题
  • 多模态大模型Ovis2.5核心技术改进点、训练方法
  • 建网站步骤ps临摹图片做网站的图片犯法吗
  • 网站建设服务的具体条件烟台企业网站开发
  • 如何做分公司网站wordpress数据库版本
  • DeviceNet 转 MODBUS TCP:倍福 CX 系列 PLC 与 MES 系统在 SMT 回流焊温度曲线监控的通讯配置案例
  • 湛江企业自助建站全国网站建设公司实力排名
  • Redux和@reduxjs/toolkit同时在Next.js项目中使用
  • 从个人贡献者到团队引领者:测试团队的知识管理与能力建设
  • 机械臂动作捕捉系统选型指南:从需求到方案,NOKOV 度量光学动捕成优选
  • 网站开发标准商务网站的推广方法有哪些
  • 注册网站要百度实名认证安不安全网站建设评审会简报
  • 卷积神经网络中的卷积运算原理