广告

Vue 3:无需单文件组件即可创建响应式应用实例的完整指南

一、快速上手:在不使用单文件组件的前提下创建应用实例

在 Vue 3 中,无需单文件组件也能构建完整的响应式应用。核心在于使用 Vue.createApp API 来创建应用实例,并通过根节点挂载到页面上。你可以选择 CDN 引入或现代打包工具,从而避免 SFC 的编译步骤。

无 SFC 的工作流强调将数据、模板与渲染逻辑放在一个简单的入口中,降低入门门槛,同时保持响应性和组件化思想的可维护性。

准备工作与环境

你需要一个可运行的浏览器环境,以及一个可用的入口文件。若使用 CDN,请在页面中引入 Vue 3 的全局对象;若使用打包工具,请确保安装了 @vue/runtime-dom,以便在浏览器中挂载与渲染。

核心目标是创建一个最小可用的应用实例,具备数据响应和模板渲染能力,而不需要任何 .vue 文件。

使用 CDN 构建最小示例

通过 CDN 使用 Vue 3 时,可以直接在全局对象 Vue 上调用 createApp,并用一个简单的模板字符串来渲染内容。

为了演示完整的工作流程,下面给出一个最小示例的要点:首先在 HTML 中定义根容器,然后在脚本中创建并挂载应用。

// CDN 引入后的最小示例(无 SFC)
const app = Vue.createApp({setup() {const count = Vue.ref(0)function inc() { count.value++ }return { count, inc }},template: `
计数:{{ count }}
` }) app.mount('#app')

此外,需要一个根容器,例如在同一 HTML 文件中放置 <div id="app"></div>,Vue 将把模板渲染到这里。

在模块化项目中引入 Vue 进行创建

若你使用打包工具,如 Vite、Webpack,请从 npm 安装 Vue,并以模块化方式导入。核心仍然是 Vue.createApp,但你可以组合更复杂的逻辑。

示例场景包括使用组合式 API、使用渲染函数自行渲染内容,或者将模板写在普通的字符串中以保持无 SFC 的简单性。

// 使用 ESM 模块(非 SFC 的常用模式)
import { createApp, ref } from 'vue'const App = {setup() {const message = ref('欢迎使用 Vue 3 的无 SFC 模式')return { message }},template: `
{{ message }}
` } createApp(App).mount('#app')

二、核心概念:响应式数据在无 SFC 情况下的实现

ref 与 reactive 的使用

在不使用 SFC 的前提下,refreactive 提供了核心的响应式能力。你可以把简单的数值绑定到模板,也可以把对象转为响应式数据以便在 UI 中直接使用。

ref 创建的值需要通过 .value 访问与修改;reactive 将对象包装为响应式代理,直接在模板中引用对象属性即可。

const app = Vue.createApp({setup() {const count = Vue.ref(0)const user = Vue.reactive({ name: 'Alice', role: '开发者' })function bump() { count.value++ }return { count, user, bump }},template: `
用户: {{ user.name }},计数: {{ count }}
` }) app.mount('#app')

计算属性与副作用

为了从现有数据派生新值,可以使用 Vue.computed;同时,可以通过副作用 API 观察数据变化,响应式系统会在相关值更新时重新渲染。

计算属性会根据依赖自动缓存,避免不必要的重复计算;watchEffect 则在依赖变化时执行副作用函数,便于实现简单的自动化响应。

const app = Vue.createApp({setup() {const count = Vue.ref(1)const double = Vue.computed(() => count.value * 2)Vue.watchEffect(() => {console.log('当前计数值:', count.value)})return { count, double }},template: `
计数: {{ count }}, 双倍: {{ double }}
` }) app.mount('#app')

生命周期与副作用清理

尽管没有 SFC,Vue 的组合式 API 仍然提供了生命周期钩子,用于在应用挂载、更新和卸载时执行逻辑。常用的有 onMountedonUnmounted 等。

通过这些钩子,你可以在组件进入页面时执行初始化,在离开页面时进行资源清理,从而避免内存泄漏与多次订阅的问题。

const app = Vue.createApp({setup() {const started = Vue.ref(false)Vue.onMounted(() => {started.value = trueconsole.log('应用已挂载')})Vue.onUnmounted(() => {console.log('应用已卸载,清理资源')})return { started }},template: `
已挂载: {{ started }}
` }) app.mount('#app')

三、实战示例:逐步搭建一个可响应的计数器应用

HTML 结构与根实例

要在无 SFC 的前提下实现一个可响应的计数器,首先需要一个根容器来承载应用。这里的根容器与模板将直接绑定,避免额外的组件文件。

根容器是应用生命周期的锚点,通过 id 与挂载点实现绑定与渲染。

<div id="app"></div>

通过上面的根容器,可以在后续的脚本中对应用进行创建、绑定与交互。

Vue 3:无需单文件组件即可创建响应式应用实例的完整指南

脚本:创建与绑定应用实例

在这个阶段,我们通过 Vue.createApp 创建应用实例,使用 ref 维护计数状态,并通过模板来呈现交互控件。

要点在于明确数据源、事件处理与渲染模板的绑定,确保 UI 能够正确地响应用户操作。

const app = Vue.createApp({setup() {const count = Vue.ref(0)function increment() { count.value++ }return { count, increment }},template: `
当前计数:{{ count }}
` }) app.mount('#app')

优化与注意事项

在无 SFC 的场景下,注意保持模板简洁、将复杂逻辑拆分到可重用的函数中,并合理使用 refcomputedwatchEffect 来控制重新渲染的范围。

如果项目逐渐变大,考虑将公共逻辑提取为可复用的组合式函数,并适时引入组件化结构,但这并不一定要求走 SFC 路线。通过合理组织,仍然可以保持清晰的代码组织和良好的开发体验。

// 仅示意:将公共逻辑提取为组合式函数
function useCounter(start = 0) {const count = Vue.ref(start)function inc() { count.value++ }return { count, inc }
}const App = {setup() {const { count, inc } = useCounter(5)return { count, inc }},template: `
计数: {{ count }}
` } Vue.createApp(App).mount('#app')

广告