当前位置: 首页 > news >正文

2.8 ref 和 自定义指令

 

ref详解

在 Vue 中,$ref是一个用于直接访问子组件实例或 DOM 元素的属性。它提供了一种方法来获取对模板中定义的 HTML 元素或子组件的引用,从而允许你直接操作它们。这种方式非常适合那些需要直接与 DOM 交互的情况,比如聚焦一个输入框、手动触发重新渲染或者调用子组件的方法等。

如何使用 ref

在模板中
  • 对于HTML元素:
    <template><input ref="myInput" type="text">
    </template>
  • 对于子组件:
    <template><ChildComponent ref="childComponent"/>
    </template>
在脚本中

要在组件的 JavaScript 部分使用 ref,你可以通过 this.$refs 来访问它。例如:

  • 访问DOM元素:
    mounted() {this.$refs.myInput.focus(); // 假设是<input>元素,这将使它获得焦点
    }
  • 访问子组件实例:
    methods: {callChildMethod() {this.$refs.childComponent.someMethod(); // 调用子组件中的某个方法}
    }

注意事项

  1. 避免过度使用:虽然 ref 提供了直接访问DOM和组件实例的能力,但应尽量减少其使用,尤其是在可以使用Vue的数据绑定、计算属性和事件处理等特性解决问题的情况下。
  2. 生命周期考虑:确保在尝试访问 ref 之前,组件已经挂载(即处于 mounted 或之后的生命周期钩子),否则可能会遇到 undefined 的情况。
  3. 响应性限制ref 并不会使被引用的对象变得响应式。如果你希望基于 ref 的值创建响应式的行为,应该依赖于 Vue 的数据驱动特性,如 v-model 或者状态管理工具。

Vue 3 中的变化(了解)

在 Vue 3 中,ref API 也得到了更新以更好地适应 Composition API 的工作方式。现在,你可以通过 ref 函数来创建响应式的引用,并且可以直接在 <template> 标签上使用 ref 属性来自动分配这些引用,而不需要通过 this.$refs 访问。

import { ref, onMounted } from 'vue';export default {setup() {const myInput = ref(null);onMounted(() => {myInput.value.focus(); // 直接访问并操作DOM元素});return { myInput };}
}

在这个例子中,myInput 是一个响应式引用,可以直接在模板中通过 ref="myInput" 关联到特定的 DOM 元素。注意,在 Composition API 中,访问实际的值时需要使用 .value

$parent

$parent 是一个实例属性,它提供了一个直接访问当前组件实例的父组件实例的途径。这在某些情况下非常有用,比如当你需要从子组件中调用父组件的方法或访问其数据时。

假设你有一个父组件和一个子组件:

父组件 (ParentComponent.vue)

<template><div><h1>父组件</h1><p>消息: {{ message }}</p><ChildComponent /></div>
</template><script>
import ChildComponent from './ChildComponent.vue';export default {components: {ChildComponent},data() {return {message: '来自父组件的消息'}},methods: {updateMessage(newMessage) {this.message = newMessage;}}
}
</script>

子组件 (ChildComponent.vue)

<template><div><button @click="changeParentMessage">更改父组件消息</button></div>
</template><script>
export default {methods: {changeParentMessage() {// 使用 $parent 访问父组件this.$parent.updateMessage('通过 $parent 修改的消息');}}
}
</script>

在这个例子中,当点击子组件中的按钮时,会触发 changeParentMessage 方法,该方法通过 this.$parent 调用了父组件的 updateMessage 方法来改变父组件的数据。

注意事项

  1. 耦合度增加:使用 $parent 会增加组件之间的耦合度,使得子组件依赖于父组件的具体实现。如果父组件改变了结构或方法名,子组件可能就会出错。
  2. 维护困难:过度使用 $parent 可能使代码更难理解和维护,因为它打破了组件的封装性。
  3. 推荐做法:通常建议使用 props 和 $emit 进行父子组件间的通信。这样可以保持组件的独立性和可复用性。

替代方案

  • Props:用于从父组件向子组件传递数据。
  • $emit:用于子组件向父组件发送事件,父组件监听这些事件并作出响应。

该方案参考前边章节2.4 组件通信-CSDN博客

总之,虽然 $parent 提供了一种快速访问父组件的方式,但在实际开发中应谨慎使用,优先考虑使用 props$emit 来实现组件间的通信。

Vue2自定义指令

Vue2允许开发者通过自定义指令扩展框架功能,实现对DOM的底层操作。自定义指令分为私有全局两种类型,可在生命周期钩子中处理元素绑定、更新、解绑等场景,适用于表单焦点、样式动态调整、交互增强等需求。官方内置指令(如v-modelv-for)无法满足特定需求时,自定义指令是重要补充。

自定义指令的类型与注册方式

私有自定义指令
  • 注册位置:在组件的directives节点下声明,仅当前组件可用。
  • 示例代码
    export default { directives: { color: { bind(el, binding) { el.style.color  = binding.value;  // 动态设置颜色 } } } 
    } 
    
  • 使用方式:在模板中通过v-指令名调用,如<div v-color="red"></div>
全局自定义指令
  • 注册方式:通过Vue.directive() 全局注册,可在所有组件中使用。
  • 示例代码
    Vue.directive('focus',  { inserted(el) { el.focus();  // 元素插入DOM后自动聚焦 } 
    }); 
    
  • 参数说明Vue.directive() 接收两个参数,第一个为指令ID(如focus),第二个为钩子函数对象。

生命周期钩子函数详解

自定义指令通过5个钩子函数控制DOM行为,各阶段触发时机如下:

钩子函数触发时机用途示例
bind指令首次绑定到元素时(元素未插入DOM)初始化样式、事件监听
inserted元素插入父节点时(父节点存在即可)执行DOM操作(如自动聚焦)
update组件VNode更新时(可能在子VNode更新前)响应数据变化更新DOM
componentUpdated组件及子VNode全部更新后处理依赖子组件的DOM逻辑
unbind指令与元素解绑时(如组件销毁)清理事件监听、定时器

指令参数与使用技巧

参数传递与接收

  • 模板中绑定参数:通过v-指令名=值动态传递,如<div v-color="themeColor"></div>
  • 钩子函数中接收:通过第二个参数binding获取,例如:
    bind(el, binding) { el.style.color  = binding.value;  // binding.value 为传递的参数值 
    } 

钩子参数

每个钩子函数接收以下参数:

  1. el: 指令所绑定的元素,可以用来直接操作 DOM。
  2. binding: 包含以下属性的对象:
    • value: 传递给指令的值。
    • oldValue: 之前的值,仅在 update 和 componentUpdated 钩子中可用。无论值是否变化都会更新。
    • arg: 参数,即指令后的冒号后面的内容(如 v-mydirective:foo 的 "foo")。
    • modifiers: 修饰符对象(如 v-mydirective.foo.bar 的 { foo: true, bar: true })。
  3. vnode: Vue 编译生成的虚拟节点。
  4. prevVnode: 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

案例:

<template><div><p v-demo:foo.bar.baz="value"  v-if="show">这是一个由组件渲染的目标元素</p><button @click="show = !show"> 切换 </button><button @click="value = '测试'"> 修改内容 </button></div>
</template><script>export default {data(){return{value:"ces",show: true}},directives: {demo: {bind: function (el, binding, vnode) {console.log('--- DemoTarget 组件内 - bind 钩子 ---');el.style.opacity = 0.5;},inserted: function (el, binding, vnode) {console.log('--- DemoTarget 组件内 - inserted 钩子 ---');el.style.opacity = 1;el.textContent = `显示值: ${binding.value}`;},update: function (el, binding, vnode, oldVnode) {if (binding.value === binding.oldValue) return;console.log('log', `update: 值从 "${binding.oldValue}" 变为 "${binding.value}"`);el.textContent = `显示值: ${binding.value}`;},componentUpdated: function (el, binding, vnode, oldVnode) {console.log('log', `componentUpdated: 组件及其子组件已更新`);},unbind: function (el, binding, vnode) {console.log('log', 'unbind: 指令已解绑');el.textContent = '指令已移除';el.style.opacity = 0.3;}}}
}
</script>

    注意事项与最佳实践

    1. 避免过度使用:优先使用组件或计算属性,仅在需底层DOM操作时使用指令。
    2. 钩子函数选择:初始化操作放bind,DOM相关操作放inserted
    3. Vue2与Vue3差异:Vue3钩子函数名称调整(如bindbeforeMount),使用时需注意版本兼容。

    实战案例:自定义弹窗指令

    通过v-popup指令实现点击元素显示弹窗的功能:

    Vue.directive('popup',  { inserted(el, binding) { el.addEventListener('click',  () => { alert(binding.value);  // 点击时弹出参数内容 }); }, unbind(el) { el.removeEventListener('click');  // 解绑时清理事件 } 
    }); 

    使用方式:<button v-popup="提示内容">点击弹窗</button>

    通过自定义指令,开发者可灵活扩展Vue功能,尤其适合封装复用性高的DOM操作逻辑。合理设计钩子函数和参数传递,能有效提升代码可维护性。

    http://www.xdnf.cn/news/1254187.html

    相关文章:

  1. vscode 打开设置
  2. 配置VScode内置Emmet自动补全代码
  3. VSCode ssh一直在Setting up SSH Host xxx: Copying VS Code Server to host with scp等待
  4. 中介效应分析 原理解释 实例分析
  5. 杂谈:大模型与垂直场景融合的技术趋势
  6. 2025世界机器人大会开幕在即,英伟达/微美全息前瞻聚焦深化场景实践布局!
  7. 基于Python的超声波OFDM数字通信链路设计与实现
  8. Self-RAG:基于自我反思的检索增强生成框架技术解析
  9. AI巨模型对决2025:五强争霸,谁能称王?
  10. 嵌入式开发学习———Linux环境下IO进程线程学习(五)
  11. 【软考系统架构设计师备考笔记4】 - 英语语法一篇通
  12. 【感知机】感知机(perceptron)模型与几何解释
  13. 并发编程常见问题排查与解决:从死锁到线程竞争的实战指南
  14. word2vector细致分解(CBOW, SKIP_GRAM, 层次soft Max, 负采样)
  15. 【前端开发】三. JS运算符
  16. 奔图P2500NW打印机手机无线连接方法
  17. JavaScript 基础语法
  18. Kubernetes中无法删除一个对象,持续处于Terminating状态的解决方案
  19. Linux发行版分类与Centos替代品
  20. 大数据存储域——HDFS存储系统
  21. 进阶向:AI聊天机器人(NLP+DeepSeek API)
  22. 【感知机】感知机(perceptron)学习策略
  23. Git 乱码文件处理全流程指南:从识别到彻底清除
  24. WebView 中控制光标
  25. VINS-Fusion+UWB辅助算法高精度实现
  26. Pytest项目_day05(requests加入headers)
  27. 移动端跨平台框架(支持Harmony、iOS、Android)
  28. cacti
  29. vue3 find 数组查找方法
  30. TrustZone技术详解————这篇是AI写的包括图