为什么我的视图部分消失了?

Why is the section of my view disappears?

我有一个用 livewire 制作的视图,它包含两个动态添加的口语部分和另一个课程和证书部分。在我添加添加证书部分之前,语言部分工作正常。现在,当用户单击证书部分的添加部分以添加新的部分时,添加的语言部分之一会消失,然后在您添加另一个语言部分后会再次出现。我猜它会在视图重新呈现后再次出现。我一直在返回并强制将函数从 render 方法移动到 update/updated/hydrate/dehydrate 但没有运气。起初,我认为它与我在我的视图中使用的 $loop->index 有关,但在更改之后我意识到它不是。我在这里遇到了死胡同,无法弄清楚这里发生了什么。

我还对正在发生的事情进行了屏幕记录,这样可能会有所帮助: https://drive.google.com/file/d/1Hq2wTKcPvhs05SKFMICaRoOAzpSyj9Iz/view?usp=sharing

查看部分:

<!-- language section -->
<div class="card card-profile shadow-sm mt-4">
    <div class="px-4 mt-4 mb-4">
        <div class="h5 font-weight-bold mb-4">Spoken languages</div>
        <div class="heading text-muted mb-4">you only can add 3 languages to your profile.</div>
            @foreach ($languages as $lindex => $language)
                <div class="card card-body mb-4" wire:key="{{ $lindex }}">
                    <div class="text-left"><span class="fa fa-trash text-gray language-delete" wire:click="removeLanguage({{ $lindex }}, {{ !empty($language['id']) ? $language['id'] : 0 }})"></span></div>
                    <div class="row">
                        <div class="form-group col-md-6">
                            <label class="" for="languageName">language</label>
                            <select class="form-control form-control-alternative" name="language-name" {{-- id="languageName" --}} wire:model="languages.{{ $lindex }}.language_name">
                                <option value="" class="form-control" selected disabled>select language</option>
                                @foreach ($language_names as $name)
                                    <option value="{{ $name->abbreviation }}" class="form-control">{{ $name->language }}</option>
                                @endforeach
                            </select>
                        </div>
                        <div class="form-group col-md-6">
                            <label class="" for="languageProficiency">proficiency level</label>
                            <select class="form-control form-control-alternative" name="language-proficiency" {{-- id="languageProficiency" --}} wire:model="languages.{{ $lindex }}.language_level">
                                <option value="" class="form-control" selected disabled>proficiency level</option>
                                @foreach ($language_levels as $level)
                                    <option value="{{ $level->level }}" class="form-control">{{ $level->name }}</option>
                                @endforeach
                            </select>
                        </div>
                    </div>
                </div>
            @endforeach

            @error('languages.*.language_level')
                <small class="text-warning">{{ $message }}</small>
            @enderror
            @error('languages.*.language_language')
                <small class="text-warning">{{ $message }}</small>
            @enderror

            @if (count($languages) < 3)
                <div class="row">
                    <div class="col-md-12">
                        <button type="button" class="btn btn-outline-secondary btn-round btn-block" wire:click="addLanguage"><span class="btn-inner--icon"><i class="fa fa-plus fa-2x"></i></span></button>
                    </div>
                </div>
            @endif

    </div>
</div>
<!-- end language section -->

<!-- other certificates section -->
<div class="card card-profile shadow-sm mt-4">
    <div class="px-4 mt-4 mb-4">
        <div class="h5 font-weight-bold mb-4">Other related certificates</div>
        <div class="heading text-muted mb-4">if you have other related certificates in your files you can add then here.</div>
        @foreach ($certificates as $cindex => $certificate)
            <div class="card card-body mb-4" wire:key="{{ $cindex }}">
                <div class="row">
                    <div class="form-group col-md-6">
                        <label class="" for="other-certificates-name">certificate name</label>
                        <input type="text" class="form-control form-control-alternative" placeholder="" name="ptherCertificatesName">
                    </div>
                    <div class="form-group col-md-6">
                        <label class="" for="other-certificates-school-name">School name</label>
                        <input type="text" class="form-control form-control-alternative" placeholder="" name="otherCertificatesSchoolName">
                    </div>
                    <div class="form-group col-md-6">
                        <label class="" for="other-certificates-verification-link">URL<small>(optional)</small></label>
                        <input type="text" class="form-control form-control-alternative text-left" placeholder="" name="otherCertificatesVerificationLink">
                    </div>
                    <div class="form-group col" dir="ltr">
                        <label class="" for="other-certificates-grad-date" dir="rtl">finished date</label>
                        <div class="input-group input-group-alternative">
                            <div class="input-group-prepend">
                            <span class="input-group-text"><i class="ni ni-calendar-grid-58"></i></span>
                            </div>
                            <input type="text" class="form-control form-control-alternative datePicker" placeholder="" name="otherCertificatesGradDate" value="">
                        </div>
                    </div>
                </div>
            </div>
        @endforeach
        @if (count($certificates) < 5)
            <div class="row">
                <div class="col-md-12">
                <button type="button" class="btn btn-outline-secondary btn-round btn-block" wire:click="addCertificate"><span class="btn-inner--icon"><i class="fa fa-plus fa-2x"></i></span></button>
                </div>
            </div>
        @endif
    </div>
</div>
<!-- end other certificates section -->

Livewire 组件控制器:

<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\CityName;
use App\Models\Language;
use App\Models\LanguageLevel;
use App\Models\User;
use App\Models\UserLanguage;
use App\Models\UserProfile;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;

class UserInfo extends Component
{
    public $name;
    public $email;
    public $phone;
    public $states = [];
    public $selectedstate;
    public $cities = [];
    public $selectedcity;
    public $jobTitle;
    public $aboutMe;

    public $employer;
    public $position;

    public $edu_course;
    public $edu_school;
    public $edu_level;
    public $edu_start_date;
    public $edu_end_date;

    public $employment_looking;
    public $employment_hired;

    public $twitter;
    public $linkedin;
    public $github;
    public $instagram;
    public $website;

    public $languages = [];
    public $language_names;
    public $language_levels;
    public $languageToDelete = [];

    public $certificates = [];
    public $certificate_name;
    public $certificate_school;
    public $certificate_link;
    public $certificate_date;
    public $certificateToDelete = [];

    public $skillsQuery;
    public $skillResults;

    public $skills;





    public function render()
    {
        $this->retriveStates();
        $this->retriveCities();
        $this->retriveLanguages();
        return view('livewire.user-info');
    }



    public function retriveStates()
    {
        $this->states = CityName::distinct()->get(['state']);
    }


    public function retriveCities()
    {
        $this->cities = CityName::where('state', $this->selectedstate)->get(['city']);
    }


    public function updatedSkillsQuery()
    {
        $this->skillResults = $this->skills->where('name', 'like', $this->skillsQuery) ?? collect();
    }


    public function retriveLanguages()
    {
        $this->language_names = Language::all();
        $this->language_levels = LanguageLevel::all();
    }


    public function addLanguage()
    {
        if (count($this->languages) <= 3)
        {
            array_push($this->languages, ['language_name'=>'', 'language_level'=>'', 'id'=>'']);
        }
        else
        {
            $this->sweetAlert('error', 'you only can add 3 languages to your profile.');
        }
    }


    public function getUserLanguages()
    {
        $this->languages = auth()->user()->userLanguages->toArray();
    }


    public function removeLanguage($languagePosition, $languageId)
    {
        if (isset($languageId))
        {
            if ($languageId == 0)
            {
                array_splice($this->languages, $languagePosition, 1);
            }
            else
            {
                array_push($this->languageToDelete, $languageId);
                array_splice($this->languages, $languagePosition, 1);
            }
        }
    }


    public function addCertificate()
    {
        if (count($this->certificates) <= 5)
        {
            array_push($this->certificates, ['name'=>'', 'school'=>'', 'link'=>'', 'date'=>'', 'id'=>'']);
            /* dd($this->languages); */
        }
        else
        {
            $this->sweetAlert('error', 'you only can add 5 certificates to your profile.');
        }
    }


    public function mount()
    {

        $this->skills = collect([
            ['name' => 'vue'],
            ['name' => 'vue'],
            ['name' => 'vue'],
            ['name' => 'laravel'],
            ['name' => 'laravel'],
            ['name' => 'laravel'],
        ]);

        $this->skillResults= [];
        $this->skillsQuery = '';
        /* $this->retriveLanguages();
        $this->retriveStates();
        $this->retriveCities(); */
        $this->getUserLanguages();
        $this->name = auth()->user()->name;
        $this->email = auth()->user()->email;
        $this->phone = auth()->user()->phone;
        $this->selectedstate = auth()->user()->userprofile->state;
        $this->selectedcity = auth()->user()->userprofile->city;
        $this->jobTitle = auth()->user()->userprofile->job_title;
        $this->aboutMe = auth()->user()->userprofile->about_me;
        $this->employer = auth()->user()->userprofile->employer;
        $this->position = auth()->user()->userprofile->position;
        $this->edu_course = auth()->user()->userprofile->edu_course;
        $this->edu_school = auth()->user()->userprofile->edu_school;
        $this->edu_level = auth()->user()->userprofile->edu_level;
        $this->edu_start_date = auth()->user()->userprofile->edu_start_date;
        $this->edu_end_date = auth()->user()->userprofile->edu_end_date;
        $this->employment_looking = auth()->user()->userprofile->employment_looking;
        $this->employment_hired = auth()->user()->userprofile->employment_hired;
        $this->twitter = auth()->user()->userprofile->twitter;
        $this->linkedin = auth()->user()->userprofile->linkedin;
        $this->github = auth()->user()->userprofile->github;
        $this->instagram = auth()->user()->userprofile->instagram;
        $this->website = auth()->user()->userprofile->website;

    }


    public function rules()
    {
        return [
            'name' => ['required', 'string', 'max:250'],
            'email' => [
                'required',
                'email',
                'max:250',
                Rule::unique('users')->ignore(auth()->id()),
            ],
            'phone' => ['required', 'digits:11'],
            'selectedstate' => 'required',
            'selectedcity' => 'required',
            'jobTitle' => ['required', 'string', 'max:250'],
            'aboutMe' => ['required', 'string', 'max:250'],
            'employer' => ['string', 'max:250'],
            'position' => ['string', 'max:250'],
            'edu_course' => ['nullable', 'string', 'max:250'],
            'edu_school' => ['nullable', 'string', 'max:250'],
            'edu_level' => ['nullable', 'string', 'max:250'],
            'edu_start_date' => ['nullable', 'string'],
            'edu_end_date' => ['nullable', 'string'],
            'employment_looking' => ['nullable', 'boolean'],
            'employment_hired' => ['nullable', 'boolean'],
            'twitter' => ['nullable', 'string', 'max:250'],
            'linkedin' => ['nullable', 'string', 'max:250'],
            'github' => ['nullable', 'string', 'max:250'],
            'instagram' => ['nullable', 'string', 'max:250'],
            'website' => ['nullable', 'string', 'max:250'],
            'languages.*.language_name' => ['required', 'exists:App\Models\Language,abbreviation'],
            'languages.*.language_level' => ['required', 'exists:App\Models\LanguageLevel,level'],
        ];
    }


    public function submit()
    {
        $user = Auth::user();

        $this->validate();

        User::where('id', auth()->id())->update([
            'name' => $this->name,
            'email' => $this->email,
            'phone' => $this->phone,
        ]);

        UserProfile::where('user_id', auth()->id())->update([
            'state' => $this->selectedstate,
            'city' => $this->selectedcity,
            'job_title' => $this->jobTitle,
            'about_me' => $this->aboutMe,
            'employer' => $this->employer,
            'position' => $this->position,
            'edu_course' => $this->edu_course,
            'edu_school' => $this->edu_school,
            'edu_level' => $this->edu_level,
            'edu_start_date' => $this->edu_start_date,
            'edu_end_date' => $this->edu_end_date,
            'employment_looking' => $this->employment_looking,
            'employment_hired' => $this->employment_hired,
            'twitter' => $this->twitter,
            'linkedin' => $this->linkedin,
            'github' => $this->github,
            'instagram' => $this->instagram,
            'website' => $this->website,
        ]);


        if (!empty($this->languageToDelete))
        {
            /* $user = Auth::user(); */
            foreach ($this->languageToDelete as $delete)
            {
                $user->userLanguages()->where('id', $delete)->delete();
            }
        }

        foreach ($this->languages as $language)
        {
            /* $user = Auth::user(); */
            $user->userLanguages()->updateOrCreate([
                'language_name' => $language['language_name'],
            ],
            [
                'language_name' => $language['language_name'],
                'language_level' => $language['language_level']
            ]
            );

        }

        $this->getUserLanguages();

        $this->sweetAlert('success', 'changes saved!');

    }


    public function sweetAlert($type, $message)
    {
        $this->alert($type, $message, [
            'position'  =>  'bottom-end',
            'timer'  =>  5000,
            'toast'  =>  true,
            'text' => null,
            'showCancelButton'  =>  false,
            'showConfirmButton'  =>  false
        ]);
    }

}

问题已解决。问题确实是由多个循环索引引起的 DOM 问题。正如我最初所想的那样,$loop->index 导致了它,我在正确的轨道上将其更改为 $languages as $lindex => $language 之类的其他东西,但显然即使这样做,这两个部分仍然具有相同的 wire:key 因为循环迭代 returns 0,1,2 依此类推。因此,通过将字符串附加到 lang{{ $loop->index }} 之类的键,它们将是唯一的,因此问题得到解决。