Vue为什么不推荐直接操作dom
Vue不推荐开发者直接操作dom(当然这并不表示不能这么做),有以下几个原因:
1、破坏了代码模块化结构导致代码腐化:
组件原本可以控制哪些dom操作可以对外暴露(即对应methods中的方法),但直接操作dom跳过了这个控制,这会导致不可预料的后果。
例如组件A中有一个输入框,且组件A没有暴露可以删除输入框的方法,此时组件A会认为输入框是必定存在的,可以放心获取输入框的信息,但在其他组件中通过直接操作dom的方式删除了这个输入框,组件A无法感知,此时获取输入框信息时就会出错。
而当直接操作dom的行为随着项目代码的膨胀越来越多时,项目代码会趋于腐化,当组件数量达到一定程度时,定位直接操作dom导致的问题耗时会呈指数级上升,这对多人参与开发的项目来说灾难性的。
用上面给出的例子来说,如果组件A的开发者不是直接操作dom行为的作者,那对这个开发者而言,定位输入框究竟在哪里被删掉了无疑是恐怖的:
任何一个组件都有可能这么做,要定位就必须一个组件一个组件排查;
即使运气不错很快排查到问题所在,也不敢随便改动,因为不清楚在其他组件里为什么要这么做,是逻辑设计的漏洞,还是代码出了bug,只有写这块逻辑的人才知道;
最可怕的是,开发者不知道以后还会有多少这样的问题,如果是个通用模块或基础组件,也许隔三差五就要来这么一次。
2、过多的直接操作dom行为增加了代码的耦合性:
当包含直接操作dom行为的组件在别处使用时,直接操作dom的代码有可能不可用。
如果直接操作dom的代码没有检查dom状态或没有严格检查dom是否为想要操作的dom,则直接复用可能导致不可预料的后果,即意味着这个组件只能在特定位置使用,耦合性提高,复用性降低。
3、操作不属于自己的dom时,dom状态无法预知:
dom归属于其他组件时,dom可能没有生成,也有可能dom所属组件并没有被加载或使用。
如dom所在组件用v-if控制了dom的隐藏/显示,这样就必须在操作dom之前判断dom的状态,增加了冗余代码;
组件状态的变化可能导致获取到的dom不是预想的dom。
如本来想获取组件A下的class为xxx的dom,但获取dom时组件A已经被替换为组件B,而组件B内恰好同样有class为xxx的dom,这样如果没有严格检查的话很容易操作了错误的dom。
直接操作dom方式可以做的事情使用VUE的虚拟dom也一样可以做
// 直接操作DOM时,常用的一些API和示例包括:
// querySelector:通过选择器获取元素。 const element = document.querySelector('.my-element');
// getElementById:通过元素ID获取元素。 const element = document.getElementById('my-element');
// createElement:创建新元素。 const newElement = document.createElement('div');
// appendChild:将子元素添加到父元素中。 const parentElement = document.querySelector('.parent-element');
parentElement.appendChild(newElement);
// removeChild:从父元素中移除子元素。 const parentElement = document.querySelector('.parent-element'); const childElement = document.querySelector('.child-element'); parentElement.removeChild(childElement);
// setAttribute:设置元素属性。 element.setAttribute('class', 'my-class');
// getAttribute:获取元素属性值。 const className = element.getAttribute('class');
// classList:操作元素的类名集合。 element.classList.add('new-class'); element.classList.remove('old-class'); element.classList.toggle('active'); element.classList.contains('my-class');
在VUE中使用虚拟dom操作
1、直接在基本元素上使用ref
<template> <div> <input ref="input"/> </div> </template> <script> export default { mounted() { const el= this.$refs.input;
// 聚焦输入框
el.focus();
// 取消聚焦
el.blur();
// 修改输入框的样式
el.style.color = 'red';
el.style.border = '1px solid blue';
// 往class中添加或移除is-active
el.classList.add('is-active');
el.classList.remove('is-active');
//主动触发鼠标移入事件
el.dispatchEvent(new MouseEvent('mouseenter'));
}
}
</script>
2、在组件处上使用ref(未循环的组件上的ref是对象)
<template> <div> <child-component ref="myChild"></child-component> </div> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, mounted(){ const child = this.$refs.myChild.$el;
// 往组件的根元素class中添加或移除is-active
el.classList.add('is-active');
el.classList.remove('is-active');
}
}
</script>
3、在组件处上使用ref(循环的组件上的ref是数组)
<template> <div> <child-component v-for="i in 5" :key="i" :ref="'myChild_'+i"></child-component> </div> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, mounted(){
// 注意此时ref对象是数组 const child = this.$refs.myChild_0[0].$el; // 往class中添加或移除is-active el.classList.add('is-active'); el.classList.remove('is-active');
}
}
</script>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)