You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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后,即使把逻辑运算符从||改为&&也无效果,甚至输入框不再响应获焦事件

解决方案

核心问题分析

  1. DOM获取时机错误:const formEl = document.querySelector('.form')在setup阶段执行,此时组件尚未挂载,DOM节点还未渲染,导致formEl始终为null
  2. 条件判断逻辑错误:外层if (lastnameInput || formEl)只要输入框存在就会绑定事件,但内部判断又要求formEl存在,导致内部代码永远不会执行;如果改成&&,因为formEl是null,事件绑定逻辑直接被跳过
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 04:36:13