4
votes

Événement pour cliquer en dehors d'un div ou d'un élément pour le fermer sur Blazor

Dans mon projet server-side Blazor , je dois fermer un menu contextuel en cliquant en dehors du menu. J'utilise une simple instruction If pour afficher / masquer le pop-up en déclenchant l'événement onClick . mais il n'existe aucun événement de ce type pour fermer la fenêtre contextuelle en cliquant en dehors du menu contextuel. donc l'utilisateur ne doit le fermer qu'en cliquant sur l'élément avec l'événement onClick . Ma question est donc de savoir comment nous pouvons mieux résoudre ce problème sans utiliser JS ?

Merci d'avance.


0 commentaires

5 Réponses :


1
votes

Ajoutez un élément <div> la taille de l'écran et indexé en z 1 plus bas que le menu contextuel, mais plus haut que le reste de l'application. Vous devrez utiliser position: fixed dans la classe CSS, puis width: 100%; height: 100%; top: 0%; left: 0%; donc il remplira la page. La valeur d'affichage CSS initiale doit être display: none; . Lorsque vous ouvrez la fenêtre contextuelle, modifiez également la propriété d'affichage du div pour display: flex pour l'ajouter au DOM, puis ajoutez un @OnClick clic @OnClick sur cette div flottante qui fermera la fenêtre contextuelle ET @OnClick propriété d'affichage div flottante sur display: none; . La div doit être claire pour que vous puissiez toujours voir le reste de l'application derrière elle, mais vous permet de cliquer en dehors de la fenêtre contextuelle pour le comportement que vous recherchez, car n'importe où en dehors de la fenêtre contextuelle sera sur la division couvrant le reste de l'écran .

Notez que dans la fenêtre contextuelle, vous devrez également redéfinir la valeur d'affichage Div flottante sur `` aucun '' lorsque vous fermez la fenêtre contextuelle depuis l'intérieur de la fenêtre contextuelle, sinon elle restera et nécessitera un clic supplémentaire pour qu'elle disparaisse.

Vous pouvez également légèrement ombrer l'élément Div avec de la transparence pour fournir un effet de surbrillance à votre popup lors de son ouverture.


1 commentaires

Merci @NikProtsman pour votre suggestion, cependant, c'est une sorte de hack que je préfère ne pas l'utiliser pour un projet réel. dans cette situation, vous pouvez facilement attribuer une fonction à la fenêtre en utilisant JS afin qu'elle obtienne tous vos clics, puis vous pouvez la filtrer et l'utiliser pour votre objectif. bien que ce ne soit pas encore mon goût: D



1
votes

Voici ce que je fais avec un div pour déclencher l'événement onfocusout où la variable ShowSelectBox est utilisée par votre instruction if pour afficher ou masquer quelque chose:

<div tabindex="0" @onfocusout="@(() => ShowSelectBox = false)">
...
</div>

J'ai utilisé cela dans une application blazor webassambly, mais devrait être la même chose pour le côté serveur.


3 commentaires

Cela ne semble malheureusement pas fonctionner, car vous devez d'abord donner le focus au popup. Donc, si vous cliquez sur le popup puis cliquez à l'extérieur, il sera fermé. Et AFAIK, vous ne pouvez pas définir la mise au point de la fenêtre sans l'utilisation de JS, comme mentionné ici: stackoverflow.com/questions/60309188/… .


"puis cliquez à l'extérieur, il sera fermé" - n'est-ce pas votre intention?


Le fait est que si vous ne cliquez pas sur la fenêtre contextuelle, le focus n'est pas activé, donc cliquer n'importe où ailleurs ne le fermera pas. Vous DEVEZ d'abord cliquer sur le popup pour lui donner le focus afin qu'un clic en dehors de celui-ci le ferme.



0
votes

C'est un peu un faff mais réussi avec une certaine interopérabilité JS. Je suis nouveau sur Blazor mais j'ai réussi à cadrer cela ensemble à partir de divers autres messages;

Ajoutez un identifiant à votre popup - appelé mine profile-popup

public partial class TopBanner : IDisposable
{        
    [Inject]
    IJSRuntime JSRuntime { get; set; }

    public void CloseProfileMenu()
    {
        profileMenu.Close();
    }

    DotNetObjectReference<ProfileOutsideClickInvokeHelper> _objRef;

    protected override void OnAfterRender(bool firstRender)
    {
        _objRef = DotNetObjectReference.Create(new ProfileOutsideClickInvokeHelper(CloseProfileMenu));
        JSRuntime.InvokeVoidAsync("attachHandlers", _objRef);
    }

    public void Dispose()
    {
        _objRef?.Dispose();
    }
}

Créez un fichier JS pour attacher un gestionnaire à l'événement click du document - si la source du clic est dans votre popup, ignorez-la, sinon lancez une méthode d'assistance à partir de votre classe d'assistance

public class ProfileOutsideClickInvokeHelper
{
    Action _action;

    public ProfileOutsideClickInvokeHelper(Action action)
    {
        _action = action;
    }

    [JSInvokable]
    public void InvokeAction()
    {
        _action.Invoke();
    }
}

Créer la classe d'assistance

    window.attachHandlers = (dotnetHelper) => {
    document.addEventListener("click", (evt) => {
        const profileElement = document.getElementById("profile-popup");
        let targetElement = evt.target;

        do {
            if (targetElement == profileElement) {
                //return as not clicked outside
                return;
            }            
            targetElement = targetElement.parentNode;
        } while (targetElement);

        dotnetHelper.invokeMethod("InvokeAction");
    });
};

Attachez le gestionnaire dans le remplacement OnAfterRender. J'ai un composant contenant le popup. Vous devez supprimer la référence d'objet

<div id="profile-popup">
        <RadzenProfileMenu @ref="profileMenu" Style="width: 200px;" >
            <Template>
                <div class="row">...

Je ne sais pas si c'est la meilleure solution, ou même une bonne solution, mais cela semble fonctionner correctement.


0 commentaires

1
votes

J'ai trouvé une solution sans utiliser JS, en utilisant l'événement onmouseover, nous pouvons définir une valeur à un bool var comme true et avec un événement onmouseout que nous pouvons définir comme false et ainsi, en vérifiant si la souris a cliqué dans ou hors d'un élément de tag

 <button @onclick="Show">Click</button>
<div  @onmouseover="MouseIn" @onmouseout="MouseOut">...</div>
    
@code{
bool IsInside; 
void Show()
{
   if(!IsInside)
   {
       ...
   }
}
void MouseIn()
{
   IsInside= true
}; 
void MouseOut()
{
   IsInside= False;
}
}


0 commentaires

0
votes

J'ai eu la même situation et j'ai fini par utiliser css :hover state. En supposant que vous ayez une fenêtre contextuelle de menu déroulant, faire de cette façon lorsque vous survolez l'élément div , la fenêtre contextuelle du menu s'affiche et lorsque vous passez la souris, la fenêtre contextuelle du menu se ferme automatiquement.

ou

Vous pouvez faire quelque chose comme,

<div class="dropdown is-right is-hoverable @(PopupCollapsed ? "is-active" : null)"
             @onclick="e => this.PopupCollapsed = !this.PopupCollapsed"
             @onfocusout="e => this.PopupCollapsed = false">
</div>

@code {
public bool PopupCollapsed { get; set; }
}


0 commentaires