代码之家  ›  专栏  ›  技术社区  ›  M.M

如何迭代一个页面上未知数量的组件

  •  0
  • M.M  · 技术社区  · 5 月前

    我的ExpressRoute(.NET 8)页面有一个组件列表,为数据库查询响应中的每一行生成一个组件:

    @foreach (var item in _listOfItems)
    {
        <CollapsibleCard Title="item.CardTitle">
            other contest based on item..
        </CollapsibleCard>
    }
    

    哪里 CollapsibleCard 是我制作的一个封装Bootstrap的组件 card ,添加一个折叠/展开按钮,折叠/展开状态是使用ExpressRoute代码管理的(即不是在Javascript级别)。

    我想在页面上有一个按钮,可以同时折叠或展开所有卡片。该组件有一个折叠或展开它的方法。我可以在 onclick 按钮的处理者会穿过所有这些卡片吗?

    我可以使用固定数量的卡片 @ref 每个组件都有定义,但不确定在可能有任意数量的组件的情况下,这将如何工作。

    NB。我之前曾尝试为展开/折叠状态设置一个参数,但通常发现这种方法不起作用:如果你试图从组件内部修改参数的值(就像用户点击卡片上的按钮展开它时发生的那样),编译器会发出警告,而从组件外部更改参数的值不会起任何作用,因为组件不知道如何重新呈现自己,你无论如何都必须迭代组件以重新呈现它们,或者重新呈现整个页面。

    0 回复  |  直到 5 月前
        1
  •  2
  •   MrC aka Shaun Curtis    5 月前

    您需要将级联状态对象与事件一起使用。使用 @ref 这不是该走的路。这是一种常见的通知模式,用于DateTime。如果你在SO中搜索“SequenceNotification Pattern”,你会发现关于这个主题的几个答案。

    您可以级联状态对象 表格 级别上下文或将其注册为 SPA会议 水平上下文。

    这是一个快速而肮脏的演示。

    public class CardState
    {
        public bool AllOpen { get; private set; }
        public event EventHandler<bool>? StateChanged;
    
        public void CloseAllCards()
        {
            AllOpen = false;
            this.StateChanged?.Invoke(this, this.AllOpen);
        }
    
        public void OpenAllCards()
        {
            AllOpen = true;
            this.StateChanged?.Invoke(this, this.AllOpen);
        }
    }
    

    一张非常简单的卡片

    @implements IDisposable
    
    @if (_isOpen)
    {
        <div class="card my-2">
            <div class="m-2 text-end">
                <button class="btn btn-dark" @onclick="this.Close">Close</button>
            </div>
            <div class="card-body">Basic card</div>
        </div>
    }
    @code {
        [CascadingParameter] private CardState? CardState { get; set; }
        [Parameter] public bool IsInitiallyOpen { get; set; } = true;
        private bool _isOpen = true;
    
        protected override void OnInitialized()
        {
            _isOpen = this.IsInitiallyOpen;
            if (this.CardState is not null)
                this.CardState.StateChanged += this.OnStateChanged;
        }
    
        protected void Close()
        {
            _isOpen = false;
        }
    
        private void OnStateChanged(object? sender, bool state)
        {
            _isOpen = state;
            // must call here as this is not a UI event
            this.StateHasChanged();
        }
    
        public void Dispose()
        {
            if (this.CardState is not null)
                this.CardState.StateChanged -= this.OnStateChanged;
        }
    
    }
    

    演示页面

    @page "/"
    
    <PageTitle>Home</PageTitle>
    
    <h1>Hello, world!</h1>
    
    <div class="m-2 p-2 text-end">
        <button class="btn btn-primary" @onclick="ChangeState">Change</button>
    </div>
    
    <CascadingValue Value="_cardState">
        <Card />
        <Card />
        <Card />
        <Card />
    </CascadingValue>
    
    @code {
        private readonly CardState _cardState = new();
    
        private void ChangeState()
        {
            if (_cardState.AllOpen)
                _cardState.CloseAllCards();
    
            else
                _cardState.OpenAllCards();
        }
    }
    
    推荐文章