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

Laravel Livewire选中Others时输入框显示后自动消失问题

问题原因
  • 原生JS手动修改DOM样式控制输入框显隐的逻辑和Livewire的渲染机制冲突:wire:model绑定值变化时会触发组件重渲染,DOM会被重置为Blade初始渲染状态(即输入框容器默认display: none),所以JS修改的显示状态会被覆盖,才会出现输入框闪一下就消失的现象。
  • 原代码存在逻辑冲突:下拉选择框和自定义输入框同时绑定user.test同一个字段,选中「Others」后只要在输入框输入内容,就会直接覆盖下拉框的选中值,导致选中状态失效。
  • 原select标签下所有option都加了selected属性,不符合HTML规范,默认选中项只能有一个。
修复方案

完全依托Livewire状态驱动视图的特性实现显隐逻辑,不要混用原生DOM操作,同时拆分字段解决值冲突问题。

1. 调整Livewire组件类代码

新增单独的属性存储「Others」选项的自定义输入值,补充对应校验规则,提交时判断取值:

<?php

namespace App\Http\Livewire\User;

use App\Models\Role;
use App\Models\User;
use Livewire\Component;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class Create extends Component
{
    public User $user;

    public array $roles = [];

    public string $password = '';

    public array $listsForFields = [];

    // 新增:存储Others选项的自定义输入内容
    public string $testCustomValue = '';


    public function mount(User $user, Request $request)
    {
        $this->user = $user;
        // 初始化test字段默认值,避免类型错误
        $this->user->test = '';
        $this->initListsForFields();
    }

    public function render()
    {
        return view('livewire.user.create');
    }

    public function submit(Request $request)
    {
        $this->validate();
        // 选中Others时,将自定义输入内容赋值给test字段存储
        if ($this->user->test === 'Others') {
            $this->user->test = $this->testCustomValue;
        }
        $this->user->password = $this->password;
        
        $this->user->save();
        $this->user->roles()->sync($this->roles);

        return redirect()->route('admin.users.index');
    }

    protected function rules(): array
    {
        return [
            'user.name' => [
                'string',
                'required',
            ],
            'user.email' => [
                'email:rfc',
                'required',
                'unique:users,email',
            ],
            'password' => [
                'string',
                'required',
            ],
            'roles' => [
                'required',
                'array',
            ],
            'roles.*.id' => [
                'integer',
                'exists:roles,id',
            ],
            'user.locale' => [
                'string',
                'nullable',
            ],
            'user.test' => [
                'nullable',
                // 限制下拉选项合法值
                'in:Yes,No,Others',
            ],
            'testCustomValue' => [
                'nullable',
                'string',
                // 选中Others时自定义输入框必填
                'required_if:user.test,Others',
            ],
        ];
    }

    protected function initListsForFields(): void
    {
        $this->listsForFields['roles'] = Role::pluck('title', 'id')->toArray();
    }
}

2. 修改Blade模板代码

移除原生JS事件和DOM操作,用Blade条件判断控制输入框显隐,修正HTML语法错误:

<form wire:submit.prevent="submit" class="pt-3">

    <div class="form-group {{ $errors->has('user.name') ? 'invalid' : '' }}">
        <label class="form-label required" for="name">{{ trans('cruds.user.fields.name') }}</label>
        <input class="form-control" type="text" name="name" id="name" required wire:model.defer="user.name">
        <div class="validation-message">
            {{ $errors->first('user.name') }}
        </div>
        <div class="help-block">
            {{ trans('cruds.user.fields.name_helper') }}
        </div>
    </div>
    <div class="form-group {{ $errors->has('user.email') ? 'invalid' : '' }}">
        <label class="form-label required" for="email">{{ trans('cruds.user.fields.email') }}</label>
        <input class="form-control" type="email" name="email" id="email" required wire:model.defer="user.email">
        <div class="validation-message">
            {{ $errors->first('user.email') }}
        </div>
        <div class="help-block">
            {{ trans('cruds.user.fields.email_helper') }}
        </div>
    </div>
    <div class="form-group {{ $errors->has('user.password') ? 'invalid' : '' }}">
        <label class="form-label required" for="password">{{ trans('cruds.user.fields.password') }}</label>
        <input class="form-control" type="password" name="password" id="password" required wire:model.defer="password">
        <div class="validation-message">
            {{ $errors->first('user.password') }}
        </div>
        <div class="help-block">
            {{ trans('cruds.user.fields.password_helper') }}
        </div>
    </div>
    <div class="form-group {{ $errors->has('roles') ? 'invalid' : '' }}">
        <label class="form-label required" for="roles">{{ trans('cruds.user.fields.roles') }}</label>
        <x-select-list class="form-control" required id="roles" name="roles" wire:model="roles" :options="$this->listsForFields['roles']" multiple />
        <div class="validation-message">
            {{ $errors->first('roles') }}
        </div>
        <div class="help-block">
            {{ trans('cruds.user.fields.roles_helper') }}
        </div>
    </div>
    <div class="form-group {{ $errors->has('user.locale') ? 'invalid' : '' }}">
        <label class="form-label" for="locale">{{ trans('cruds.user.fields.locale') }}</label>
        <input class="form-control" type="text" name="locale" id="locale" wire:model.defer="user.locale">
        <div class="validation-message">
            {{ $errors->first('user.locale') }}
        </div>
        <div class="help-block">
            {{ trans('cruds.user.fields.locale_helper') }}
        </div>
    </div>
    <div class="form-group {{ $errors->has('user.test') ? 'invalid' : '' }}">
        <label class="form-label">{{ trans('cruds.user.fields.test') }}</label>
        {{-- 移除原生onchange事件,删除option上多余的selected属性 --}}
        <select class="form-control" name="test" wire:model="user.test">
            <option value="" disabled selected>{{ trans('global.pleaseSelect') }}...</option>
            <option value="Yes">Yes</option>
            <option value="No">No</option>
            <option value="Others">Others</option>
        </select>
        <div class="validation-message">
            {{ $errors->first('user.test') }}
        </div>
        <div class="help-block">
            {{ trans('cruds.user.fields.test_helper') }}
        </div>
    </div>

    {{-- 用Blade条件判断控制显隐,移除原生style隐藏逻辑 --}}
    @if($user->test === 'Others')
    <div class="form-group {{ $errors->has('testCustomValue') ? 'invalid' : '' }}">
        <label class="form-label required" for="testCustomValue">Input Test</label>
        {{-- 绑定到独立的自定义值字段,避免和下拉选项值冲突 --}}
        <input class="form-control" type="text" name="testCustomValue" id="testCustomValue" wire:model.defer="testCustomValue" style="text-transform:uppercase">
        <div class="validation-message">
            {{ $errors->first('testCustomValue') }}
        </div>
    </div>
    @endif

    <div class="form-group">
        <button class="mr-2 btn btn-indigo" type="submit">
            {{ trans('global.save') }}
        </button>
        <a href="{{ route('admin.users.index') }}" class="btn btn-secondary">
            {{ trans('global.cancel') }}
        </a>
    </div>
</form>
{{-- 删除原有的原生script代码,不需要手动编写testCheck函数 --}}

修改后不再依赖原生JS操作DOM,组件重渲染时会自动根据$user->test的状态判断输入框是否显示,不会出现状态重置问题,同时表单数据绑定、校验逻辑都能正常运行。

内容的提问来源于stack exchange,提问作者KrutSednar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 13:12:23