document.title を設定したい!
Blazor アプリを開発してて、ページ (ドキュメント) のタイトル (ブラウザのタブに表示されるテキストですね) を、コンポーネントごとに設定したいことってありませんか?
残念ながら、Blazor 上の標準的な C# コードだけでは、これは実現できないはず、です。
というのも、Blazor というかそのコンポーネントのレンダリング対象は、<app>
要素の内部の DOM に限られているためです。
なので、<app>
要素の外側というか親側というか、とにかく <head>
要素は普通には Blazor で扱えません。
ではどうするかといえば、Blazor 上の C# コードから JavaScript 相互運用機能を利用して、JavaScript に頼る必要があります。
document.title = "ここにC#コードから渡された値が来るように実装する(詳細略)"
とはいえ、自前でこれを実装するのは、不可能ではないにせよ、面倒な仕事です。
ということで、内部的には上記の仕組みでタイトルを変更することのできる Blazor コンポーネント "Blazor Head Element Helper" を、NuGet パッケージとして公開しております!
"Blazor Head Element Helper" の使い方
まずは "Blazor Head Element Helper" NuGet パッケージ (パッケージ ID は "Toolbelt.Blazor.HeadElement") をプロジェクトに追加します。
> dotnet add package Toolbelt.Blazor.HeadElement --version 1.0.0
次に、対象の Blazor アプリの Startup.ConfigureServices()
にて、"Head Element Helper" のサービスを DI 機構に登録します。
using Toolbelt.Blazor.Extensions.DependencyInjection; // <- この行を追加し...
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHeadElementHelper(); // <- この行を追加する。
...
ここまで準備できたらいよいよコンポーネント側のコーディングに移るのですが、その前に、_Import.razor
ファイルで、"Toolbelt.Blazor.HeadElement" 名前空間を既定で開いておくとよいです。
@* This is "_Imports.razor" *@
...
@using Toolbelt.Blazor.HeadElement
こうしておけば、見事、いずれのコンポーネントでも、下記のように <Title>
コンポーネントを置いておくだけで、そのコンポーネントがレンダリングされるときは、そのページのタイトルが設定されるようになります!
@* This is "Pages/Counter.razor" *@
@page "/counter"
<Title>Counter (@currentCount)</Title>
さらにおまけで、タイトルだけでなく、<head>
要素内の <meta>
要素も、設定可能です!
<Meta Property="ogp:title" Content="Counter" />
これで OGP 対応もバッチリですね!
...?
サーバー側事前レンダリングは...?
ちょっと待って下さい。
各種検索クローラや SNS サーバーからは、結局、最初の HTTP GET 要求でサーバーから返されたコンテンツしか見えません。
ですので冒頭で説明したとおり、JavaScript で動的にタイトルやメタ要素を変更しているだけなら、まったく OGP 対応になってませんね!
しかしご安心を。
サーバー側 (クライアントサイド Blazor の場合は、ASP.NET Core ホスティングが必要) に "Toolbelt.Blazor.HeadElement.ServerPrerendering" NuGet パッケージを追加してみて下さい。
> dotnet add package Toolbelt.Blazor.HeadElement.ServerPrerendering
その上で、サーバー側 Startup.Configure()
メソッド内にて、app.UseStaticFiles()
より前の行に、"Head Element Server Prerendering" ミドルウェアの登録行を追加します。
using Toolbelt.Blazor.Extensions.DependencyInjection; // <- この行を追加し...
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseHeadElementServerPrerendering(); // <- この行を "app.UseStaticFile" より前に追加。
...
app.UseStaticFiles()
...
すると、あら不思議!
HTTP GET 要求で返される HTML コンテンツ内の <title>
要素や <meta>
要素群が、.razor ファイル内で <Title>
コンポーネントや <Meta>
コンポーネントで実装したとおりの内容になっている
はずです。
よかったよかった。
デモンストレーションサイト
下記に、"Blazor Head Element Helper" とそのサーバー側事前レンダリング機能を利用したデモンストレーションサイトを公開してます。
実際にこのデモンストレーションサイトに掲載している各観光ポイントページの URL を Twiiter にツイートしたりしてみると、ちゃんと Twitter カード形式で表示されるはず、です (下記)。
[This is a demonstration of "Blazor Head Element Helper"] Museum of Pop Culture - The Museum of Pop Culture, or MoPOP (previously called EMP Museum) is a nonprofit museum dedicated to contemporary popular culture. https://t.co/08i4OwuOqS #blazor
— @jsakamoto (@jsakamoto) November 1, 2019
このデモンストレーションサイトのソースコードは下記で閲覧可能です。
"Blazor Head Element Helper" は、サーバーサイド Blazor (Blazor Server App)、クライアントサイド Blazor (Blazor WebAssembly App) のいずれのホスティングモデルでも動作します。
これで Blazor アプリでも、OGP 対応できますね!
Happy Coding! :)