简体   繁体   中英

Getting the size of a Blazor page with Javascript

I'm learning JSInterop with Blazor. I would like to get the width and the height of a Blazor page in oder to size à canvas.

I'm using the default Blazor template with the menu bar on the left part of the screen. 在此处输入图像描述

On the html part of the Canvas Test 1 page I have:

@page "/canvas_test1"
@inject IJSRuntime JsRuntime
<canvas @ref="canvas1"></canvas>
<button @onclick="SetCanvasSize">Set canvas size</button>

In the code part I have:

ElementReference canvas1;
async Task SetCanvasSize()
{
    await JsRuntime.InvokeVoidAsync("SetCanvasSize", canvas1);
}

In the Javascript file I have:

function SetCanvasSize(element) {
ctx = element.getContext('2d');
console.log(window.innerWidth);
console.log(document.documentElement.scrollWidth);
}

But both methodes window.innerWidth and document.documentElement.scrollWidth give the width of the entire window not only the page that contains the canvas.

How can I get the width of only the page without the side menu?

Thank you

I think you're a little confused about what a Page is in Blazor. It's basically a component that you provide a route to for navigation. If you include a layout (which is usually set by default), that is in fact part of the page. All the things on the page, like your canvas, are just html elements. It is correctly telling you the size of the window, which you can see will change if you resize your browser.

html elements have the properties "offsetWidth" and "offsetHeight." So, for your use you want to pass the element to measure, and use element.offsetWidth :

function GetCanvasSize(element) {
     alert ("Element measurements: " + element.offsetWidth + ", " + element.offsetHeight);
}

You can see more of the members of html elements here, including common methods and events: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetWidth

Note that this list is missing some important things you'd like to know, especially the various touch events which you'll need for dragging elements on mobile clients (mouse events won't work on phones).

You need to get the dimensions of the containing element. You also need to listen for resizing events.

I use a service that can take a ref for any element and listen for changes.

bCore.js

export function listenToWindowResize(dotNetHelper) {

    function resizeEventHandler() {
        dotNetHelper.invokeMethodAsync('WindowResizeEvent');
    }

    window.addEventListener("resize", resizeEventHandler);

    dotNetHelper.invokeMethodAsync('WindowResizeEvent');
}

export function getBoundingRectangle(element, parm) {
    return element.getBoundingClientRect();
}

export function getWindowSizeDetails(parm) {

    var e = window, a = 'inner';

    if (!('innerWidth' in window)) {
        a = 'client';
        e = document.documentElement || document.body;
    }

    let windowSize =
    {
        innerWidth: e[a + 'Width'],
        innerHeight: e[a + 'Height'],
        screenWidth: window.screen.width,
        screenHeight: window.screen.height
    };

    return windowSize;
}

JSInteropCoreService.cs

public class JSInteropCoreService : IJSInteropCoreService, IAsyncDisposable
{
    private readonly Lazy<Task<IJSObjectReference>> moduleTask;
    private bool isResizing;
    private System.Timers.Timer resizeTimer;
    private DotNetObjectReference<JSInteropCoreService> jsInteropCoreServiceRef;

    public JSInteropCoreService(IJSRuntime jsRuntime)
    {
        this.resizeTimer = new System.Timers.Timer(interval: 25);
        this.isResizing = false;
        this.resizeTimer.Elapsed += async (sender, elapsedEventArgs) => await DimensionsChanged(sender!, elapsedEventArgs);

        this.moduleTask = new(() => jsRuntime.InvokeAsync<IJSObjectReference>(
          identifier: "import", args: "./_content/BJSInteroptCore/bCore.js").AsTask());
    }

    public event NotifyResizing OnResizing;
    public event NotifyResize OnResize;

    public async ValueTask InitializeAsync()
    {
        IJSObjectReference module = await GetModuleAsync();

        this.jsInteropCoreServiceRef = DotNetObjectReference.Create(this);

        await module.InvokeVoidAsync(identifier: "listenToWindowResize", this.jsInteropCoreServiceRef);

        this.BrowserSizeDetails = await module.InvokeAsync<BrowserSizeDetails>(identifier: "getWindowSizeDetails");

    }

    public async ValueTask<BrowserSizeDetails> GetWindowSizeAsync()
    {
        IJSObjectReference module = await GetModuleAsync();
        return await module.InvokeAsync<BrowserSizeDetails>(identifier: "getWindowSizeDetails");
    }

    public async ValueTask<ElementBoundingRectangle> GetElementBoundingRectangleAsync(ElementReference elementReference)
    {
        IJSObjectReference module = await GetModuleAsync();
        return await module.InvokeAsync<ElementBoundingRectangle>(identifier: "getBoundingRectangle", elementReference);
    }

    [JSInvokable]
    public ValueTask WindowResizeEvent()
    {
        if (this.isResizing is not true)
        {
            this.isResizing = true;
            OnResizing?.Invoke(this.isResizing);
        }
        DebounceResizeEvent();
        return ValueTask.CompletedTask;
    }

    public BrowserSizeDetails BrowserSizeDetails { get; private set; } = new BrowserSizeDetails();

    private void DebounceResizeEvent()
    {
        if (this.resizeTimer.Enabled is false)
        {
            Task.Run(async () =>
            {
                this.BrowserSizeDetails = await GetWindowSizeAsync();
                isResizing = false;
                OnResizing?.Invoke(this.isResizing);
                OnResize?.Invoke();
            });
            this.resizeTimer.Restart();
        }
    }

    private async ValueTask DimensionsChanged(object sender, System.Timers.ElapsedEventArgs e)
    {
        this.resizeTimer.Stop();
        this.BrowserSizeDetails = await GetWindowSizeAsync();
        isResizing = false;
        OnResizing?.Invoke(this.isResizing);
        OnResize?.Invoke();
    }

    public async ValueTask DisposeAsync()
    {
        if (moduleTask.IsValueCreated)
        {
            IJSObjectReference module = await GetModuleAsync();
            await module.DisposeAsync();
        }
    }

    private async Task<IJSObjectReference> GetModuleAsync()
        => await this.moduleTask.Value;
}
public class ElementBoundingRectangle
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Width { get; set; }
    public double Height { get; set; }
    public double Top { get; set; }
    public double Right { get; set; }
    public double Bottom { get; set; }
    public double Left { get; set; }
}
public class BrowserSizeDetails
{
    public double InnerWidth { get; set; }
    public double InnerHeight { get; set; }
    public int ScreenWidth { get; set; }
    public int ScreenHeight { get; set; }
}

I debounce the resize events using a 25ms interval to prevent lag.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM