<template> <div> <h1>{{ message }}</h1> <button @click="changeMessage">改变消息</button> </div> </template> <script> export default { data() { return { message: '初始消息' }; }, methods: { changeMessage() { this.message = '消息已改变'; } } }; </script> <style scoped> h1 { color: blue; } </style>在上述代码中,<template> 定义组件 HTML 结构,含标题与按钮,用双花括号{{ }}数据绑定,按钮绑定点击事件。<script> 以export default导出包含数据message(用于模板显示)及方法changeMessage(改变message值)的对象。<style> 设定组件内 h1 标签文字颜色为蓝色。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>堆代码 duidaima.com</title> <style> [data-v="component1"].test { color: blue; font-size: 24px; } [data-v="component2"].test { color: red; font-size: 20px; } </style> </head> <body> <div data-v="component1" class="test"> <h1>这是组件1的标题</h1> <p>这是组件1的一些内容描述。</p > </div> <div data-v="component2" class="test"> <h1>这是组件2的标题</h1> <p>这是组件2的一些内容描述。</p > </div> </body> </html>
加上作用域的样式,就只会作用于对应的作用域。如果是 vite 的话,使用的是 vIte 服务器( vite 启动后会在浏览器上启动一个服务器,用于模块的编译)里的 @vue/compiler-sfc。效果跟 vue2 的是一样的。具体也会在后面讲解。
// 读取.vue文件内容 function readVueFile(filePath) { // 简单假设能读取到文件内容,实际需用Node.js文件系统API处理 return vueFileContent; } // 堆代码 duidaima.com // 拆分.vue文件为template、script、style部分 function splitVueFile(vueFileContent) { return [ vueFileContent.match(/<template>([\s\S]*?)<\/template>/)[1].trim(), vueFileContent.match(/<script>([\s\S]*?)<\/script>/)[1].trim(), vueFileContent .match(/<style([\s\S]*?)>([\s\S]*?)<\/style>/)[2] .trim(), ]; } // 编译template为渲染函数 function compileTemplate(template) { // <template> // <div> // <h1>{{ message }}</h1> // <button @click="changeMessage">改变消息</button> // </div> // </template> returnfunction render() { // 经过一系列逻辑,处理成下面这样 return h("div", [ h("h1", this.message), h( "button", { on: { click: this.changeMessage, }, }, "改变消息" ), ]); }; } // 提取script内容作为模块(简化处理) function extractScriptModule(script) { return script; } // 处理style(简单处理scoped添加作用域,很简化) function handleStyle(style) { if (style.includes("scoped")) { return style.replace(/([^\s,]+)/g, "$1[data-v-uniqueId]"); } return style; } // 主函数模拟处理整个.vue文件 function processVueFile(filePath) { const content = readVueFile(filePath); const [template, script, style] = splitVueFile(content); const renderFunction = compileTemplate(template); const scriptModule = extractScriptModule(script); const processedStyle = handleStyle(style); return { template: renderFunction, script: scriptModule, style: processedStyle, }; } // 示例调用 const result = processVueFile("example.vue");1. 模板部分,就是被编译成渲染函数。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Vue App without SFC</title> <link rel="stylesheet" href="styles.css"> </head> <body> <div id="app"></div> <script src="vue.js"></script> <script src="app.js"></script> </body> </html>在styles.css文件中定义样式:
h1 { color: green; }在app.js文件中编写 Vue 应用的逻辑并实例化 Vue:
var app = new Vue({ el: '#app', data: { message: 'Hello from non - SFC Vue' }, methods: { changeMessage() { this.message = 'Message changed'; } }, template: ` <div> <h1>{{ message }}</h1> <button @click="changeMessage">Change Message</button> </div> ` });这种方式存在一些明显的弊端: