Skip to content

Vue 快速上手与指令(上)(二) ​

本页对应 Vue 快速上手与指令(上),共 7 段视频,约 1 小时 0 分。

学习目标 ​

  1. 能够说明 Vue 响应式数据变化驱动页面更新的机制,并使用 Vue 开发者工具查看、修改数据以验证页面自动更新。
  2. 能够区分 v-show 与 v-if 的隐藏方式、性能开销和适用场景,并根据频繁或非频繁切换需求选择正确指令。
  3. 能够使用 v-if、v-else-if、v-else 编写多条件渲染逻辑,正确添加条件并保证分支互斥。
  4. 能够使用 v-on 的内联语句、methods 方法及 @ 简写完成事件绑定,并通过 this 访问 data 中的数据。
  5. 能够为事件处理函数传递参数,并在模板或方法中正确获取事件对象($event 或形参)处理输入等交互。
  6. 能够使用 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 数据挂到实例上

易错点:不要脱离实例直接写属性名;在方法里访问 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开发者工具安装步骤示意图

易错点:不要从不明来源随便下载插件包;安装后如果浏览器提示扩展权限或需要启用,按浏览器提示处理,并刷新 Vue 页面再验证。

安装后的验证:F12 看 Vue 面板 ​

为什么需要:安装是否成功,不能只看下载完成,而要在实际页面里看到 Vue 调试面板。笔记明确说:“安装之后可以 F12 后看到多一个 Vue 的调试面板。”

怎么想:验证动作很简单:打开 Vue 页面 → 按 F12 → 找多出来的 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 与 v-if 对比图

易错点:v-show 不是销毁元素;初始条件为 false 时节点仍在 DOM 中,只是不可见;不要把它当成“条件创建节点”。

v-if:按条件创建或移除节点 ​

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

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,但本质仍是“一个实参对应一个形参”。

课件图示 ​

课件第24页:我们已经掌握了基础的模板渲染,其实除了基本的模板渲染,Vue背后还做了大量工作。

课件第25页:数据 视图界面 修改数据 数据改变,视图会自动更新 自动更新视图 Dom操作 监

课件第26页:总结 总结 1. 什么是响应式呢? 数据改变,视图自动更新 使用Vue 开发→

课件第33页:v-show 1. 作用:控制元素显示隐藏 2. 语法:v-show = "表达

课件第36页:Vue 指令v-on 1. 作用:注册事件 2. 语法: ①v-on:事件名=

课件第44页:Vue 指令v-for 1. 作用:基于数据循环,多次渲染整个元素 2. 遍历数

课件第53页:Vue 指令v-model 1. 作用: 给表单元素使用, 双向数据绑定 ①数据

课件第2页:Angular Vue React 【Vue】前端必备岗位技能

代码示例 ​

示例 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>姓名:&#123;&#123; uname &#125;&#125;</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,图片立即换;页面上不存在字面量形式的路径。

原视频对照 ​

#视频时长
1v-show和v-if指令(33)08:37
2v-if和v-else-if和v-else指令(34)08:55
3v-on指令(内联写法)(35)06:39
4v-on指令(使用函数)(36)09:38
5v-on指令(给函数传参)(37-40)08:10
6v-on指令(事件对象)07:03
7v-bind指令(41)11:32

小结 ​

  1. 响应式的核心纪律是“只改数据,不碰 DOM”。上面所有练习一旦出现 querySelector,就是走回老路了——判断自己是否真学懂 Vue,看这一点就够了。
  2. v-show 与 v-if 的选择标准是切换频率,不是功能强弱。能完成同样的事,差的是销毁重建的开销与状态保留。
  3. @ 就是 v-on:,: 就是 v-bind:。看到简写要能瞬间还原成完整指令,这是读懂他人代码和应对面试的基本功。
  4. methods 里的 this 永远指向实例,它是访问 data、其他方法、乃至后续计算属性的唯一入口,忘了 this 就等于换了个变量。
  5. 事件对象在哪用决定怎么写:模板中用 $event,方法形参中用 e;显式传参时事件对象不再自动赠送,必须手动按顺序传、按顺序接。
  6. v-bind 只有一个判断标准:值是不是变量。加冒号即表达式,不加即字符串,这条规则反过来验证也成立,别凭感觉加。
  7. v-text / v-html 是覆盖式渲染,要保留原有文字就用插值;v-html 有安全风险,只喂可信内容。
  8. 调试顺序固定为“先看 data,再看页面”:DevTools 里数据变了而页面没变,是模板绑定写错;数据都没变,是事件没绑上或方法没生效——按这个顺序排查,绝大多数问题三十秒内定位。