Vue非单文件组件
一、什么是非单文件组件?
非单文件组件(Non-Single File Component) 是指不使用
.vue
文件,而是通过 JavaScript 对象直接定义 Vue 组件的方式。
它不依赖 .vue
文件解析,通常在以下环境中使用:
- 直接通过
<script src="https://unpkg.com/vue@2.7"></script>
引入 Vue - 使用全局
Vue
对象创建实例和组件 - 组件的模板(template)以字符串或 DOM 元素形式存在
二、非单文件组件的基本语法
1. 创建 Vue 实例
<div id="app">{{ message }}
</div><script src="https://unpkg.com/vue@2.7"></script>
<script>
const app = new Vue({el: '#app',data: {message: 'Hello Vue!'}
})
</script>
✅ 这是最基础的 Vue 使用方式,无需构建工具。
2. 定义全局组件
使用 Vue.component(tagName, options)
定义全局组件。
Vue.component('my-button', {template: '<button @click="clickHandler">点击我 ({{ count }})</button>',data() {return {count: 0}},methods: {clickHandler() {this.count++this.$emit('click', this.count)}}
})
<div id="app"><my-button @click="onBtnClick"></my-button>
</div>
new Vue({el: '#app',methods: {onBtnClick(count) {console.log('按钮被点击了第', count, '次')}}
})
3. 模板的三种写法
方式 1:内联模板字符串(如上)
template: '<div>这是组件内容</div>'
⚠️ 缺点:不支持换行,可读性差。
方式 2:使用 <script type="text/x-template">
<script type="text/x-template" id="my-modal-template"><div class="modal"><h3>{{ title }}</h3><p>{{ content }}</p><button @click="$emit('close')">关闭</button></div>
</script>
Vue.component('my-modal', {template: '#my-modal-template',props: ['title', 'content']
})
✅ 推荐用于复杂模板,HTML 结构清晰。
方式 3:使用 render
函数(高级)
Vue.component('dynamic-component', {render(h) {return h('div', {style: { color: 'red' }}, '这是通过 render 函数创建的')}
})
✅ 更灵活,可动态生成 DOM,但学习成本高。
三、局部组件注册
除了全局注册,也可以在组件内部注册局部组件:
const ChildComponent = {template: '<span>我是局部组件</span>'
}new Vue({el: '#app',components: {'child-comp': ChildComponent},template: '<div><child-comp /></div>'
})
✅ 局部组件不会污染全局命名空间,推荐使用。
四、非单文件组件 vs 单文件组件(SFC)
特性 | 非单文件组件 | 单文件组件(SFC) |
---|---|---|
文件格式 | .html + .js | .vue |
构建工具 | 不需要 | 需要(Webpack/Vite) |
模板写法 | 字符串 / x-template / render | <template> 标签 |
样式支持 | 需外部 CSS 或 <style> | <style scoped> |
开发体验 | 差(分散、难维护) | 好(集中、高亮、热重载) |
适用场景 | 简单嵌入、遗留项目 | 现代化项目开发 |
TypeScript 支持 | 差 | 好 |
组件作用域样式 | 需手动处理 | scoped 或 CSS Modules |
✅ 结论:SFC 是现代开发的首选,非 SFC 适用于特定场景。
五、实际使用场景
1. 在传统 HTML 项目中嵌入 Vue
<!-- legacy-project.html -->
<!DOCTYPE html>
<html>
<head><script src="https://unpkg.com/vue@2.7"></script>
</head>
<body><div id="vue-app"><product-list :products="products"></product-list></div><script>Vue.component('product-list', {props: ['products'],template: `<ul><li v-for="p in products" :key="p.id">{{ p.name }} - ¥{{ p.price }}</li></ul>`})new Vue({el: '#vue-app',data: {products: [{ id: 1, name: '商品A', price: 99 },{ id: 2, name: '商品B', price: 199 }]}})</script>
</body>
</html>
✅ 无需改造整个项目,即可引入 Vue 增强交互。
2. 微前端中的轻量级 Vue 模块
在微前端架构中,主应用可能不使用 Vue,但子应用可以使用非 SFC 方式动态加载 Vue 功能。
3. 快速原型验证
<!-- demo.html -->
<script src="https://unpkg.com/vue@2.7"></script>
<div id="app"><counter :value="count" @increment="count++"></counter>
</div><script>
Vue.component('counter', {props: ['value'],template: '<div>计数: {{ value }} <button @click="$emit(\'increment\')">+</button></div>'
})new Vue({ el: 'app', data: { count: 0 } })
</script>
✅ 几行代码即可验证想法,无需配置工程。
六、注意事项与最佳实践
✅ 推荐做法
- 复杂项目使用 SFC:结构清晰,工具链完善。
- 非 SFC 用于简单功能嵌入:避免过度使用。
- 使用
x-template
提升可读性:避免长字符串模板。 - 注意全局命名污染:优先使用局部注册。
- 手动清理事件/定时器:在
beforeDestroy
中。
❌ 避免
- 在非 SFC 中写大型组件
- 模板字符串中写复杂逻辑
- 忽略浏览器兼容性(如 IE 不支持 ES6)
七、Vue 3 中的非 SFC 支持
Vue 3 依然支持非单文件组件,但推荐使用 CDN + Composition API:
<script src="https://unpkg.com/vue@3"></script>
<div id="app">{{ count }}</div><script>
const { createApp, ref } = VuecreateApp({setup() {const count = ref(0)return { count }}
}).mount('#app')
</script>
✅ Vue 3 的
createApp
更适合 CDN 使用。
八、总结
场景 | 推荐方案 |
---|---|
新项目开发 | ✅ 单文件组件(SFC) |
传统项目嵌入 | ✅ 非单文件组件 |
快速原型 | ✅ 非单文件组件 |
微前端子应用 | ✅ 非 SFC 或独立构建 SFC |
学习 Vue 原理 | ✅ 非 SFC 更直观 |
📌 核心思想:
非单文件组件是 Vue 的“原生形态”,它不依赖构建工具,灵活性高,适用于轻量级、嵌入式场景。
而单文件组件是工程化的产物,更适合大型项目。
九、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!