ASP.NET Core'da .NET yöntemlerinden JavaScript işlevlerini çağırma Blazor

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Bu makalede. .NET'ten JavaScript (JS) işlevlerini çağırma açıklanmaktadır.

'den JS.NET yöntemlerini çağırma hakkında bilgi için bkz . ASP.NET Core'da BlazorJavaScript işlevlerinden .NET yöntemlerini çağırma.

İşlevleri çağırma JS

IJSRuntime , çerçeve tarafından Blazor kaydedilir. .NET'ten çağrısı JS yapmak için soyutlama ekleyin IJSRuntime ve aşağıdaki yöntemlerden birini çağırın:

İşlevleri çağıran JS önceki .NET yöntemleri için:

  • İşlev tanımlayıcısı (String), genel kapsama () göredirwindow. öğesini çağırmak window.someScope.someFunctioniçin tanımlayıcıdır someScope.someFunction. çağrılmadan önce işlevi kaydetmeye gerek yoktur.
  • bir işleve JSiçinde herhangi bir JS sayıda ON-serializable bağımsız değişkeni Object[] geçirin.
  • İptal belirteci (CancellationToken), işlemlerin iptal edilmesi gerektiğini belirten bir bildirim yar.
  • TimeSpan bir işlemin zaman sınırını JS temsil eder.
  • Dönüş TValue türü de ON serileştirilebilir olmalıdır JS. TValue döndürülen ON türüyle en iyi eşleyen .NET türüyle JSeşleşmelidir.
  • Yöntemler için InvokeAsync A JS Promise döndürülür. InvokeAsync dosyasının işaretini Promise kaldırın ve tarafından Promisebeklenen değeri döndürür.

Blazor Sunucu tarafı uygulamalar için varsayılan olan ön giriş etkinleştirilmiş uygulamalar için, giriş öncesi sırasında 'a JS çağrı yapılamaz. Daha fazla bilgi için Prerendering bölümüne bakın.

Aşağıdaki örnek, tabanlı bir JSkod çözücüye dayanırTextDecoder. Örnekte, bir gereksinimi geliştirici kodundan var olan JS bir JS API'ye yükleyen bir C# yönteminden bir işlevin nasıl çağrıldığını gösterir. JS işlevi bir C# yönteminden bayt dizisini kabul eder, dizinin kodunu çözer ve metni görüntülemek üzere bileşene döndürür.

<script>
  window.convertArray = (win1251Array) => {
    var win1251decoder = new TextDecoder('windows-1251');
    var bytes = new Uint8Array(win1251Array);
    var decodedArray = win1251decoder.decode(bytes);
    return decodedArray;
  };
</script>

Not

Konum hakkında genel yönergeler JS ve üretim uygulamalarına yönelik önerilerimiz için bkz . ASP.NET Core Blazor uygulamalarında JavaScript konumu.

Aşağıdaki bileşen:

  • convertArrayJS Bir düğmeyi (Convert Array) seçerken ile InvokeAsync işlevini çağırır.
  • JS İşlev çağrıldıktan sonra geçirilen dizi bir dizeye dönüştürülür. Dize, görüntü ()text için bileşene döndürülür.

CallJs1.razor:

@page "/call-js-1"
@inject IJSRuntime JS

<PageTitle>Call JS 1</PageTitle>

<h1>Call JS Example 1</h1>

<p>
    <button @onclick="ConvertArray">Convert Array</button>
</p>

<p>
    @text
</p>

<p>
    Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>: 
    <a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0472710/">David Krumholtz on IMDB</a>
</p>

@code {
    private MarkupString text;

    private uint[] quoteArray = 
        new uint[]
        {
            60, 101, 109, 62, 67, 97, 110, 39, 116, 32, 115, 116, 111, 112, 32,
            116, 104, 101, 32, 115, 105, 103, 110, 97, 108, 44, 32, 77, 97,
            108, 46, 60, 47, 101, 109, 62, 32, 45, 32, 77, 114, 46, 32, 85, 110,
            105, 118, 101, 114, 115, 101, 10, 10,
        };

    private async Task ConvertArray()
    {
        text = new(await JS.InvokeAsync<string>("convertArray", quoteArray));
    }
}

CallJsExample1.razor:

@page "/call-js-example-1"
@inject IJSRuntime JS

<h1>Call JS <code>convertArray</code> Function</h1>

<p>
    <button @onclick="ConvertArray">Convert Array</button>
</p>

<p>
    @text
</p>

<p>
    Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>: 
    <a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0472710/">David Krumholtz on IMDB</a>
</p>

@code {
    private MarkupString text;

    private uint[] quoteArray = 
        new uint[]
        {
            60, 101, 109, 62, 67, 97, 110, 39, 116, 32, 115, 116, 111, 112, 32,
            116, 104, 101, 32, 115, 105, 103, 110, 97, 108, 44, 32, 77, 97,
            108, 46, 60, 47, 101, 109, 62, 32, 45, 32, 77, 114, 46, 32, 85, 110,
            105, 118, 101, 114, 115, 101, 10, 10,
        };

    private async Task ConvertArray()
    {
        text = new(await JS.InvokeAsync<string>("convertArray", quoteArray));
    }
}

CallJsExample1.razor:

@page "/call-js-example-1"
@inject IJSRuntime JS

<h1>Call JS <code>convertArray</code> Function</h1>

<p>
    <button @onclick="ConvertArray">Convert Array</button>
</p>

<p>
    @text
</p>

<p>
    Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>: 
    <a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0472710/">David Krumholtz on IMDB</a>
</p>

@code {
    private MarkupString text;

    private uint[] quoteArray = 
        new uint[]
        {
            60, 101, 109, 62, 67, 97, 110, 39, 116, 32, 115, 116, 111, 112, 32,
            116, 104, 101, 32, 115, 105, 103, 110, 97, 108, 44, 32, 77, 97,
            108, 46, 60, 47, 101, 109, 62, 32, 45, 32, 77, 114, 46, 32, 85, 110,
            105, 118, 101, 114, 115, 101, 10, 10,
        };

    private async Task ConvertArray()
    {
        text = new(await JS.InvokeAsync<string>("convertArray", quoteArray));
    }
}

CallJsExample1.razor:

@page "/call-js-example-1"
@inject IJSRuntime JS

<h1>Call JS <code>convertArray</code> Function</h1>

<p>
    <button @onclick="ConvertArray">Convert Array</button>
</p>

<p>
    @text
</p>

<p>
    Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>: 
    <a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0472710/">David Krumholtz on IMDB</a>
</p>

@code {
    private MarkupString text;

    private uint[] quoteArray = 
        new uint[]
        {
            60, 101, 109, 62, 67, 97, 110, 39, 116, 32, 115, 116, 111, 112, 32,
            116, 104, 101, 32, 115, 105, 103, 110, 97, 108, 44, 32, 77, 97,
            108, 46, 60, 47, 101, 109, 62, 32, 45, 32, 77, 114, 46, 32, 85, 110,
            105, 118, 101, 114, 115, 101, 10, 10,
        };

    private async Task ConvertArray()
    {
        text = new(await JS.InvokeAsync<string>("convertArray", quoteArray));
    }
}

CallJsExample1.razor:

@page "/call-js-example-1"
@inject IJSRuntime JS

<h1>Call JS <code>convertArray</code> Function</h1>

<p>
    <button @onclick="ConvertArray">Convert Array</button>
</p>

<p>
    @text
</p>

<p>
    Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>: 
    <a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0472710/">David Krumholtz on IMDB</a>
</p>

@code {
    private MarkupString text;

    private uint[] quoteArray = 
        new uint[]
        {
            60, 101, 109, 62, 67, 97, 110, 39, 116, 32, 115, 116, 111, 112, 32,
            116, 104, 101, 32, 115, 105, 103, 110, 97, 108, 44, 32, 77, 97,
            108, 46, 60, 47, 101, 109, 62, 32, 45, 32, 77, 114, 46, 32, 85, 110,
            105, 118, 101, 114, 115, 101, 10, 10,
        };

    private async Task ConvertArray()
    {
        text = new MarkupString(await JS.InvokeAsync<string>("convertArray", 
            quoteArray));
    }
}

Kullanıcı hareketleriyle sınırlı JavaScript API'si

Bu bölüm sunucu tarafı bileşenleri için geçerlidir.

Bazı tarayıcı JavaScript (JS) API'leri yalnızca (MDN belgeleri) gibi Fullscreen API bir kullanıcı hareketi bağlamında yürütülebilir. Kullanıcı arabirimi olay işlemesi zaman uyumsuz olarak gerçekleştirildiğinden ve genellikle kullanıcı hareketi bağlamında artık olmadığından, bu API'ler sunucu tarafı bileşenlerindeki birlikte çalışma mekanizması aracılığıyla JS çağrılamıyor. Uygulamanın ui olayını tamamen JavaScript'te işlemesi gerekir, bu nedenle 'nin @onclick yönerge özniteliği yerine Blazorkullanınonclick.

Döndürülen değeriInvokeVoidAsync () okumadan JavaScript işlevlerini çağırma

Şu durumlarda kullanın InvokeVoidAsync :

  • JavaScript (JS) çağrısının sonucunu okumak için .NET gerekli değildir.
  • JSişlevleri void(0)/void 0 veya undefined döndürür.

Bir displayTickerAlert1JS işlev sağlayın. işlevi ile çağrılır InvokeVoidAsync ve bir değer döndürmez:

<script>
  window.displayTickerAlert1 = (symbol, price) => {
    alert(`${symbol}: $${price}!`);
  };
</script>

Not

Konum hakkında genel yönergeler JS ve üretim uygulamalarına yönelik önerilerimiz için bkz . ASP.NET Core Blazor uygulamalarında JavaScript konumu.

Bileşen (.razor) örneği (InvokeVoidAsync)

TickerChangedhandleTickerChanged1 aşağıdaki bileşende yöntemini çağırır.

CallJs2.razor:

@page "/call-js-2"
@inject IJSRuntime JS

<PageTitle>Call JS 2</PageTitle>

<h1>Call JS Example 2</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@code {
    private string? stockSymbol;
    private decimal price;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
        price = Random.Shared.Next(1, 101);
        await JS.InvokeVoidAsync("displayTickerAlert1", stockSymbol, price);
    }
}

CallJsExample2.razor:

@page "/call-js-example-2"
@inject IJSRuntime JS

<h1>Call JS Example 2</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@code {
    private string? stockSymbol;
    private decimal price;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
        price = Random.Shared.Next(1, 101);
        await JS.InvokeVoidAsync("displayTickerAlert1", stockSymbol, price);
    }
}

CallJsExample2.razor:

@page "/call-js-example-2"
@inject IJSRuntime JS

<h1>Call JS Example 2</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@code {
    private string? stockSymbol;
    private decimal price;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
        price = Random.Shared.Next(1, 101);
        await JS.InvokeVoidAsync("displayTickerAlert1", stockSymbol, price);
    }
}

CallJsExample2.razor:

@page "/call-js-example-2"
@inject IJSRuntime JS

<h1>Call JS Example 2</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@code {
    private Random r = new();
    private string stockSymbol;
    private decimal price;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + r.Next(0, 26))}{(char)('A' + r.Next(0, 26))}";
        price = r.Next(1, 101);
        await JS.InvokeVoidAsync("displayTickerAlert1", stockSymbol, price);
    }
}

CallJsExample2.razor:

@page "/call-js-example-2"
@inject IJSRuntime JS

<h1>Call JS Example 2</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol != null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@code {
    private Random r = new Random();
    private string stockSymbol;
    private decimal price;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + r.Next(0, 26))}{(char)('A' + r.Next(0, 26))}";
        price = r.Next(1, 101);
        await JS.InvokeVoidAsync("displayTickerAlert1", stockSymbol, price);
    }
}

Sınıf (.cs) örneği (InvokeVoidAsync)

JsInteropClasses1.cs:

using Microsoft.JSInterop;

namespace BlazorSample;

public class JsInteropClasses1(IJSRuntime js) : IDisposable
{
    private readonly IJSRuntime js = js;

    public async ValueTask TickerChanged(string symbol, decimal price)
    {
        await js.InvokeVoidAsync("displayTickerAlert1", symbol, price);
    }

    public void Dispose()
    {
        // The following prevents derived types that introduce a
        // finalizer from needing to re-implement IDisposable.
        GC.SuppressFinalize(this);
    }
}
using Microsoft.JSInterop;

public class JsInteropClasses1 : IDisposable
{
    private readonly IJSRuntime js;

    public JsInteropClasses1(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask TickerChanged(string symbol, decimal price)
    {
        await js.InvokeVoidAsync("displayTickerAlert1", symbol, price);
    }

    public void Dispose()
    {
    }
}
using Microsoft.JSInterop;

public class JsInteropClasses1 : IDisposable
{
    private readonly IJSRuntime js;

    public JsInteropClasses1(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask TickerChanged(string symbol, decimal price)
    {
        await js.InvokeVoidAsync("displayTickerAlert1", symbol, price);
    }

    public void Dispose()
    {
    }
}
using System;
using System.Threading.Tasks;
using Microsoft.JSInterop;

public class JsInteropClasses1 : IDisposable
{
    private readonly IJSRuntime js;

    public JsInteropClasses1(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask TickerChanged(string symbol, decimal price)
    {
        await js.InvokeVoidAsync("displayTickerAlert1", symbol, price);
    }

    public void Dispose()
    {
    }
}
using System;
using System.Threading.Tasks;
using Microsoft.JSInterop;

public class JsInteropClasses1 : IDisposable
{
    private readonly IJSRuntime js;

    public JsInteropClasses1(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask TickerChanged(string symbol, decimal price)
    {
        await js.InvokeVoidAsync("displayTickerAlert1", symbol, price);
    }

    public void Dispose()
    {
    }
}

TickerChangedhandleTickerChanged1 aşağıdaki bileşende yöntemini çağırır.

CallJs3.razor:

@page "/call-js-3"
@implements IDisposable
@inject IJSRuntime JS

<PageTitle>Call JS 3</PageTitle>

<h1>Call JS Example 3</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@code {
    private string? stockSymbol;
    private decimal price;
    private JsInteropClasses1? jsClass;

    protected override void OnInitialized()
    {
        jsClass = new(JS);
    }

    private async Task SetStock()
    {
        if (jsClass is not null)
        {
            stockSymbol = 
                $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
            price = Random.Shared.Next(1, 101);
            await jsClass.TickerChanged(stockSymbol, price);
        }
    }

    public void Dispose() => jsClass?.Dispose();
}

CallJsExample3.razor:

@page "/call-js-example-3"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call JS Example 3</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@code {
    private string? stockSymbol;
    private decimal price;
    private JsInteropClasses1? jsClass;

    protected override void OnInitialized()
    {
        jsClass = new(JS);
    }

    private async Task SetStock()
    {
        if (jsClass is not null)
        {
            stockSymbol = 
                $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
            price = Random.Shared.Next(1, 101);
            await jsClass.TickerChanged(stockSymbol, price);
        }
    }

    public void Dispose() => jsClass?.Dispose();
}

CallJsExample3.razor:

@page "/call-js-example-3"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call JS Example 3</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@code {
    private string? stockSymbol;
    private decimal price;
    private JsInteropClasses1? jsClass;

    protected override void OnInitialized()
    {
        jsClass = new(JS);
    }

    private async Task SetStock()
    {
        if (jsClass is not null)
        {
            stockSymbol = 
                $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
            price = Random.Shared.Next(1, 101);
            await jsClass.TickerChanged(stockSymbol, price);
        }
    }

    public void Dispose() => jsClass?.Dispose();
}

CallJsExample3.razor:

@page "/call-js-example-3"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call JS Example 3</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@code {
    private Random r = new();
    private string stockSymbol;
    private decimal price;
    private JsInteropClasses1 jsClass;

    protected override void OnInitialized()
    {
        jsClass = new(JS);
    }

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + r.Next(0, 26))}{(char)('A' + r.Next(0, 26))}";
        price = r.Next(1, 101);
        await jsClass.TickerChanged(stockSymbol, price);
    }

    public void Dispose() => jsClass?.Dispose();
}

CallJsExample3.razor:

@page "/call-js-example-3"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call JS Example 3</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol != null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@code {
    private Random r = new Random();
    private string stockSymbol;
    private decimal price;
    private JsInteropClasses1 jsClass;

    protected override void OnInitialized()
    {
        jsClass = new JsInteropClasses1(JS);
    }

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + r.Next(0, 26))}{(char)('A' + r.Next(0, 26))}";
        price = r.Next(1, 101);
        await jsClass.TickerChanged(stockSymbol, price);
    }

    public void Dispose() => jsClass?.Dispose();
}

JavaScript işlevlerini çağırma ve döndürülen bir değeri okuma (InvokeAsync)

.NET'in bir JavaScript (JS) çağrısının sonucunu okuması gerektiğinde kullanınInvokeAsync.

Bir displayTickerAlert2JS işlev sağlayın. Aşağıdaki örnek, çağıranın görüntülemesi için bir dize döndürür:

<script>
  window.displayTickerAlert2 = (symbol, price) => {
    if (price < 20) {
      alert(`${symbol}: $${price}!`);
      return "User alerted in the browser.";
    } else {
      return "User NOT alerted.";
    }
  };
</script>

Not

Konum hakkında genel yönergeler JS ve üretim uygulamalarına yönelik önerilerimiz için bkz . ASP.NET Core Blazor uygulamalarında JavaScript konumu.

Bileşen (.razor) örneği (InvokeAsync)

TickerChangedhandleTickerChanged2 yöntemini çağırır ve döndürülen dizeyi aşağıdaki bileşende görüntüler.

CallJs4.razor:

@page "/call-js-4"
@inject IJSRuntime JS

<PageTitle>Call JS 4</PageTitle>

<h1>Call JS Example 4</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@if (result is not null)
{
    <p>@result</p>
}

@code {
    private string? stockSymbol;
    private decimal price;
    private string? result;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
        price = Random.Shared.Next(1, 101);
        var interopResult = 
            await JS.InvokeAsync<string>("displayTickerAlert2", stockSymbol, price);
        result = $"Result of TickerChanged call for {stockSymbol} at " +
            $"{price.ToString("c")}: {interopResult}";
    }
}

CallJsExample4.razor:

@page "/call-js-example-4"
@inject IJSRuntime JS

<h1>Call JS Example 4</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@if (result is not null)
{
    <p>@result</p>
}

@code {
    private string? stockSymbol;
    private decimal price;
    private string? result;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
        price = Random.Shared.Next(1, 101);
        var interopResult = 
            await JS.InvokeAsync<string>("displayTickerAlert2", stockSymbol, price);
        result = $"Result of TickerChanged call for {stockSymbol} at " +
            $"{price.ToString("c")}: {interopResult}";
    }
}

CallJsExample4.razor:

@page "/call-js-example-4"
@inject IJSRuntime JS

<h1>Call JS Example 4</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@if (result is not null)
{
    <p>@result</p>
}

@code {
    private string? stockSymbol;
    private decimal price;
    private string? result;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
        price = Random.Shared.Next(1, 101);
        var interopResult = 
            await JS.InvokeAsync<string>("displayTickerAlert2", stockSymbol, price);
        result = $"Result of TickerChanged call for {stockSymbol} at " +
            $"{price.ToString("c")}: {interopResult}";
    }
}

CallJsExample4.razor:

@page "/call-js-example-4"
@inject IJSRuntime JS

<h1>Call JS Example 4</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@if (result is not null)
{
    <p>@result</p>
}

@code {
    private Random r = new();
    private string stockSymbol;
    private decimal price;
    private string result;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + r.Next(0, 26))}{(char)('A' + r.Next(0, 26))}";
        price = r.Next(1, 101);
        var interopResult = 
            await JS.InvokeAsync<string>("displayTickerAlert2", stockSymbol, price);
        result = $"Result of TickerChanged call for {stockSymbol} at " +
            $"{price.ToString("c")}: {interopResult}";
    }
}

CallJsExample4.razor:

@page "/call-js-example-4"
@inject IJSRuntime JS

<h1>Call JS Example 4</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol != null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@if (result != null)
{
    <p>@result</p>
}

@code {
    private Random r = new Random();
    private string stockSymbol;
    private decimal price;
    private string result;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + r.Next(0, 26))}{(char)('A' + r.Next(0, 26))}";
        price = r.Next(1, 101);
        var interopResult = 
            await JS.InvokeAsync<string>("displayTickerAlert2", stockSymbol, price);
        result = $"Result of TickerChanged call for {stockSymbol} at " +
            $"{price.ToString("c")}: {interopResult}";
    }
}

Sınıf (.cs) örneği (InvokeAsync)

JsInteropClasses2.cs:

using Microsoft.JSInterop;

namespace BlazorSample;

public class JsInteropClasses2(IJSRuntime js) : IDisposable
{
    private readonly IJSRuntime js = js;

    public async ValueTask<string> TickerChanged(string symbol, decimal price)
    {
        return await js.InvokeAsync<string>("displayTickerAlert2", symbol, price);
    }

    public void Dispose()
    {
        // The following prevents derived types that introduce a
        // finalizer from needing to re-implement IDisposable.
        GC.SuppressFinalize(this);
    }
}
using Microsoft.JSInterop;

public class JsInteropClasses2 : IDisposable
{
    private readonly IJSRuntime js;

    public JsInteropClasses2(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask<string> TickerChanged(string symbol, decimal price)
    {
        return await js.InvokeAsync<string>("displayTickerAlert2", symbol, price);
    }

    public void Dispose()
    {
    }
}
using Microsoft.JSInterop;

public class JsInteropClasses2 : IDisposable
{
    private readonly IJSRuntime js;

    public JsInteropClasses2(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask<string> TickerChanged(string symbol, decimal price)
    {
        return await js.InvokeAsync<string>("displayTickerAlert2", symbol, price);
    }

    public void Dispose()
    {
    }
}
using System;
using System.Threading.Tasks;
using Microsoft.JSInterop;

public class JsInteropClasses2 : IDisposable
{
    private readonly IJSRuntime js;

    public JsInteropClasses2(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask<string> TickerChanged(string symbol, decimal price)
    {
        return await js.InvokeAsync<string>("displayTickerAlert2", symbol, price);
    }

    public void Dispose()
    {
    }
}
using System;
using System.Threading.Tasks;
using Microsoft.JSInterop;

public class JsInteropClasses2 : IDisposable
{
    private readonly IJSRuntime js;

    public JsInteropClasses2(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask<string> TickerChanged(string symbol, decimal price)
    {
        return await js.InvokeAsync<string>("displayTickerAlert2", symbol, price);
    }

    public void Dispose()
    {
    }
}

TickerChangedhandleTickerChanged2 yöntemini çağırır ve döndürülen dizeyi aşağıdaki bileşende görüntüler.

CallJs5.razor:

@page "/call-js-5"
@implements IDisposable
@inject IJSRuntime JS

<PageTitle>Call JS 5</PageTitle>

<h1>Call JS Example 5</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@if (result is not null)
{
    <p>@result</p>
}

@code {
    private string? stockSymbol;
    private decimal price;
    private JsInteropClasses2? jsClass;
    private string? result;

    protected override void OnInitialized()
    {
        jsClass = new(JS);
    }

    private async Task SetStock()
    {
        if (jsClass is not null)
        {
            stockSymbol = 
                $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
            price = Random.Shared.Next(1, 101);
            var interopResult = await jsClass.TickerChanged(stockSymbol, price);
            result = $"Result of TickerChanged call for {stockSymbol} at " +
                $"{price.ToString("c")}: {interopResult}";
        }
    }

    public void Dispose() => jsClass?.Dispose();
}

CallJsExample5.razor:

@page "/call-js-example-5"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call JS Example 5</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@if (result is not null)
{
    <p>@result</p>
}

@code {
    private string? stockSymbol;
    private decimal price;
    private JsInteropClasses2? jsClass;
    private string? result;

    protected override void OnInitialized()
    {
        jsClass = new(JS);
    }

    private async Task SetStock()
    {
        if (jsClass is not null)
        {
            stockSymbol = 
                $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
            price = Random.Shared.Next(1, 101);
            var interopResult = await jsClass.TickerChanged(stockSymbol, price);
            result = $"Result of TickerChanged call for {stockSymbol} at " +
                $"{price.ToString("c")}: {interopResult}";
        }
    }

    public void Dispose() => jsClass?.Dispose();
}

CallJsExample5.razor:

@page "/call-js-example-5"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call JS Example 5</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@if (result is not null)
{
    <p>@result</p>
}

@code {
    private string? stockSymbol;
    private decimal price;
    private JsInteropClasses2? jsClass;
    private string? result;

    protected override void OnInitialized()
    {
        jsClass = new(JS);
    }

    private async Task SetStock()
    {
        if (jsClass is not null)
        {
            stockSymbol = 
                $"{(char)('A' + Random.Shared.Next(0, 26))}{(char)('A' + Random.Shared.Next(0, 26))}";
            price = Random.Shared.Next(1, 101);
            var interopResult = await jsClass.TickerChanged(stockSymbol, price);
            result = $"Result of TickerChanged call for {stockSymbol} at " +
                $"{price.ToString("c")}: {interopResult}";
        }
    }

    public void Dispose() => jsClass?.Dispose();
}

CallJsExample5.razor:

@page "/call-js-example-5"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call JS Example 5</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@if (result is not null)
{
    <p>@result</p>
}

@code {
    private Random r = new();
    private string stockSymbol;
    private decimal price;
    private JsInteropClasses2 jsClass;
    private string result;

    protected override void OnInitialized()
    {
        jsClass = new(JS);
    }

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + r.Next(0, 26))}{(char)('A' + r.Next(0, 26))}";
        price = r.Next(1, 101);
        var interopResult = await jsClass.TickerChanged(stockSymbol, price);
        result = $"Result of TickerChanged call for {stockSymbol} at " +
            $"{price.ToString("c")}: {interopResult}";
    }

    public void Dispose() => jsClass?.Dispose();
}

CallJsExample5.razor:

@page "/call-js-example-5"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call JS Example 5</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol != null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@if (result != null)
{
    <p>@result</p>
}

@code {
    private Random r = new Random();
    private string stockSymbol;
    private decimal price;
    private JsInteropClasses2 jsClass;
    private string result;

    protected override void OnInitialized()
    {
        jsClass = new JsInteropClasses2(JS);
    }

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + r.Next(0, 26))}{(char)('A' + r.Next(0, 26))}";
        price = r.Next(1, 101);
        var interopResult = await jsClass.TickerChanged(stockSymbol, price);
        result = $"Result of TickerChanged call for {stockSymbol} at " +
            $"{price.ToString("c")}: {interopResult}";
    }

    public void Dispose() => jsClass?.Dispose();
}

Dinamik içerik oluşturma senaryoları

BuildRenderTree ile dinamik içerik oluşturma için şu özniteliği kullanın[Inject]:

[Inject]
IJSRuntime JS { get; set; }

Ön Kayıt

Bu bölüm, bileşenleri önceden Razor oluşturan sunucu tarafı uygulamalar için geçerlidir. Prerendering, Prerender ASP.NET Core bileşenlerinde ele alınmıştır.Razor

Not

Web Apps'te Blazor etkileşimli yönlendirme için iç gezinti, sunucudan yeni sayfa içeriği istemeyi içermez. Bu nedenle, iç sayfa istekleri için ön kayıt gerçekleşmez. Uygulama etkileşimli yönlendirmeyi benimsediyse, önyükleme davranışını gösteren bileşen örnekleri için tam sayfa yeniden yükleme gerçekleştirin. Daha fazla bilgi için bkz . Prerender ASP.NET Core Razor bileşenleri.

Bu bölüm, sunucu tarafı uygulamalar ve bileşenleri önceden Razor oluşturan barındırılan Blazor WebAssembly uygulamalar için geçerlidir. Prerendering, Prerender kapsamındadır ve ASP.NET Core Razor bileşenlerini tümleştirir.

Bir uygulama önceden çalıştırılırken JavaScript' e ()JS çağrılması gibi bazı eylemler mümkün değildir.

Aşağıdaki örnekte işlevi ile JSRuntimeExtensions.InvokeVoidAsync çağrılır setElementText1 ve bir değer döndürmez.

Not

Konum hakkında genel yönergeler JS ve üretim uygulamalarına yönelik önerilerimiz için bkz . ASP.NET Core Blazor uygulamalarında JavaScript konumu.

<script>
  window.setElementText1 = (element, text) => element.innerText = text;
</script>

Uyarı

Yukarıdaki örnek DOM'yi yalnızca gösterim amacıyla doğrudan değiştirir. ILE DOM'un JS doğrudan değiştirilmesi çoğu senaryoda önerilmez çünkü JS 'nin değişiklik izlemesini Blazoretkileyebilir. Daha fazla bilgi için bkz. ASP.NET Core Blazor JavaScript birlikte çalışabilirliği (JSbirlikte çalışma).

Yaşam OnAfterRender{Async} döngüsü olayı , sunucudaki ön kayıt işlemi sırasında çağrılmaz. Bileşen işleninceye OnAfterRender{Async} ve ön kayıt sonrasında istemcide etkileşimli hale gelene kadar birlikte çalışma çağrılarını geciktirmek JS için yöntemini geçersiz kılın.

PrerenderedInterop1.razor:

@page "/prerendered-interop-1"
@using Microsoft.JSInterop
@inject IJSRuntime JS

<PageTitle>Prerendered Interop 1</PageTitle>

<h1>Prerendered Interop Example 1</h1>

<div @ref="divElement">Text during render</div>

@code {
    private ElementReference divElement;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JS.InvokeVoidAsync(
                "setElementText1", divElement, "Text after render");
        }
    }
}

Not

Yukarıdaki örnek, istemciyi genel işlevlerle kirletir. Üretim uygulamalarında daha iyi bir yaklaşım için bkz . JavaScript modüllerinde JavaScript yalıtımı.

Örnek:

export setElementText1 = (element, text) => element.innerText = text;

Aşağıdaki bileşen, bir bileşenin başlatma mantığının bir parçası olarak birlikte çalışma özelliğinin, ön kayıtla uyumlu bir şekilde nasıl kullanılacağını JS gösterir. Bileşeni, içinden OnAfterRenderAsyncbir işleme güncelleştirmesi tetiklemenin mümkün olduğunu gösterir. Geliştirici, bu senaryoda sonsuz döngü oluşturmaktan kaçınmak için dikkatli olmalıdır.

Aşağıdaki örnek için işlevi ile IJSRuntime.InvokeAsync çağrılır setElementText2 ve bir değer döndürür.

Not

Konum hakkında genel yönergeler JS ve üretim uygulamalarına yönelik önerilerimiz için bkz . ASP.NET Core Blazor uygulamalarında JavaScript konumu.

<script>
  window.setElementText2 = (element, text) => {
    element.innerText = text;
    return text;
  };
</script>

Uyarı

Yukarıdaki örnek DOM'yi yalnızca gösterim amacıyla doğrudan değiştirir. ILE DOM'un JS doğrudan değiştirilmesi çoğu senaryoda önerilmez çünkü JS 'nin değişiklik izlemesini Blazoretkileyebilir. Daha fazla bilgi için bkz. ASP.NET Core Blazor JavaScript birlikte çalışabilirliği (JSbirlikte çalışma).

JSRuntime.InvokeAsync çağrıldığında, bileşen işleninceye ElementReference kadar HTML DOM öğesi olmadığından yalnızca içinde kullanılır ve önceki yaşam döngüsü yöntemlerinde kullanılmazOnAfterRenderAsync.

StateHasChanged , birlikte çalışma çağrısından JS alınan yeni durumla bileşeni yeniden oluşturmaya çağrılır (daha fazla bilgi için bkz . ASP.NET Core Razor bileşeni işleme). Kod sonsuz döngü oluşturmaz çünkü StateHasChanged yalnızca olduğunda data çağrılır null.

PrerenderedInterop2.razor:

@page "/prerendered-interop-2"
@using Microsoft.AspNetCore.Components
@using Microsoft.JSInterop
@inject IJSRuntime JS

<PageTitle>Prerendered Interop 2</PageTitle>

<h1>Prerendered Interop Example 2</h1>

<p>
    Get value via JS interop call:
    <strong id="val-get-by-interop">@(infoFromJs ?? "No value yet")</strong>
</p>

<p>
    Set value via JS interop call: 
    <strong id="val-set-by-interop" @ref="divElement"></strong>
</p>



@code {
    private string? infoFromJs;
    private ElementReference divElement;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && infoFromJs == null)
        {
            infoFromJs = await JS.InvokeAsync<string>(
                "setElementText2", divElement, "Hello from interop call!");

            StateHasChanged();
        }
    }
}

Not

Yukarıdaki örnek, istemciyi genel işlevlerle kirletir. Üretim uygulamalarında daha iyi bir yaklaşım için bkz . JavaScript modüllerinde JavaScript yalıtımı.

Örnek:

export setElementText2 = (element, text) => {
  element.innerText = text;
  return text;
};

İstemci tarafı bileşenlerinde zaman uyumlu JS birlikte çalışma

Bu bölüm yalnızca istemci tarafı bileşenleri için geçerlidir.

JS interop çağrıları, çağrılan kodun zaman uyumlu veya zaman uyumsuz olmasına bakılmaksızın varsayılan olarak zaman uyumsuzdur. Bileşenlerin sunucu tarafı ve istemci tarafı işleme modları arasında uyumlu olduğundan emin olmak için çağrılar varsayılan olarak zaman uyumsuz olarak yapılır. Sunucuda, tüm JS birlikte çalışma çağrıları bir ağ bağlantısı üzerinden gönderildiğinden zaman uyumsuz olmalıdır.

Bileşeninizin yalnızca WebAssembly üzerinde çalıştığından JS eminseniz zaman uyumlu birlikte çalışma çağrıları yapmayı seçebilirsiniz. Bu, zaman uyumsuz çağrılar yapmaktan biraz daha az ek yüke sahiptir ve sonuçları beklerken ara durum olmadığından daha az işleme döngüsüne neden olabilir.

İstemci tarafı bileşeninde .NET'ten JavaScript'e zaman uyumlu bir çağrı yapmak içinIJSInProcessRuntime, birlikte çalışma çağrısı yapmak için öğesine yayın IJSRuntime yapınJS:

@inject IJSRuntime JS

...

@code {
    protected override void HandleSomeEvent()
    {
        var jsInProcess = (IJSInProcessRuntime)JS;
        var value = jsInProcess.Invoke<string>("javascriptFunctionIdentifier");
    }
}

ASP.NET Core 5.0 veya üzeri istemci tarafı bileşenleriyle IJSObjectReference çalışırken, bunun yerine zaman uyumlu olarak kullanabilirsiniz IJSInProcessObjectReference . IJSInProcessObjectReferenceIAsyncDisposable/IDisposable uygular ve aşağıdaki örnekte gösterildiği gibi bellek sızıntısını önlemek için çöp toplama için atılmalıdır:

@inject IJSRuntime JS
@implements IAsyncDisposable

...

@code {
    ...
    private IJSInProcessObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSInProcessObjectReference>("import", 
            "./scripts.js");
        }
    }

    ...

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}

JavaScript konumu

JavaScript konumu makalesinde açıklanan yaklaşımlardan herhangi birini kullanarak JavaScript (JS) kodunu yükleyin:

Betikleri modüllerde JSyalıtma hakkında bilgi için JavaScript modüllerinde JavaScript yalıtımı bölümüne bakın.

Uyarı

Etiket dinamik olarak güncelleştirilemediğinden, yalnızca bileşenin statik sunucu tarafı işlemeyi (statik SSR) benimsemesi garanti edilirse bir bileşen dosyasına (.razor) etiket yerleştirin<script>.<script>

Uyarı

Etiket dinamik olarak güncelleştirilemediğinden <script> bir etiketi bileşen dosyasına (.razor) yerleştirmeyin<script>.

JavaScript modüllerinde JavaScript yalıtımı

Blazor, standart JavaScript modüllerinde JavaScript (JS) yalıtımını etkinleştirir (ECMAScript belirtimi). JavaScript modülü yükleme işlemi, diğer web uygulaması türleriyle aynı şekilde Blazor çalışır ve modüllerin uygulamanızda nasıl tanımlandığını özelleştirebilirsiniz. JavaScript modüllerini kullanma kılavuzu için bkz . MDN Web Belgeleri: JavaScript modülleri.

JS yalıtımı aşağıdaki avantajları sağlar:

  • İçeri aktarılan JS artık genel ad alanını kirletmez.
  • Kitaplık ve bileşenlerin kullanıcılarının ilgili JS'yi içeri aktarması gerekmez.

işleciyle import() dinamik içeri aktarma, ASP.NET Core ve Blazorile desteklenir:

if ({CONDITION}) import("/additionalModule.js");

Yukarıdaki örnekte yer tutucu, modülün {CONDITION} yüklenmesi gerekip gerekmediğini belirlemek için koşullu denetimi temsil eder.

Tarayıcı uyumluluğu için bkz . Kullanabilir miyim: JavaScript modülleri: dinamik içeri aktarma.

Örneğin, aşağıdaki JS modül tarayıcı JS penceresi istemini göstermek için bir işlevi dışarı aktarır. Aşağıdaki JS kodu bir dış JS dosyaya yerleştirin.

wwwroot/scripts.js:

export function showPrompt(message) {
  return prompt(message, 'Type anything here');
}

Önceki JS modülü bir uygulamaya veya sınıf kitaplığına klasörde statik bir web varlığı wwwroot olarak ekleyin ve ardından örneği çağırarak InvokeAsync modülü .NET koduna aktarın IJSRuntime .

IJSRuntime modülü IJSObjectReferenceolarak içeri aktarır. Bu, .NET kodundan bir JS nesneye başvuruyu temsil eder. Modülden dışarı aktarılan JS işlevleri çağırmak için komutunu IJSObjectReference kullanın.

CallJs6.razor:

@page "/call-js-6"
@implements IAsyncDisposable
@inject IJSRuntime JS

<PageTitle>Call JS 6</PageTitle>

<h1>Call JS Example 6</h1>

<p>
    <button @onclick="TriggerPrompt">Trigger browser window prompt</button>
</p>

<p>
    @result
</p>

@code {
    private IJSObjectReference? module;
    private string? result;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import",
                "./scripts.js");
        }
    }

    private async Task TriggerPrompt()
    {
        result = await Prompt("Provide some text");
    }

    public async ValueTask<string?> Prompt(string message) =>
        module is not null ? 
            await module.InvokeAsync<string>("showPrompt", message) : null;

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}

CallJsExample6.razor:

@page "/call-js-example-6"
@implements IAsyncDisposable
@inject IJSRuntime JS

<h1>Call JS Example 6</h1>

<p>
    <button @onclick="TriggerPrompt">Trigger browser window prompt</button>
</p>

<p>
    @result
</p>

@code {
    private IJSObjectReference? module;
    private string? result;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import", 
                "./scripts.js");
        }
    }

    private async Task TriggerPrompt()
    {
        result = await Prompt("Provide some text");
    }

    public async ValueTask<string?> Prompt(string message) =>
        module is not null ? 
            await module.InvokeAsync<string>("showPrompt", message) : null;

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}

CallJsExample6.razor:

@page "/call-js-example-6"
@implements IAsyncDisposable
@inject IJSRuntime JS

<h1>Call JS Example 6</h1>

<p>
    <button @onclick="TriggerPrompt">Trigger browser window prompt</button>
</p>

<p>
    @result
</p>

@code {
    private IJSObjectReference? module;
    private string? result;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import", 
                "./scripts.js");
        }
    }

    private async Task TriggerPrompt()
    {
        result = await Prompt("Provide some text");
    }

    public async ValueTask<string?> Prompt(string message) =>
        module is not null ? 
            await module.InvokeAsync<string>("showPrompt", message) : null;

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}

CallJsExample6.razor:

@page "/call-js-example-6"
@implements IAsyncDisposable
@inject IJSRuntime JS

<h1>Call JS Example 6</h1>

<p>
    <button @onclick="TriggerPrompt">Trigger browser window prompt</button>
</p>

<p>
    @result
</p>

@code {
    private IJSObjectReference module;
    private string result;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import", 
                "./scripts.js");
        }
    }

    private async Task TriggerPrompt()
    {
        result = await Prompt("Provide some text");
    }

    public async ValueTask<string> Prompt(string message)
    {
        return await module.InvokeAsync<string>("showPrompt", message);
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}

Yukarıdaki örnekte:

  • Kural gereği import tanımlayıcı, özellikle modülü içeri aktarmak için kullanılan özel bir JS tanımlayıcıdır.
  • Modülün dış JS dosyasını kararlı statik web varlığı yolunu kullanarak belirtin: ./{SCRIPT PATH AND FILE NAME (.js)}burada:
    • JS dosyasının doğru statik varlık yolunu oluşturabilmek için geçerli dizinin yol segmenti (./) gereklidir.
    • {SCRIPT PATH AND FILE NAME (.js)} yer tutucusu, wwwroot altındaki yol ve dosya adıdır.
  • içinde çöp toplamaIAsyncDisposable.DisposeAsynciçin öğesini IJSObjectReference atılır.

Bir modülü dinamik olarak içeri aktarmak için bir ağ isteği gerekir, bu nedenle yalnızca çağrılarak InvokeAsynczaman uyumsuz olarak gerçekleştirilebilir.

IJSInProcessObjectReference , işlevleri istemci tarafı bileşenlerinde zaman uyumlu olarak çağrılabilen bir JS nesneye başvuru temsil eder. Daha fazla bilgi için istemci tarafı bileşenlerinde zaman uyumlu JS birlikte çalışma bölümüne bakın.

Not

Dış JS dosya bir Razor sınıf kitaplığı tarafından sağlandığında, modülün JS dosyasını kararlı statik web varlığı yolunu kullanarak belirtin: : ./_content/{PACKAGE ID}/{SCRIPT PATH AND FILE NAME (.js)}

  • JS dosyasının doğru statik varlık yolunu oluşturabilmek için geçerli dizinin yol segmenti (./) gereklidir.
  • {PACKAGE ID} yer tutucusu, kitaplığın paket kimliğidir. Proje dosyasında <PackageId> belirtilmediyse varsayılan olarak projenin derleme adı paket kimliği olur. Aşağıdaki örnekte kitaplığın derleme adıdır ComponentLibrary ve kitaplığın proje dosyası belirtilmez <PackageId>.
  • {SCRIPT PATH AND FILE NAME (.js)} yer tutucusu, wwwroot altındaki yol ve dosya adıdır. Aşağıdaki örnekte, dış JS dosya (script.js) sınıf kitaplığının wwwroot klasörüne yerleştirilir.
  • module, bileşen sınıfının (private IJSObjectReference? module;) özel null atanabilir IJSObjectReference değeridir.
module = await js.InvokeAsync<IJSObjectReference>(
    "import", "./_content/ComponentLibrary/scripts.js");

Daha fazla bilgi için bkz. Razor sınıf kitaplığından (RCL) ASP.NET Core Razor bileşenlerini kullanma.

Belgeler boyuncaBlazor, örnekler daha yeni .mjs dosya uzantısını (RFC 9239) değil modül dosyaları için dosya uzantısını kullanır.js. Belgelerimiz, Mozilla Foundation belgelerinin .js dosya uzantısını kullanmaya devam etmesiyle aynı nedenlerle dosya uzantısını .js kullanmaya devam ediyor. Daha fazla bilgi için bkz . Aside — .mjs versus .js (MDN belgeleri).

Öğelere yönelik başvuruları yakalama

Bazı JavaScript (JS) birlikte çalışma senaryolarında HTML öğelerine başvurular gerekir. Örneğin, kullanıcı arabirimi kitaplığı başlatma için bir öğe başvurusu gerektirebilir veya veya playgibi click bir öğede komut benzeri API'leri çağırmanız gerekebilir.

Aşağıdaki yaklaşımı kullanarak bir bileşendeki HTML öğelerine yönelik başvuruları yakalayın:

  • HTML öğesine bir @ref öznitelik ekleyin.
  • Adı özniteliğin değeriyle @ref eşleşen türde ElementReference bir alan tanımlayın.

Aşağıdaki örnekte, öğesine bir başvuru yakalama gösterilmektedir username<input> :

<input @ref="username" ... />

@code {
    private ElementReference username;
}

Uyarı

yalnızca ile Blazoretkileşimde olmayan boş bir öğenin içeriğini sessize almak için bir öğe başvurusu kullanın. Bu senaryo, bir üçüncü taraf API öğeye içerik sağladığında kullanışlıdır. Blazor öğesiyle etkileşim kurmadığından, öğesinin gösterimi ile DOM arasında Blazorçakışma olasılığı yoktur.

Aşağıdaki örnekte, bu öğenin liste öğelerini () nesneden doldurmak için DOM ile etkileşime girildiğinden, birlikte çalışma aracılığıyla JS kullanarak MyList sıralanmamış listenin (<li>ul) içeriğinin sessize Todos alınması tehlikelidir:Blazor

<ul @ref="MyList">
    @foreach (var item in Todos)
    {
        <li>@item.Text</li>
    }
</ul>

MyList Yalnızca DOM içeriğini okumak veya bir olayı tetiklemek için öğe başvurusunun kullanılması desteklenir.

Birlikte çalışma öğenin içeriğini sessize alır ve Blazor öğeye MyList farkları uygulamayı denerseJS, farklar DOM ile eşleşmez. Öğe başvurusuyla birlikte çalışma yoluyla JS listenin MyList içeriğinin değiştirilmesi desteklenmez.

Daha fazla bilgi için bkz. ASP.NET Core Blazor JavaScript birlikte çalışabilirliği (JSbirlikte çalışma).

birlikte ElementReference çalışma aracılığıyla JS koda JS geçirilir. Kod JS , normal DOM API'leriyle kullanabileceği bir HTMLElement örnek alır. Örneğin, aşağıdaki kod bir öğeye fare tıklaması göndermeyi sağlayan bir .NET uzantısı yöntemini (TriggerClickEvent) tanımlar.

İşlev, geçirilen HTML öğesinde (clickelement):JSclickElement

window.interopFunctions = {
  clickElement : function (element) {
    element.click();
  }
}

Değer döndürmeyen bir JS işlevi çağırmak için kullanın JSRuntimeExtensions.InvokeVoidAsync. Aşağıdaki kod, yakalanan ElementReferenceile önceki işlevi çağırarak istemci tarafı click olayını tetiklerJS:

@inject IJSRuntime JS

<button @ref="exampleButton">Example Button</button>

<button @onclick="TriggerClick">
    Trigger click event on <code>Example Button</code>
</button>

@code {
    private ElementReference exampleButton;

    public async Task TriggerClick()
    {
        await JS.InvokeVoidAsync(
            "interopFunctions.clickElement", exampleButton);
    }
}

Uzantı yöntemi kullanmak için örneği alan IJSRuntime statik bir uzantı yöntemi oluşturun:

public static async Task TriggerClickEvent(this ElementReference elementRef, 
    IJSRuntime js)
{
    await js.InvokeVoidAsync("interopFunctions.clickElement", elementRef);
}

clickElement yöntemi doğrudan nesne üzerinde çağrılır. Aşağıdaki örnekte, yönteminin TriggerClickEvent ad alanından JsInteropClasses kullanılabilir olduğu varsayılır:

@inject IJSRuntime JS
@using JsInteropClasses

<button @ref="exampleButton">Example Button</button>

<button @onclick="TriggerClick">
    Trigger click event on <code>Example Button</code>
</button>

@code {
    private ElementReference exampleButton;

    public async Task TriggerClick()
    {
        await exampleButton.TriggerClickEvent(JS);
    }
}

Önemli

exampleButton Değişken yalnızca bileşen işlendikten sonra doldurulur. Koda doldurulmamış ElementReference bir kod geçirilirse, JS kod değerini nullJS alır. Bileşen işleme tamamlandıktan sonra öğe başvurularını işlemek için veya bileşen yaşam döngüsü yöntemlerini kullanınOnAfterRenderAsync.OnAfterRender

Genel türlerle çalışırken ve bir değer döndürürken kullanın ValueTask<TResult>:

public static ValueTask<T> GenericMethod<T>(this ElementReference elementRef, 
    IJSRuntime js)
{
    return js.InvokeAsync<T>("{JAVASCRIPT FUNCTION}", elementRef);
}

Yer {JAVASCRIPT FUNCTION} tutucu, işlev tanımlayıcısıdır JS .

GenericMethod türüne sahip nesne üzerinde doğrudan çağrılır. Aşağıdaki örnekte, ad alanından JsInteropClasses kullanılabilir olduğu varsayılırGenericMethod:

@inject IJSRuntime JS
@using JsInteropClasses

<input @ref="username" />

<button @onclick="OnClickMethod">Do something generic</button>

<p>
    returnValue: @returnValue
</p>

@code {
    private ElementReference username;
    private string? returnValue;

    private async Task OnClickMethod()
    {
        returnValue = await username.GenericMethod<string>(JS);
    }
}
@inject IJSRuntime JS
@using JsInteropClasses

<input @ref="username" />

<button @onclick="OnClickMethod">Do something generic</button>

<p>
    returnValue: @returnValue
</p>

@code {
    private ElementReference username;
    private string? returnValue;

    private async Task OnClickMethod()
    {
        returnValue = await username.GenericMethod<string>(JS);
    }
}
@inject IJSRuntime JS
@using JsInteropClasses

<input @ref="username" />

<button @onclick="OnClickMethod">Do something generic</button>

<p>
    returnValue: @returnValue
</p>

@code {
    private ElementReference username;
    private string returnValue;

    private async Task OnClickMethod()
    {
        returnValue = await username.GenericMethod<string>(JS);
    }
}

Bileşenler arasında başvuru öğeleri

ElementReference Bileşenler arasında geçirilemiyor çünkü:

Bir üst bileşenin bir öğe başvuruyu diğer bileşenler için kullanılabilir hale getirmesi için, üst bileşen şunları yapabilir:

  • Alt bileşenlerin geri çağırmaları kaydetmesine izin verin.
  • Geçirilen öğe başvurusuyla olay sırasında OnAfterRender kayıtlı geri çağırmaları çağırın. Dolaylı olarak, bu yaklaşım alt bileşenlerin üst öğenin öğe başvurusuyla etkileşim kurmasına olanak tanır.
<style>
    .red { color: red }
</style>
<script>
  function setElementClass(element, className) {
    var myElement = element;
    myElement.classList.add(className);
  }
</script>

Not

Konum hakkında genel yönergeler JS ve üretim uygulamalarına yönelik önerilerimiz için bkz . ASP.NET Core Blazor uygulamalarında JavaScript konumu.

CallJs7.razor (üst bileşen):

@page "/call-js-7"

<PageTitle>Call JS 7</PageTitle>

<h1>Call JS Example 7</h1>

<h2 @ref="title">Hello, world!</h2>

Welcome to your new app.

<SurveyPrompt Parent="this" Title="How is Blazor working for you?" />

CallJsExample7.razor (üst bileşen):

@page "/call-js-example-7"

<h1>Call JS Example 7</h1>

<h2 @ref="title">Hello, world!</h2>

Welcome to your new app.

<SurveyPrompt Parent="this" Title="How is Blazor working for you?" />

CallJsExample7.razor (üst bileşen):

@page "/call-js-example-7"

<h1>Call JS Example 7</h1>

<h2 @ref="title">Hello, world!</h2>

Welcome to your new app.

<SurveyPrompt Parent="this" Title="How is Blazor working for you?" />

CallJsExample7.razor (üst bileşen):

@page "/call-js-example-7"

<h1>Call JS Example 7</h1>

<h2 @ref="title">Hello, world!</h2>

Welcome to your new app.

<SurveyPrompt Parent="this" Title="How is Blazor working for you?" />

CallJsExample7.razor (üst bileşen):

@page "/call-js-example-7"

<h1>Call JS Example 7</h1>

<h2 @ref="title">Hello, world!</h2>

Welcome to your new app.

<SurveyPrompt Parent="this" Title="How is Blazor working for you?" />

CallJs7.razor.cs:

using Microsoft.AspNetCore.Components;

namespace BlazorSample.Pages;

public partial class CallJs7 : 
    ComponentBase, IObservable<ElementReference>, IDisposable
{
    private bool disposing;
    private readonly List<IObserver<ElementReference>> subscriptions = [];
    private ElementReference title;

    protected override void OnAfterRender(bool firstRender)
    {
        base.OnAfterRender(firstRender);

        foreach (var subscription in subscriptions)
        {
            try
            {
                subscription.OnNext(title);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }

    public void Dispose()
    {
        disposing = true;

        foreach (var subscription in subscriptions)
        {
            try
            {
                subscription.OnCompleted();
            }
            catch (Exception)
            {
            }
        }

        subscriptions.Clear();

        // The following prevents derived types that introduce a
        // finalizer from needing to re-implement IDisposable.
        GC.SuppressFinalize(this);
    }

    public IDisposable Subscribe(IObserver<ElementReference> observer)
    {
        if (disposing)
        {
            throw new InvalidOperationException("Parent being disposed");
        }

        subscriptions.Add(observer);

        return new Subscription(observer, this);
    }

    private class Subscription(IObserver<ElementReference> observer,
        CallJs7 self) : IDisposable
    {
        public IObserver<ElementReference> Observer { get; } = observer;
        public CallJs7 Self { get; } = self;

        public void Dispose() => Self.subscriptions.Remove(Observer);
    }
}

CallJsExample7.razor.cs:

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components;

namespace BlazorSample.Pages;

public partial class CallJsExample7 : 
    ComponentBase, IObservable<ElementReference>, IDisposable
{
    private bool disposing;
    private IList<IObserver<ElementReference>> subscriptions = 
        new List<IObserver<ElementReference>>();
    private ElementReference title;

    protected override void OnAfterRender(bool firstRender)
    {
        base.OnAfterRender(firstRender);

        foreach (var subscription in subscriptions)
        {
            try
            {
                subscription.OnNext(title);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }

    public void Dispose()
    {
        disposing = true;

        foreach (var subscription in subscriptions)
        {
            try
            {
                subscription.OnCompleted();
            }
            catch (Exception)
            {
            }
        }

        subscriptions.Clear();
    }

    public IDisposable Subscribe(IObserver<ElementReference> observer)
    {
        if (disposing)
        {
            throw new InvalidOperationException("Parent being disposed");
        }

        subscriptions.Add(observer);

        return new Subscription(observer, this);
    }

    private class Subscription : IDisposable
    {
        public Subscription(IObserver<ElementReference> observer, 
            CallJsExample7 self)
        {
            Observer = observer;
            Self = self;
        }

        public IObserver<ElementReference> Observer { get; }
        public CallJsExample7 Self { get; }

        public void Dispose()
        {
            Self.subscriptions.Remove(Observer);
        }
    }
}

CallJsExample7.razor.cs:

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components;

namespace BlazorSample.Pages;

public partial class CallJsExample7 : 
    ComponentBase, IObservable<ElementReference>, IDisposable
{
    private bool disposing;
    private IList<IObserver<ElementReference>> subscriptions = 
        new List<IObserver<ElementReference>>();
    private ElementReference title;

    protected override void OnAfterRender(bool firstRender)
    {
        base.OnAfterRender(firstRender);

        foreach (var subscription in subscriptions)
        {
            try
            {
                subscription.OnNext(title);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }

    public void Dispose()
    {
        disposing = true;

        foreach (var subscription in subscriptions)
        {
            try
            {
                subscription.OnCompleted();
            }
            catch (Exception)
            {
            }
        }

        subscriptions.Clear();
    }

    public IDisposable Subscribe(IObserver<ElementReference> observer)
    {
        if (disposing)
        {
            throw new InvalidOperationException("Parent being disposed");
        }

        subscriptions.Add(observer);

        return new Subscription(observer, this);
    }

    private class Subscription : IDisposable
    {
        public Subscription(IObserver<ElementReference> observer, 
            CallJsExample7 self)
        {
            Observer = observer;
            Self = self;
        }

        public IObserver<ElementReference> Observer { get; }
        public CallJsExample7 Self { get; }

        public void Dispose()
        {
            Self.subscriptions.Remove(Observer);
        }
    }
}

CallJsExample7.razor.cs:

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components;

namespace BlazorSample.Pages
{
    public partial class CallJsExample7 : 
        ComponentBase, IObservable<ElementReference>, IDisposable
    {
        private bool disposing;
        private IList<IObserver<ElementReference>> subscriptions = 
            new List<IObserver<ElementReference>>();
        private ElementReference title;

        protected override void OnAfterRender(bool firstRender)
        {
            base.OnAfterRender(firstRender);

            foreach (var subscription in subscriptions)
            {
                try
                {
                    subscription.OnNext(title);
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }

        public void Dispose()
        {
            disposing = true;

            foreach (var subscription in subscriptions)
            {
                try
                {
                    subscription.OnCompleted();
                }
                catch (Exception)
                {
                }
            }

            subscriptions.Clear();
        }

        public IDisposable Subscribe(IObserver<ElementReference> observer)
        {
            if (disposing)
            {
                throw new InvalidOperationException("Parent being disposed");
            }

            subscriptions.Add(observer);

            return new Subscription(observer, this);
        }

        private class Subscription : IDisposable
        {
            public Subscription(IObserver<ElementReference> observer, 
                CallJsExample7 self)
            {
                Observer = observer;
                Self = self;
            }

            public IObserver<ElementReference> Observer { get; }
            public CallJsExample7 Self { get; }

            public void Dispose()
            {
                Self.subscriptions.Remove(Observer);
            }
        }
    }
}

CallJsExample7.razor.cs:

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components;

namespace BlazorSample.Pages
{
    public partial class CallJsExample7 : 
        ComponentBase, IObservable<ElementReference>, IDisposable
    {
        private bool disposing;
        private IList<IObserver<ElementReference>> subscriptions = 
            new List<IObserver<ElementReference>>();
        private ElementReference title;

        protected override void OnAfterRender(bool firstRender)
        {
            base.OnAfterRender(firstRender);

            foreach (var subscription in subscriptions)
            {
                try
                {
                    subscription.OnNext(title);
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }

        public void Dispose()
        {
            disposing = true;

            foreach (var subscription in subscriptions)
            {
                try
                {
                    subscription.OnCompleted();
                }
                catch (Exception)
                {
                }
            }

            subscriptions.Clear();
        }

        public IDisposable Subscribe(IObserver<ElementReference> observer)
        {
            if (disposing)
            {
                throw new InvalidOperationException("Parent being disposed");
            }

            subscriptions.Add(observer);

            return new Subscription(observer, this);
        }

        private class Subscription : IDisposable
        {
            public Subscription(IObserver<ElementReference> observer, 
                CallJsExample7 self)
            {
                Observer = observer;
                Self = self;
            }

            public IObserver<ElementReference> Observer { get; }
            public CallJsExample7 Self { get; }

            public void Dispose()
            {
                Self.subscriptions.Remove(Observer);
            }
        }
    }
}

Yukarıdaki örnekte, uygulamanın ad alanı şeklindedir BlazorSample. Kodu yerel olarak test ediyorsanız ad alanını güncelleştirin.

SurveyPrompt.razor (alt bileşen):

<div class="alert alert-secondary mt-4">
    <span class="oi oi-pencil me-2" aria-hidden="true"></span>
    <strong>@Title</strong>

    <span class="text-nowrap">
        Please take our
        <a target="_blank" class="font-weight-bold link-dark" href="https://go.microsoft.com/fwlink/?linkid=2186158">brief survey</a>
    </span>
    and tell us what you think.
</div>

@code {
    // Demonstrates how a parent component can supply parameters
    [Parameter]
    public string? Title { get; set; }
}
<div class="alert alert-secondary mt-4">
    <span class="oi oi-pencil me-2" aria-hidden="true"></span>
    <strong>@Title</strong>

    <span class="text-nowrap">
        Please take our
        <a target="_blank" class="font-weight-bold link-dark" href="https://go.microsoft.com/fwlink/?linkid=2186157">brief survey</a>
    </span>
    and tell us what you think.
</div>

@code {
    // Demonstrates how a parent component can supply parameters
    [Parameter]
    public string? Title { get; set; }
}
<div class="alert alert-secondary mt-4" role="alert">
    <span class="oi oi-pencil mr-2" aria-hidden="true"></span>
    <strong>@Title</strong>

    <span class="text-nowrap">
        Please take our
        <a target="_blank" class="font-weight-bold" 
            href="https://go.microsoft.com/fwlink/?linkid=2109206">brief survey</a>
    </span>
    and tell us what you think.
</div>

@code {
    [Parameter]
    public string? Title { get; set; }
}
<div class="alert alert-secondary mt-4" role="alert">
    <span class="oi oi-pencil mr-2" aria-hidden="true"></span>
    <strong>@Title</strong>

    <span class="text-nowrap">
        Please take our
        <a target="_blank" class="font-weight-bold" 
            href="https://go.microsoft.com/fwlink/?linkid=2109206">brief survey</a>
    </span>
    and tell us what you think.
</div>

@code {
    [Parameter]
    public string Title { get; set; }
}
<div class="alert alert-secondary mt-4" role="alert">
    <span class="oi oi-pencil mr-2" aria-hidden="true"></span>
    <strong>@Title</strong>

    <span class="text-nowrap">
        Please take our
        <a target="_blank" class="font-weight-bold" 
            href="https://go.microsoft.com/fwlink/?linkid=2109206">brief survey</a>
    </span>
    and tell us what you think.
</div>

@code {
    [Parameter]
    public string Title { get; set; }
}

SurveyPrompt.razor.cs:

using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace BlazorSample.Components;

public partial class SurveyPrompt : 
    ComponentBase, IObserver<ElementReference>, IDisposable
{
    private IDisposable? subscription = null;

    [Parameter]
    public IObservable<ElementReference>? Parent { get; set; }

    [Inject]
    public IJSRuntime? JS {get; set;}

    protected override void OnParametersSet()
    {
        base.OnParametersSet();

        subscription?.Dispose();
        subscription = Parent?.Subscribe(this);
    }

    public void OnCompleted()
    {
        subscription = null;
    }

    public void OnError(Exception error)
    {
        subscription = null;
    }

    public void  OnNext(ElementReference value)
    {
        _ = (JS?.InvokeAsync<object>(
            "setElementClass", [value, "red"]));
    }

    public void Dispose()
    {
        subscription?.Dispose();

        // The following prevents derived types that introduce a
        // finalizer from needing to re-implement IDisposable.
        GC.SuppressFinalize(this);
    }
}
using System;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace BlazorSample.Shared;

public partial class SurveyPrompt : 
    ComponentBase, IObserver<ElementReference>, IDisposable
{
    private IDisposable? subscription = null;

    [Parameter]
    public IObservable<ElementReference>? Parent { get; set; }

    [Inject]
    public IJSRuntime? JS {get; set;}

    protected override void OnParametersSet()
    {
        base.OnParametersSet();

        subscription?.Dispose();
        subscription = 
            Parent is not null ? Parent.Subscribe(this) : null;
    }

    public void OnCompleted()
    {
        subscription = null;
    }

    public void OnError(Exception error)
    {
        subscription = null;
    }

    public void OnNext(ElementReference value)
    {
        JS.InvokeAsync<object>(
            "setElementClass", new object[] { value, "red" });
    }

    public void Dispose()
    {
        subscription?.Dispose();
    }
}
using System;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace BlazorSample.Shared;

public partial class SurveyPrompt : 
    ComponentBase, IObserver<ElementReference>, IDisposable
{
    private IDisposable? subscription = null;

    [Parameter]
    public IObservable<ElementReference>? Parent { get; set; }

    [Inject]
    public IJSRuntime? JS {get; set;}

    protected override void OnParametersSet()
    {
        base.OnParametersSet();

        subscription?.Dispose();
        subscription = 
            Parent is not null ? Parent.Subscribe(this) : null;
    }

    public void OnCompleted()
    {
        subscription = null;
    }

    public void OnError(Exception error)
    {
        subscription = null;
    }

    public void OnNext(ElementReference value)
    {
        JS.InvokeAsync<object>(
            "setElementClass", new object[] { value, "red" });
    }

    public void Dispose()
    {
        subscription?.Dispose();
    }
}
using System;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace BlazorSample.Shared
{
    public partial class SurveyPrompt : 
        ComponentBase, IObserver<ElementReference>, IDisposable
    {
        private IDisposable subscription = null;

        [Parameter]
        public IObservable<ElementReference> Parent { get; set; }

        [Inject]
        public IJSRuntime JS {get; set;}

        protected override void OnParametersSet()
        {
            base.OnParametersSet();

            subscription?.Dispose();
            subscription = Parent.Subscribe(this);
        }

        public void OnCompleted()
        {
            subscription = null;
        }

        public void OnError(Exception error)
        {
            subscription = null;
        }

        public void OnNext(ElementReference value)
        {
            JS.InvokeAsync<object>(
                "setElementClass", new object[] { value, "red" });
        }

        public void Dispose()
        {
            subscription?.Dispose();
        }
    }
}
using System;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace BlazorSample.Shared
{
    public partial class SurveyPrompt : 
        ComponentBase, IObserver<ElementReference>, IDisposable
    {
        private IDisposable subscription = null;

        [Parameter]
        public IObservable<ElementReference> Parent { get; set; }

        [Inject]
        public IJSRuntime JS {get; set;}

        protected override void OnParametersSet()
        {
            base.OnParametersSet();

            subscription?.Dispose();
            subscription = Parent.Subscribe(this);
        }

        public void OnCompleted()
        {
            subscription = null;
        }

        public void OnError(Exception error)
        {
            subscription = null;
        }

        public void OnNext(ElementReference value)
        {
            JS.InvokeAsync<object>(
                "setElementClass", new object[] { value, "red" });
        }

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

Yukarıdaki örnekte, uygulamanın ad alanı klasördeki Shared paylaşılan bileşenlerle birliktedirBlazorSample. Kodu yerel olarak test ediyorsanız ad alanını güncelleştirin.

JavaScript birlikte çalışma çağrılarını sağlamlaştırma

Bu bölüm yalnızca Etkileşimli Sunucu bileşenleri için geçerlidir, ancak koşullar uygunsa istemci tarafı bileşenleri birlikte çalışma zaman aşımları da ayarlayabilir JS .

Sunucu etkileşimi olan sunucu tarafı uygulamalarda JavaScript (JS) birlikte çalışma ağ hataları nedeniyle başarısız olabilir ve güvenilir değil olarak değerlendirilmelidir. Varsayılan olarak, Blazor uygulamalar birlikte çalışma çağrıları için JS bir dakikalık zaman aşımı kullanır. Bir uygulama daha agresif bir zaman aşımına dayanabiliyorsa, aşağıdaki yaklaşımlardan birini kullanarak zaman aşımını ayarlayın.

ile CircuitOptions.JSInteropDefaultCallTimeoutiçinde Program.cs genel bir zaman aşımı ayarlayın:

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents(options => 
        options.JSInteropDefaultCallTimeout = {TIMEOUT});
builder.Services.AddServerSideBlazor(
    options => options.JSInteropDefaultCallTimeout = {TIMEOUT});

ile yönteminde Startup.ConfigureServicesStartup.csCircuitOptions.JSInteropDefaultCallTimeoutgenel bir zaman aşımı ayarlayın:

services.AddServerSideBlazor(
    options => options.JSInteropDefaultCallTimeout = {TIMEOUT});

Yer {TIMEOUT} tutucu bir TimeSpan 'dir (örneğin, TimeSpan.FromSeconds(80)).

Bileşen kodunda çağrı başına zaman aşımı ayarlayın. Belirtilen zaman aşımı tarafından JSInteropDefaultCallTimeoutayarlanan genel zaman aşımını geçersiz kılar:

var result = await JS.InvokeAsync<string>("{ID}", {TIMEOUT}, new[] { "Arg1" });

Yukarıdaki örnekte:

  • Yer {TIMEOUT} tutucu bir TimeSpan 'dir (örneğin, TimeSpan.FromSeconds(80)).
  • Yer {ID} tutucu, işlevin çağırılacağının tanımlayıcısıdır. Örneğin, değeri someScope.someFunction işlevini window.someScope.someFunctionçağırır.

Birlikte çalışma hatalarının yaygın nedenlerinden JS biri sunucu tarafı bileşenlerindeki ağ hataları olsa da, istemci tarafı bileşenleri için birlikte çalışma çağrıları için JS çağrı başına zaman aşımları ayarlanabilir. İstemci tarafı bileşeni için bağlantı hattı olmasa SignalR da, JS birlikte çalışma çağrıları geçerli olan diğer nedenlerden dolayı başarısız olabilir.

Kaynak tükenmesi hakkında daha fazla bilgi için bkz . ASP.NET Core Blazor etkileşimli sunucu tarafı işleme için tehdit azaltma kılavuzu.

Döngüsel nesne başvurularından kaçının

Döngüsel başvurular içeren nesneler istemcide aşağıdakilerden biri için seri hale getirilemez:

  • .NET yöntemi çağrıları.
  • Dönüş türü döngüsel başvurulara sahip olduğunda JavaScript yöntemi C# dilinden çağrılar.

Kullanıcı arabirimini işleyen JavaScript kitaplıkları

Bazen tarayıcı DOM'sinde görünür kullanıcı arabirimi öğeleri üreten JavaScript (JS) kitaplıkları kullanmak isteyebilirsiniz. İlk bakışta, bu zor görünebilir çünkü Blazorfark eden sistem DOM öğelerinin ağacı üzerinde denetim sahibi olmayı kullanır ve bazı dış kodlar DOM ağacını sessize alır ve farkları uygulama mekanizmasını geçersiz kıldığında hatalarla karşılaşır. Bu belirli bir Blazorsınırlama değildir. Aynı zorluk, fark tabanlı ui çerçevelerinde de ortaya çıkar.

Neyse ki, harici olarak oluşturulan kullanıcı arabirimini bir bileşen kullanıcı arabirimine güvenilir bir Razor şekilde eklemek kolaydır. Önerilen teknik, bileşenin kodunun (.razor dosyası) boş bir öğe üretmesini sağlamaktır. Blazor'nin fark sistemi söz konusu olduğunda, öğe her zaman boş olduğundan işleyici öğeye yineleme yapmaz ve bunun yerine içeriğini yalnız bırakır. Bu, öğeyi rastgele dış tarafından yönetilen içerikle doldurmayı güvenli hale getirir.

Aşağıdaki örnekte kavramı gösterilmektedir. deyimi içinde if olduğundatruefirstRender, birlikte çalışma kullanarak JS dışında Blazor ile unmanagedElement etkileşime geçin. Örneğin, öğesini doldurmak için bir dış JS kitaplık çağırın. Blazor bu bileşen kaldırılana kadar öğenin içeriğini yalnız bırakır. Bileşen kaldırıldığında, bileşenin dom alt ağacının tamamı da kaldırılır.

<h1>Hello! This is a Razor component rendered at @DateTime.Now</h1>

<div @ref="unmanagedElement"></div>

@code {
    private ElementReference unmanagedElement;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            ...
        }
    }
}

Açık kaynak Mapbox API'lerini kullanarak etkileşimli bir haritayı işleyen aşağıdaki örneği göz önünde bulundurun.

Aşağıdaki JS modül uygulamaya yerleştirilir veya bir Razor sınıf kitaplığından kullanılabilir hale getirilir.

Not

Mapbox eşlemesini oluşturmak için Mapbox Oturum Açma'dan bir erişim belirteci alın ve aşağıdaki kodda göründüğü yeri {ACCESS TOKEN} belirtin.

wwwroot/mapComponent.js:

import 'https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js';

mapboxgl.accessToken = '{ACCESS TOKEN}';

export function addMapToElement(element) {
  return new mapboxgl.Map({
    container: element,
    style: 'mapbox://styles/mapbox/streets-v11',
    center: [-74.5, 40],
    zoom: 9
  });
}

export function setMapCenter(map, latitude, longitude) {
  map.setCenter([longitude, latitude]);
}

Doğru stil oluşturmak için konak HTML sayfasına aşağıdaki stil sayfası etiketini ekleyin.

Öğe işaretlemesine <head> (içeriğin konumu) aşağıdaki <link> öğeyi <head> ekleyin:

<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" 
    rel="stylesheet" />

CallJs8.razor:

@page "/call-js-8"
@implements IAsyncDisposable
@inject IJSRuntime JS

<PageTitle>Call JS 8</PageTitle>

<HeadContent>
    <link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" 
        rel="stylesheet" />
</HeadContent>

<h1>Call JS Example 8</h1>

<div @ref="mapElement" style='width:400px;height:300px'></div>

<button @onclick="() => ShowAsync(51.454514, -2.587910)">Show Bristol, UK</button>
<button @onclick="() => ShowAsync(35.6762, 139.6503)">Show Tokyo, Japan</button>

@code
{
    private ElementReference mapElement;
    private IJSObjectReference? mapModule;
    private IJSObjectReference? mapInstance;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            mapModule = await JS.InvokeAsync<IJSObjectReference>(
                "import", "./mapComponent.js");
            mapInstance = await mapModule.InvokeAsync<IJSObjectReference>(
                "addMapToElement", mapElement);
        }
    }

    private async Task ShowAsync(double latitude, double longitude)
    {
        if (mapModule is not null && mapInstance is not null)
        {
            await mapModule.InvokeVoidAsync("setMapCenter", mapInstance, 
                latitude, longitude).AsTask();
        }
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (mapInstance is not null)
        {
            await mapInstance.DisposeAsync();
        }

        if (mapModule is not null)
        {
            await mapModule.DisposeAsync();
        }
    }
}

CallJsExample8.razor:

@page "/call-js-example-8"
@implements IAsyncDisposable
@inject IJSRuntime JS

<h1>Call JS Example 8</h1>

<div @ref="mapElement" style='width:400px;height:300px'></div>

<button @onclick="() => ShowAsync(51.454514, -2.587910)">Show Bristol, UK</button>
<button @onclick="() => ShowAsync(35.6762, 139.6503)">Show Tokyo, Japan</button>

@code
{
    private ElementReference mapElement;
    private IJSObjectReference? mapModule;
    private IJSObjectReference? mapInstance;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            mapModule = await JS.InvokeAsync<IJSObjectReference>(
                "import", "./mapComponent.js");
            mapInstance = await mapModule.InvokeAsync<IJSObjectReference>(
                "addMapToElement", mapElement);
        }
    }

    private async Task ShowAsync(double latitude, double longitude)
    {
        if (mapModule is not null && mapInstance is not null)
        {
            await mapModule.InvokeVoidAsync("setMapCenter", mapInstance, 
                latitude, longitude).AsTask();
        }
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (mapInstance is not null)
        {
            await mapInstance.DisposeAsync();
        }

        if (mapModule is not null)
        {
            await mapModule.DisposeAsync();
        }
    }
}

CallJsExample8.razor:

@page "/call-js-example-8"
@implements IAsyncDisposable
@inject IJSRuntime JS

<h1>Call JS Example 8</h1>

<div @ref="mapElement" style='width:400px;height:300px'></div>

<button @onclick="() => ShowAsync(51.454514, -2.587910)">Show Bristol, UK</button>
<button @onclick="() => ShowAsync(35.6762, 139.6503)">Show Tokyo, Japan</button>

@code
{
    private ElementReference mapElement;
    private IJSObjectReference? mapModule;
    private IJSObjectReference? mapInstance;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            mapModule = await JS.InvokeAsync<IJSObjectReference>(
                "import", "./mapComponent.js");
            mapInstance = await mapModule.InvokeAsync<IJSObjectReference>(
                "addMapToElement", mapElement);
        }
    }

    private async Task ShowAsync(double latitude, double longitude)
    {
        if (mapModule is not null && mapInstance is not null)
        {
            await mapModule.InvokeVoidAsync("setMapCenter", mapInstance, 
                latitude, longitude).AsTask();
        }
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (mapInstance is not null)
        {
            await mapInstance.DisposeAsync();
        }

        if (mapModule is not null)
        {
            await mapModule.DisposeAsync();
        }
    }
}

Yukarıdaki örnek etkileşimli bir harita kullanıcı arabirimi oluşturur. Kullanıcı:

  • Kaydırmak veya yakınlaştırmak için sürükleyebilir.
  • Önceden tanımlanmış konumlara atlamak için düğmeleri seçin.

Mapbox street map of Tokyo, Japan with buttons to select Bristol, United Kingdom and Tokyo, Japan

Yukarıdaki örnekte:

  • <div> ile @ref="mapElement" ilgili olarak boş Blazor bırakılır. Betik, mapbox-gl.js öğesini güvenli bir şekilde doldurabilir ve içeriğini değiştirebilir. Bu tekniği, kullanıcı arabirimini işleyen herhangi bir JS kitaplıkla kullanın. Üçüncü taraf JS SPA çerçevesindeki bileşenleri, sayfanın diğer bölümlerine ulaşmaya ve değiştirmeye çalışmadıkları sürece bileşenlerin içine Razor ekleyebilirsiniz. Dış kodun boş olarak dikkate alınmayan Blazor öğeleri değiştirmesi güvenli değildir.JS
  • Bu yaklaşımı kullanırken DOM öğelerinin nasıl Blazor korunduğundan veya yok edildiğinden bahseden kuralları aklınızda bulundurun. DOM öğeleri varsayılan olarak mümkün olduğunda korunduğu için bileşen düğme tıklama olaylarını güvenli bir şekilde işler ve mevcut harita örneğini güncelleştirir. Bir döngünün içinden @foreach harita öğelerinin listesini işlediyseniz, bileşen örneklerinin korunmasını sağlamak için kullanmak @key istiyorsunuz. Aksi takdirde, liste verilerindeki değişiklikler bileşen örneklerinin önceki örneklerin durumunu istenmeyen bir şekilde korumasına neden olabilir. Daha fazla bilgi için bkz. öğeler, bileşenler ve model nesneleri arasındaki ilişkiyi korumak için yönerge özniteliğini kullanma@key.
  • Örnek, bir ES6 modülü içindeki mantığı ve bağımlılıkları kapsüller JS ve tanımlayıcıyı import kullanarak modülü dinamik olarak yükler. Daha fazla bilgi için bkz . JavaScript modüllerinde JavaScript yalıtımı.

Bayt dizisi desteği

Blazor , bayt dizilerinin Base64'e kodlanması/kodunun çözülmesini önleyen iyileştirilmiş bayt dizisi JavaScript (JS) birlikte çalışmasını destekler. Aşağıdaki örnek, JavaScript'e bayt dizisi geçirmek için birlikte çalışma kullanır JS .

Bir receiveByteArrayJS işlev sağlayın. işlevi ile çağrılır InvokeVoidAsync ve bir değer döndürmez:

<script>
  window.receiveByteArray = (bytes) => {
    let utf8decoder = new TextDecoder();
    let str = utf8decoder.decode(bytes);
    return str;
  };
</script>

Not

Konum hakkında genel yönergeler JS ve üretim uygulamalarına yönelik önerilerimiz için bkz . ASP.NET Core Blazor uygulamalarında JavaScript konumu.

CallJs9.razor:

@page "/call-js-9"
@inject IJSRuntime JS

<h1>Call JS Example 9</h1>

<p>
    <button @onclick="SendByteArray">Send Bytes</button>
</p>

<p>
    @result
</p>

<p>
    Quote &copy;2005 <a href="https://www.uphe.com">Universal Pictures</a>:
    <a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>

@code {
    private string? result;

    private async Task SendByteArray()
    {
        var bytes = new byte[] { 0x45, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69,
            0x6e, 0x67, 0x27, 0x73, 0x20, 0x73, 0x68, 0x69, 0x6e, 0x79, 0x2c,
            0x20, 0x43, 0x61, 0x70, 0x74, 0x69, 0x61, 0x6e, 0x2e, 0x20, 0x4e,
            0x6f, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x72, 0x65, 0x74, 0x2e };

        result = await JS.InvokeAsync<string>("receiveByteArray", bytes);
    }
}

CallJsExample9.razor:

@page "/call-js-example-9"
@inject IJSRuntime JS

<h1>Call JS Example 9</h1>

<p>
    <button @onclick="SendByteArray">Send Bytes</button>
</p>

<p>
    @result
</p>

<p>
    Quote &copy;2005 <a href="https://www.uphe.com">Universal Pictures</a>:
    <a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>

@code {
    private string? result;

    private async Task SendByteArray()
    {
        var bytes = new byte[] { 0x45, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69,
            0x6e, 0x67, 0x27, 0x73, 0x20, 0x73, 0x68, 0x69, 0x6e, 0x79, 0x2c,
            0x20, 0x43, 0x61, 0x70, 0x74, 0x69, 0x61, 0x6e, 0x2e, 0x20, 0x4e,
            0x6f, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x72, 0x65, 0x74, 0x2e };

        result = await JS.InvokeAsync<string>("receiveByteArray", bytes);
    }
}

JavaScript'ten .NET çağırırken bayt dizisi kullanma hakkında bilgi için bkz . ASP.NET Core'da BlazorJavaScript işlevlerinden .NET yöntemlerini çağırma.

.NET'ten JavaScript'e akış

Blazor doğrudan .NET'ten JavaScript'e veri akışını destekler. Akışlar kullanılarak DotNetStreamReferenceoluşturulur.

DotNetStreamReference bir .NET akışını temsil eder ve aşağıdaki parametreleri kullanır:

  • stream: JavaScript'e gönderilen akış.
  • leaveOpen: Akışın iletimden sonra açık bırakılıp bırakılmadığını belirler. Bir değer sağlanmazsa, leaveOpen varsayılan olarak olur false.

JavaScript'te, verileri almak için bir dizi arabelleği veya okunabilir bir akış kullanın:

  • ArrayBufferKullanma:

    async function streamToJavaScript(streamRef) {
      const data = await streamRef.arrayBuffer();
    }
    
  • Kullanma ReadableStream:

    async function streamToJavaScript(streamRef) {
      const stream = await streamRef.stream();
    }
    

C# kodunda:

using var streamRef = new DotNetStreamReference(stream: {STREAM}, leaveOpen: false);
await JS.InvokeVoidAsync("streamToJavaScript", streamRef);

Yukarıdaki örnekte:

  • Yer tutucu, {STREAM} JavaScript'e gönderilen öğesini Stream temsil eder.
  • JS eklenen IJSRuntime bir örnektir.

ASP.NET Core'daki Blazor JavaScript işlevlerinden .NET yöntemlerini çağırmak, JavaScript'ten .NET'e akışla ters işlemi kapsar.

ASP.NET Core Blazor dosya indirmeleri , içinde Blazorbir dosyanın nasıl indirilme şeklini kapsar.

JavaScript özel durumlarını yakalama

Özel durumları yakalamak JS için birlikte çalışma alanını JS bir-trycatchblokta sarmalayıp bir yakalayın.JSException

Aşağıdaki örnekte nonFunctionJS işlev mevcut değildir. İşlev bulunamazsa, JSException aşağıdaki hatayı gösteren bir Message ile yakalanmış olur:

Could not find 'nonFunction' ('nonFunction' was undefined).

CallJs11.razor:

@page "/call-js-11"
@inject IJSRuntime JS

<PageTitle>Call JS 11</PageTitle>

<h1>Call JS Example 11</h1>

<p>
    <button @onclick="CatchUndefinedJSFunction">Catch Exception</button>
</p>

<p>
    @result
</p>

<p>
    @errorMessage
</p>

@code {
    private string? errorMessage;
    private string? result;

    private async Task CatchUndefinedJSFunction()
    {
        try
        {
            result = await JS.InvokeAsync<string>("nonFunction");
        }
        catch (JSException e)
        {
            errorMessage = $"Error Message: {e.Message}";
        }
    }
}

CallJsExample11.razor:

@page "/call-js-example-11"
@inject IJSRuntime JS

<h1>Call JS Example 11</h1>

<p>
    <button @onclick="CatchUndefinedJSFunction">Catch Exception</button>
</p>

<p>
    @result
</p>

<p>
    @errorMessage
</p>

@code {
    private string? errorMessage;
    private string? result;

    private async Task CatchUndefinedJSFunction()
    {
        try
        {
            result = await JS.InvokeAsync<string>("nonFunction");
        }
        catch (JSException e)
        {
            errorMessage = $"Error Message: {e.Message}";
        }
    }
}

CallJsExample11.razor:

@page "/call-js-example-11"
@inject IJSRuntime JS

<h1>Call JS Example 11</h1>

<p>
    <button @onclick="CatchUndefinedJSFunction">Catch Exception</button>
</p>

<p>
    @result
</p>

<p>
    @errorMessage
</p>

@code {
    private string? errorMessage;
    private string? result;

    private async Task CatchUndefinedJSFunction()
    {
        try
        {
            result = await JS.InvokeAsync<string>("nonFunction");
        }
        catch (JSException e)
        {
            errorMessage = $"Error Message: {e.Message}";
        }
    }
}

CallJsExample11.razor:

@page "/call-js-example-11"
@inject IJSRuntime JS

<h1>Call JS Example 11</h1>

<p>
    <button @onclick="CatchUndefinedJSFunction">Catch Exception</button>
</p>

<p>
    @result
</p>

<p>
    @errorMessage
</p>

@code {
    private string errorMessage;
    private string result;

    private async Task CatchUndefinedJSFunction()
    {
        try
        {
            result = await JS.InvokeAsync<string>("nonFunction");
        }
        catch (JSException e)
        {
            errorMessage = $"Error Message: {e.Message}";
        }
    }
}

CallJsExample11.razor:

@page "/call-js-example-11"
@inject IJSRuntime JS

<h1>Call JS Example 11</h1>

<p>
    <button @onclick="CatchUndefinedJSFunction">Catch Exception</button>
</p>

<p>
    @result
</p>

<p>
    @errorMessage
</p>

@code {
    private string errorMessage;
    private string result;

    private async Task CatchUndefinedJSFunction()
    {
        try
        {
            result = await JS.InvokeAsync<string>("nonFunction");
        }
        catch (JSException e)
        {
            errorMessage = $"Error Message: {e.Message}";
        }
    }
}

Uzun süre çalışan bir JavaScript işlevini durdurma

C# kodundan uzun süre çalışan bir JSJavaScript işlevini durdurmak için bileşeninde ile bir CancellationTokenSource AbortController kullanın.

Aşağıdaki JSHelpers sınıf, longRunningFnçağrıldığını belirtene AbortController.abort kadar AbortController.signal sürekli saymak için uzun süre çalışan simülasyon işlevi içerir. sleep İşlev, uzun süre çalışan işlevin yavaş yürütülmesini simüle etmek için gösterim amaçlıdır ve üretim kodunda mevcut olmaz. Bir bileşen çağırdığında stopFn, longRunningFn üzerinde döngü koşullu denetimi AbortSignal.abortedaracılığıyla while durdurulacak şekilde işaretlenir.

<script>
  class Helpers {
    static #controller = new AbortController();

    static async #sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }

    static async longRunningFn() {
      var i = 0;
      while (!this.#controller.signal.aborted) {
        i++;
        console.log(`longRunningFn: ${i}`);
        await this.#sleep(1000);
      }
    }

    static stopFn() {
      this.#controller.abort();
      console.log('longRunningFn aborted!');
    }
  }

  window.Helpers = Helpers;
</script>

Not

Konum hakkında genel yönergeler JS ve üretim uygulamalarına yönelik önerilerimiz için bkz . ASP.NET Core Blazor uygulamalarında JavaScript konumu.

Aşağıdaki bileşen:

CallJs12.razor:

@page "/call-js-12"
@inject IJSRuntime JS

<h1>Cancel long-running JS interop</h1>

<p>
    <button @onclick="StartTask">Start Task</button>
    <button @onclick="CancelTask">Cancel Task</button>
</p>

@code {
    private CancellationTokenSource? cts;

    private async Task StartTask()
    {
        cts = new CancellationTokenSource();
        cts.Token.Register(() => JS.InvokeVoidAsync("Helpers.stopFn"));

        await JS.InvokeVoidAsync("Helpers.longRunningFn");
    }

    private void CancelTask()
    {
        cts?.Cancel();
    }

    public void Dispose()
    {
        cts?.Cancel();
        cts?.Dispose();
    }
}

CallJsExample12.razor:

@page "/call-js-example-12"
@inject IJSRuntime JS

<h1>Cancel long-running JS interop</h1>

<p>
    <button @onclick="StartTask">Start Task</button>
    <button @onclick="CancelTask">Cancel Task</button>
</p>

@code {
    private CancellationTokenSource? cts;

    private async Task StartTask()
    {
        cts = new CancellationTokenSource();
        cts.Token.Register(() => JS.InvokeVoidAsync("Helpers.stopFn"));

        await JS.InvokeVoidAsync("Helpers.longRunningFn");
    }

    private void CancelTask()
    {
        cts?.Cancel();
    }

    public void Dispose()
    {
        cts?.Cancel();
        cts?.Dispose();
    }
}

Tarayıcının geliştirici araçları konsolu, düğme seçildikten sonra ve düğme seçildikten sonra Start Task işlev durdurulduğunda uzun süre çalışan JS işlevin yürütülmesini Cancel Task gösterir:

longRunningFn: 1
longRunningFn: 2
longRunningFn: 3
longRunningFn aborted!

JavaScript [JSImport]/[JSExport] birlikte çalışma

Bu bölüm istemci tarafı bileşenleri için geçerlidir.

'nin arabirime dayalı birlikte çalışma mekanizmasını kullanarak Blazoristemci tarafı bileşenlerinde JavaScript (JS) ile etkileşime alternatif olarak, .NET 7 veya sonraki sürümleri hedefleyen uygulamalar için birlikte[JSImport]JS/[JSExport] çalışma API'sini kullanabilirsiniz.IJSRuntimeJS

Daha fazla bilgi için bkz. ASP.NET Core Blazorile JavaScript JSİçeri/JSDışarı Aktarma birlikte çalışma .

Özetlenmemiş JavaScript birlikte çalışma

Bu bölüm istemci tarafı bileşenleri için geçerlidir.

Arabirimi kullanan IJSUnmarshalledRuntime özetlenmemiş birlikte çalışma kullanım dışıdır ve JavaScript [JSImport]/[JSExport] birlikte çalışmasıyla değiştirilmelidir.

Daha fazla bilgi için bkz. ASP.NET Core Blazorile JavaScript JSİçeri/JSDışarı Aktarma birlikte çalışma .

Özetlenmemiş JavaScript birlikte çalışma

Blazor WebAssembly .NET nesneleri JavaScript (JS) birlikte çalışma için seri hale getirildiğinde ve aşağıdakilerden biri doğru olduğunda bileşenler düşük performansla karşılaşabilir:

  • Yüksek hacimli .NET nesneleri hızla serileştirilir. Örneğin, fare tekerleğini döndürmek gibi bir giriş cihazının taşınması temelinde birlikte çalışma çağrıları yapıldığında düşük performans oluşabilir JS .
  • Büyük .NET nesneleri veya birçok .NET nesnesi birlikte çalışma için JS seri hale getirilmelidir. Örneğin, birlikte çalışma çağrıları onlarca dosyayı seri hale getirme gerektirdiğinde JS düşük performansa neden olabilir.

IJSUnmarshalledObjectReference , .NET verilerini seri hale getirme yükü olmadan işlevleri çağrılabilen bir JS nesneye başvuruyu temsil eder.

Aşağıdaki örnekte:

  • Dize ve tamsayı içeren bir yapı , 'ye JSseri durumdan geçirilir.
  • JS işlevleri verileri işler ve çağırana boole veya dize döndürür.
  • Dize JS doğrudan .NET string nesnesine dönüştürülemez. İşlev, unmarshalledFunctionReturnString bir JS dizenin dönüştürülme işlemini yönetmek için çağırırBINDING.js_string_to_mono_string.

Not

Aşağıdaki örnekler bu senaryo için tipik kullanım örnekleri değildir çünkü 'a JS geçirilen yapı düşük bileşen performansına neden olmaz. Örnek, yalnızca seri durumdan çıkarılmamış .NET verilerini geçirme kavramlarını göstermek için küçük bir nesne kullanır.

<script>
  window.returnObjectReference = () => {
    return {
      unmarshalledFunctionReturnBoolean: function (fields) {
        const name = Blazor.platform.readStringField(fields, 0);
        const year = Blazor.platform.readInt32Field(fields, 8);

        return name === "Brigadier Alistair Gordon Lethbridge-Stewart" &&
            year === 1968;
      },
      unmarshalledFunctionReturnString: function (fields) {
        const name = Blazor.platform.readStringField(fields, 0);
        const year = Blazor.platform.readInt32Field(fields, 8);

        return BINDING.js_string_to_mono_string(`Hello, ${name} (${year})!`);
      }
    };
  }
</script>

Not

Konum hakkında genel yönergeler JS ve üretim uygulamalarına yönelik önerilerimiz için bkz . ASP.NET Core Blazor uygulamalarında JavaScript konumu.

Uyarı

js_string_to_mono_string İşlev adı, davranışı ve varlığı,.NET'in gelecek bir sürümünde değiştirilebilir. Örneğin:

  • İşlev büyük olasılıkla yeniden adlandırılacaktır.
  • İşlevin kendisi, dizelerin çerçeve tarafından otomatik olarak dönüştürülmesi yerine kaldırılabilir.

CallJsExample10.razor:

@page "/call-js-example-10"
@using System.Runtime.InteropServices
@using Microsoft.JSInterop
@inject IJSRuntime JS

<h1>Call JS Example 10</h1>

@if (callResultForBoolean)
{
    <p>JS interop was successful!</p>
}

@if (!string.IsNullOrEmpty(callResultForString))
{
    <p>@callResultForString</p>
}

<p>
    <button @onclick="CallJSUnmarshalledForBoolean">
        Call Unmarshalled JS & Return Boolean
    </button>
    <button @onclick="CallJSUnmarshalledForString">
        Call Unmarshalled JS & Return String
    </button>
</p>

<p>
    <a href="https://www.doctorwho.tv">Doctor Who</a>
    is a registered trademark of the <a href="https://www.bbc.com/">BBC</a>.
</p>

@code {
    private bool callResultForBoolean;
    private string? callResultForString;

    private void CallJSUnmarshalledForBoolean()
    {
        var unmarshalledRuntime = (IJSUnmarshalledRuntime)JS;

        var jsUnmarshalledReference = unmarshalledRuntime
            .InvokeUnmarshalled<IJSUnmarshalledObjectReference>(
                "returnObjectReference");

        callResultForBoolean = 
            jsUnmarshalledReference.InvokeUnmarshalled<InteropStruct, bool>(
                "unmarshalledFunctionReturnBoolean", GetStruct());
    }

    private void CallJSUnmarshalledForString()
    {
        var unmarshalledRuntime = (IJSUnmarshalledRuntime)JS;

        var jsUnmarshalledReference = unmarshalledRuntime
            .InvokeUnmarshalled<IJSUnmarshalledObjectReference>(
                "returnObjectReference");

        callResultForString = 
            jsUnmarshalledReference.InvokeUnmarshalled<InteropStruct, string>(
                "unmarshalledFunctionReturnString", GetStruct());
    }

    private InteropStruct GetStruct()
    {
        return new InteropStruct
        {
            Name = "Brigadier Alistair Gordon Lethbridge-Stewart",
            Year = 1968,
        };
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct InteropStruct
    {
        [FieldOffset(0)]
        public string Name;

        [FieldOffset(8)]
        public int Year;
    }
}
@page "/call-js-example-10"
@using System.Runtime.InteropServices
@using Microsoft.JSInterop
@inject IJSRuntime JS

<h1>Call JS Example 10</h1>

@if (callResultForBoolean)
{
    <p>JS interop was successful!</p>
}

@if (!string.IsNullOrEmpty(callResultForString))
{
    <p>@callResultForString</p>
}

<p>
    <button @onclick="CallJSUnmarshalledForBoolean">
        Call Unmarshalled JS & Return Boolean
    </button>
    <button @onclick="CallJSUnmarshalledForString">
        Call Unmarshalled JS & Return String
    </button>
</p>

<p>
    <a href="https://www.doctorwho.tv">Doctor Who</a>
    is a registered trademark of the <a href="https://www.bbc.com/">BBC</a>.
</p>

@code {
    private bool callResultForBoolean;
    private string callResultForString;

    private void CallJSUnmarshalledForBoolean()
    {
        var unmarshalledRuntime = (IJSUnmarshalledRuntime)JS;

        var jsUnmarshalledReference = unmarshalledRuntime
            .InvokeUnmarshalled<IJSUnmarshalledObjectReference>(
                "returnObjectReference");

        callResultForBoolean = 
            jsUnmarshalledReference.InvokeUnmarshalled<InteropStruct, bool>(
                "unmarshalledFunctionReturnBoolean", GetStruct());
    }

    private void CallJSUnmarshalledForString()
    {
        var unmarshalledRuntime = (IJSUnmarshalledRuntime)JS;

        var jsUnmarshalledReference = unmarshalledRuntime
            .InvokeUnmarshalled<IJSUnmarshalledObjectReference>(
                "returnObjectReference");

        callResultForString = 
            jsUnmarshalledReference.InvokeUnmarshalled<InteropStruct, string>(
                "unmarshalledFunctionReturnString", GetStruct());
    }

    private InteropStruct GetStruct()
    {
        return new InteropStruct
        {
            Name = "Brigadier Alistair Gordon Lethbridge-Stewart",
            Year = 1968,
        };
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct InteropStruct
    {
        [FieldOffset(0)]
        public string Name;

        [FieldOffset(8)]
        public int Year;
    }
}

Bir IJSUnmarshalledObjectReference örnek C# kodunda atılmıyorsa, içinde JSatılabilir. Aşağıdaki dispose işlev, öğesinden JSçağrıldığında nesne başvuruyu atar:

window.exampleJSObjectReferenceNotDisposedInCSharp = () => {
  return {
    dispose: function () {
      DotNet.disposeJSObjectReference(this);
    },

    ...
  };
}

Dizi türleri kullanılarak js_typed_array_to_arraynesnelerden JS .NET nesnelerine dönüştürülebilir, ancak JS dizinin türü alınmış bir dizi olması gerekir. 'den JS diziler C# kodunda .NET nesne dizisi (object[]) olarak okunabilir.

Dize dizileri gibi diğer veri türleri dönüştürülebilir, ancak yeni bir Mono dizi nesnesi () oluşturulmasını ve değerinin (mono_obj_array_newmono_obj_array_set) ayarlanmasını gerektirir.

Uyarı

JS, ve mono_obj_array_setgibi js_typed_array_to_arraymono_obj_array_newçerçeve tarafından Blazor sağlanan işlevler, .NET'in gelecek sürümlerinde ad değişikliklerine, davranış değişikliklerine veya kaldırılmasına tabidir.

JavaScript birlikte çalışma nesnesi başvurularının elden çıkarılması

JavaScript (JS) birlikte çalışma makalelerinin tüm örnekleri tipik nesne atma desenlerini gösterir:

  • .NET'ten ararkenJS, bu makalede açıklandığı gibi bellek sızıntısını JS önlemek için .NET'ten veya kaynağından JS oluşturulanlarıJSObjectReferenceIJSObjectReference/IJSInProcessObjectReference/atın.

  • .NET JSçağrısı yaparken, ASP.NET Core'daki BlazorJavaScript işlevlerinden .NET yöntemlerini çağırma bölümünde açıklandığı gibi , .NET belleğinin sızmasını önlemek için .NET'ten veya kaynağından JS oluşturulan DotNetObjectReference bir öğesini atın.

JS birlikte çalışma nesne başvuruları, birlikte çalışma çağrısının JS yanında başvuruyu oluşturan bir tanımlayıcı tarafından anahtarlanan bir eşleme olarak uygulanır. Nesne atma işlemi .NET'ten veya JS taraftan başlatıldığında, Blazor girdiyi eşlemeden kaldırır ve nesneye başka güçlü bir başvuru olmadığı sürece nesne çöp olarak toplanabilir.

.NET yönetilen belleğinin sızmasını önlemek için en azından .NET tarafında oluşturulan nesneleri her zaman atın.

Bileşen atma sırasında DOM temizleme görevleri

Daha fazla bilgi için bkz. ASP.NET Core Blazor JavaScript birlikte çalışabilirliği (JSbirlikte çalışma).

Bağlantı hattı olmayan JavaScript birlikte çalışma çağrıları

Daha fazla bilgi için bkz. ASP.NET Core Blazor JavaScript birlikte çalışabilirliği (JSbirlikte çalışma).

Ek kaynaklar