Vue项目中原生JS设置HTMLElement.style修改表单样式无效求助
问题:Vue项目中输入框获焦时无法修改表单样式
在大型Vue项目中,原本尝试通过切换类名实现「指定输入框获焦时修改表单背景色」的效果,失败后改用原生JS通过.style操作DOM,但目前仅能修改输入框自身背景色,表单样式完全无变化。
相关代码
<template> <form @submit.prevent ref="formElement" class="w-full form"> <h1 class="mt-5 mb-3 text-2xl text-primary font-bold capitalize md:mt-0 md:mb-5 md:text-3xl" > {{ t('fullNameForm.title') }} </h1> <p class="mb-5 text-sm text-secondary md:mb-10"> {{ t('fullNameForm.description') }} </p> <div class="flex flex-col gap-y-4"> <Input id="firstName" autocomplete="given-name" :errors="v$.firstName.$errors" v-model.trim="v$.firstName.$model" > {{ t('firstName') }} </Input> <Input id="lastName" autocomplete="family-name" :errors="v$.lastName.$errors" v-model.trim="v$.lastName.$model" > {{ t('lastName') }} </Input> </div> <div class="w-full h-24 px-4 py-6 absolute left-0 bottom-0 sm:static sm:px-0" > <Button type="submit" :loading="loading" :disabled="v$.$invalid" class="w-full h-12 capitalize" @click="submit()" > {{ t('next') }} </Button> </div> </form> </template> <script lang="ts"> import { defineComponent, ref, reactive, onMounted } from 'vue' import { useStore } from 'vuex' import { useI18n } from 'vue-i18n' import useVuelidate from '@vuelidate/core' import { required, minLength, maxLength } from '@vuelidate/validators' import Input from '@/components/Input.vue' import Button from '@/components/ButtonV2.vue' export default defineComponent({ name: 'FullNameForm', components: { Input, Button }, emits: ['submit'], setup(props, { emit }) { const store = useStore() const { t } = useI18n() const formElement = ref<HTMLElement | null>(null) const formEl = document.querySelector('.form') as HTMLElement | null onMounted(() => { window.addEventListener('keydown', event => { if (event.key === 'Enter') submit() }) const lastnameInput = document.querySelector( '#lastName' ) as HTMLElement | null if (lastnameInput || formEl) { lastnameInput?.addEventListener('focus', () => { lastnameInput.style.backgroundColor = 'red' if (formElement.value && formEl && lastnameInput) { formElement.value.style.backgroundColor = 'orange' formElement.value.classList.add('keyboard') formEl.style.backgroundColor = 'gray' } }) } }) return { t, form, v$, loading, submit, formElement } } }) </script> <style scoped> .form.keyboard { background: rgb(81, 179, 146); } </style>
已排查的问题
- 内部嵌套的条件判断始终不生效
- 外层条件判断加入
formEl或formElement后,即使把逻辑运算符从||改为&&也无效果,甚至输入框不再响应获焦事件
解决方案
核心问题分析
- DOM获取时机错误:
const formEl = document.querySelector('.form')在setup阶段执行,此时组件尚未挂载,DOM节点还未渲染,导致formEl始终为null - 条件判断逻辑错误:外层
if (lastnameInput || formEl)只要输入框存在就会绑定事件,但内部判断又要求formEl存在,导致内部代码永远不会执行;如果改成&&,因为formEl是null,事件绑定逻辑直接被跳过 - Scoped样式隔离:通过原生JS添加的
keyboard类,受Vue scoped样式影响,可能无法正确作用于表单元素
方案1:用Vue响应式写法替代原生DOM操作(推荐)
完全遵循Vue的响应式开发模式,避免直接操作DOM:
<template> <form @submit.prevent ref="formElement" class="w-full form" :class="{ keyboard: isLastNameFocused }"> <!-- 其他内容不变 --> <Input id="lastName" autocomplete="family-name" :errors="v$.lastName.$errors" v-model.trim="v$.lastName.$model" @focus="isLastNameFocused = true" @blur="isLastNameFocused = false" > {{ t('lastName') }} </Input> <!-- 其他内容不变 --> </form> </template> <script lang="ts"> import { defineComponent, ref, reactive, onMounted } from 'vue' // 其他导入不变 export default defineComponent({ // 其他配置不变 setup(props, { emit }) { // 新增响应式变量标记输入框是否获焦 const isLastNameFocused = ref(false) // 保留Enter键提交逻辑,移除原生DOM操作代码 onMounted(() => { window.addEventListener('keydown', event => { if (event.key === 'Enter') submit() }) }) return { t, form, v$, loading, submit, formElement, isLastNameFocused } } }) </script> <style scoped> .form.keyboard { background: rgb(81, 179, 146); } </style>
方案2:修复原生JS操作的问题
如果必须保留原生DOM操作,调整代码如下:
<script lang="ts"> // ...其他代码 setup(props, { emit }) { // ...其他变量 const formElement = ref<HTMLElement | null>(null) onMounted(() => { window.addEventListener('keydown', event => { if (event.key === 'Enter') submit() }) // 将DOM获取逻辑移到onMounted内,确保组件已挂载 const lastnameInput = document.querySelector('#lastName') as HTMLElement | null const formEl = document.querySelector('.form') as HTMLElement | null // 确保输入框和表单元素都存在才绑定事件 if (lastnameInput && formElement.value && formEl) { lastnameInput.addEventListener('focus', () => { lastnameInput.style.backgroundColor = 'red' formElement.value.style.backgroundColor = 'orange' formElement.value.classList.add('keyboard') formEl.style.backgroundColor = 'gray' }) // 补充blur事件恢复样式 lastnameInput.addEventListener('blur', () => { lastnameInput.style.backgroundColor = '' formElement.value.style.backgroundColor = '' formElement.value.classList.remove('keyboard') formEl.style.backgroundColor = '' }) } }) return { // ...返回变量 } } </script>
内容的提问来源于stack exchange,提问作者Tomas Gil Amoedo
相关产品推荐
相关产品推荐

