主题
Vue 快速上手与指令(上)(二)
本页对应 Vue 快速上手与指令(上),共 7 段视频,约 1 小时 0 分。
学习目标
- 能够说明 Vue 响应式数据变化驱动页面更新的机制,并使用 Vue 开发者工具查看、修改数据以验证页面自动更新。
- 能够区分 v-show 与 v-if 的隐藏方式、性能开销和适用场景,并根据频繁或非频繁切换需求选择正确指令。
- 能够使用 v-if、v-else-if、v-else 编写多条件渲染逻辑,正确添加条件并保证分支互斥。
- 能够使用 v-on 的内联语句、methods 方法及
@简写完成事件绑定,并通过this访问 data 中的数据。 - 能够为事件处理函数传递参数,并在模板或方法中正确获取事件对象(
$event或形参)处理输入等交互。 - 能够使用 v-bind 及其简写
:动态绑定src、title、alt等属性,并判断属性值是变量还是普通字符串。
知识点
一、响应式到底解决什么问题
为什么需要:如果按传统写法,数据一改,我们往往要自己找到页面元素,再手动改内容或样式。Vue 的响应式要解决的就是这个麻烦:数据变,视图对应变。
怎么想:把页面看成 data 的映射。data 里的值改了,模板中用到这个值的地方就跟着更新。前面用 v-show、v-if 控制显示隐藏时,条件从 true 改成 false,元素就隐藏;再改回 true,元素又显示,这就是响应式在起作用。
怎么做:在 data 中定义数据,在模板里使用它;需要变化时改数据,而不是先想着 document.querySelector 找元素。
易错点:响应式不是“自动帮你改任意 DOM”,而是“你改实例上的数据,Vue 让视图跟着更新”。不要把它理解成页面先变、数据后变;转写稿调试时明确说过:肯定是 data 先变,数据变了之后页面才更新。
二、如何访问和修改 data 中的数据
为什么需要:data 里的数据最终要被模板和代码访问,必须有一个统一入口。
怎么想:笔记里说得很直接:data 中的数据最终会被添加到实例上。所以访问和修改都围绕“实例”来做。
怎么做:访问用“实例.属性名”,修改用“实例.属性名 = 值”。
js
// 访问数据
实例.属性名
// 修改数据
实例.属性名 = 值
易错点:不要脱离实例直接写属性名;在方法里访问 data 时,要用 this.属性名。转写稿里强调过,直接写 flag 方法里找不到,必须写 this.flag,因为 this 指向 Vue 实例。
三、响应式演示:改数据,看页面自动更新
为什么需要:只看概念容易糊涂,必须用调试过程验证“数据变,视图变”。
怎么想:找一个由数据控制的地方,改 data 中的值,观察页面是否自动更新。
怎么做:转写稿中的调试过程可以这样复现:把条件从 true 改为 false,页面隐藏;再改回 true,页面又显示。用 Vue 调试工具点 true/false 的勾选,数据被改后页面自动更新。点加减按钮时,count 从 100 变成 101,页面数字也跟着变;改分数时,score 从 65 按 shift 减 10 变成 55,成绩评定也从 C 变成 D。整个过程不需要手动找元素改页面。
易错点:改完数据要观察“数据先变、页面后更新”;不要把调试工具里改的值和页面显示割裂开。页面自动更新是结果,不是让你手动再改一遍 DOM。
四、在方法中修改数据:this 指向实例
为什么需要:点击按钮、输入内容等事件里,经常要改 data。方法写在 methods 中,必须能访问到实例数据。
怎么想:methods 与 data 平级;方法内部用 this 访问当前 Vue 实例,所以 this.flag 就是 data 里的 flag。
怎么做:例如点击按钮切换显示隐藏,可以写:
js
this.flag = !this.flag如果做余额扣减,可以写:
js
this.money -= n模板调用方法名要与 methods 中的方法名一致;需要传参时,模板里传几个,函数形参就接几个。
易错点:方法里不要直接写 flag = !flag;方法名写错会提示未定义;传参时形参名和函数体里使用的名字要一致。转写稿里特意用 n 举例:形参叫什么是自由的,但函数体里必须用同一个名字。
五、总结:把“改数据”作为习惯
为什么需要:响应式是 Vue 数据驱动思想的基础,后面指令、事件、属性绑定都会反复用到。
怎么想:先问“这个变化对应哪个 data”,再改那个数据;页面显示交给 Vue 更新。
怎么做:记住三句话:响应式就是数据变、视图对应变;访问和修改 data 用“实例.属性名”;方法里用 this.属性名。调试时可以用调试工具改数据,观察页面自动更新。
易错点:不要把 v-show、v-if 的显示隐藏本身当成响应式原理,它们只是响应式驱动视图更新的表现;不要改数据后又手动操作 DOM;不要忘记 this。把“改数据”练成习惯,后面的案例会顺很多。
本节要解决什么问题
为什么需要:Vue 是数据驱动视图的框架,页面变化往往不是直接改 DOM,而是数据变化后自动更新。只靠浏览器默认的控制台和元素面板,很难快速看清组件里的数据项、条件值和绑定关系,所以需要安装 Vue 开发者工具,也就是 Vue Devtools。
怎么想:先把“安装工具”和“验证工具”分开。安装只是第一步,安装后还要能按 F12 找到 Vue 调试面板,才算真正可用。本节笔记给了两条安装途径:谷歌应用商店和极简插件,其中极简插件被标注为推荐。
怎么做:按下面两条途径任选其一安装;安装完成后打开一个 Vue 页面,按 F12,检查是否多出 Vue 调试面板。
易错点:不要把“装了插件”直接等同于“当前页面一定能看到面板”。安装后先刷新页面、重新打开 F12 再检查;如果当前页面不是 Vue 页面,面板不出现也不奇怪。
安装途径一:通过谷歌应用商店安装
为什么需要:谷歌应用商店是浏览器插件的常规来源,适合能正常访问国外网站的环境。笔记中明确写了“通过谷歌应用商店安装(国外网站)”。
怎么想:如果你的网络环境能打开 Chrome 应用商店,就优先走商店安装;如果打不开,不要在这里反复耗时间,直接换下一种方式。
怎么做:打开谷歌应用商店,找到 Vue 开发者工具并安装;安装完成后在浏览器扩展列表中确认已启用。
易错点:商店访问受网络环境影响,打不开不等于插件本身有问题;安装后要刷新目标页面,不要只在扩展管理页里看“已安装”就结束。
安装途径二:极简插件下载(推荐)
为什么需要:笔记把极简插件标注为“推荐”,并给出地址 https://chrome.zzzmh.cn/index。对访问谷歌商店不方便的环境,这是更实际的安装入口。
怎么想:先进入极简插件站点,再按页面提供的 Vue 开发者工具下载/安装入口操作;具体步骤以笔记图示为准,不凭记忆乱点。
怎么做:打开 https://chrome.zzzmh.cn/index,按图示完成下载与安装。笔记中的安装步骤图如下:

易错点:不要从不明来源随便下载插件包;安装后如果浏览器提示扩展权限或需要启用,按浏览器提示处理,并刷新 Vue 页面再验证。
安装后的验证:F12 看 Vue 面板
为什么需要:安装是否成功,不能只看下载完成,而要在实际页面里看到 Vue 调试面板。笔记明确说:“安装之后可以 F12 后看到多一个 Vue 的调试面板。”
怎么想:验证动作很简单:打开 Vue 页面 → 按 F12 → 找多出来的 Vue 面板。看到面板,才说明当前页面能被工具识别。
怎么做:按 F12 打开开发者工具,观察是否出现 Vue 调试面板。笔记中的效果图如下:

易错点:如果没看到,先刷新页面、关掉 F12 再重开;不要在“扩展已安装”和“页面已识别”之间混淆。
用调试面板观察数据驱动
为什么需要:安装工具的目的不是摆设,而是调试。转写稿里多次用 Vue 调试工具改数据观察页面:调试 v-show/v-if 时,把布尔条件从 true 改成 false,页面立即隐藏;调试成绩评定时改 score,从 65 改到 55、75、85,评定随之变化;调试 v-on 时看 count 从 100 变成 101,或看余额 money 减 5、减 10、减 8;调试 v-bind 时改图片 URL 换图。这些过程说明:面板能直接改组件数据,并触发页面响应式更新。
怎么想:转写稿里的“V杠设/被告的受”应理解为 v-show,“V杆业务/VR if”应理解为 v-if,“圈一可立”应理解为 @click,“myer/mys”应理解为 methods,“daser”应理解为 data。理解这些正确术语后,再看调试面板就不容易被同音字带偏。
怎么做:在 Vue 面板中找到对应数据项,修改布尔值、数字或字符串,观察页面是否自动更新;例如把控制显示隐藏的布尔值改成相反值,把分数改成不同区间,把数量加减,把图片地址换成另一张图。
易错点:调试时改的是数据,不是直接改 DOM;刷新页面后数据会回到初始值,这是正常现象。不要把“面板里改了值”误认为“源码已经改了”。
指令是什么,为什么要先学它
指令是 Vue 提供的、带 v- 前缀 的特殊标签属性。它解决的核心问题是:以前我们操作 DOM 要“找元素、绑事件、改样式”,步骤多且容易和业务逻辑混在一起;Vue 指令让我们更多“改数据”,页面自动更新。按笔记可分六类:内容渲染 v-html/v-text、条件渲染 v-show/v-if/v-else/v-else-if、事件绑定 v-on、属性绑定 v-bind、双向绑定 v-model、列表渲染 v-for。本节重点从条件、事件、属性绑定切入,先建立最常用的写法。
v-show 与 v-if:都控制显隐,底层不同
为什么需要:页面经常要根据条件显示或隐藏元素,比如购物车浮层、登录提示。
怎么想:两者都能按条件控制显隐,但隐藏方式不同,所以适用场景不同。v-show 通过样式 display:none 隐藏,元素还在;v-if 条件为假时直接把元素移除。频繁切换用 v-show,因为不用反复创建/移除;不频繁切换用 v-if 更合理。
怎么做:表达式为真显示,为假隐藏。
html
<div id="app">
<div v-show="flag">v-show 控制的盒子</div>
<div v-if="flag">v-if 控制的盒子</div>
</div>js
data() {
return { flag: true }
}调试时把 flag 改为 false,页面都隐藏;审查元素会发现 v-show 的 div 还在,只是加了 display:none,而 v-if 的 div 被移除了。
易错点:不要因为“都能隐藏”就混用;频繁切换别用 v-if,否则反复创建移除,性能开销更大。
v-if / v-else-if / v-else:多条件分支
为什么需要:一个条件不够时,比如成绩评定要分 A/B/C/D,性别要分男/女。
怎么想:写法跟 JS 的 if / else if / else 一样:带 if 的都要条件,v-else 不加条件。
怎么做:
html
<p v-if="sex === 1">男</p>
<p v-else>女</p>
<p v-if="score >= 90">A</p>
<p v-else-if="score >= 80 && score < 90">B</p>
<p v-else-if="score >= 60 && score < 80">C</p>
<p v-else>D</p>调试时改 score,比如 65 显示 C,改成 85 显示 B,页面随数据自动更新。
易错点:v-else-if 要带条件,v-else 不带条件;条件判断别只写一个等号,那是赋值,至少用 ==,更推荐 ===。
v-on:内联写法与 @ 简写
为什么需要:点击、输入、鼠标移入等都要注册事件。以前 addEventListener 步骤多,Vue 用 v-on 直接绑。
怎么想:逻辑只有一行,可以内联写在模板里;逻辑多行就放到 methods。
怎么做:
html
<button v-on:click="count--">减</button>
<span>{{ count }}</span>
<button @click="count++">加</button>v-on:click 可简写为 @click。点击后先变的是数据,数据变了页面再自动更新。
易错点:内联只适合简单逻辑;不要写“找 span 再改内容”的 DOM 思维,直接改数据。
v-on:methods 中写函数与 this
为什么需要:事件逻辑复杂时,全塞在模板里难维护。
怎么想:函数写在 methods 里,和 data 平级;模板里写方法名。
怎么做:
html
<button @click="toggle">切换</button>
<h1 v-show="flag">标题</h1>js
data() { return { flag: true } },
methods: {
toggle() {
this.flag = !this.flag
}
}易错点:方法里访问 data 要用 this.flag,不能直接写 flag;this 指向当前 Vue 实例。方法名要和模板里调用的名字一致。
v-on:传参和事件对象
为什么需要:不同按钮减不同金额,或输入时读取输入框内容。
怎么想:需要额外数据就传参,形参和实参一一对应;需要事件对象时,模板中用 $event,方法中用形参 e。
怎么做:
html
<button @click="buy(5)">可乐 5 元</button>
<button @click="buy(10)">咖啡 10 元</button>
<input @input="getValue($event)">js
methods: {
buy(n) { this.money -= n },
getValue(e) { this.result = e.target.value }
}易错点:传了几个参数就接几个形参;如果既要传参又要事件对象,要显式把 $event 传进去,并注意顺序一对一。
v-bind:让属性值变成变量
为什么需要:图片 src、提示 title、alt 等属性有时来自 data,需要动态绑定。
怎么想:属性值是普通字符串就不加冒号;属性值是变量或表达式,才在属性名前加 v-bind:。
怎么做:
html
<img v-bind:src="url" v-bind:alt="altText">
<img :src="url" :alt="altText">js
data() {
return {
url: './img/01.png',
altText: '我是波仔'
}
}v-bind: 可简写为 :。改 url 数据,图片会自动换。
易错点:不要“全加冒号”。alt="我是波仔" 是普通字符串,不加冒号;altText 是变量,才写 :alt="altText"。反过来,加了冒号,后面就应写变量或表达式。
其余三类先建立地图
v-html/v-text 属于内容渲染,v-model 属于双向绑定,v-for 属于列表渲染。本节转写重点在条件、事件、属性绑定;这三类先记住归属和用途,后续结合表单、列表案例再展开。学习时抓住同一条主线:先想数据怎么变,再让指令把数据接到页面上,而不是回到手动操作 DOM 的老路。
内容渲染指令要解决什么问题
原生开发里,要把数据显示到页面上,通常得先 querySelector 找到元素,再改 innerText 或 innerHTML。数据一变,还要再手动改一次。Vue 的内容渲染指令就是把“找元素、改内容”这一步交给模板:开发者只在 data 里维护数据,模板里用指令声明“这个元素的内容来自哪个变量”。转写稿里有一句很关键:指令虽然是 Vue 提供的特殊语法,但写的时候“就当成属性来用即可”。所以 v-text、v-html 都写在标签上,等号右边放的是表达式或 data 中的变量。
本节常用两个内容渲染指令:v-text 类似 innerText,v-html 类似 innerHTML。它们都会覆盖标签原有内容,这是最先要记住的点。
v-text:把数据当纯文本渲染
为什么需要:当数据只是普通文本,不希望其中的 <、> 被当成标签解析时,用 v-text 更直接。它类似 innerText,会把内容当纯文本放进元素。
怎么想:模板里写 <p v-text="uname">姓名:</p>,Vue 会去 data 里找 uname,把它的值渲染到 p 中。注意 v-text 会覆盖 p 标签里原来的“姓名:”,不是追加。
怎么做:语法是 <p v-text="变量名"></p>。如果写成 <p v-text="'uname'"></p>,引号里的 uname 才是字符串;不加引号时,uname 是变量/表达式。
易错点:第一,误以为会保留原内容;第二,把变量名写成字符串;第三,v-text 不会解析 HTML 标签,标签会按文本显示。
v-html:把数据当 HTML 渲染
为什么需要:当内容本身是一段带标签的富文本,需要把 <strong>、<h2> 等标签的样式呈现出来时,用 v-html。它类似 innerHTML。
怎么想:<p v-html="intro">简介:</p> 中,intro 是 data 里的变量。Vue 把 intro 的值塞进 p,并且按 HTML 解析,所以 strong 会加粗,h2 会呈现标题样式。它同样会覆盖 p 原有的“简介:”。
怎么做:语法是 <p v-html="变量名"></p>。变量值可以是普通字符串,也可以是包含标签的字符串。
易错点:第一,v-html 会覆盖原内容;第二,它存在 XSS 风险,不要直接把用户输入交给 v-html;第三,示例代码中 intro 末尾写成了 <h2>,严格来说应闭合为 </h2>,浏览器会容错,但结构不严谨;第四,HTML 区域里不要用 // 当注释,代码里的 // 既然指令是... 在 HTML 中会被当成文本显示,应改成 <!-- --> 或删掉。
代码演示与调试观察
笔记代码如下,保留原样:
html
<div id="app">
<h2>个人信息</h2>
// 既然指令是vue提供的特殊的html属性,所以我们写的时候就当成属性来用即可
<p v-text="uname">姓名:</p>
<p v-html="intro">简介:</p>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
uname:'张三',
intro:'<h2>这是一个<strong>非常优秀</strong>的boy<h2>'
}
})
</script>运行后,第一个 p 中原来的“姓名:”会被“张三”覆盖;第二个 p 中原来的“简介:”会被 intro 覆盖,并且 strong 会加粗。可以按转写稿中调试 v-show/v-if 的思路,用浏览器开发者工具或 Vue 调试工具修改 uname、intro,观察页面自动更新;再审查元素看结构:v-text 的 p 里只有文本节点,v-html 的 p 里会生成 h2、strong 等子节点。这样就能直观看出“纯文本”和“解析 HTML”的差别。
小结
v-text 和 v-html 都是内容渲染指令,核心差别是:前者按纯文本处理,后者按 HTML 解析。两者都会覆盖元素原有内容;等号右边要放变量或表达式,不要误写成普通字符串。需要渲染富文本时用 v-html,但必须注意来源安全;只是显示文本时优先用 v-text 或插值。
条件渲染要解决什么问题
条件渲染指令用于按条件控制 DOM 的显示与隐藏。为什么需要:页面上有些内容是否出现取决于数据状态,例如是否登录、成绩等级、性别展示;如果手动操作 DOM,代码会绕且难维护。怎么想:把“条件”交给 Vue,条件为真就显示,为假就隐藏;具体用哪个指令,要看隐藏方式和切换频率。怎么做:本节掌握 v-show、v-if,以及配合 v-if 使用的 v-else、v-else-if。易错点:不要只记“都能隐藏”,要区分隐藏时是改样式还是移除节点。
v-show:用 display 控制显示隐藏
为什么需要:当元素需要频繁切换显示隐藏时,用 v-show 更合适。怎么想:元素仍然留在页面结构中,只切换 CSS 的 display:none,所以切换成本较低。怎么做:语法是 v-show="表达式",表达式值为 true 显示,为 false 隐藏;原理是切换 display:none;场景是频繁切换。转写稿中强调,用审查元素观察时,v-show 控制的盒子并没有被删除,只是加了隐藏样式。

易错点:v-show 不是销毁元素;初始条件为 false 时节点仍在 DOM 中,只是不可见;不要把它当成“条件创建节点”。
v-if:按条件创建或移除节点
为什么需要:当内容要么显示、要么隐藏,且不频繁切换时,用 v-if 更直接。怎么想:条件为真才创建元素节点,条件为假就把元素节点移除,所以它更像“条件渲染”。怎么做:语法是 v-if="表达式",值为 true 显示,为 false 隐藏;原理是基于条件判断是否创建或移除元素节点;场景是不频繁切换。转写稿中提醒:v-if 隐藏时“干脆一些”,直接把元素移除。

易错点:频繁切换时不要优先用 v-if,因为反复创建、移除元素性能开销更大;审查元素时看不到被 v-if 移除的节点,这是正常现象。
在示例中观察 v-show 与 v-if 的差异
为什么需要:只看概念容易混淆,必须通过调试看清“改样式”和“移除节点”的差别。怎么想:先让 flag 为 true,两个盒子都显示;再改为 false,观察页面和 DOM。怎么做:保留下面示例,用 Vue 调试工具把 flag 的勾选去掉,数据变为 false 后页面会自动更新;审查 #app 可以看到 v-show 的盒子还在,只是 display:none,而 v-if 的盒子被移除了。易错点:改的是数据,不是手动找元素改样式;页面能自动更新,是因为数据变化驱动了视图。
js
<div id="app">
<div v-show="flag" class="box">我是v-show控制的盒子</div>
<div v-if="flag" class="box">我是v-if控制的盒子</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
flag: false
}
})
</script>v-else 与 v-else-if:多条件分支
为什么需要:一个条件只能控制“显示/隐藏”,遇到性别、成绩等级这类多分支判断时,需要 v-else 和 v-else-if 辅助 v-if。怎么想:写法类似 JavaScript 的 if / else if / else;带 if 的要写条件,v-else 不写条件。怎么做:v-else-if="表达式" 继续判断,v-else 兜底;它们需要紧接着 v-if 使用。下面示例中 gender 为 2 时显示“女”;score 为 95 时按从高到低判断显示 A。转写稿中调试到 score 为 65 时显示 C,改分数后页面自动切换等级。
js
<div id="app">
<p v-if="gender === 1">性别:♂ 男</p>
<p v-else>性别:♀ 女</p>
<hr>
<p v-if="score >= 90">成绩评定A:奖励电脑一台</p>
<p v-else-if="score >= 70">成绩评定B:奖励周末郊游</p>
<p v-else-if="score >= 60">成绩评定C:奖励零食礼包</p>
<p v-else>成绩评定D:惩罚一周不能玩手机</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
gender: 2,
score: 95
}
})
</script>易错点:v-else 后面不要加表达式;v-else-if 必须带条件;它们要紧接着 v-if 使用,中间不要随意插入其他条件元素;多条件判断要注意顺序,像成绩示例按高到低写,避免前面的条件把后面的情况提前截住。
为什么用 v-on:先建立“改数据”的思路
在原生 JS 里给按钮注册点击事件,通常要先 querySelector 找到元素,再 addEventListener,元素一多就很啰嗦。Vue 提供 v-on 指令专门注册事件,语法是 v-on:事件名="内联语句"、v-on:事件名="处理函数"、v-on:事件名="处理函数(实参)",并且 v-on: 可以简写成 @。
这里要先想清楚:事件触发后,不要总想着“怎么找到 DOM 再改 DOM”,而是改 Vue 实例里的数据;数据一变,页面会自动更新。下面用计数器验证:点“+”时执行 count++,点“-”时执行 count--。
html
<div id="app">
<button @click="count--">-</button>
<span>{{ count }}</span>
<button v-on:click="count++">+</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
count: 100
}
})
</script>调试时可以打开 Vue 调试工具观察:点击加号后,是 count 先变化,随后页面才更新。易错点是内联语句里不要写 this.count++,模板作用域里直接写 count++ 即可。
事件处理函数:逻辑多了就放进 methods
如果点击后只执行一行,内联写法很方便;如果逻辑有多行,就应该写成事件处理函数。处理函数要放在与 data 同级的 methods 配置项中。为什么?因为 methods 专门存放方法,结构清晰;而且 methods 里的普通函数内部 this 指向 Vue 实例,可以通过 this.xxx 访问数据。
以“切换显示隐藏”为例:数据 isShow 控制 h1 的显示隐藏,按钮点击调用 fn,在 fn 中执行 this.isShow = !this.isShow。
html
<div id="app">
<button @click="fn">切换显示隐藏</button>
<h1 v-show="isShow">黑马程序员</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isShow: true
},
methods: {
fn () {
this.isShow = !this.isShow
}
}
})
</script>易错点有两个:第一,方法名必须和模板中写的一致;转写稿里特意演示过,如果模板写了 @click="fn",但 methods 中没有 fn,控制台会报 fn is not defined 一类错误。第二,方法中访问数据要写 this.isShow,不能直接写 isShow。
给处理函数传参:不同按钮减不同的钱
当多个按钮共用同一个处理函数,但需要的参数不同,就要在模板中传实参,例如 @click="fn(5)"、@click="fn(10)"。函数定义时用形参接收,形参叫什么都可以,关键是“一个实参对应一个形参”。
看自动售货机案例:余额 money 初始为 100,点可乐传 5,点咖啡传 10,点牛奶传 8,方法里执行 this.money -= n。
html
<style>
.box {
border: 3px solid #000000;
border-radius: 10px;
padding: 20px;
margin: 20px;
width: 200px;
}
h3 {
margin: 10px 0 20px 0;
}
p {
margin: 20px;
}
</style>
<div id="app">
<div class="box">
<h3>小黑自动售货机</h3>
<button @click="fn(5)">可乐5元</button>
<button @click="fn(10)">咖啡10元</button>
<button @click="fn(8)">牛奶8元</button>
</div>
<p>银行卡余额:{{ money }}元</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
money: 100
},
methods: {
fn (n) {
this.money -= n
}
}
})
</script>易错点:模板里写了 fn(5),方法定义就要有对应形参;不要被形参名字干扰,写 n、x 都可以,只要函数体里使用的是同一个名字。
事件对象:模板中用 $event,方法中用形参 e
有时需要获取事件对象,例如输入框输入时读取 event.target.value。在模板中,Vue 内置了固定写法 $event;如果调用方法时不传参数,方法可以直接用形参 e 接收事件对象;如果既传普通参数又需要事件对象,就要显式传 $event,例如 fn(100, $event),方法中按顺序接收。
例如输入框输入内容,实时写入 result,下方 p 标签展示 result。模板内联写法可用 @input="result = $event.target.value";用方法则写 @input="fn",方法写成 fn (e) { this.result = e.target.value }。
易错点:$event 是模板中的固定写法,不要写成 event;在 methods 中则用形参接收,形参名通常写 e,但本质仍是“一个实参对应一个形参”。
课件图示








代码示例
示例 1:响应式特性 + 内容渲染指令(v-text / v-html)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>响应式 & 内容渲染指令</title>
</head>
<body>
<div id="app">
<h2>个人信息</h2>
<!-- 指令是 Vue 提供的特殊 html 属性,直接当属性写即可 -->
<p v-text="uname">姓名:</p>
<p v-html="intro">简介:</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
uname: '张三',
intro: '<h2>这是一个<strong>非常优秀</strong>的boy</h2>'
}
})
// 响应式演示:打开控制台执行下面两行,页面会自动更新
// app.uname = '李四'
// app.intro = '<h3>换一段简介</h3>'
</script>
</body>
</html>关键行与易错点
data中的数据最终会被添加到实例上,因此访问用实例.属性名(如app.uname),修改用实例.属性名 = 值(如app.uname = '李四'),改完页面自动更新,这就是“数据变,视图对应变”的响应式。v-text="uname"类似innerText,会覆盖标签原有内容,所以<p v-text="uname">姓名:</p>里的“姓名:”不会显示。v-html="intro"类似innerHTML,能把字符串里的标签解析并渲染出样式;同样会覆盖原有内容。不要用它渲染用户输入的内容(有 XSS 风险)。- 易错:把
v-text当成插值写进标签中间,或忘记加引号写成v-text=uname。
示例 2:条件渲染指令(v-show / v-if / v-else-if / v-else)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>条件渲染指令</title>
<style>
.box {
width: 220px;
height: 60px;
line-height: 60px;
text-align: center;
margin: 10px 0;
background: #e8f4ff;
border: 1px solid #7aa7d9;
}
</style>
</head>
<body>
<div id="app">
<!-- 控制显示隐藏的两种方式 -->
<div v-show="flag" class="box">我是v-show控制的盒子</div>
<div v-if="flag" class="box">我是v-if控制的盒子</div>
<hr>
<!-- v-if / v-else:二选一 -->
<p v-if="gender === 1">性别:♂ 男</p>
<p v-else>性别:♀ 女</p>
<hr>
<!-- v-if / v-else-if / v-else:多条件判断 -->
<p v-if="score >= 90">成绩评定A:奖励电脑一台</p>
<p v-else-if="score >= 70">成绩评定B:奖励周末郊游</p>
<p v-else-if="score >= 60">成绩评定C:奖励零食礼包</p>
<p v-else>成绩评定D:惩罚一周不能玩手机</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
flag: true, // 改成 false,两个盒子都会隐藏,但原理不同
gender: 2, // 1 表示男,2 表示女
score: 95 // 可在控制台改:app.score = 65
}
})
</script>
</body>
</html>关键行与易错点
v-show原理是切换display: none,元素节点一直存在(审查元素能看到,只是加了样式),适合频繁切换的场景,如购物车悬浮框。v-if原理是条件为 false 时直接把元素节点移除,为 true 时重新创建,性能开销更大,适合不频繁切换的场景,如“登录后这句提示永远不显示”。v-else/v-else-if必须紧跟在v-if后面使用,中间不能插入其他元素;v-else不加条件,v-else-if必须加条件(“带 if 的都要加条件”)。- 易错:把判断写成
v-if="gender = 1"(单等号是赋值,应为===或==);把v-else写在隔了一个标签之后导致失效。
示例 3:事件绑定(v-on)+ 属性绑定(v-bind)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>事件绑定 & 属性绑定</title>
<style>
.box {
border: 3px solid #000000;
border-radius: 10px;
padding: 20px;
margin: 20px;
width: 240px;
}
h3 { margin: 10px 0 20px 0; }
p { margin: 20px; }
img { width: 180px; display: block; margin: 20px; }
</style>
</head>
<body>
<div id="app">
<!-- 1. 内联语句:逻辑只有一行,直接写在指令里 -->
<button @click="count--">-</button>
<span>{{ count }}</span>
<button v-on:click="count++">+</button>
<!-- 2. 事件处理函数:逻辑较多时,只写方法名 -->
<button @click="toggle">切换显示隐藏</button>
<h1 v-show="isShow">黑马程序员</h1>
<!-- 3. 给事件处理函数传参 -->
<div class="box">
<h3>小黑自动售货机</h3>
<button @click="buy(5)">可乐5元</button>
<button @click="buy(10)">咖啡10元</button>
<button @click="buy(8)">牛奶8元</button>
</div>
<p>银行卡余额:{{ money }}元</p>
<!-- 4. 事件对象:模板中用固定的 $event -->
<input type="text" @input="result = $event.target.value">
<p>你输入的是:{{ result }}</p>
<!-- 5. 属性绑定:值来自 data 时必须加 v-bind,可简写为 : -->
<img v-bind:src="url" :alt="alt" title="静态属性不用绑定">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
count: 100,
isShow: true,
money: 100,
result: '',
url: 'images/logo.png', // 换成你自己的图片路径
alt: '我是波仔'
},
// methods 与 data 平级,所有方法写在这里
methods: {
toggle() {
// methods 中的 this 永远指向 Vue 实例
this.isShow = !this.isShow
},
buy(n) {
// n 是行参,接收 5 / 10 / 8
this.money -= n
}
// 若既传参又想拿事件对象:buy(n, e) {},模板写 @click="buy(5, $event)"
}
})
</script>
</body>
</html>关键行与易错点
v-on:事件名可简写为@,如@click、@input;这是最常用的写法。- 内联语句适合一行逻辑,如
@click="count++"、@click="count--";多行逻辑要抽到methods里,指令处只写方法名(如@click="toggle")。 - 事件处理函数必须写在 和 data 平级的
methods配置项里,方法内部的this都指向 Vue 实例,所以改数据要写this.isShow = !this.isShow,不能直接写isShow。 - 不传参时方法名后不加小括号;一旦要传参就写
buy(5),形参名随意(写n还是x都行),只要形参和函数体里用的名字一致。 - 事件对象:在模板中用
$event(固定写法),如$event.target.value;在 methods 中用形参 e,如handleInput(e) { this.result = e.target.value }。若同时传自定义参数和事件对象,按“一个实参对一个形参”原则写成@click="fn(100, $event)"。 v-bind:src="url"可简写为:src="url":加了冒号,后面的值一定是 data 中的变量或表达式;不加冒号就是普通字符串。像title="静态文字"这种固定值不要加冒号。- 易错:调用方法却忘了在
methods里定义,控制台会报Property or method "fn" is not defined;或把methods写进了data里导致取不到。
常见错误
1. v-else / v-else-if 报“没有相邻的 v-if”
- 现象:控制台报
v-else/v-else-if has no adjacent v-if,页面只渲染一部分分支。 - 原因:
v-else、v-else-if必须紧挨着上一个v-if/v-else-if,中间夹了注释以外的任何元素(包括<hr>、<div>)都会断开配对。 - 修法:把中间元素移到整组条件之外;或用
<template>包住整组判断,保证兄弟节点相邻。
2. methods 里直接写 flag = !flag
- 现象:点击无反应,或报
flag is not defined;DevTools 里 data 完全没变。 - 原因:
methods里的this指向 Vue 实例,data 挂在实例上,裸写的flag是函数内的局部变量(不存在的变量)。 - 修法:一律
this.flag = !this.flag;访问其他方法、计算属性同理,全部走this.。
3. 方法名对不上 → Property or method 'fn' is not defined
- 现象:一进页面就报错,控制台提示某属性/方法未定义,且报错次数等于模板里调用的次数。
- 原因:模板里写了
@click="fn",但methods里没写、拼错,或把方法写进了data、写到了methods外面。 - 修法:
methods与data平级;函数名与模板调用名逐字符核对;多个方法用逗号分隔。
4. 传了参数就拿不到事件对象
- 现象:
@click="fn(5)"后函数里e是undefined,e.target直接报错。 - 原因:一旦显式写了实参,Vue 就不再自动把事件对象塞进第一个形参。
- 修法:手动传
$event,如@click="fn($event, 5)",形参按顺序一一对应接收。
5. 属性值加不加冒号搞混
- 现象:
src="url"图片 404,路径变成了字面量url;或者给纯文本加了冒号导致显示空白/报错。 - 原因:加了
:就按表达式解析,不加就按字符串解析——判断标准只有“这个值是不是变量”。 - 修法:变量用
:src="url",固定文本用src="xxx.png";title="我是波仔"这种不要加冒号。
6. 用 v-text / v-html 还想着保留标签里的文字
- 现象:
<p v-text="uname">姓名:</p>渲染后“姓名:”不见了。 - 原因:这两条指令都会覆盖元素原有内容。
- 修法:前缀文字放进插值或单独标签:
<p>姓名:{{ uname }}</p>;v-html只用于可信内容,避免 XSS。
7. 频繁切换的场景误用 v-if
- 现象:反复点击切换时卡顿;切换后输入框里的内容、组件内部状态被重置。
- 原因:
v-if是销毁/重建节点,v-show只切display。 - 修法:按“切换频率”选:频繁切换(购物车面板、折叠展开)用
v-show;一次性的登录提示、权限区块用v-if。
练习
练习 1:成绩等级(条件链) 用 v-if / v-else-if / v-else 把 score 渲染成 A/B/C/D 四档,并在 DevTools 里手动改 score 验证。要求:四档互斥,页面任何时刻只出现一个 <p>。再故意在 v-if 和 v-else-if 之间插一个 <hr>,观察报错并修好它。
练习 2:显示隐藏双版本对比 同一个“点击按钮切换标题”的功能,用 v-show 和 v-if 各写一遍。F12 打开 Elements,分别在隐藏状态下检查该元素是否还在 DOM 里,用自己的话写下两者的差别。再补一个“切换后输入框内容是否保留”的小实验。
练习 3:计数器(内联 + 简写) 用 data.count 做加减计数器,减号用完整写法 v-on:click="count--",加号用简写 @click="count++"。要求全程不出现任何 DOM 查找代码,只改数据。打开 Vue 调试面板,说出“数据先变还是页面先变”。
练习 4:自动售货机(methods + 传参) 余额 money = 100,三个按钮分别扣 5 / 10 / 8 元。要求:只写一个 buy(n) 方法,三个按钮传不同实参;方法内用 this.money 改数据。验收:连点可乐 3 次余额为 85,且控制台无任何报错。
练习 5:输入框实时同步(事件对象) 输入框内容实时显示到下方 <p>。先用内联写法 @input="result = $event.target.value" 实现;再改成调用方法,方法里接收 e 并 this.result = e.target.value。最后加一个需求:同时把输入长度也显示出来,练习 @input="fn($event, 100)" 这种“事件对象 + 额外实参”的传参顺序。
练习 6:图片轮播雏形(v-bind) 用 data 里的 imgUrl、altText 绑定到 <img>,写两个按钮切换不同图片。要求:src 和 alt 用 : 绑定,title 用普通属性写死一段中文。验收:改 DevTools 里的 imgUrl,图片立即换;页面上不存在字面量形式的路径。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | v-show和v-if指令(33) | 08:37 |
| 2 | v-if和v-else-if和v-else指令(34) | 08:55 |
| 3 | v-on指令(内联写法)(35) | 06:39 |
| 4 | v-on指令(使用函数)(36) | 09:38 |
| 5 | v-on指令(给函数传参)(37-40) | 08:10 |
| 6 | v-on指令(事件对象) | 07:03 |
| 7 | v-bind指令(41) | 11:32 |
小结
- 响应式的核心纪律是“只改数据,不碰 DOM”。上面所有练习一旦出现
querySelector,就是走回老路了——判断自己是否真学懂 Vue,看这一点就够了。 v-show与v-if的选择标准是切换频率,不是功能强弱。能完成同样的事,差的是销毁重建的开销与状态保留。@就是v-on:,:就是v-bind:。看到简写要能瞬间还原成完整指令,这是读懂他人代码和应对面试的基本功。methods里的this永远指向实例,它是访问 data、其他方法、乃至后续计算属性的唯一入口,忘了this就等于换了个变量。- 事件对象在哪用决定怎么写:模板中用
$event,方法形参中用e;显式传参时事件对象不再自动赠送,必须手动按顺序传、按顺序接。 v-bind只有一个判断标准:值是不是变量。加冒号即表达式,不加即字符串,这条规则反过来验证也成立,别凭感觉加。v-text/v-html是覆盖式渲染,要保留原有文字就用插值;v-html有安全风险,只喂可信内容。- 调试顺序固定为“先看 data,再看页面”:DevTools 里数据变了而页面没变,是模板绑定写错;数据都没变,是事件没绑上或方法没生效——按这个顺序排查,绝大多数问题三十秒内定位。