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

Vue.extend

Vue.extend 是 Vue 2 中的一个重要 API,用于基于一个组件配置对象创建一个“可复用的组件构造函数”。它是 Vue 内部构建组件的底层机制之一,适用于某些高级用法,比如手动挂载组件、弹窗动态渲染等。

⚠️ 在 Vue 3 中已被移除,Vue 3 使用 defineComponent 替代组件定义方式,推荐改用 Composition API 和函数式组件模式。

🧩 Vue.extend 的基本用法

const MyComponent = Vue.extend({template: '<div>Hello {{ name }}</div>',data() {return {name: 'World'};}
});

这个 MyComponent 是一个构造函数,你可以像创建 Vue 实例一样使用它:

const vm = new MyComponent();
vm.$mount('#app'); // 或者不传参数,使用 vm.$mount() + DOM 操作手动插入

📦 使用场景举例

✅ 动态创建组件实例(如弹窗)

const Popup = Vue.extend({template: '<div class="popup">我是弹窗</div>'
});const instance = new Popup();
instance.$mount(); // 不传参数,不插入页面
document.body.appendChild(instance.$el); // 手动挂载

✅ 结合 propsData 动态传值

const Alert = Vue.extend({props: ['message'],template: '<div class="alert">{{ message }}</div>'
});const alertInstance = new Alert({propsData: {message: '操作成功'}
});
alertInstance.$mount();
document.body.appendChild(alertInstance.$el);

✅ 用于组件库或插件封装(如 Message、Toast)

很多组件库(如 Element UI)内部使用 Vue.extend 构建弹窗或消息提示组件。

🔍深入理解:Vue.extend 做了什么?

本质上:

Vue.extend(ComponentOptions)

会返回一个新的组件构造函数,该构造函数是基于你传入的选项创建的,继承自 Vue 构造器,具备 Vue 实例的能力。

相当于内部做了:

function SubComponent() {Vue.call(this); // 继承 Vue 构造器// ...
}
SubComponent.prototype = Object.create(Vue.prototype);

所以你可以这样理解:

  • Vue.extend 类似于类的继承
  • 生成的构造器可以多次 new 实例化
  • 实例是完整的 Vue 实例,具备 data、methods、watch、生命周期等功能

❗ 注意事项

问题原因
this.xxx 报错未通过 $mount 激活组件
propsData 无效只能传给 Vue.extend 的实例,而不是组件本身
内存泄漏手动创建的组件需要手动 $destroy() 和移除 DOM

🚫 Vue 3 替代方案

Vue.extend 在 Vue 3 被移除,推荐使用:

✅ defineComponent + createApp

import { createApp, defineComponent } from 'vue';const Alert = defineComponent({props: ['message'],template: '<div>{{ message }}</div>'
});const app = createApp(Alert, { message: '你好 Vue 3' });
const container = document.createElement('div');
document.body.appendChild(container);
app.mount(container);

✅ 总结

内容Vue.extend
定义方式const Ctor = Vue.extend(options)
本质返回继承自 Vue 的构造函数
常见用途弹窗、动态组件、组件库
Vue 3 替代defineComponent + createApp()

例子

Vue 2 弹窗组件的样式增强版,加入了:

  • ✅ 遮罩层(点击遮罩可关闭)
  • ✅ 居中弹出 + 阴影 + 圆角
  • ✅ 动画效果(淡入、淡出)
  • ✅ 简洁现代风格(仿 Element UI)

🗂️ 目录结构

├── index.html
├── main.js
├── MyDialog.js

📄 MyDialog.js — 定义弹窗组件

// MyDialog.js
import Vue from 'vue';const MyDialog = Vue.extend({props: ['message'],data() {return {visible: false};},mounted() {// 延迟显示以触发动画setTimeout(() => this.visible = true, 10);},methods: {close() {this.visible = false;setTimeout(() => {this.$destroy();if (this.$el && this.$el.parentNode) {this.$el.parentNode.removeChild(this.$el);}}, 300); // 延迟移除以匹配动画},onMaskClick(e) {if (e.target === this.$el) {this.close();}}},template: `<div class="dialog-mask" @click="onMaskClick"><div class="dialog-box" :class="{ 'dialog-show': visible, 'dialog-hide': !visible }"><p class="dialog-message">{{ message }}</p><button class="dialog-close" @click="close">关闭</button></div></div>`,style: `.dialog-mask {position: fixed;top: 0; left: 0;width: 100vw; height: 100vh;background: rgba(0, 0, 0, 0.4);display: flex;align-items: center;justify-content: center;z-index: 9999;}.dialog-box {background: white;border-radius: 8px;padding: 20px 24px;box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);transform: scale(0.9);opacity: 0;transition: all 0.3s ease;min-width: 300px;}.dialog-show {transform: scale(1);opacity: 1;}.dialog-hide {transform: scale(0.9);opacity: 0;}.dialog-message {font-size: 16px;margin-bottom: 16px;}.dialog-close {background-color: #409eff;border: none;color: white;padding: 8px 16px;border-radius: 4px;cursor: pointer;}.dialog-close:hover {background-color: #66b1ff;}`
});// 注入样式(确保样式在页面中)
const style = document.createElement('style');
style.textContent = MyDialog.options.style;
document.head.appendChild(style);export default MyDialog;

📄 main.js — 使用 Vue.extend 创建实例并挂载

// main.js
import Vue from 'vue';
import MyDialog from './MyDialog.js';new Vue({el: '#app',methods: {showDialog() {const DialogConstructor = MyDialog;const instance = new DialogConstructor({propsData: {message: '这是一个提示弹窗'}});instance.$mount(); // 手动挂载组件document.body.appendChild(instance.$el); // 插入到页面}},template: `<div><button @click="showDialog">打开弹窗</button></div>`
});

📄 index.html — 引入脚本

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>增强版 Vue.extend 弹窗示例</title><style>/* 弹窗遮罩层样式 */.dialog-overlay {position: fixed;top: 0;left: 0;width: 100%;height: 100%;background: rgba(0, 0, 0, 0.6);display: flex;align-items: center;justify-content: center;z-index: 1000;}/* 弹窗内容样式 */.dialog-content {background: #fff;padding: 20px;border-radius: 5px;text-align: center;min-width: 300px;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);}/* 过渡动画 - 淡入淡出 */.dialog-fade-enter-active,.dialog-fade-leave-active {transition: opacity 0.3s;}.dialog-fade-enter,.dialog-fade-leave-to {opacity: 0;}</style>
</head>
<body><div id="app"></div><!-- Vue 2 官方 CDN --><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><!-- 使用 type="module" 加载我们的脚本 --><script type="module" src="./main.js"></script>
</body>
</html>

相关文章:

  • CentOS7更新 GLIBC 2.25
  • 区块链可投会议CCF C--APSEC 2025 截止7.13 附录用率
  • ISO 26262-5 区分失效模式
  • 阿里千问系列:Qwen3技术报告解读(下)
  • 英语科研词汇现象及语言演变探讨
  • 用 Python 构建自动驾驶的实时通信系统:让车辆“交流”起来!
  • YOLOV8涨点技巧之空间通道协作注意力(SCCA)-应用于自动驾驶领域
  • 类欧几里得算法(floor_sum)
  • git 把一个分支A的某一个 commit 应用到另一个分支B上
  • LLM 使用本地模型 提取新生成 文本 的token ID序列
  • 使用中文作为map的可以,需要注意什么
  • 差分数组知识笔记
  • java 加密算法的简单使用
  • 医学写作人才管理策略
  • Leetcode 刷题记录 11 —— 二叉树第二弹
  • 获取 Stream 对象的方式
  • 内存管理(第五、六章)
  • RocketMQ 深度解析:消息中间件核心原理与实践指南
  • AUTOSAR图解==>AUTOSAR_SRS_ICUDriver
  • 关于 Web 安全:5. 认证绕过与权限控制分析
  • 高端大气网站欣赏/今日头条新闻消息
  • 沧州网站建设公司电话/营销模式有几种
  • wordpress 相册调用/自动app优化官网
  • 网站开发怎么设置打印按钮/百度推广在线客服
  • 温州最新消息/优化关键词是什么意思
  • 网站建设有免费的吗/论坛发帖