mirror of
https://gitee.com/ant-design-blazor/ant-design-blazor.git
synced 2024-12-14 17:01:18 +08:00
4b04f09832
* perf: avoid memory leak #1834 Avoid memory leak by remove the exclusive parameter and logic in the code block on AddEventListener method in DomEventService class. The following are the components affected: components/affix/Affix.razor.cs components/anchor/Anchor.razor.cs components/carousel/Carousel.razor.cs components/core/Component/Overlay/Overlay.razor.cs components/core/Component/Overlay/OverlayTrigger.razor.cs components/core/JsInterop/DomEventService.cs components/descriptions/Descriptions.razor.cs components/dropdown/DropdownButton.cs components/grid/Row.razor.cs components/input/Input.cs components/input/TextArea.razor.cs components/layout/Sider.razor.cs components/list/ListItem.razor.cs components/select/Select.razor.cs components/select/internal/SelectContent.razor.cs components/slider/Slider.razor.cs components/table/Table.razor.cs components/tabs/Tabs.razor.cs * fix override AddEventListener method in AntDesign.TestKit project * add register/remove event listerner for exclusive use in DomEventService class * move _dotNetObjects to DomEventListerner class/service, so that users not required to maintain it in each component. * * move share/reuse dom event listerner methods to DomEventListerner class * remove method 'AddEventListener' that no longer exists in DomEventService class in AntDesign.TestKit project * * change the component referring to an IDomEventListerner interface instead of a concrete class, so that the component can be tested via a mock TestDomEventListerner. * introduce DisposeShared and Dispose method in DomEventListerner to ease user remove callback from DomEventListerner * register IDomEventListerner into DI container instead of create manually * fix FormatKey * fix FormatKey * fix tests * fix test * fix test Co-authored-by: James Yeung <shunjiey@hotmail.com>
217 lines
7.4 KiB
C#
217 lines
7.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text.Json;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using AntDesign.JsInterop;
|
|
using Microsoft.AspNetCore.Components;
|
|
|
|
namespace AntDesign
|
|
{
|
|
public partial class Carousel : AntDomComponentBase
|
|
{
|
|
private const string PrefixCls = "ant-carousel";
|
|
|
|
private string TrackStyle
|
|
{
|
|
get
|
|
{
|
|
if (Effect == CarouselEffect.ScrollX && IsHorizontal)
|
|
{
|
|
return $"width: {TotalWidth}px; opacity: 1; transform: translate3d(-{SlickWidth * (IndexOfSlick(ActiveSlick) + 1)}px, 0px, 0px);transition: -webkit-transform 500ms ease 0s;";
|
|
}
|
|
else if (Effect == CarouselEffect.ScrollX && !IsHorizontal)
|
|
{
|
|
return $"height: {TotalHeight}px; opacity: 1; transform: translate3d(0px, -{SlickHeight * (IndexOfSlick(ActiveSlick) + 1)}px, 0px);transition: -webkit-transform 500ms ease 0s;";
|
|
}
|
|
else if (Effect == CarouselEffect.Fade && IsHorizontal)
|
|
{
|
|
return $"width: {TotalWidth}px; opacity: 1;";
|
|
}
|
|
else if (Effect == CarouselEffect.Fade && !IsHorizontal)
|
|
{
|
|
return $"height: {TotalHeight}px; opacity: 1;";
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
internal string SlickClonedStyle => $"width: {SlickWidth}px;";
|
|
private string SlickListStyle => IsHorizontal ? string.Empty : $"height: {SlickHeight}px";
|
|
internal int SlickWidth { get; set; } = -1;
|
|
private int SlickHeight { get; set; } = -1;
|
|
private int TotalWidth => SlickWidth * (_slicks.Count * 2 + 1);
|
|
private int TotalHeight => SlickHeight * (_slicks.Count * 2 + 1);
|
|
private List<CarouselSlick> _slicks = new List<CarouselSlick>();
|
|
internal CarouselSlick ActiveSlick { get; set; }
|
|
private Timer _timer;
|
|
private ClassMapper SlickSliderClassMapper { get; } = new ClassMapper();
|
|
private bool IsHorizontal => DotPosition == CarouselDotPosition.Top || DotPosition == CarouselDotPosition.Bottom;
|
|
|
|
#region Parameters
|
|
|
|
[Parameter]
|
|
public RenderFragment ChildContent { get; set; }
|
|
|
|
/// <summary>
|
|
/// The position of the dots, which can be one of Top, Bottom, Left or Right, <see cref="CarouselDotPosition"/>
|
|
/// </summary>
|
|
[Parameter]
|
|
public string DotPosition { get; set; } = CarouselDotPosition.Bottom;
|
|
|
|
/// <summary>
|
|
/// Whether to scroll automatically
|
|
/// </summary>
|
|
[Parameter]
|
|
public TimeSpan Autoplay { get; set; } = TimeSpan.Zero;
|
|
|
|
/// <summary>
|
|
/// Transition effect, <see cref="CarouselEffect"/>
|
|
/// </summary>
|
|
[Parameter]
|
|
public string Effect { get; set; } = CarouselEffect.ScrollX;
|
|
|
|
#endregion Parameters
|
|
|
|
[Inject] public IDomEventListener DomEventListener { get; set; }
|
|
|
|
public void Next() => GoTo(_slicks.IndexOf(ActiveSlick) + 1);
|
|
|
|
public void Previous() => GoTo(_slicks.IndexOf(ActiveSlick) - 1);
|
|
|
|
public void GoTo(int index)
|
|
{
|
|
if (index >= _slicks.Count)
|
|
{
|
|
index = 0;
|
|
}
|
|
else if (index < 0)
|
|
{
|
|
index = _slicks.Count - 1;
|
|
}
|
|
|
|
Activate(_slicks[index]);
|
|
}
|
|
|
|
private void SetClass()
|
|
{
|
|
SlickSliderClassMapper.Clear()
|
|
.Add("slick-slider slick-initialized")
|
|
.If("slick-vertical", () => !IsHorizontal);
|
|
|
|
ClassMapper.Clear()
|
|
.Add(PrefixCls)
|
|
.If($"{PrefixCls}-vertical", () => !IsHorizontal)
|
|
.If($"{PrefixCls}-rtl", () => RTL);
|
|
}
|
|
|
|
protected override void OnParametersSet()
|
|
{
|
|
base.OnParametersSet();
|
|
|
|
SetClass();
|
|
|
|
if (Effect != CarouselEffect.ScrollX && Effect != CarouselEffect.Fade)
|
|
{
|
|
throw new ArgumentOutOfRangeException($"{nameof(Effect)} must be one of {nameof(CarouselEffect)}.{nameof(CarouselEffect.ScrollX)} or {nameof(CarouselEffect)}.{nameof(CarouselEffect.Fade)}.");
|
|
}
|
|
|
|
_timer?.Dispose();
|
|
if (Autoplay != TimeSpan.Zero)
|
|
{
|
|
_timer = new Timer(AutoplaySlick, null, (int)Autoplay.TotalMilliseconds, (int)Autoplay.TotalMilliseconds);
|
|
}
|
|
}
|
|
|
|
protected async override Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
await base.OnAfterRenderAsync(firstRender);
|
|
if (firstRender)
|
|
{
|
|
Resize();
|
|
DomEventListener.AddShared<JsonElement>("window", "resize", Resize);
|
|
}
|
|
}
|
|
|
|
private async void Resize(JsonElement e = default)
|
|
{
|
|
DomRect listRect = await JsInvokeAsync<DomRect>(JSInteropConstants.GetBoundingClientRect, Ref);
|
|
if ((SlickWidth != (int)listRect.Width && IsHorizontal)
|
|
|| (SlickHeight != (int)listRect.Height && !IsHorizontal)
|
|
|| IsHorizontal && !string.IsNullOrEmpty(SlickListStyle)
|
|
|| !IsHorizontal && string.IsNullOrEmpty(SlickListStyle))
|
|
{
|
|
SlickWidth = (int)listRect.Width;
|
|
SlickHeight = (int)listRect.Height;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
internal void RemoveSlick(CarouselSlick slick)
|
|
{
|
|
var slicks = new List<CarouselSlick>(_slicks ?? new List<CarouselSlick>());
|
|
slicks.Remove(slick);
|
|
_slicks = slicks;
|
|
InvokeAsync(async () =>
|
|
{
|
|
await InvokeAsync(StateHasChanged).ConfigureAwait(false);
|
|
});
|
|
}
|
|
|
|
internal void AddSlick(CarouselSlick slick)
|
|
{
|
|
var slicks = new List<CarouselSlick>(_slicks ?? new List<CarouselSlick>());
|
|
slicks.Add(slick);
|
|
_slicks = slicks;
|
|
if (ActiveSlick == null)
|
|
{
|
|
Activate(_slicks[0]);
|
|
}
|
|
InvokeStateHasChanged();
|
|
}
|
|
|
|
internal int IndexOfSlick(CarouselSlick slick)
|
|
{
|
|
return _slicks.IndexOf(slick);
|
|
}
|
|
|
|
private void Activate(CarouselSlick slick)
|
|
{
|
|
this.ActiveSlick = slick;
|
|
}
|
|
|
|
private async void AutoplaySlick(object state)
|
|
{
|
|
var index = IndexOfSlick(ActiveSlick) + 1;
|
|
if (index == _slicks.Count)
|
|
{
|
|
index = 0;
|
|
}
|
|
if (_slicks == null || _slicks.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
this.Activate(_slicks[index]);
|
|
|
|
// The current thread is not associated with the Dispatcher.
|
|
// Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state
|
|
await InvokeAsync(() => StateHasChanged());
|
|
|
|
if (index == 0 && Effect == CarouselEffect.ScrollX)
|
|
{
|
|
await Task.Delay((int)Autoplay.TotalMilliseconds / 2);
|
|
}
|
|
|
|
await InvokeAsync(() => StateHasChanged());
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
DomEventListener.Dispose();
|
|
_slicks.Clear();
|
|
base.Dispose(disposing);
|
|
}
|
|
}
|
|
}
|