Vue2 过滤器与自定义指令
过滤器 (Filters)
Vue3 已移除过滤器,推荐使用 computed 或全局方法替代。
局部过滤器
vue
<template>
<div>
<!-- 使用过滤器 -->
<p>{{ message | capitalize }}</p>
<p>{{ price | currency('¥') }}</p>
<!-- 过滤器串联 -->
<p>{{ text | filterA | filterB }}</p>
<!-- v-bind 中使用 -->
<div :title="title | formatTitle"></div>
</div>
</template>
<script>
export default {
data() {
return {
message: 'hello vue',
price: 1234.5,
text: 'hello',
title: 'my-title'
}
},
// 局部过滤器
filters: {
capitalize(value) {
if (!value) return ''
return value.charAt(0).toUpperCase() + value.slice(1)
},
currency(value, symbol = '¥') {
return symbol + value.toFixed(2)
},
formatTitle(value) {
return value.replace(/-/g, ' ')
}
}
}
</script><template>
<div>
<!-- 使用过滤器 -->
<p>{{ message | capitalize }}</p>
<p>{{ price | currency('¥') }}</p>
<!-- 过滤器串联 -->
<p>{{ text | filterA | filterB }}</p>
<!-- v-bind 中使用 -->
<div :title="title | formatTitle"></div>
</div>
</template>
<script>
export default {
data() {
return {
message: 'hello vue',
price: 1234.5,
text: 'hello',
title: 'my-title'
}
},
// 局部过滤器
filters: {
capitalize(value) {
if (!value) return ''
return value.charAt(0).toUpperCase() + value.slice(1)
},
currency(value, symbol = '¥') {
return symbol + value.toFixed(2)
},
formatTitle(value) {
return value.replace(/-/g, ' ')
}
}
}
</script>全局过滤器
js
// main.js
Vue.filter('capitalize', (value) => {
if (!value) return ''
return value.charAt(0).toUpperCase() + value.slice(1)
})
Vue.filter('currency', (value, symbol = '¥') => {
return symbol + Number(value).toFixed(2)
})// main.js
Vue.filter('capitalize', (value) => {
if (!value) return ''
return value.charAt(0).toUpperCase() + value.slice(1)
})
Vue.filter('currency', (value, symbol = '¥') => {
return symbol + Number(value).toFixed(2)
})过滤器 vs computed
| 特性 | 过滤器 | computed |
|---|---|---|
| 复用性 | 全局注册可多处使用 | 每个组件需单独定义 |
| 参数 | 支持传参 | 不支持额外参数 |
| 使用场景 | 文本格式化(日期、金额、大小写) | 复杂数据转换 |
| Vue3 | 已移除 | 保留 |
vue3 替代方式
js
// 全局方法
app.config.globalProperties.$filters = {
capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
// 使用
// {{ $filters.capitalize(message) }}// 全局方法
app.config.globalProperties.$filters = {
capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
// 使用
// {{ $filters.capitalize(message) }}自定义指令
注册方式
js
// 全局注册
Vue.directive('focus', {
inserted(el) {
el.focus()
}
})
// 局部注册
export default {
directives: {
focus: {
inserted(el) {
el.focus()
}
}
}
}// 全局注册
Vue.directive('focus', {
inserted(el) {
el.focus()
}
})
// 局部注册
export default {
directives: {
focus: {
inserted(el) {
el.focus()
}
}
}
}vue
<template>
<input v-focus>
</template><template>
<input v-focus>
</template>钩子函数
| 钩子 | 调用时机 |
|---|---|
bind | 指令第一次绑定到元素时(只调用一次) |
inserted | 被绑定元素插入父节点时 |
update | 所在组件的 VNode 更新时 |
componentUpdated | 所在组件的 VNode 及其子 VNode 全部更新后 |
unbind | 指令与元素解绑时(只调用一次) |
钩子参数
js
Vue.directive('demo', {
bind(el, binding, vnode) {
// el — 指令绑定的 DOM 元素
// binding:
// .name — 指令名,不含 v-
// .value — 指令的绑定值
// .oldValue — 上一次的绑定值(仅 update 和 componentUpdated)
// .expression — 字符串形式的表达式
// .arg — 传给指令的参数
// .modifiers — 修饰符对象
// vnode — Vue 编译生成的虚拟节点
console.log(binding.value) // 指令值
console.log(binding.arg) // 参数
console.log(binding.modifiers) // 修饰符对象
}
})Vue.directive('demo', {
bind(el, binding, vnode) {
// el — 指令绑定的 DOM 元素
// binding:
// .name — 指令名,不含 v-
// .value — 指令的绑定值
// .oldValue — 上一次的绑定值(仅 update 和 componentUpdated)
// .expression — 字符串形式的表达式
// .arg — 传给指令的参数
// .modifiers — 修饰符对象
// vnode — Vue 编译生成的虚拟节点
console.log(binding.value) // 指令值
console.log(binding.arg) // 参数
console.log(binding.modifiers) // 修饰符对象
}
})使用示例
vue
<template>
<div>
<!-- 传值 -->
<div v-color="'red'">红色文字</div>
<div v-color="themeColor">动态颜色</div>
<!-- 带参数 -->
<div v-color:background="'blue'">蓝色背景</div>
<!-- 带修饰符 -->
<div v-color.delay="'red'">延迟变色</div>
</div>
</template>
<script>
export default {
data() {
return { themeColor: 'green' }
},
directives: {
color: {
bind(el, binding) {
if (binding.arg === 'background') {
el.style.backgroundColor = binding.value
} else {
el.style.color = binding.value
}
},
update(el, binding) {
if (binding.arg === 'background') {
el.style.backgroundColor = binding.value
} else {
el.style.color = binding.value
}
}
}
}
}
</script><template>
<div>
<!-- 传值 -->
<div v-color="'red'">红色文字</div>
<div v-color="themeColor">动态颜色</div>
<!-- 带参数 -->
<div v-color:background="'blue'">蓝色背景</div>
<!-- 带修饰符 -->
<div v-color.delay="'red'">延迟变色</div>
</div>
</template>
<script>
export default {
data() {
return { themeColor: 'green' }
},
directives: {
color: {
bind(el, binding) {
if (binding.arg === 'background') {
el.style.backgroundColor = binding.value
} else {
el.style.color = binding.value
}
},
update(el, binding) {
if (binding.arg === 'background') {
el.style.backgroundColor = binding.value
} else {
el.style.color = binding.value
}
}
}
}
}
</script>常用自定义指令示例
v-focus — 自动获取焦点
js
Vue.directive('focus', {
inserted(el) {
el.focus()
}
})Vue.directive('focus', {
inserted(el) {
el.focus()
}
})v-permission — 权限控制
js
Vue.directive('permission', {
inserted(el, binding) {
const permissions = ['admin', 'editor']
if (!permissions.includes(binding.value)) {
el.parentNode && el.parentNode.removeChild(el)
}
}
})Vue.directive('permission', {
inserted(el, binding) {
const permissions = ['admin', 'editor']
if (!permissions.includes(binding.value)) {
el.parentNode && el.parentNode.removeChild(el)
}
}
})vue
<template>
<button v-permission="'admin'">管理员按钮</button>
</template><template>
<button v-permission="'admin'">管理员按钮</button>
</template>v-debounce — 防抖
js
Vue.directive('debounce', {
bind(el, binding) {
let timer
el.addEventListener('click', () => {
clearTimeout(timer)
timer = setTimeout(() => {
binding.value()
}, binding.arg || 300)
})
}
})Vue.directive('debounce', {
bind(el, binding) {
let timer
el.addEventListener('click', () => {
clearTimeout(timer)
timer = setTimeout(() => {
binding.value()
}, binding.arg || 300)
})
}
})vue
<template>
<button v-debounce:500="handleSubmit">防抖提交</button>
</template><template>
<button v-debounce:500="handleSubmit">防抖提交</button>
</template>指令简写
如果 bind 和 update 行为相同,可以直接传入函数:
js
Vue.directive('color', (el, binding) => {
el.style.color = binding.value
})
// 等价于:
Vue.directive('color', {
bind(el, binding) { el.style.color = binding.value },
update(el, binding) { el.style.color = binding.value }
})Vue.directive('color', (el, binding) => {
el.style.color = binding.value
})
// 等价于:
Vue.directive('color', {
bind(el, binding) { el.style.color = binding.value },
update(el, binding) { el.style.color = binding.value }
})指令命名规范
- 多个单词用 kebab-case:
v-my-directive - 不推荐使用驼峰命名
Cao Note