大宇宇宇
发布于 2025-09-01 / 6 阅读
0
0

vue中的指令以及自定义指令

在 Vue 中,指令(Directives) 是以 v- 开头的特殊属性,用于在模板中添加响应式行为。以下是面试中需要掌握的核心指令及要点:


一、常用内置指令

1. v-bind

  • 作用:动态绑定 HTML 属性(如 classstylehref 等)。

  • 简写:(冒号)。

2. v-model

  • 作用:在表单控件上创建双向数据绑定(本质是 v-bind + v-on 的语法糖)。

  • 适用元素<input><select><textarea> 及组件。

3. v-for

  • 作用:基于数组/对象循环渲染列表。

  • 语法v-for="(item, index) in items"必须绑定 :key(避免重复渲染问题)。

4. v-if / v-else-if / v-else

  • 作用条件渲染(动态添加/移除 DOM 元素)。

  • 注意v-if 有更高的切换开销,v-show 有更高的初始渲染开销。

5. v-show

  • 作用条件显示(通过 CSS display 控制显示/隐藏,DOM 始终存在)。

  • 适用场景:频繁切换显示状态(如弹窗)。

6. v-on

  • 作用:监听 DOM 事件。

  • 简写@(如 @click)。

7. v-html

  • 作用:渲染 HTML 字符串(需注意 XSS 风险,避免渲染用户输入)。

8. v-text

  • 作用:更新元素的 textContent(等同于 {{ }} 插值,但会覆盖子元素)。

9. v-once

  • 作用:只渲染元素/组件一次,后续数据变化不再更新(用于优化静态内容)。

10. v-cloak

  • 作用:解决 Vue 编译前“闪动”问题(结合 CSS [v-cloak] { display: none } 使用)。


二、指令对比(高频面试点)

v-if vs v-show

特性

v-if

v-show

DOM 操作

动态添加/移除 DOM

仅切换 display 属性

初始渲染

惰性渲染(条件为真时才渲染)

无论条件如何,都会渲染

切换开销

高(需重建/销毁组件)

低(仅修改 CSS)

适用场景

条件极少变化时(如权限控制)

频繁切换显示状态(如 Tab)


三、自定义指令

什么是自定义指令

自定义指令是用来操作 DOM 的。尽管 Vue 推崇数据驱动视图的理念,但并非所有情况都适合数据驱动。自定义指令就是一种有效的补充和扩展,不仅可用于定义任何的 DOM 操作,并且是可复用的。

自定义指令的第二用处是用于集成第三方插件。我们知道任何软件开发领域都可以分为四层:底层是原生的API,上层是通用框架,再上层是通用组件,最上层才是具体的业务代码。一个通用框架,必须搭配一套完整的通用组件,才能真正奠定其江湖地位。

如何创建自定义指令

下面定义了一个 v-test 指令绑定数据 name

<template>
  <div class="hello">
  	<div v-test='name'></div>
  </div>
</template>
<script>
export default {
  data () {
    return {
     name:'我是名字',
    }
  },
  directives:{
  	test:{
  		// 指令的定义
	    inserted: function (el, binding) {
	       // el为绑定元素,可以对其进行dom操作
	       console.log(binding) // binding 一个对象,包含很多属性
	    },
	    bind: function (el, binding, vnode) {
		    el.innerHTML =binding.value
		  }
  	}
  },
  created:function(){
  },
  mounted:function(){ 
  },
  methods:{
  }
}
</script>

我们可以全局自定义一个指令 v-red,来修改 HTML 元素的背景色为红色

<div id="box">
   hello
   <span v-red> welcome</span>
</div>
<script type="text/javascript">
    Vue.directive('red',{
        inserted: function(el){
            el.style.background = 'red';
        }
    });
    var vm = new Vue({
        data:{
        
        },
    }).$mount('#box'); 
</script>

自定义指令相关参数

钩子函数

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

钩子函数参数

  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

  • unbind:只调用一次,指令与元素解绑时调用。

指令钩子函数会被传入以下参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM 。

  • binding:一个对象,包含以下属性:

  1. name:指令名,不包括 v- 前缀。

  2. value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。

  3. oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。

  4. expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 “1 + 1”。

  5. arg:传给指令的参数,可选。例如 v-my-directive: foo 中,参数为 “foo”。

  6. modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。

  • vnode: Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。

  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

注意:除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。

常见使用场景

1. 自动聚焦

Vue.directive('focus', {
  inserted: (el) => el.focus()
})
// 使用:<input v-focus>

2. 权限控制

Vue.directive('permission', {
  inserted: (el, binding) => {
    if (!hasPermission(binding.value)) {
      el.parentNode.removeChild(el) // 无权限时移除元素
    }
  }
})
// 使用:<button v-permission="'admin'">删除</button>

3. 图片懒加载

Vue.directive('lazy', {
  inserted: (el, binding) => {
    const observer = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        el.src = binding.value // 进入视口时加载图片
        observer.unobserve(el)
      }
    })
    observer.observe(el)
  }
})
// 使用:<img v-lazy="imageUrl">

4. 防抖/节流

Vue.directive('debounce', {
  bind: (el, binding) => {
    let timer = null
    el.addEventListener('click', () => {
      clearTimeout(timer)
      timer = setTimeout(() => binding.value(), 500)
    })
  }
})
// 使用:<button v-debounce="handleClick">提交</button>

函数简写

若只需 bindupdate 时执行相同逻辑,可简写为函数:

Vue.directive('color', (el, binding) => {
  el.style.color = binding.value
})
// 使用:<div v-color="'red'">Hello</div>

动态指令参数(Vue 2.6.0+)

支持动态参数,实现灵活指令:

// dynamicColor 可以是 'color'/'background' 等
directives: {
  color: (el, binding) => {
    el.style[binding.arg] = binding.value // 动态设置样式属性
  }
}

四、面试回答模板

问题:Vue 中有哪些常用指令?它们的作用是什么?
回答
Vue 的核心指令包括:

  1. v-bind:动态绑定属性(简写 :),如 :src="url"

  2. v-model:表单双向绑定(本质是 v-bind + v-on)。

  3. v-for:循环渲染列表,必须加 :key 避免重复渲染问题。

  4. v-if / v-show:条件渲染,v-if 是动态增删 DOM,v-show 是切换 CSS display

  5. v-on:事件监听(简写 @),如 @click="handler"

  6. v-html:渲染 HTML(注意 XSS 风险)。

  7. v-once:静态内容优化(只渲染一次)。

  8. v-cloak:解决编译前闪动问题。
    此外,Vue 支持自定义指令,通过钩子函数(如 inserted)操作 DOM。

自定义指令与组件的区别?

  • 指令:直接操作 DOM,封装底层逻辑(如权限、DOM 事件)。

  • 组件:可复用的 UI 单元,关注视图层和业务逻辑。

何时用自定义指令?

  • 需直接操作 DOM(如聚焦、滚动)。

  • 封复用性强的底层功能(如权限、懒加载、格式化)。

  • 避免在组件中写过多 DOM 操作代码。

binding 参数中的 valueexpression 区别?

  • value:指令绑定值的计算结果(如 v-color="1+1"value: 2)。

  • expression原始字符串表达式(如 "1+1")。

Vue 3 中自定义指令的变化?

  • 钩子名调整(insertedmountedbindbeforeMount)。

  • 支持 Fragment,指令可绑定到组件根节点外的元素。

  • 新增 created 钩子(在元素属性或事件监听器应用前调用)。


五、注意事项

  • v-forv-if 优先级
    Vue 2.x 中 v-for 优先级更高,会先循环再判断条件;Vue 3.x 中 v-if 优先级更高。避免同时使用,改用计算属性过滤数据。

  • key 的作用
    唯一标识节点,用于虚拟 DOM 的 Diff 算法,提升渲染效率。


评论