Skip to content

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
  • 不推荐使用驼峰命名