Blazor表格:点击非下拉区域关闭编辑态的实现求助
Hey there! Let's sort out that "click anywhere outside the dropdown to exit edit mode" problem you're facing. Blazor's built-in @onfocusout works great for element-specific focus loss, but it can't catch clicks on totally unrelated parts of the page—so we'll use a tiny bit of JavaScript interop to make this happen. Don't worry, I'll break this down step by step so it's super easy to follow, even if you've never touched JS before.
Step 1: Add the JavaScript to Your Project
First, we need a small JS script to listen for clicks across the whole page and tell Blazor when we click outside your dropdown.
If you're using Server-side Blazor, open your _Host.cshtml file. For WebAssembly Blazor, open index.html. Scroll to just before the closing </body> tag and add this code:
<script> // Store a reference to our Blazor component so JS can talk to it let blazorComponentInstance = null; // This lets Blazor pass us a reference to the component window.setBlazorComponentRef = function(instance) { blazorComponentInstance = instance; }; // Clean up the reference when the component is destroyed window.clearBlazorComponentRef = function() { blazorComponentInstance = null; }; // Listen for every click on the page window.addEventListener('click', function(event) { // Get the dropdown container (your <td> with id "dropdown") const dropdownContainer = document.getElementById('dropdown'); // Check if we clicked OUTSIDE the dropdown and the dropdown is visible if (dropdownContainer && !dropdownContainer.contains(event.target)) { // If we have a component reference, tell Blazor to stop editing if (blazorComponentInstance) { blazorComponentInstance.invokeMethodAsync('StopEditWhenClickedOutside'); } } }); </script>
Step 2: Update Your Blazor Component
Now we'll modify your component to connect with the JS script, handle the callback, and clean up properly.
First, add these lines at the top of your component:
@inject IJSRuntime JSRuntime @implements IAsyncDisposable
Then update your @code block with the following logic (replace YourComponentName with the actual name of your component):
@code { private DotNetObjectReference<YourComponentName>? _componentRef; private bool isDropdown = false; // Keep your existing variable and search.blah method here protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { // Create a reference to this component so JS can call its methods _componentRef = DotNetObjectReference.Create(this); await JSRuntime.InvokeVoidAsync("setBlazorComponentRef", _componentRef); } await base.OnAfterRenderAsync(firstRender); } // This method will be called by JavaScript when clicking outside the dropdown [JSInvokable] public void StopEditWhenClickedOutside() { if (isDropdown) { StopEdit(); } } // Your existing BeginEdit method (keep this!) private void BeginEdit() { isDropdown = true; StateHasChanged(); } // Your existing StopEdit method (keep this too!) private void StopEdit() { isDropdown = false; StateHasChanged(); } // Clean up the component reference to avoid memory leaks public async ValueTask DisposeAsync() { if (_componentRef != null) { _componentRef.Dispose(); await JSRuntime.InvokeVoidAsync("clearBlazorComponentRef"); } } }
Step 3: Tweak Your HTML Markup
You had duplicate @onfocusout attributes on your dropdown <td>—let's clean that up, and make sure the IDs are set correctly:
<td class="@(isDropdown ? "hide" : "")" @onclick="BeginEdit"> This is a test </td> <td class="@(isDropdown ? "" : "hide")" id="dropdown"> <div class="input-group input-group-sm mb-3"> <BlazoredTypeahead SearchMethod="search.blah" @bind-Value="@variable" EnableDropDown="true" Debounce="500"> <SelectedTemplate Context="ctx"> @ctx </SelectedTemplate> <ResultTemplate Context="ctx"> @ctx </ResultTemplate> </BlazoredTypeahead> </div> </td>
How This Works
- The JS script listens for every click on the page. When it detects a click outside your dropdown
<td>, it calls theStopEditWhenClickedOutsidemethod in your Blazor component. - The
DotNetObjectReferencelets JS "talk" directly to your component, which is how we trigger the edit mode to turn off. - We clean up the reference when the component is disposed to avoid memory leaks—super important for long-running apps!
If you have multiple rows in your table (instead of just one test row), you'll need to use unique IDs for each dropdown (like id="dropdown-@row.Id"), and adjust the JS to check against the active dropdown. But for your current setup, this should work perfectly.
内容的提问来源于stack exchange,提问作者mymemesarespiciest

