Vue自定义指令在数据变化时怎么不重新执行?
大家好,我在写一个自定义指令用来监听页面元素高度变化,但发现当绑定的数据更新后,指令里的逻辑没重新触发,这是怎么回事啊?
比如我写了这个v-resize指令:
Vue.directive('resize', {
bind(el, binding) {
const update = () => {
binding.value(el.offsetHeight)
}
window.addEventListener('resize', update)
}
})
然后在组件里这样用:
v-resize="handleHeight" 绑定的方法只在第一次渲染时触发,当我通过按钮修改了元素的padding导致高度变化后,指令没重新执行,这是不是要用其他钩子函数?
我试过在指令里加个console.log发现确实没再执行,难道必须手动解绑再绑定?感觉哪里漏了关键点…
componentUpdated钩子监听更新。bind只会在指令第一次绑定到元素时触发,之后数据变化或者 DOM 状态变化时,它不会自动重新执行。所以你需要用其他钩子函数来监听这些变化。第一步,咱们得明白 Vue 自定义指令有几个关键的钩子函数:
-
bind:只调用一次,指令绑定到元素时。-
inserted:元素插入父节点时调用。-
update:所在组件的 VNode 更新时调用,但注意性能问题,可能会被优化跳过。-
componentUpdated:所在组件的 VNode 及其子组件的 VNode 全部更新后调用。-
unbind:指令从元素上解绑时调用。针对你的需求,需要在元素高度变化时重新触发逻辑,可以利用
componentUpdated钩子,同时还需要监听窗口大小变化。第二步,我们改写一下你的指令代码:
第三步,解释一下代码改动的原因:
1.
bind中添加了事件监听器,并且把回调存储在元素的一个私有属性里(__resizeHandler__),方便后续清理。2.
componentUpdated是重点,当组件更新时会触发这个钩子,这样可以捕获到由于 padding 或者其他样式变化导致的高度改变。3.
unbind用来清理事件监听器,确保组件销毁时不会留下垃圾代码。第四步,使用这个指令时不需要额外修改,直接像原来一样用就可以了:
v-resize="handleHeight"其中
handleHeight是你定义的处理函数,比如这样:最后提醒一点,自定义指令虽然强大,但如果逻辑特别复杂的话,可能需要用渲染函数或者更高级的组合式 API 来实现类似功能。不过对于监听页面高度变化这种场景,上面的方案已经足够用了。
试试看,应该能解决你的问题!如果还有其他疑问随时问哈。