mirror of
https://gitee.com/LongbowEnterprise/BootstrapBlazor.git
synced 2024-11-30 02:58:37 +08:00
refactor(IntersectionObserver): add AutoUnobserverWhenIntersection parameter (#3990)
* refactor: 更新 OnIntersecting 回调方法参数 * doc: 更新示例 * doc: 增加本地化 * test: 更新单元测试 * doc: 更新示例 * doc: 更新示例组件 * refactor: 更正脚本方法名称 * refactor: 更新逻辑 * refactor: 更新参数 * doc: 更新示例 * doc: 更新示例增加视频状态文字 * doc: 更新本地化文本内容 * test: 更新单元测试 * doc: 格式化文档 * doc: 更新示例 * doc: 增加示例 * test: 更新单元测试 * test: 更新单元测试 * test: 更新单元测试
This commit is contained in:
parent
7126ee9a33
commit
f9f13536c9
@ -0,0 +1,4 @@
|
|||||||
|
@inherits WebSiteModuleComponentBase
|
||||||
|
@attribute [JSModuleAutoLoader("Components/VideoDemo.razor.js", AutoInvokeInit = false, AutoInvokeDispose = false)]
|
||||||
|
|
||||||
|
<video id="@Id" controls preload="auto" autoplay width="350" src="https://archive.org/download/BigBuckBunny_124/Content/big_buck_bunny_720p_surround.mp4"></video>
|
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||||
|
|
||||||
|
namespace BootstrapBlazor.Server.Components.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// VideoDemo 组件
|
||||||
|
/// </summary>
|
||||||
|
public partial class VideoDemo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 开始播放方法
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task Play() => InvokeVoidAsync("play", Id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 暂停方法
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task Pause() => InvokeVoidAsync("pause", Id);
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
export function play(id) {
|
||||||
|
const video = document.getElementById(id);
|
||||||
|
video.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pause(id) {
|
||||||
|
const video = document.getElementById(id);
|
||||||
|
video.pause();
|
||||||
|
}
|
@ -15,7 +15,7 @@
|
|||||||
{
|
{
|
||||||
<IntersectionObserverItem>
|
<IntersectionObserverItem>
|
||||||
<div class="bb-list-item">
|
<div class="bb-list-item">
|
||||||
<img src="@image"/>
|
<img src="@image" />
|
||||||
</div>
|
</div>
|
||||||
</IntersectionObserverItem>
|
</IntersectionObserverItem>
|
||||||
}
|
}
|
||||||
@ -33,13 +33,13 @@
|
|||||||
<li>@((MarkupString)Localizer["IntersectionObserverLoadDesc3"].Value)</li>
|
<li>@((MarkupString)Localizer["IntersectionObserverLoadDesc3"].Value)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<IntersectionObserver OnIntersecting="OnLoadMoreAsync" Threshold="1" AutoUnobserve="false">
|
<IntersectionObserver OnIntersecting="OnLoadMoreAsync" Threshold="1" AutoUnobserveWhenIntersection="false">
|
||||||
<div class="bb-list-load scroll">
|
<div class="bb-list-load scroll">
|
||||||
<div class="bb-list-demo">
|
<div class="bb-list-demo">
|
||||||
@foreach (var image in _items)
|
@foreach (var image in _items)
|
||||||
{
|
{
|
||||||
<div class="bb-list-item">
|
<div class="bb-list-item">
|
||||||
<img src="@image"/>
|
<img src="@image" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@ -52,4 +52,36 @@
|
|||||||
</IntersectionObserver>
|
</IntersectionObserver>
|
||||||
</DemoBlock>
|
</DemoBlock>
|
||||||
|
|
||||||
<AttributeTable Items="@GetAttributes()"/>
|
<DemoBlock Title="@Localizer["IntersectionObserverVisibleTitle"]"
|
||||||
|
Introduction="@Localizer["IntersectionObserverVisibleIntro"]"
|
||||||
|
Name="Visible">
|
||||||
|
<section ignore><p>@((MarkupString)Localizer["IntersectionObserverVisibleDesc"].Value)</p></section>
|
||||||
|
<p class="text-center @_textColorString">@_videoStateString</p>
|
||||||
|
<IntersectionObserver OnIntersecting="OnVisibleChanged" Threshold="1" AutoUnobserveWhenIntersection="false">
|
||||||
|
<div class="bb-video-demo scroll">
|
||||||
|
<div class="bb-video">
|
||||||
|
<IntersectionObserverItem>
|
||||||
|
<VideoDemo @ref="_video"></VideoDemo>
|
||||||
|
</IntersectionObserverItem>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</IntersectionObserver>
|
||||||
|
</DemoBlock>
|
||||||
|
|
||||||
|
<DemoBlock Title="@Localizer["IntersectionObserverThresholdTitle"]"
|
||||||
|
Introduction="@Localizer["IntersectionObserverThresholdIntro"]"
|
||||||
|
Name="Threshold">
|
||||||
|
<section ignore><p>@((MarkupString)Localizer["IntersectionObserverThresholdDesc"].Value)</p></section>
|
||||||
|
<p class="text-center">@_thresholdValueString</p>
|
||||||
|
<IntersectionObserver OnIntersecting="OnThresholdChanged" Threshold="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1" AutoUnobserveWhenIntersection="false">
|
||||||
|
<div class="bb-list-load scroll" style="height: 200px;">
|
||||||
|
<div class="d-flex" style="height: 600px; justify-content: center; align-items: center;">
|
||||||
|
<IntersectionObserverItem>
|
||||||
|
<div class="bb-list-item bg-info"></div>
|
||||||
|
</IntersectionObserverItem>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</IntersectionObserver>
|
||||||
|
</DemoBlock>
|
||||||
|
|
||||||
|
<AttributeTable Items="@GetAttributes()" />
|
||||||
|
@ -13,6 +13,8 @@ public partial class IntersectionObservers
|
|||||||
|
|
||||||
private List<string> _items = default!;
|
private List<string> _items = default!;
|
||||||
|
|
||||||
|
private VideoDemo _video = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -24,20 +26,58 @@ public partial class IntersectionObservers
|
|||||||
_items = Enumerable.Range(1, 20).Select(i => $"https://picsum.photos/160/160?random={i}").ToList();
|
_items = Enumerable.Range(1, 20).Select(i => $"https://picsum.photos/160/160?random={i}").ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task OnIntersectingAsync(int index)
|
private Task OnIntersectingAsync(IntersectionObserverEntry entry)
|
||||||
{
|
{
|
||||||
_images[index] = GetImageUrl(index);
|
if (entry.IsIntersecting)
|
||||||
StateHasChanged();
|
{
|
||||||
|
_images[entry.Index] = GetImageUrl(entry.Index);
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnLoadMoreAsync(int index)
|
private async Task OnLoadMoreAsync(IntersectionObserverEntry entry)
|
||||||
{
|
{
|
||||||
await Task.Delay(1000);
|
if (entry.IsIntersecting)
|
||||||
_items.AddRange(Enumerable.Range(_items.Count + 1, 20).Select(i => $"https://picsum.photos/160/160?random={i}"));
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
_items.AddRange(Enumerable.Range(_items.Count + 1, 20)
|
||||||
|
.Select(i => $"https://picsum.photos/160/160?random={i}"));
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? _videoStateString;
|
||||||
|
private string? _textColorString = "text-muted";
|
||||||
|
|
||||||
|
private async Task OnVisibleChanged(IntersectionObserverEntry entry)
|
||||||
|
{
|
||||||
|
if (entry.IsIntersecting)
|
||||||
|
{
|
||||||
|
_videoStateString = Localizer["IntersectionObserverVisiblePlayLabel"];
|
||||||
|
_textColorString = "text-success";
|
||||||
|
await _video.Play();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_videoStateString = Localizer["IntersectionObserverVisiblePauseLabel"];
|
||||||
|
_textColorString = "text-danger";
|
||||||
|
await _video.Pause();
|
||||||
|
}
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string? _thresholdValueString;
|
||||||
|
|
||||||
|
private Task OnThresholdChanged(IntersectionObserverEntry entry)
|
||||||
|
{
|
||||||
|
_thresholdValueString = entry.IntersectionRatio.ToString("P");
|
||||||
|
StateHasChanged();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetImageUrl(int index) => $"https://picsum.photos/160/160?random={index}";
|
private static string GetImageUrl(int index) => $"https://picsum.photos/160/160?random={index}";
|
||||||
|
|
||||||
private AttributeItem[] GetAttributes() =>
|
private AttributeItem[] GetAttributes() =>
|
||||||
@ -68,17 +108,25 @@ public partial class IntersectionObservers
|
|||||||
},
|
},
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
Name = "AutoUnobserve",
|
Name = nameof(IntersectionObserver.AutoUnobserveWhenIntersection),
|
||||||
Description = Localizer["AttributeAutoUnobserve"],
|
Description = Localizer["AttributeAutoUnobserveWhenIntersection"],
|
||||||
Type = "bool",
|
Type = "bool",
|
||||||
ValueList = "true|false",
|
ValueList = "true|false",
|
||||||
DefaultValue = "true"
|
DefaultValue = "true"
|
||||||
},
|
},
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
Name = "OnIntersectingAsync",
|
Name = nameof(IntersectionObserver.AutoUnobserveWhenNotIntersection),
|
||||||
|
Description = Localizer["AttributeAutoUnobserveWhenNotIntersection"],
|
||||||
|
Type = "bool",
|
||||||
|
ValueList = "true|false",
|
||||||
|
DefaultValue = "false"
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Name = "OnIntersecting",
|
||||||
Description = Localizer["AttributeOnIntersectingAsync"],
|
Description = Localizer["AttributeOnIntersectingAsync"],
|
||||||
Type = "Func<int, Task>",
|
Type = "Func<IntersectionObserverEntry, Task>",
|
||||||
ValueList = " — ",
|
ValueList = " — ",
|
||||||
DefaultValue = " — "
|
DefaultValue = " — "
|
||||||
},
|
},
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
border: var(--bs-border-width) solid var(--bs-border-color);
|
border: var(--bs-border-width) solid var(--bs-border-color);
|
||||||
border-radius: var(--bs-border-radius);
|
border-radius: var(--bs-border-radius);
|
||||||
padding: .25rem;
|
padding: .25rem;
|
||||||
height: 500px;
|
height: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bb-list-load {
|
.bb-list-load {
|
||||||
border: var(--bs-border-width) solid var(--bs-border-color);
|
border: var(--bs-border-width) solid var(--bs-border-color);
|
||||||
border-radius: var(--bs-border-radius);
|
border-radius: var(--bs-border-radius);
|
||||||
padding: .25rem;
|
padding: .25rem;
|
||||||
height: 500px;
|
height: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bb-list-demo {
|
.bb-list-demo {
|
||||||
@ -40,3 +40,13 @@
|
|||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
padding: .5rem 0;
|
padding: .5rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bb-video-demo {
|
||||||
|
height: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bb-video {
|
||||||
|
height: 600px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 160px;
|
||||||
|
}
|
||||||
|
@ -6600,11 +6600,20 @@
|
|||||||
"IntersectionObserverLoadDesc1": "By setting <code>Threshold=\"1.0\"</code> to constrain the loading indicator to be fully visible, perform the load more action",
|
"IntersectionObserverLoadDesc1": "By setting <code>Threshold=\"1.0\"</code> to constrain the loading indicator to be fully visible, perform the load more action",
|
||||||
"IntersectionObserverLoadDesc2": "Ensure that the loading indicator visibility is always checked by setting <code>AutoUnobserve=\"false\"</code> to prevent automatic removal of the check once it becomes visible",
|
"IntersectionObserverLoadDesc2": "Ensure that the loading indicator visibility is always checked by setting <code>AutoUnobserve=\"false\"</code> to prevent automatic removal of the check once it becomes visible",
|
||||||
"IntersectionObserverLoadDesc3": "Simulate network delay of 1s by setting the <code>OnLoadMoreAsync</code> method",
|
"IntersectionObserverLoadDesc3": "Simulate network delay of 1s by setting the <code>OnLoadMoreAsync</code> method",
|
||||||
|
"IntersectionObserverVisibleTitle": "Threshold",
|
||||||
|
"IntersectionObserverVisibleIntro": "By setting <code>Threshold</code> specifying a ratio of intersection area to total bounding box area for the observed target",
|
||||||
|
"IntersectionObserverVisibleDesc": "In this example, <code>Threshold=\"1\"</code> is set, which means that the trigger condition is to play when the video is fully visible, otherwise it will automatically pause",
|
||||||
|
"IntersectionObserverVisiblePauseLabel": "Video Paused",
|
||||||
|
"IntersectionObserverVisiblePlayLabel": "Video Playing",
|
||||||
|
"IntersectionObserverThresholdTitle": "IntersectionRatio",
|
||||||
|
"IntersectionObserverThresholdIntro": "After setting <code>Threshold</code>, the intersection ratio between the observed element and the root element is obtained through the callback parameter <code>IntersectionObserveEntry</code> attribute <code>IntersectionRatio</code>",
|
||||||
|
"IntersectionObserverThresholdDesc": "Drag the scroll bar of the <code>div</code> below to observe data changes",
|
||||||
"AttributeUseElementViewport": "The element that is used as the viewport for checking visibility of the target",
|
"AttributeUseElementViewport": "The element that is used as the viewport for checking visibility of the target",
|
||||||
"AttributeRootMargin": "Margin around the root. Can have values similar to the CSS margin property",
|
"AttributeRootMargin": "Margin around the root. Can have values similar to the CSS margin property",
|
||||||
"AttributeThreshold": "Either a single number or an array of numbers which indicate at what percentage of the target's visibility the observer's callback should be executed",
|
"AttributeThreshold": "Either a single number or an array of numbers which indicate at what percentage of the target's visibility the observer's callback should be executed",
|
||||||
"AttributeAutoUnobserve": "Whether to automatically cancel the observation",
|
"AttributeAutoUnobserveWhenIntersection": "Whether to automatically cancel the observation when element visible",
|
||||||
|
"AttributeAutoUnobserveWhenNotIntersection": "Whether to automatically cancel the observation when element invisible",
|
||||||
"AttributeOnIntersectingAsync": "The callback when intersecting",
|
"AttributeOnIntersectingAsync": "The callback when intersecting",
|
||||||
"AttributeChildContent": "Child componenet"
|
"AttributeChildContent": "Child component"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6600,10 +6600,19 @@
|
|||||||
"IntersectionObserverLoadDesc1": "通过设置 <code>Threshold=\"1.0\"</code> 约束正在加载指示符完全可见时,执行加载更多操作",
|
"IntersectionObserverLoadDesc1": "通过设置 <code>Threshold=\"1.0\"</code> 约束正在加载指示符完全可见时,执行加载更多操作",
|
||||||
"IntersectionObserverLoadDesc2": "通过设置 <code>AutoUnobserve=\"false\"</code> 保证始终检测正在加载指示符可见性,防止可见后自动移除检测",
|
"IntersectionObserverLoadDesc2": "通过设置 <code>AutoUnobserve=\"false\"</code> 保证始终检测正在加载指示符可见性,防止可见后自动移除检测",
|
||||||
"IntersectionObserverLoadDesc3": "通过设置 <code>OnLoadMoreAsync</code> 方法模拟网络延时 1s",
|
"IntersectionObserverLoadDesc3": "通过设置 <code>OnLoadMoreAsync</code> 方法模拟网络延时 1s",
|
||||||
|
"IntersectionObserverVisibleTitle": "触发阈值",
|
||||||
|
"IntersectionObserverVisibleIntro": "通过设置 <code>Threshold</code> 调整触发条件",
|
||||||
|
"IntersectionObserverVisibleDesc": "本例中设置 <code>Threshold=\"1\"</code> 即触发条件为视频完全可见时播放,否则自动暂停",
|
||||||
|
"IntersectionObserverVisiblePauseLabel": "视频已暂停",
|
||||||
|
"IntersectionObserverVisiblePlayLabel": "视频已开始播放",
|
||||||
|
"IntersectionObserverThresholdTitle": "阈值变化观察",
|
||||||
|
"IntersectionObserverThresholdIntro": "通过设置 <code>Threshold</code> 后通过回调参数 <code>IntersectionObserveEntry</code> 属性 <code>IntersectionRatio</code> 获得观察元素与根元素交叉率",
|
||||||
|
"IntersectionObserverThresholdDesc": "拖动下方 <code>div</code> 滚动条,可观察数据变化",
|
||||||
"AttributeUseElementViewport": "是否使用当前元素作为视窗",
|
"AttributeUseElementViewport": "是否使用当前元素作为视窗",
|
||||||
"AttributeRootMargin": "根元素边距",
|
"AttributeRootMargin": "根元素边距",
|
||||||
"AttributeThreshold": "可见性阈值",
|
"AttributeThreshold": "可见性阈值",
|
||||||
"AttributeAutoUnobserve": "是否自动取消观察",
|
"AttributeAutoUnobserveWhenIntersection": "元素可见时是否自动取消观察",
|
||||||
|
"AttributeAutoUnobserveWhenNotIntersection": "元素不可见时是否自动取消观察",
|
||||||
"AttributeOnIntersectingAsync": "可见回调方法",
|
"AttributeOnIntersectingAsync": "可见回调方法",
|
||||||
"AttributeChildContent": "子组件"
|
"AttributeChildContent": "子组件"
|
||||||
}
|
}
|
||||||
|
@ -29,16 +29,22 @@ public partial class IntersectionObserver
|
|||||||
public string? Threshold { get; set; }
|
public string? Threshold { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获得/设置 是否自动取消观察 默认 true 可见后自动取消观察提高性能
|
/// 获得/设置 可见后是否自动取消观察 默认 true 可见后自动取消观察提高性能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool AutoUnobserve { get; set; } = true;
|
public bool AutoUnobserveWhenIntersection { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 不可见后是否自动取消观察 默认 false 不可见后自动取消观察提高性能
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public bool AutoUnobserveWhenNotIntersection { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获得/设置 已经交叉回调方法
|
/// 获得/设置 已经交叉回调方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Func<int, Task>? OnIntersecting { get; set; }
|
public Func<IntersectionObserverEntry, Task>? OnIntersecting { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获得/设置 子组件
|
/// 获得/设置 子组件
|
||||||
@ -54,19 +60,19 @@ public partial class IntersectionObserver
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, new { UseElementViewport, RootMargin, Threshold, AutoUnobserve, Callback = nameof(TriggerIntersecting) });
|
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, new { UseElementViewport, RootMargin, Threshold, AutoUnobserveWhenIntersection, AutoUnobserveWhenNotIntersection, Callback = nameof(TriggerIntersecting) });
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 交叉检测回调方法 由 JavaScript 调用
|
/// 交叉检测回调方法 由 JavaScript 调用
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index"></param>
|
/// <param name="entry"><see cref="IntersectionObserverEntry"/> 实例</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[JSInvokable]
|
[JSInvokable]
|
||||||
public async Task TriggerIntersecting(int index)
|
public async Task TriggerIntersecting(IntersectionObserverEntry entry)
|
||||||
{
|
{
|
||||||
if (OnIntersecting != null)
|
if (OnIntersecting != null)
|
||||||
{
|
{
|
||||||
await OnIntersecting(index);
|
await OnIntersecting(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,18 +11,27 @@ export function init(id, invoke, options) {
|
|||||||
if (options.useElementViewport === false) {
|
if (options.useElementViewport === false) {
|
||||||
options.root = el;
|
options.root = el;
|
||||||
}
|
}
|
||||||
const { root, rootMargin, threshold, autoUnobserve, callback } = options;
|
if (options.threshold && options.threshold.indexOf(' ') > 0) {
|
||||||
|
options.threshold = options.threshold.split(' ');
|
||||||
|
}
|
||||||
|
const { root, rootMargin, threshold, autoUnobserveWhenIntersection, autoUnobserveWhenNotIntersection, callback } = options;
|
||||||
const option = { root, rootMargin: rootMargin ?? '0px 0px 0px 0px', threshold: threshold ?? 0 };
|
const option = { root, rootMargin: rootMargin ?? '0px 0px 0px 0px', threshold: threshold ?? 0 };
|
||||||
|
|
||||||
const observer = new IntersectionObserver(entries => {
|
const observer = new IntersectionObserver(entries => {
|
||||||
entries.forEach(entry => {
|
entries.forEach(entry => {
|
||||||
if (entry.isIntersecting) {
|
if(entry.isIntersecting && autoUnobserveWhenIntersection) {
|
||||||
if (autoUnobserve) {
|
observer.unobserve(entry.target);
|
||||||
observer.unobserve(entry.target);
|
|
||||||
}
|
|
||||||
const index = items.indexOf(entry.target);
|
|
||||||
invoke.invokeMethodAsync(callback, index);
|
|
||||||
}
|
}
|
||||||
|
else if(!entry.isIntersecting && autoUnobserveWhenNotIntersection) {
|
||||||
|
observer.unobserve(entry.target);
|
||||||
|
}
|
||||||
|
const index = items.indexOf(entry.target);
|
||||||
|
invoke.invokeMethodAsync(callback, {
|
||||||
|
isIntersecting: entry.isIntersecting,
|
||||||
|
index,
|
||||||
|
time: entry.time,
|
||||||
|
intersectionRatio: entry.intersectionRatio
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}, option);
|
}, option);
|
||||||
|
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||||
|
|
||||||
|
namespace BootstrapBlazor.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 交叉检测项实例类
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
public class IntersectionObserverEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 检测项与根元素交叉比率 0 - 1 之间
|
||||||
|
/// </summary>
|
||||||
|
public float IntersectionRatio { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 是否正在交叉
|
||||||
|
/// </summary>
|
||||||
|
public bool IsIntersecting { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 当前项索引
|
||||||
|
/// </summary>
|
||||||
|
public int Index { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 与文档创建时间差
|
||||||
|
/// </summary>
|
||||||
|
public double Time { get; set; }
|
||||||
|
}
|
@ -17,7 +17,8 @@ public class IntersectionObserverTest : BootstrapBlazorTestBase
|
|||||||
pb.Add(a => a.UseElementViewport, false);
|
pb.Add(a => a.UseElementViewport, false);
|
||||||
pb.Add(a => a.RootMargin, "10px 20px 30px 40px");
|
pb.Add(a => a.RootMargin, "10px 20px 30px 40px");
|
||||||
pb.Add(a => a.Threshold, "0.5");
|
pb.Add(a => a.Threshold, "0.5");
|
||||||
pb.Add(a => a.AutoUnobserve, true);
|
pb.Add(a => a.AutoUnobserveWhenIntersection, false);
|
||||||
|
pb.Add(a => a.AutoUnobserveWhenNotIntersection, false);
|
||||||
pb.Add(a => a.ChildContent, builder =>
|
pb.Add(a => a.ChildContent, builder =>
|
||||||
{
|
{
|
||||||
builder.OpenComponent<IntersectionObserverItem>(0);
|
builder.OpenComponent<IntersectionObserverItem>(0);
|
||||||
@ -41,14 +42,23 @@ public class IntersectionObserverTest : BootstrapBlazorTestBase
|
|||||||
builder.AddAttribute(1, "ChildContent", new RenderFragment(builder => builder.AddContent(0, "observer-item")));
|
builder.AddAttribute(1, "ChildContent", new RenderFragment(builder => builder.AddContent(0, "observer-item")));
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
});
|
});
|
||||||
pb.Add(a => a.OnIntersecting, index =>
|
pb.Add(a => a.OnIntersecting, entry =>
|
||||||
{
|
{
|
||||||
count = index;
|
if (entry.IsIntersecting && entry.Time == 100 && entry.IntersectionRatio == 0.5f)
|
||||||
|
{
|
||||||
|
count = entry.Index;
|
||||||
|
}
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await cut.InvokeAsync(() => cut.Instance.TriggerIntersecting(10));
|
await cut.InvokeAsync(() => cut.Instance.TriggerIntersecting(new IntersectionObserverEntry()
|
||||||
|
{
|
||||||
|
IsIntersecting = true,
|
||||||
|
Index = 10,
|
||||||
|
Time = 100.00,
|
||||||
|
IntersectionRatio = 0.5f
|
||||||
|
}));
|
||||||
Assert.Equal(10, count);
|
Assert.Equal(10, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user