Vue2学习(1)--了解基本方法与概念
本文内容的方法演示也都是通过一个html文件来演示的旨在简易的了解Vue用法。要学习Vue ,先安装好环境试一下创建一个html文件,安装扩展在vscode中安装Volar,Vue(Official)Live ServerLive Server这是一个轻量级的本地静态文件服务器插件。它的核心作用是实时预览。当你修改代码并保存时它会自动刷新浏览器让你立即看到更改效果。重要提示Live Server 仅适用于普通的 HTML/CSS/JS 静态页面。对于真正的 Vue 工程化项目包含 .vue 单文件组件Live Server 无法解析这些文件。Vue 项目必须通过终端运行 npm run dev 来启动开发服务器。怎样创建并使用一个html文件new一个新文件将后缀更改为html内部写完需要的html代码后右下角找到Go Live点击就会自动跳转到默认浏览器打开这个html文件且在你修改代码保存后浏览器会自动刷新。这里有个技巧是输入!按tab就会自动生成一个标准的HTML结构。一、HTML模板为了防止乱码、保证兼容性以及代码规范建议在最前面写例如以下这段的模板代码。!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleVue el 挂载点详解/title !-- 引入 Vue.js -- script srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/script style /* 简单的样式让界面更清晰 */ /style /head代码片段所在位置作用讲解是否必须!DOCTYPE html文件最顶部文档类型声明。告诉浏览器这是一个 HTML5 文档防止浏览器进入怪异模式Quirks Mode。必须 (虽然浏览器能猜但规范开发必须写)html langzh-CN根标签语言定义。langzh-CN告诉搜索引擎和辅助设备如读屏软件该网页主要使用简体中文。建议写 (对 SEO 和无障碍访问很重要)meta charsetUTF-8head内字符编码。指定文档使用 UTF-8 编码。作用防止网页出现乱码特别是中文。必须 (如果不写中文会变成乱码)titleVue el 挂载点详解/titlehead内页面标题。显示在浏览器的标签页上也是搜索引擎抓取的重要信息。建议写 (不写也没语法错误但不专业)script src...vue.js/scripthead内引入 Vue 库。这是 Vue 框架的“引擎”。作用让浏览器认识new Vue()这种语法。必须 (没有它Vue 代码全是报错)style ... /stylehead内内部样式表。用于在 HTML 文档内部集中编写 CSS 样式代码如字体、颜色、布局等控制页面的外观表现。非必须 (如果不需要任何自定义样式可以不写但如果要美化页面则必须有它或外链CSS)二、Vue常用指令学习Vue先来学习一个Vue的常用指令Vue指令是写在HTML标签内部的它们以标签属性的形式存在。1、数据绑定类型v-bind(简写为:):作用用于动态绑定一个或多个 HTML 属性、组件 prop 或样式类名。简单来说就是告诉 Vue“请把引号里的内容当成 JavaScript 变量或表达式去解析而不是当成普通的纯文本字符串”。举例解释1、绑定变量img :srcimageUrl:srcimageUrl作用它的核心作用是告诉 Vue 引擎“不要把我后面的内容当成普通的字符串而是去 JavaScript 的数据如 data中寻找对应的变量”。如果没有这个冒号Vue 会认为你只是想把一张叫 imageUrl 的图片显示出来。2、绑定表达式!-- 三元运算符判断 -- div :classisActive ? active-class : /div !-- 如果Vue中的isActive为true, 渲染到浏览器上的真实 HTML 是 div classactive-class/div 否则渲染到浏览器上的真实 HTML 是 div/div --v-text:作用更新元素的文本内容相当于 {{ }} 插值会覆盖元素原有内容。与{{}}的区别1. 覆盖机制不同v-text 会覆盖元素原有的默认内容。例如 p v-textgender性别/p最终页面上只会显示变量 gender 的值“性别”这两个字会被完全替换掉。{{ }} 只是占位符。例如 p姓名: {{username}}/p它只会替换大括号的位置保留“姓名: ”等原有文本。2. 防闪屏效果在网络较慢、Vue 还未完成编译时使用 {{message}} 可能会让用户短暂看到乱码一样的 {{message}即闪屏现象。而 v-text 直接绑定属性在内容未渲染时该元素内部是空的从而完美避开了这个问题。v-html:作用更新元素的 innerHTML可以渲染真实的 HTML 标签。注意 容易导致 XSS 攻击仅对可信内容使用。举例解释div idapp !-- 使用 v-html 渲染 -- div v-htmlcontent/div /div new Vue({ el: #app, data: { content: h2 stylecolor: blue;Vue渲染HTML/h2p这是一段富文本内容/p } }) !-- 页面上会直接显示出一个蓝色的二级标题和一段正文而不是把 h2 这些标签当作普通文字显示出来。 --防止XSS漏洞1、尽量避免使用。2、前端二次防御比如使用 DOMPurify能自动过滤掉恶意的 script 标签、事件处理器如 onerror以及 javascript: 协议等高危内容。3、后端净化在后端接收到用户提交的内容并写入数据库之前必须使用成熟的后端清洗库进行处理。严格采用白名单机制只允许安全的标签如 b、i、a和安全的属性如限制 a 的 href 只能是 http/https 协议坚决移除未在白名单内的任何内容。2、双向绑定指令v-model:作用能在视图页面输入框和数据JS变量之间建立实时同步通道。举例解释1. 基础文本输入 !-- 单行文本 -- input typetext v-modelusername p你输入的是{{ username }}/p !-- 多行文本 -- textarea v-modelbio/textarea 2. 复选框 (checkbox) !--单个复选框绑定布尔值勾选为 true取消勾选为 false。-- input typecheckbox v-modelisAgree 同意协议 !--多个复选框组绑定数组被勾选的选项的 value 会自动推入该数组取消勾选则移除。-- input typecheckbox v-modelhobbies valuereading 阅读 input typecheckbox v-modelhobbies valuecoding 编程 3. 单选按钮 (radio) !--多个 radio 共享同一个 v-model 变量当前选中项的 value 会被赋给该变量。-- input typeradio v-modelgender valuemale 男 input typeradio v-modelgender valuefemale 女 4. 下拉选择框 (select) !--v-model 绑定的是 option 标签的 value 属性而不是显示的文本。-- select v-modelselectedCity option disabled value请选择城市/option option valuebeijing北京/option option valueshanghai上海/option /select提供修饰符.lazy默认情况下每次敲击键盘都会触发更新加上 .lazy 后只有在输入框“失去焦点”或按回车时才更新数据非常适合搜索框防抖。.number自动将用户输入转换为数值类型避免1 2 12这种字符串拼接问题。input v-model.numberage typenumber.trim自动过滤用户输入的首尾空白字符。3、条件与列表渲染指令v-if/v-else-if/v-else作用根据表达式的真假来决定是否渲染元素。条件为假时会直接将元素从 DOM 树中彻底销毁删除条件为真时再重新创建。适用于切换不频繁的场景如权限控制、用户登录状态。举例解释!DOCTYPE html html langzh-CN head meta charsetUTF-8 titlev-if / v-else-if / v-else 演示 (Vue 2版)/title !-- 引入 Vue 2 -- script srchttps://unpkg.com/vue2/dist/vue.js/script style body { font-family: Arial, sans-serif; padding: 20px; line-height: 1.6; } .box { margin-top: 15px; padding: 10px; border-radius: 4px; background-color: #f4f4f4; } button { padding: 5px 10px; cursor: pointer; } /style /head body div idapp !-- 1. 基础多分支条件链 -- h2学生成绩评级/h2 input typenumber v-model.numberscore placeholder请输入分数(0-100) / div classbox p v-ifscore 90 优秀表现非常棒/p p v-else-ifscore 60✅ 及格继续加油哦/p p v-else❌ 不及格需要复习啦。/p /div /div script new Vue({ el: #app, data() { return { score: 60 // 默认分数为 60 }; } }); /script /body /html可以看到分数不一样走的if分支不一致。v-show作用无论条件真假元素都会被渲染只是通过切换 CSS 的 display: none 来控制隐藏。初始渲染开销稍大但频繁切换的性能更好如弹窗、折叠面板。举例解释!DOCTYPE html html langzh-CN head meta charsetUTF-8 titlev-show 控制显隐示例/title !-- 引入 Vue 2 -- script srchttps://unpkg.com/vue2/dist/vue.js/script style body { font-family: Arial, sans-serif; padding: 20px; line-height: 1.6; } .box { margin-top: 15px; padding: 15px; border-radius: 4px; background-color: #f4f4f4; max-width: 400px;} button { padding: 8px 15px; cursor: pointer; background-color: #42b983; color: white; border: none; border-radius: 4px;} button:hover { background-color: #3aa773; } /style /head body div idapp !-- 1. 触发切换的按钮 -- button clicktoggleShow点击切换文本显隐/button !-- 2. 被 v-show 控制的元素 -- div classbox v-showisVisible 你好我是被 v-show 控制的文本。br 当你点击上面的按钮时我会瞬间消失或出现。 /div /div script new Vue({ el: #app, data() { return { // 定义响应式变量初始值为 true默认显示 isVisible: true }; }, methods: { // 定义切换函数反转 isVisible 的值 toggleShow() { this.isVisible !this.isVisible; } } }); /script /body /html点击按钮后isVisible反转状态v-for作用基于数组或对象循环渲染 DOM 列表。使用时强烈建议绑定唯一的 key 属性如 :keyitem.id这能帮助 Vue 高效追踪节点状态避免列表排序或过滤时出现状态错乱。核心规则参数作用遍历数组时最多2个参数第 1 个参数固定代表当前项的值数组元素。第 2 个参数可选固定代表索引从0开始。遍历对象时最多3个参数第 1 个参数固定代表属性的值 (Value)。第 2 个参数可选固定代表属性的键名 (Key)。第 3 个参数可选固定代表遍历的索引 (Index)。遍历整数或字符串时最多2个参数第 1 个参数固定代表当前的迭代值数字从1递增字符串为单个字符。第 2 个参数可选固定代表索引从0开始。举例解释!DOCTYPE html html langzh-CN head meta charsetUTF-8 titlev-for 列表渲染演示 (Vue 2)/title !-- 引入 Vue 2 -- script srchttps://unpkg.com/vue2/dist/vue.js/script style body { font-family: Arial, sans-serif; padding: 20px; line-height: 1.6; } .box { margin-top: 15px; padding: 10px; border-radius: 4px; background-color: #f9f9f9; max-width: 400px;} ul { list-style-type: none; padding: 0; } li { padding: 5px 0; } /style /head body div idapp !-- 1. 遍历普通数组 -- h3游戏列表/h3 div classbox ul !-- item 代表数组中的每一项index 代表索引从0开始 -- li v-for(item, index) in games :keyindex {{ index 1 }}. {{ item }} /li /ul /div !-- 2. 遍历对象数组 -- h3 stylemargin-top: 20px;人员信息/h3 div classbox ul li v-for(p, index) in persons :keyp.id strong{{ index 1 }}. {{ p.name }}/strong 的详细信息br !--遍历对象 这里就是传入的前两个参数还可以继续加一个index -- span v-for(val, key) in p :keykey {{ key }}: {{ val }} /span /li /ul /div !-- 3. 迭代整数 当直接使用 v-forn in 10 这种形式时 n代表当前的迭代次数它的值会从 1 开始递增直到达到指定的整数上限例如这里的 10。 -- h3 stylemargin-top: 20px;数字生成/h3 div classbox span v-forcount of 5 :keycount stylemargin-right: 10px; {{ count }} /span /div /div script new Vue({ el: #app, data() { return { // 普通字符串数组 games: [三角洲, 王者, 燕云], // 对象数组 persons: [ { id: 1, name: 张三, age: 18 }, { id: 2, name: 李四, age: 20 }, { id: 3, name: 王五, age: 22 } ] }; } }); /script /body /html4、事件处理指令v-on:缩写完整语法v-on:click处理语句简写click处理语句与v-bind区别v-bind是将当前属性绑定后面的script变量v-on是当前方法触发后执行后面的script语句作用监听 DOM 事件的核心指令它的主要作用是实现用户与页面的交互。当指定的事件如点击、输入等被触发时Vue 会执行相应的 JavaScript 代码。修饰符.prevent阻止默认行为。例如 form submit.preventonSubmit 可以阻止表单提交后页面刷新。.stop阻止事件冒泡。例如 a click.stopdoThis 点击时不会向外层父级元素传递点击事件。.once确保事件只触发一次。例如 button click.onceshout(1)ok/button。举例解释!--1、内联事件处理器适合极简单的逻辑 你可以直接在模板中编写简单的表达式。 -- button clickcount点击 1/button p当前计数{{ count }}/p !--2、方法事件处理器 将事件绑定到在 methods 中定义的函数上。这样可以让模板保持整洁且逻辑更易维护。 -- button clickgreet打招呼/button methods: { greet() { alert(Hello Vue!); } } !--3、传递参数与获取原生事件对象 ( $ event) 有时候需要同时传递自定义参数和原生的 DOM 事件对象这时可以使用特殊的 $event 变量 -- button clickwarn(hello, $event)点我警告/button methods: { warn(message, event) { console.log(message); // 输出: hello console.log(event.target.tagName); // 输出: BUTTON (获取触发事件的DOM元素) } }经常配合使用的处理语句$emit)button click$emit(add-cart,value)做事情/button这里的 $emit(add-cart) 就像是子组件向外发射了一个名为 add-cart 的信号弹。而在父组件里add-cart 就是专门用来捕捉这个信号弹的雷达。一旦子组件触发了这个事件父组件就会立刻执行等号后面的方法。!--父组件中-- add-cartmethod 一旦子组件触发了这个事件父组件就会立刻执行等号后面的method方法 methods:{ method(value){ console.log(使用了{value}); }; }5、辅助指令v-pre跳过编译告诉 Vue 编译器“完全忽略这个区域”。它会跳过当前元素及其所有子节点的编译过程Vue 不会解析其中的任何插值表达式如{{ message }}、指令或组件语法而是将其作为纯静态 HTML 原样输出。适用场景展示原始代码在编写技术文档或教程时需要原样展示 {{ message }} 这样的文本而不是让 Vue 去解析它。纯静态内容大段不需要 Vue 管理的说明文字、版权信息、法律条款等使用它可以减少不必要的 AST 遍历与指令解析降低首次挂载时的内存占用。v-once只渲染一次实现“单次渲染语义”。元素或组件在首次渲染后就会被标记为静态节点。此后无论响应式数据如何变化Vue 都会跳过该节点的后续更新和虚拟 DOM 差异对比diff视图永远保持第一次渲染的样子。注意如果你把本应随数据变化的区域加了 v-once会导致界面“假死”用户看到旧数据而无法刷新。v-cloak防止页面闪烁解决页面初次加载时的“未编译模板闪现”问题。当网络较慢或 Vue 尚未完成挂载时用户可能会短暂看到原始的 {{ message }} 标签。v-cloak 会保留在元素上直到 Vue 实例挂载完成后才自动移除。需要配合CSS使用。6、自定义指令1、注册方式全局注册使用 Vue.directive(指令名称, { ... }) 方法注册后可以在项目任意组件中使用。局部注册在组件的 directives 选项中定义仅在当前组件内可用。2、钩子函数与核心参数一个指令的定义对象可以提供多个可选的钩子函数最常用的包括bind指令第一次绑定到元素时调用常用于初始化设置。inserted被绑定的元素插入父节点时调用常用于获取焦点等 DOM 操作。update所在组件的 VNode 更新时调用。unbind指令与元素解绑时调用常用于清理工作如移除事件监听器。这些钩子函数会接收以下核心参数el指令所绑定的真实 DOM 元素可以直接对其进行样式或属性修改。binding一个包含指令信息的对象。最常用的是 binding.value获取传递给指令的绑定值、binding.arg传给指令的参数以及 binding.modifiers修饰符对象。示例!DOCTYPE html html langzh-CN head meta charsetUTF-8 titlev-color 自定义指令演示 (Vue 2)/title !-- 引入 Vue 2 -- script srchttps://unpkg.com/vue2/dist/vue.js/script style body { font-family: Arial, sans-serif; padding: 30px; line-height: 1.6; } .demo-box { margin-top: 20px; padding: 15px; border-radius: 4px; background-color: #f9f9f9; max-width: 500px;} button { padding: 6px 12px; margin-right: 8px; cursor: pointer; border-radius: 4px; border: 1px solid #ccc;} p { font-size: 20px; font-weight: bold; margin: 10px 0;} /style /head body div idapp h2 v-color 自定义指令效果展示/h2 div classdemo-box !-- 使用自定义指令将当前 textColor 的值传递给 binding.value -- p v-colortextColor这是一段会随数据变化的文字/p p当前绑定的颜色值code{{ textColor }}/code/p !-- 通过点击按钮修改响应式数据从而触发 update 钩子 -- button clicktextColor red变红/button button clicktextColor blue变蓝/button button clicktextColor #FF9800变橙/button /div /div script // 1. 全局注册自定义指令 v-color Vue.directive(color, { // 当指令第一次绑定到元素时调用初始化 bind(el, binding) { el.style.color binding.value; }, // 当所在组件的 VNode 更新时调用数据发生变化时重新执行 update(el, binding) { el.style.color binding.value; } }); // 2. 创建 Vue 实例 new Vue({ el: #app, data() { return { textColor: green // 初始颜色 }; } }); /script /body /html初始默认是红色证明bind起到了作用而点击变蓝文字会变蓝证明了update起到了作用。三、Vue常用方法学完了常用指令再来看看Vue的常用方法Vue 中的方法本质上就是 JavaScript 代码1、data定义响应式数据作用数据的源头Vue 会自动监听这里的变量变化并刷新页面。2、methods事件处理与业务逻辑作用存放各种函数通常用来响应用户的点击click或表单提交等操作。3、computed计算属性作用基于现有数据自动计算出新的值。自带缓存机制只有当依赖的数据发生变化时才会重新计算。常用于字符串拼接、列表过滤等。示例!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleVue computed/title script srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/script /head body div idapp p姓input v-modelfirstName/p p名input v-modellastName/p !-- 像普通变量一样使用不需要加括号 -- h2全名{{ fullName }}/h2 /div script new Vue({ el: #app, data() { return { firstName: 张, lastName: 三 } }, computed: { fullName() { // 只要 firstName 或 lastName 变了这里就会自动重新执行 return this.firstName this.lastName; } } }); /script /body /html当姓或者名修改的时候全名自动修改4、watch侦听器作用专门用来“盯”某个特定数据的变化。一旦该数据发生改变就立刻去执行一段特定的逻辑比如发送网络请求、打印日志。数据变化传参规则Vue 在检测到数据变化时会按照严格的顺序把值塞进这两个参数里第一个参数 代表变化后的新值。第二个参数代表变化前的旧值。名字是可以随便起的示例!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleVue watch/title script srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/script /head body div idapp p搜索框input v-modelkeyword placeholder随便输入点什么/p p stylecolor:gray;请打开浏览器控制台(F12)查看打印结果/p /div script new Vue({ el: #app, data() { return { keyword: } }, watch: { // 监听 keyword 的变化 keyword(newVal, oldVal) { console.log(关键词从 ${oldVal} 变成了 ${newVal}); // 实际开发中这里通常会写 axios.get(...) 去请求后端接口 } } }); /script /body /html可以看到在输入1,2,3的过程中keyword值变化这个函数也执行了打印日志。在这个例子中它只是打印了日志。但在实际开发中watch最常见的用途是“防抖”和“发送请求”。5、mounted生命周期钩子作用在组件的 DOM 元素完全渲染到页面上之后触发。非常适合用来获取 DOM 节点、初始化第三方图表库等。具体意思Vue实例初始化完成过后并且页面上的 DOM 节点HTML标签已经真实渲染出来了Vue 就会自动帮你运行 mounted() 里的代码。我们可以把 Vue 启动的过程分成几个关键节点准备阶段Vue 读取了你的 data知道了 name Hello Vue!但此时页面上还是空的或者显示着原始的 {{ name }} 占位符。挂载阶段Vue 在内存里把 {{ name }} 替换成了 Hello Vue!准备好了最终的 HTML但还没把它贴到网页上。完成挂载Vue 把准备好的 HTML 正式贴到了网页上。就在这一瞬间mounted() 的代码才会被执行。特点只执行一次在组件的整个生命周期里mounted() 只会执行一次。示例!DOCTYPE html html head meta charsetutf-8 script srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/script /head body div idapp !-- 1. 页面上有一个元素 -- h1 reftitle等待被修改.../h1 !-- 2. 有一个按钮点击后会改变元素内容 -- button clickchangeText点击我改变文字/button /div script new Vue({ el: #app, mounted() { // 3. Vue一挂载页面一显示立刻执行这里的代码 console.log(页面已经显示在屏幕上了); // 安全地操作DOM this.$refs.title.innerText 我是 mounted 钩子修改的文字; this.$refs.title.style.color red; }, methods: { changeText() { // mounted 里的代码执行完后这个按钮的功能依然可用 this.$refs.title.innerText 文字被用户点击改变了; } } }); /script /body /html可以看到界面初始上的文字并不是等待被修改...,而是我是 mounted 钩子修改的文字证明mounted在HTML渲染完毕后立即就执行了。点击按钮仍然可以改变内容。四、其他常用需注意这里还有一些我觉得需要注意的点1、el:挂载点核心作用决定了 Vue 的势力范围。常用写法#id通过 ID 查找最常用div idapp.class通过类名查找div classcontainertag通过标签名查找body(不推荐)示例解说!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleVue el 挂载点详解/title !-- 引入 Vue.js -- script srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/script /head body !-- 区域 A被 Vue 管理的区域 (通过 idapp 绑定) -- div idapp classbox managed h3区域 AVue 的势力范围 (el: #app)/h3 p当前数据strong{{ message }}/strong/p button clickchangeMessage点击我修改数据/button p stylefont-size: 12px;(这里的 {{ message }} 会被替换成真实数据)/p /div !-- 区域 B未被 Vue 管理的区域 (没有对应的 el) -- div idother-zone classbox unmanaged h3区域 B普通 HTML 区域/h3 p当前数据strong{{ message }}/strong/p button clickchangeMessage点击我修改数据/button p stylefont-size: 12px;(注意看这里的 {{ message }} 没有被解析直接显示出来了)/p /div script // 创建 Vue 实例 var vm new Vue({ // 【关键点】这里指定了 elVue 只会去管 id 为 app 的那个 div el: #app, data: { message: 你好我是 Vue }, methods: { changeMessage: function() { alert(数据正在被修改); } } }); /script /body /html可以看到区域A的Message被解析成了“你好我是Vue!而区域B的没有而点击区域B的”点击我修改数据按钮没反应点击区域A的”点击我修改数据“会有弹出以下提示。1、完成两个挂载第一步修改 HTML增加第二个容器在body 中除了原来的 div idapp我们再添加一个 div idapp2body div idapp !--传递自定义参数事件修饰符 -- input typebutton value点击改名 clickChangeUser !--vue修改数据方式this.变量名-- h2{{username}}/h2 /div div idapp2 h2 clickchangeUser{{username}}/h2 /div /body第二步编写 JavaScript创建两个实例在 script 标签中我们实例化两次 new Vue()script var app new Vue({ el: #app, data: { username: 张三 }, methods:{ ChangeUser:function(){ this.username张四; } } }); var app2 new Vue({ el: #app2, // 指定第二个挂载点 data: { username: 李四 }, methods: { changeUser: function () { app.username 赵五; } } }); /script不同的Vue也可以通过名字引用其他Vue的成员。这里点击改名只会修改张三为张四点击李四会修改张三为赵五。2、template 和 div 的对比特性divtemplate(内部包裹器)最终渲染结果会直接渲染为真实的 DOM 节点不会渲染到页面上属于“隐形”容器主要用途用于页面的视觉布局、组织结构、添加样式仅用于组织代码逻辑避免产生冗余的 DOM 节点支持v-show支持通过 CSSdisplay:none隐藏不支持因为它本身就不生成 DOM 节点当你在一个标签上写了 v-foritem in list 时Vue 会把这个标签当作一个模具根据数组的长度循环克隆出多少个一模一样的标签。 假设你的数据 list 有 3 条数据我们来看看这两种写法的区别示例1把 v-for 写在 div 上ul div v-foritem in list :keyitem.id li{{ item.name }}/li span{{ item.desc }}/span /div /ulVue 会把 div 作为模具进行 3 次克隆。最终浏览器解析出来的真实 DOM 结构是这样的ul !-- 第1个克隆出的 div -- div li苹果/li span红色的水果/span /div !-- 第2个克隆出的 div -- div li香蕉/li span黄色的水果/span /div !-- 第3个克隆出的 div -- div li橘子/li span酸甜的水果/span /div /ul页面上凭空多出了 3 个 div 盒子可能会破坏你原本写好的 CSS 排版样式。2把 v-for 写在 template 上ul template v-foritem in list :keyitem.id li{{ item.name }}/li span{{ item.desc }}/span /template /ulVue 在执行 v-for 时虽然也是克隆了 3 次但 template 自身在渲染完毕后会自动“消失”。--------------------------------------------------------------------------------------------------------------------------------本篇结束