主题
v-cloak与v-pre 与 v-once(Lesson3 1/3)
本页对应 Lesson03,共 5 段视频,约 1 小时 29 分。
学习目标
- 能说明
v-cloak解决插值表达式闪烁的原理,编写配套 CSS 与 Vue 实例,并验证挂载完成后该属性被移除。 - 能分别构造示例验证
v-pre跳过元素编译、v-once仅渲染初始值的行为,并准确描述二者差异。 - 能指出未使用过滤器时格式化商品价格、时间戳的常见实现方式,并说明其在职责分离和复用性上的局限。
- 能声明局部过滤器,在插值表达式和属性绑定中通过管道符调用过滤器,并验证未注册过滤器时的报错现象。
- 能编写过滤器完成价格保留指定小数位并添加货币前缀、时间戳转年月日时分秒,并能通过传参与默认值控制格式化结果。
- 能解释过滤器本质是函数、第一个参数为待过滤数据、后续参数为调用时传入参数,并据此排查过滤器返回值与渲染结果不一致的问题。
知识点
先复现问题:为什么会出现双大括号闪烁
为什么需要:Vue 通过编译模板把 {{item}} 替换成真实数据。如果 Vue 文件加载慢,或实例挂载被延迟,浏览器会先把原始 HTML 渲染出来,用户就会短暂看到 {{item}} 这样的双大括号。
怎么想:转写稿里用 setTimeout 把 new Vue(...) 延迟 3000 毫秒,就是为了放大“尚未挂载”的阶段。此时页面上的 v-for 还没被 Vue 处理,{{item}} 会原样显示。等挂载完成后,列表才变成 1、2、3、4。
怎么做:先按笔记写一个带 v-for 的容器,并用延迟模拟加载慢:
html
<div id="app">
<p v-for="(item,index) in arr" :key="index">{{item}}</p>
</div>易错点:不要把“延迟”理解成正式项目必须写 setTimeout。它只是课堂调试手段,用来观察挂载前和挂载后的差异。
v-cloak 的作用:挂载前隐藏,挂载后显示
为什么需要:只靠延迟会看到双大括号,体验很差。我们需要一个标记:Vue 没挂载完时隐藏元素,挂载完成后自动显示。
怎么想:转写稿中在 #app 上加了 v-cloak,然后打开开发者工具的 Elements 面板观察:刷新时元素上有 v-cloak 属性;等挂载完成后,这个属性被 Vue 移除了。也就是说,v-cloak 本身不是用来显示数据的,而是配合 CSS 做“挂载前隐藏”。
怎么做:给容器加 v-cloak:
html
<div id="app" v-cloak>
<p v-for="(item,index) in arr" :key="index">{{item}}</p>
</div>易错点:只写 v-cloak 不写 CSS 是看不到效果的。转写稿里一开始也出现“加了 v-cloak 但还能看到双大括号”的情况,原因就是还没有给 [v-cloak] 写隐藏样式。
配合 CSS:用属性选择器隐藏元素
为什么需要:Vue 只负责在挂载完成后移除 v-cloak 属性,隐藏动作要靠 CSS 完成。
怎么想:用属性选择器 [v-cloak] 选中拥有该属性的元素,设置 display:none。挂载前属性存在,元素隐藏;挂载后属性被移除,选择器失效,元素显示。
怎么做:在 head 的 style 中写:
css
[v-cloak]{
display:none;
}易错点:样式要能作用到带 v-cloak 的元素;不要写成只对某个子元素生效。转写稿中“机子play读音呢”实际就是 display:none,要写正确。
完整示例与调试过程
下面保留本节笔记代码。转写稿中的调试顺序是:先延迟挂载,观察双大括号;再加 v-cloak,观察属性;最后加 [v-cloak]{display:none;},确认挂载前不显示、挂载后正常显示。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
[v-cloak]{
display:none;
}
</style>
<script src="lib/vue.js"></script>
</head>
<body>
<div id="app" v-cloak>
<p v-for="(item,index) in arr" :key="index">{{item}}</p>
</div>
</body>
<script>
// 当挂载完成后,Vue会将v-cloak属性移除。解决屏幕闪烁问题
// 1- 在未挂载完Vue时,会增加v-cloak属性,为该属性增加样式display:none;将拥有该属性的元素隐藏
// 2- 当挂载完成后,Vue会将v-cloak属性移除。样式不会起作用,即会显示元素。
setTimeout(()=>{
new Vue({
el:"#app",
data:{
arr:[1,2,3,4]
}
})
},3000)
</script>
</html>易错点:v-cloak 要加在需要隐藏的挂载容器上;转写稿里的“微杠破循环”就是 v-for,不要写错指令名。挂载完成后属性会自动移除,不需要手动删除。它解决的是“模板未编译前的闪烁”,不是所有加载问题。
先看本节完整示例
本节围绕两个“只影响编译/响应行为”的指令:v-pre 与 v-once。先保留笔记中的完整代码,后面逐段拆解。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="lib/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="str">
<p>{{str}}</p>
<p v-pre>大家好,你们现在学习的是Vue,可以借助插值表达式{{str}}输出数据状态str</p>
<p v-once>str的初始值为:{{str}}</p>
</div>
</body>
<script>
// v-pre:为元素增加该指令后,该元素即被数据响应跳过。(不会对其元素进行解析)
// v-once:只响应初始值,后续数据再次发生改变,使用该指令的元素不会对数据进行响应。
new Vue({
el: "#app",
data: {
str: "你现在过的还好吗?"
}
})
</script>运行后,输入框通过 v-model="str" 绑定 str。普通 <p>{{str}}</p> 会随输入变化;而带 v-pre 和 v-once 的两个 <p> 表现不同。转写稿中正是通过“改输入框、看下面几行是否变化”来演示这两个指令的差异。
v-pre:让插值表达式原样显示
为什么需要:有时我们不是要输出 str 的值,而是要把“{{str}} 这种写法本身”展示给别人看,例如做教学提示、文档说明。如果直接写 {{str}},Vue 会把它当成插值表达式解析掉,页面上就看不到双花括号了。转写稿中举例:想提示“可以借助插值表达式 {{str}} 输出数据状态 str”,但直接写会被 Vue 编译,于是需要 v-pre。
怎么想:v-pre 的作用不是“隐藏”,也不是“阻止数据变化”,而是告诉 Vue:这个元素不要按模板去解析。转写稿的表述是“为该元素增加该指令后,该元素即被数据响应跳过,不会对其元素进行解析”。所以元素内部的 {{str}} 会作为普通文本保留下来。
怎么做:在目标元素上添加 v-pre:
html
<p v-pre>大家好,你们现在学习的是Vue,可以借助插值表达式{{str}}输出数据状态str</p>页面中会原样看到 {{str}}。此时再修改输入框,v-pre 这一行不会因为 str 改变而重新渲染成数据值。
易错点:第一,v-pre 不是把内容藏起来,内容仍然显示,只是不编译;第二,不要把它和 v-cloak 混淆,转写稿中 v-cloak 解决的是挂载前双花括号闪烁问题,而 v-pre 是主动跳过解析;第三,v-pre 加在元素上后,元素内部的模板语法都不应按正常插值来理解,所以不要指望它内部再写 {{str}} 还能输出数据。
v-once:只响应初始值
为什么需要:有些内容只希望在第一次渲染时取一次数据,后续数据变化不再更新这一块。转写稿中写得很直接:“只响应初始值,后续数据再次发生改变,使用该指令的元素不会对数据进行响应。”本节示例用它显示 str 的初始值。
怎么想:普通插值 {{str}} 是响应式的,str 一变,视图就更新;v-once 则把这一处的渲染“定格”在初始渲染结果上。它不是修改 data,也不是让整个页面都失去响应,只影响使用了该指令的元素。
怎么做:在元素上添加 v-once:
html
<p v-once>str的初始值为:{{str}}</p>初始时显示“str 的初始值为:你现在过的还好吗?”。随后在输入框中修改 str,普通 <p>{{str}}</p> 会变化,而 v-once 这一行仍显示初始值。转写稿中反复演示“再改,它下面还变吗?不变”,就是在确认这一行为。
易错点:第一,v-once 不是“数据只读”,str 本身仍然可以被 v-model 修改;第二,它只让当前元素不随后的数据变化更新,其他普通插值照常响应;第三,不要把 v-once 当成 v-pre:v-once 会解析一次插值并显示初始值,v-pre 则连插值都不解析,直接显示 {{str}} 原文。
对比调试:一行普通插值、一行 v-pre、一行 v-once
按本节代码运行时,可以这样观察:
- 初始状态:普通行、
v-pre行、v-once行都显示各自内容。 - 在输入框输入新内容:普通行跟着变;
v-pre行仍显示字面量{{str}};v-once行仍显示初始值。 - 这个对比说明:
v-pre解决“模板语法要不要被解析”,v-once解决“解析后还要不要继续响应数据变化”。
转写稿中还强调“该元素即被数据响应跳过”“只响应初始值”,这两句话可以作为判断依据:看到 v-pre,先想“跳过解析”;看到 v-once,先想“只渲染一次初始结果”。本节不需要把它们扩大到其他指令上,先把这两个边界记清楚即可。
先明确本节主线
本节笔记只有一句核心定义:过滤器用于对数据进行格式化处理。转写稿前半段复习了动态 script、回调与 Promise,后面还讲了 v-cloak、v-pre、v-once,这些不属于“过滤器”主线;下面只围绕过滤器整理,并把转写稿里“先不用过滤器→发现不便→定义过滤器→调试参数”的过程补出来。本节无图片,代码依据转写稿口述整理。
为什么需要过滤器:模板里直接格式化会越来越乱
为什么需要:商品价格从接口来时常是 12.345,时间常是时间戳。用户看不懂时间戳,价格也通常要保留两位小数并加货币标识。
怎么想:先不用过滤器,直接在插值表达式里写 item.price.toFixed(2),再拼 '¥';时间则写一个 methods.formatTime,模板里调用 {{ formatTime(item.add_time) }}。这样能跑,但模板里混入太多格式化逻辑,复用和阅读都差。
怎么做:转写稿的结论是“专职专责”——格式化数据交给过滤器。过滤器本质是一个函数,返回什么,页面就渲染什么。
易错点:不要把“过滤器”写成“过滤期”;它不是万能的,Vue3 已移除过滤器,Vue2 中才是重点;复杂业务逻辑仍应封装成函数,不要全塞进模板。
过滤器的定义与基本调用
为什么需要:定义后可在插值表达式中用管道符 | 调用,模板更干净。
怎么想:先写使用处,再补定义处。转写稿中先写 {{ item.price | currency }},但此时没有 currency,控制台会报“找不到过滤器”。
怎么做:在 Vue 配置对象的 filters 中定义局部过滤器。示例按转写稿整理:
html
<div id="app">
<p v-for="item in list" :key="item.id">
商品名称:{{ item.goods_name }}
商品价格:{{ item.price | currency }}
上架时间:{{ item.add_time | formatTime }}
</p>
</div>js
new Vue({
el: '#app',
data: {
list: [
{ id: 1, goods_name: '水果葡萄', price: 12.345, add_time: Date.now() }
]
},
filters: {
currency(v) {
return v.toFixed(2)
}
}
})调试时转写稿先让 currency 返回 100,页面价格都变成 100,证明过滤器被调用;再接收参数 v 并输出,确认 v 就是被过滤的价格;最后返回 v.toFixed(2)。
易错点:管道符是竖线 |,不是数字 1;过滤器名要和使用处一致;局部过滤器只在当前 Vue 实例/组件可用;属性绑定中也可用管道符,但转写稿只点明场景,未展开代码。
过滤器参数:第一个参数永远是被过滤的数据
为什么需要:价格有时保留两位,有时保留一位;货币符号可能是 ¥ 也可能是 $,需要参数化。
怎么想:转写稿强调:过滤器函数接收的第一个参数永远是被过滤的数据,从第二个参数开始才是使用时传入的参数。
怎么做:按转写稿整理为:
js
filters: {
currency(v, n = 2, type = '¥') {
return type + v.toFixed(n)
}
}使用时:{{ item.price | currency }} 默认两位、羊头;{{ item.price | currency(3, '$') }} 表示保留三位并加美元标识。
易错点:不要以为括号里第一个 1 会传给 v;v 始终是管道左边的数据。默认参数要写对,n = 2 表示不传时保留两位;toFixed 返回字符串,拼货币符号时要注意字符串拼接。
时间格式化:先验证调用,再补 padStart
为什么需要:时间戳直接展示用户看不懂,要转成年月日时分秒。
怎么想:转写稿先用 methods.formatTime 返回 100,页面都变 100,证明模板调用成功;再在方法里 new Date(t),用 getFullYear()、getMonth() + 1、getDate()、getHours()、getMinutes()、getSeconds() 拼接。
怎么做:位数不足用 toString().padStart(2, '0') 补零。转写稿中“panda”应纠正为 padStart,“get most”是 getMonth,“get day”是 getDate。整理成过滤器:
js
formatTime(t) {
const time = new Date(t)
const y = time.getFullYear()
const m = (time.getMonth() + 1).toString().padStart(2, '0')
const d = time.getDate().toString().padStart(2, '0')
const h = time.getHours().toString().padStart(2, '0')
const min = time.getMinutes().toString().padStart(2, '0')
const s = time.getSeconds().toString().padStart(2, '0')
return `${y}-${m}-${d} ${h}:${min}:${s}`
}易错点:月份要 +1;补零前先转字符串,数字没有 padStart;getDate() 才是“日”,不要和 getDay() 混淆;过滤器返回什么,页面就显示什么。
调试顺序与易错点汇总
为什么需要:转写稿的调试价值在于“先证明调用链,再补格式化”。
怎么想:使用处写过滤器→报找不到→定义 filters→先返回固定值→再输出参数→最后写真实格式化→再传参调默认值。
怎么做:按“固定值验证、参数验证、真实逻辑验证”三步走。
易错点:filters 是对象,不是 methods;过滤器名不要和变量名混淆;模板中管道右侧是过滤器名,不是函数调用时必须加括号,传参才加括号;不要把 v-cloak 等指令混进过滤器定义。
从“原始数据不好看”说起
为什么需要:商品价格是 12.345,上架时间是时间戳,直接渲染给用户看,既不直观也不统一。
怎么想:先不用过滤器,直接在插值里写格式化语句,或者定义方法返回格式化结果,也能完成。但这样会把“数据展示格式”散落在模板和业务逻辑里。
怎么做:Vue2 提供过滤器,专门把数据“过滤”成要展示的样子。转写稿也强调:过滤器的主要作用是对数据进行格式化处理,做到专职专责。
易错点:过滤器不是万能的,它不改变原数据,只决定最终渲染内容;Vue3 已移除过滤器,本节按 Vue2 学习。
过滤器的本质与两种使用位置
为什么需要:知道本质,才能理解参数和返回值。
怎么想:过滤器本质是一个函数,输入被过滤的数据,返回格式化后的内容。
怎么做:使用时写在管道符 | 右边:{{ 数据 | 过滤器名 }};也可带参数:{{ 数据 | 过滤器名(参数1, 参数2) }}。笔记指出应用主要有两种:插值 {{}} 和属性渲染 v-bind:xxx="过滤器"。
易错点:管道符是单个 |,不是逻辑或 ||;过滤器名没定义时,Vue 会报“找不到过滤器”。
定义局部过滤器 filters
为什么需要:先声明过滤器,模板里才能使用。
怎么想:在 Vue 配置对象中增加 filters,它的值是一个对象;对象属性名就是过滤器名,属性值是函数。
怎么做:函数返回值就是过滤后要渲染的内容;函数第一个参数固定是“要被过滤的数据”,从第二个参数开始才是使用时传入的参数。比如 100.12345 | currency(1) 对应 currency(v,n){ /* v:100, n:1 */ }。
易错点:不要写成 filter;不要误以为传入的第一个参数是括号里的参数,第一个参数永远是管道符左边的数据。
调试过程:从固定返回到真实格式化
为什么需要:转写稿中先让过滤器返回 100,观察到所有价格都变成 100,从而确认“返回值即渲染内容”。
怎么想:先验证过滤器是否被调用,再逐步换成真实逻辑。
怎么做:currency(v) 中先 return "¥"+v.toFixed(2);需要参数时写 currency2(v,n=2,type="¥"),调用 currency2(1,"$") 时 n 为 1、type 为 $。日期过滤器用 new Date(t) 取出年月日时分秒,再用 padStart(2,0) 补零。
易错点:toFixed 返回字符串;getMonth() 要加 1;补零前先转字符串;参数顺序不能乱。
完整示例代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="lib/vue.js"></script>
</head>
<body>
<div id="app">
<div v-for="item in goodsList" :key="item.id">
<p>商品名称:{{item.goodsName}}</p>
<p>商品价格1:{{item.goodsPrice | currency}}</p>
<p>商品价格2:{{item.goodsPrice | currency2(1,"$")}}</p>
<p>上架时间:{{item.addTime | date}}</p>
<hr/>
</div>
</div>
</body>
<script>
// 1- 过滤器的本质是一个函数
// 2- 过滤器应用主要有两种:1-插值{{}} 2-属性渲染v-bind:xxx="过滤器"
// 3- 过滤器分为全局过滤器以及局部过滤器
// 4- 过滤器在使用时:
// 4-1 数据 | 过滤器的名字 (|:管道符)
// 4-2 数据 | 过滤器的名字(参数1,参数2,...) (|:管道符)
// 5- 定义过滤器:
// 5-1 在Vue配置对象中增加属性filters,值是一个对象
// 5-2 filters对象的属性名即是过滤器的名字,属性值是函数。
// 5-3 过滤器函数返回的值即是过滤后要渲染的内容。
// 5-4 过滤器函数接收的第一个参数即是要被过滤的数据
// 5-5 过滤器接收的第二个参数开始才是使用过滤器传递的参数
// 比如使用时 100.12345 | currency(1) ,过滤器 currency(v,n){/*v:100,n:1*/}
new Vue({
el:"#app",
data:{
goodsList:[
{
id:1,
goodsName:"葡萄",
goodsPrice:12.345,
addTime:Date.now()
},{
id:2,
goodsName:"梨",
goodsPrice: 45.678,
addTime: Date.now()-998887666
}
]
},
filters:{
// v是被过滤的数据
currency(v){
return "¥"+v.toFixed(2);
},
currency2(v,n=2,type="¥"){
console.log(v,n);
return type+v.toFixed(n);
},
// 声明了一个名字为date的过滤器,t即是要过滤的数据
date(t){
const timer = new Date(t);
return timer.getFullYear()+"-"+
(timer.getMonth()+1).toString().padStart(2,0)+"-"+
timer.getDate().toString().padStart(2,0)+" "+
timer.getHours().toString().padStart(2,0)+":"+
timer.getMinutes().toString().padStart(2,0)+":"+
timer.getSeconds().toString().padStart(2,0);
}
}
})
</script>
</html>易错点小结
为什么需要:过滤器语法短,错误往往藏在参数顺序和声明位置。
怎么想:先看模板有没有写 |,再看 filters 中名字是否一致,最后看函数第一个参数是否当成“被过滤数据”。
怎么做:模板中先写数据,再写管道符,再写过滤器名;传参时按 currency2(1,"$") 的顺序对照函数形参。
易错点:局部过滤器只在当前 Vue 实例可用;过滤器函数必须有返回值;不要修改原数据;日期补零要处理 getMonth()+1;未定义过滤器会直接报错。
课堂画面





代码示例
示例一:v-cloak 解决插值表达式闪烁
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-cloak</title>
<style>
[v-cloak]{
display:none;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app" v-cloak>
<p v-for="(item,index) in arr" :key="index">{{item}}</p>
</div>
</body>
<script>
// 当挂载完成后,Vue会将v-cloak属性移除。解决屏幕闪烁问题
// 1- 在未挂载完Vue时,会增加v-cloak属性,为该属性增加样式display:none;将拥有该属性的元素隐藏
// 2- 当挂载完成后,Vue会将v-cloak属性移除。样式不会起作用,即会显示元素。
setTimeout(()=>{
new Vue({
el:"#app",
data:{
arr:[1,2,3,4]
}
})
},3000)
</script>
</html>要点解释:
[v-cloak]{display:none}是属性选择器,必须写成中括号;写成v-cloak{}是元素选择器,不会生效。v-cloak必须写在 Vue 的挂载元素(这里是#app)上,写在子元素上无效。- 挂载完成后 Vue 会自动把
v-cloak属性移除,样式失效,元素才显示出来。 - 易错点:CSS 必须放在
head中且先于渲染生效;如果不加setTimeout延迟(模拟 Vue 加载慢),页面瞬间就编译完,看不到闪烁现象,会误以为指令没用。
示例二:v-pre 与 v-once
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-pre 与 v-once</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="str">
<p>{{str}}</p>
<p v-pre>大家好,你们现在学习的是Vue,可以借助插值表达式{{str}}输出数据状态str</p>
<p v-once>str的初始值为:{{str}}</p>
</div>
</body>
<script>
// v-pre:为元素增加该指令后,该元素即被数据响应跳过。(不会对其元素进行解析)
// v-once:只响应初始值,后续数据再次发生改变,使用该指令的元素不会对数据进行响应。
new Vue({
el: "#app",
data: {
str: "你现在过的还好吗?"
}
})
</script>
</html>要点解释:
v-pre让 Vue 跳过该元素及其子元素的编译,{{str}}会原样显示成两个大括号,适合演示语法或防止无用编译。v-once只做一次性渲染,绑定初始值;之后str再变,该<p>不会更新(但普通<p>{{str}}</p>会变)。- 易错点:
v-pre元素内部的v-model、v-for等指令也全部失效,别把它加到需要响应式的父容器上;v-once不是“只改一次”,而是“不再随数据更新”。
示例三:过滤器的基本使用(插值 + 传参 + 局部过滤器)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>过滤器</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div v-for="item in goodsList" :key="item.id">
<p>商品名称:{{item.goodsName}}</p>
<p>商品价格1:{{item.goodsPrice | currency}}</p>
<p>商品价格2:{{item.goodsPrice | currency2(1,"$")}}</p>
<p>上架时间:{{item.addTime | date}}</p>
<hr/>
</div>
</div>
</body>
<script>
// 1- 过滤器的本质是一个函数
// 2- 过滤器应用主要有两种:1-插值{{}} 2-属性渲染v-bind:xxx="过滤器"
// 3- 过滤器分为全局过滤器以及局部过滤器
// 4- 过滤器在使用时:
// 4-1 数据 | 过滤器的名字 (|:管道符)
// 4-2 数据 | 过滤器的名字(参数1,参数2,...) (|:管道符)
// 5- 定义过滤器:
// 5-1 在Vue配置对象中增加属性filters,值是一个对象
// 5-2 filters对象的属性名即是过滤器的名字,属性值是函数。
// 5-3 过滤器函数返回的值即是过滤后要渲染的内容。
// 5-4 过滤器函数接收的第一个参数即是要被过滤的数据
// 5-5 过滤器接收的第二个参数开始才是使用过滤器传递的参数
new Vue({
el:"#app",
data:{
goodsList:[
{
id:1,
goodsName:"葡萄",
goodsPrice:12.345,
addTime:Date.now()
},{
id:2,
goodsName:"梨",
goodsPrice: 45.678,
addTime: Date.now()-998887666
}
]
},
filters:{
// v是被过滤的数据
currency(v){
return "¥"+v.toFixed(2);
},
currency2(v,n=2,type="¥"){
console.log(v,n);
return type+v.toFixed(n);
},
// 声明了一个名字为date的过滤器,t即是要过滤的数据
date(t){
const timer = new Date(t);
return timer.getFullYear()+"-"+
(timer.getMonth()+1).toString().padStart(2,0)+"-"+
timer.getDate().toString().padStart(2,0)+" "+
timer.getHours().toString().padStart(2,0)+":"+
timer.getMinutes().toString().padStart(2,0)+":"+
timer.getSeconds().toString().padStart(2,0);
}
}
})
</script>
</html>要点解释:
- 用法是
数据 | 过滤器名,管道符|左边是被过滤的数据,右边是过滤器名;currency2(1,"$")这种写法才是在传参。 - 过滤器函数第一个形参永远是“被过滤的数据”,
currency2(v,n=2,type="¥")里的n、type才是使用者传进来的实参,顺序很容易搞反。 filters写在 Vue 配置对象里是局部过滤器,只能在#app内使用;全局过滤器用Vue.filter("名字", fn)注册。- 易错点:
getMonth()从 0 开始,必须+1;月份/日期补零要先toString()再padStart(2,0),因为padStart是字符串方法,直接对数字调用会报错。 - 易错点:过滤器只用于“格式化展示”,不要在过滤器里改原数据;Vue 3 已移除过滤器,面试/迁移时要注意。
常见错误
现象:页面仍先闪出
{{item}},几秒后才正常渲染。
原因:只写了v-cloak,没有配套[v-cloak]{ display:none; }。
修法:样式必须存在且选择器正确,v-cloak加在需要隐藏的挂载根元素上。现象:
v-pre元素里的{{str}}始终不更新,误以为响应式失效。
原因:v-pre会跳过该元素及其子元素的编译,插值表达式不会被解析。
修法:需要显示动态数据时移除v-pre;只把它用于展示原始模板或跳过编译的静态片段。现象:
v-once元素首次显示后,输入框修改数据但该元素不变化。
原因:v-once只按初始值渲染一次,后续数据变化不再响应。
修法:需要持续响应的区域不要加v-once;仅用于确定不会变化的初始快照。现象:过滤器写成
currency(v,n),使用时传了1,但v不是1,结果不符合预期。
原因:过滤器第一个参数永远是被过滤的数据,使用处传入的参数从第二个形参开始接收。
修法:按currency(value, n, type)定义,使用时写{{ price | currency(2, "$") }}。现象:过滤器写了逻辑但页面显示
undefined或原数据未格式化。
原因:过滤器函数没有return,或误把复杂副作用逻辑放进过滤器。
修法:过滤器必须返回格式化后的值;复杂业务逻辑放methods/computed,过滤器只做纯格式化。现象:局部过滤器在另一个组件/实例中不可用,控制台报“过滤器未定义”。
原因:在某个 Vue 配置对象的filters中定义的是局部过滤器,作用域仅限当前实例/组件。
修法:当前实例使用就放局部filters;需要跨组件复用时改用全局过滤器或抽成普通工具函数。
练习
改错题:下面代码异步挂载 Vue 后仍会闪烁,请指出缺失项并修正。
html<div id="app" v-cloak>{{ msg }}</div>选择题:以下场景分别应选
v-pre、v-once还是都不使用?- A. 展示一段包含
{{ }}的 Vue 教学示例,不希望被编译。 - B. 展示用户首次进入页面时的初始昵称,后续改名不影响该处展示。
- C. 商品价格需要随输入框实时变化。
- A. 展示一段包含
实现题:在 Vue2 局部过滤器中实现
currency(value, digits = 2, symbol = "¥"),要求保留指定小数位并拼接货币符号,给出模板调用示例。改错题:现有过滤器
fmt(v, n),模板写成{{ price | fmt(price, 2) }},请说明参数问题并改为正确写法。实现题:写一个时间格式化过滤器
date(t),把时间戳输出为YYYY-MM-DD HH:mm:ss,要求月、日、时、分、秒不足两位补0。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 复习 | 46:07 |
| 2 | v-cloak | 07:07 |
| 3 | v-pre 与 v-once | 05:47 |
| 4 | 未使用过滤器 | 13:10 |
| 5 | 过滤器的基本使用 | 17:44 |
小结
v-cloak解决的是“编译前模板闪现”,不是网络慢、组件加载慢的通用 loading 方案。v-pre和v-once都是在控制“是否编译/是否继续响应”,不要拿它们当样式或性能优化的万能开关。- 过滤器适合“输入一个值、输出一个展示值”的纯格式化场景,不适合承载请求、DOM 操作等副作用。
- 过滤器参数顺序是高频踩坑点:第一个参数固定是管道左侧数据,使用处传参从第二个形参开始。
- 局部过滤器优先用于当前组件;跨组件复用再考虑全局过滤器或普通工具函数。
- 复杂格式化逻辑应优先抽成函数,避免模板中堆叠多个过滤器导致可读性下降。
- Vue3 已移除过滤器,Vue2 项目中使用过滤器时要为后续迁移保留“可替换为方法/计算属性”的设计。