在 Blazor 组件中获取当前 URL

我需要知道当前页面的 URL,以便检查是否需要对元素应用某种样式。下面的代码就是一个例子。

    @using Microsoft.AspNetCore.Blazor.Services
@inject IUriHelper UriHelper
@implements IDisposable


<h1>@url</h1>
<nav>
<div class="nav-wrapper">
<a href="#" class="brand-logo">Blazor</a>
<ul id="nav-mobile" class="right hide-on-med-and-down">
<li>
<NavLink href="/" Match=NavLinkMatch.All>
Home
</NavLink>
</li>
<li>
<NavLink href="/counter">
Counter
</NavLink>
</li>
<li>
<NavLink href="/fetchdata">
Fetch data
</NavLink>
</li>
</ul>
</div>
</nav>


@functions {


private string url = string.Empty;


protected override void OnInit()
{
url = UriHelper.GetAbsoluteUri();
UriHelper.OnLocationChanged += OnLocationChanged;
}


private void OnLocationChanged(object sender, LocationChangedEventArgs e)
{
url = newUriAbsolute;
}


public void Dispose()
{
UriHelper.OnLocationChanged -= OnLocationChanged;
}
}

I used the same approach used in the NavLink component in the Blazor repository, but it did not work. Any ideas?.

68876 次浏览

There is no use in connecting to the OnLocationChanged event in a page or component, as they get loaded and disposed on demand.

You should register to this event in app.cshtml as that won't be disposed.

You should listen to a LocationChange of the IUriHelper, which triggers the function to do what you want for example:

@using Microsoft.AspNetCore.Blazor.Components
@using Microsoft.Extensions.Logging
@inject Microsoft.AspNetCore.Blazor.Services.IUriHelper UriHelper
@inject ILogger<NavItem> logger


<li class="m-menu__item @(Active ? "m-menu__item--active" : "")">
<a href=@Url class="m-menu__link ">
<span class="m-menu__item-here"></span>
<i class="m-menu__link-icon @Icon"></i>
<span class="m-menu__link-text">@Text</span>
</a>
</li>


@functions {
protected override void OnInit()
{
UriHelper.OnLocationChanged += OnLocationChanges;
}
[Parameter]
private string Url { get; set; }
[Parameter]
private string Icon { get; set; }
[Parameter]
private string Text { get; set; }
private bool Active = false;
private void OnLocationChanges(object sender, string newLocation)
{
bool active = newLocation.Contains(Url);
if(active != Active) //Only re-render the components that need it
{
Active = active;
StateHasChanged();
logger.LogInformation("Location Change To:" + newLocation);
}
}
}

Use the Uri property from the NavigationManager class.

How it works

Get it from injection before using it on .razor pages:

@inject NavigationManager MyNavigationManager

Or like this in a .cs file if you prefer the "code-behind" experience:

using Microsoft.AspNetCore.Components;
// ...
[Inject]
public NavigationManager MyNavigationManager {get; set;} = default!;

Sample

@page "/navigate"
@inject NavigationManager MyNavigationManager


<h1>Current URL</h1>


<p>@(MyNavigationManager.Uri)</p>


More about navigation (NavigateTo, BaseUri, ToAbsoluteUri, ToBaseRelativePath, ... ) at: URI and navigation state helpers

NavigationManager cheatsheet

MyNavigationManager.Uri
#> https://localhost:5001/counter/3?q=hi


MyNavigationManager.BaseUri
#> https://localhost:5001/


MyNavigationManager.NavigateTo("http://new location")
#> Navigates to new location


MyNavigationManager.LocationChanged
#> An event that fires when the navigation location has changed.


MyNavigationManager.ToAbsoluteUri("pepe")
#> https://localhost:5001/pepe


MyNavigationManager.ToBaseRelativePath(MyNavigationManager.Uri)
#> counter/3?q=hi


Helper: AddQueryParm( "q2", "bye" ) // (*1)
#> https://localhost:5001/counter/3?q=hi&q2=bye


Helper: GetQueryParm( "q" )
#> hi

(*1) Net6 introduces GetUriWithQueryParameter. More info: Manipulate the query string from Blazor

Helpers code:

@code {


[Parameter]
public string Id { get; set; }


// Blazor: add parm to URL
string AddQueryParm(string parmName, string parmValue)
{
var uriBuilder = new UriBuilder(MyNavigationManager.Uri);
var q = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
q[parmName] = parmValue;
uriBuilder.Query = q.ToString();
var newUrl = uriBuilder.ToString();
return newUrl;
}


// Blazor: get query parm from the URL
string GetQueryParm(string parmName)
{
var uriBuilder = new UriBuilder(MyNavigationManager.Uri);
var q = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
return q[parmName] ?? "";
}


}

First of all, inject NavigationManager into the component in which you need to get the current URL as below:

@inject NavigationManager NavManager

Now use the below line to get the current URL:

string Url = NavManager.Uri.ToString();

In my case I only needed the Uri of the page and not the base Uri aswell.

I keep all my code in a razor.cs file so I inject NavigationManager from code-behind like this:

[Inject] public NavigationManager Navigation { get; set; }

Navigation.Uri yeilds: https://localhost:5001/nail-square-singel-shear-timber-timber

So to get the page Uri just do like this:

Navigation.Uri.Replace(Navigation.BaseUri,"")

The above yields: nail-square-singel-shear-timber-timber