如何在 blazor 中创建通用树视图组件?

Jas*_*res 4 c# asp.net-web-api asp.net-core blazor blazor-webassembly

你可以帮帮我吗?我想在 Blazor WebAssembly 中制作一个通用的树视图组件,但我有点迷失于如何做到这一点,我希望能够将任何类型的对象列表传递给组件,目前我已经做了一些非常简单的事情,使用名为目录的对象加载组件,但我想将其替换为 Titem,以便能够发送任何类型的列表

索引剃刀

@page "/index"

<h1>Treeview</h1>

<Treeview Directorios="directorios"></Treeview>

@code {
    public Directorio[] directorios;

    protected async override Task OnInitializedAsync()
    {
        var fall2014 = new Directorio("Fall 2014", new Directorio[] { }, new string[] { "image1.jpg", "image2.jpg", "image3.jpg" });
        var summer2014 = new Directorio("Summer 2014", new Directorio[] { }, new string[] { "image10.jpg", "image20.jpg", "image30.jpg" });

        var pictures = new Directorio("Pictures", new Directorio[] { fall2014, summer2014 }, new string[] { });

        var music = new Directorio("Music", new Directorio[] { }, new string[] { "song1.mp3", "song2.mp3" });

        directorios = new Directorio[] { pictures, music };
    }
}
Run Code Online (Sandbox Code Playgroud)

组件.razor

<ul>
    @foreach (var dir in Directorios)
    {
        <li>
            <span @onclick="@dir.toggle">@dir.getIcon()</span>
            <span>@dir.nombre</span>

            @if (dir.expanded)
            {
                <div>
                    <ul>
                        @foreach (var archivo in dir.archivos)
                        {
                            <li>@archivo</li>
                        }
                    </ul>
                    <Treeview Directorios="@dir.directorios"></Treeview>
                </div>
            }
        </li>
    }
</ul>

@code {

     [Parameter] public Directorio[] Directorios { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

目录.cs

public class Directorio
    {
        public bool expanded = false;
        public string nombre;
        public string[] archivos;
        public Directorio[] directorios;
        public Directorio(string nombre, Directorio[] directorios, string[] archivos)
        {
            this.nombre = nombre;
            this.directorios = directorios;
            this.archivos = archivos;
        }
        public void toggle()
        {
            expanded = !expanded;
        }
        public string getIcon()
        {
            if (expanded)
            {
                return "-";
            }
            return "+";
        }
    }
Run Code Online (Sandbox Code Playgroud)

Jam*_*714 7

试试这个。

将来也许我会制作一个组合树并在这里与您分享。如果您也能做到这一点,请随时将其发布在这里。

1.Treeview.razor

@typeparam Tvalue
@inherits TreeviewBase<Tvalue>

<ul class="parentUl">
    @if (AllItems != null)
    {
        @foreach (var Pitem in AllItems)
        {
            if (GetPropertyValue(Pitem, ParentId) == ""|| Convert.ToInt32(GetPropertyValue(Pitem, ParentId)) == 0)
            {

                if (Convert.ToBoolean(GetPropertyValue(Pitem, HasChildren)))
                {
                    <li>
                        
                        <span @onclick="@(()=>SpanToggle(Pitem))" class="@_caretcss[Convert.ToInt32(@GetPropertyValue(Pitem, Id))]">@GetPropertyValue(Pitem, Text)</span>
                        
                        <ul class="@_nestedcss[Convert.ToInt32(@GetPropertyValue(Pitem, Id))]">

                            @foreach (var Citem in AllItems)
                            {
                                if (GetPropertyValue(Pitem, Id) == GetPropertyValue(Citem, ParentId))
                                {
                                    if (Convert.ToBoolean(GetPropertyValue(Citem, HasChildren)))
                                    {

                                        <li>
                                            <span @onclick="@(()=>SpanToggle(Citem))" class="@_caretcss[Convert.ToInt32(@GetPropertyValue(Citem, Id))]">@GetPropertyValue(Citem, Text)</span>
                                            <ul class="@_nestedcss[Convert.ToInt32(@GetPropertyValue(Citem, Id))]">
                                                @foreach (var C1item in AllItems)
                                                {
                                                    if (GetPropertyValue(Citem, Id) == GetPropertyValue(C1item, ParentId))
                                                    {
                                                        if (Convert.ToBoolean(GetPropertyValue(C1item, HasChildren)))
                                                        {
                                                            <li>
                                                                <span @onclick="@(()=>SpanToggle(C1item))" class="@_caretcss[Convert.ToInt32(@GetPropertyValue(C1item, Id))]">@GetPropertyValue(C1item, Text)</span>

                                                                <ul class="@_nestedcss[Convert.ToInt32(@GetPropertyValue(C1item, Id))]">
                                                                    @foreach (var C2item in AllItems)
                                                                    {
                                                                        if (GetPropertyValue(C1item, Id) == GetPropertyValue(C2item, ParentId))
                                                                        {
                                                                            if (Convert.ToBoolean(GetPropertyValue(C2item, HasChildren)))
                                                                            {
                                                                                <li>
                                                                                    <span @onclick="@(()=>SpanToggle(C2item))" class="@_caretcss[Convert.ToInt32(@GetPropertyValue(C2item, Id))]">@GetPropertyValue(C1item, Text)</span>
                                                                                </li>
                                                                            }
                                                                            else
                                                                            {
                                                                                <li>@GetPropertyValue(C2item, Text)</li>
                                                                            }
                                                                        }
                                                                    }
                                                                </ul>
                                                            </li>
                                                        }
                                                        else
                                                        {
                                                            <li>@GetPropertyValue(C1item, Text)</li>
                                                        }
                                                    }
                                                }
                                            </ul>
                                        </li>
                                    }
                                    else
                                    {
                                        <li>@GetPropertyValue(Citem, Text)</li>
                                    }
                                }
                            }
                        </ul>
                    </li>
                }
                else
                {
                    <li>@GetPropertyValue(Pitem, Text)</li>
                }
            }

        }
    }
</ul>

Run Code Online (Sandbox Code Playgroud)

2.样式.css

<style type="text/css">
    /*css reference W3schools. "with small modification."*/
    /* css begin*/
    .parentUl li ul {
        border-left: dashed 2px black;
        height: fit-content;
        border-start-end-radius: 2px;
    }

    ul, .parentUl {
        list-style-type: none;
    }

        .parentUl ul li {
            position: relative;
        }

            .parentUl ul li:before {
                content: "";
                position: absolute;
                top: 13px;
                left: -40px;
                width: 40px;
                height: 1px;
                border-bottom: dashed 2px black;
            }

    .parentUl {
        margin: 0;
        padding: 0;
    }

    .caret {
        cursor: pointer;
        -webkit-user-select: none; /* Safari 3.1+ */
        -moz-user-select: none; /* Firefox 2+ */
        -ms-user-select: none; /* IE 10+ */
        user-select: none;
    }

        .caret::before {
            content: "\25B6";
            color: black;
            display: inline-block;
            margin-right: 6px;
            transition: all 0.45s;
        }

    .caret-down::before {
        -ms-transform: rotate(60deg); /* IE 9 */
        -webkit-transform: rotate(60deg); /* Safari */
        transform: rotate(60deg);
        transition: all 0.45s; 
    }

    .nested {
        display: none;
        transition: all 0.45s;
    }

    .active {
        display: block;
        transition: all 0.45s;
    }

    /*css end*/
</style>

Run Code Online (Sandbox Code Playgroud)

3.TreeviewBase.cs

public partial class TreeviewBase<Tvalue>:ComponentBase
    {

        [Parameter]
        public List<Tvalue> DataSource { get; set; }
        [Parameter]
        public string Id { get; set; }
        [Parameter]
        public string ParentId { get; set; }
        [Parameter]
        public string HasChildren { get; set; }
        [Parameter]
        public string Text { get; set; }
        [Parameter]
        public string Expanded { get; set; }

        protected List<Tvalue> AllItems;
        protected Dictionary<int, bool> _caretDown= new Dictionary<int, bool>();
        protected Dictionary<int, string> _caretcss=new Dictionary<int,string>();
        protected Dictionary<int, string> _nestedcss=new Dictionary<int,string>();
       
        protected override Task OnInitializedAsync()
        {
            //asigning to its new instance to avoid exceptions.
            AllItems = new List<Tvalue>();
            AllItems = DataSource.ToArray().ToList();

            if (AllItems != null)
            {
                foreach (var item in AllItems)
                {
                     var _id = Convert.ToInt32(GetPropertyValue(item, Id));
                    
                    //initializing fields with default value.
                    _caretDown.Add(_id, true);
                    _caretcss.Add(_id, "caret");
                    _nestedcss.Add(_id, "nested");
                }

            }


            return base.OnInitializedAsync();
        }


        protected override Task OnParametersSetAsync()
        {
            //This will check if the first item in the
            // list/collection has a "parentId" then remove the "parentId" from it. 
            //Because we use the first item as a reference in the razor file, so it must not have "parentId".

            var Parem = AllItems.First();
            switch (GetPropertyType(Parem, ParentId))
            {
                case "Int32":
                    if (Convert.ToInt32(GetPropertyValue(Parem, ParentId)) > 0)
                    {
                        SetPropertyValue<int>(Parem, ParentId, 0);
                    }
                    break;
                case "String":
                    if (GetPropertyValue(Parem, ParentId) != "")
                    {
                        SetPropertyValue<string>(Parem, ParentId, "");
                    }

                    break;
                default:
                    break;
            }

            return base.OnParametersSetAsync();
        }



        protected void SpanToggle(Tvalue item)
        {
           var _clckdItemid = Convert.ToInt32(GetPropertyValue(item, Id));

            _caretcss[_clckdItemid] = _caretDown[_clckdItemid] ? "caret caret-down" : "caret";
            _nestedcss[_clckdItemid] = _caretDown[_clckdItemid] ? "active" : "nested";
            _caretDown[_clckdItemid] = !_caretDown[_clckdItemid];
        }

        #region reflection methodes to get your property type, propert value and also set property value 
        protected string GetPropertyValue(Tvalue item, string Property)
        {

            if (item != null)
            {
                return item.GetType().GetProperty(Property).GetValue(item, null).ToString();
            }
            return "";

        }

        protected void SetPropertyValue<T>(Tvalue item, string Property, T value)
        {
            if (item != null)
            {
                item.GetType().GetProperty(Property).SetValue(item, value);
            }
        }

        protected string GetPropertyType(Tvalue item, string Property)
        {

            if (item != null)
            {
           return item.GetType().GetProperty(Property).PropertyType.Name;

            }
            return null;
        }
        #endregion
    }
Run Code Online (Sandbox Code Playgroud)
  1. 索引剃刀
public partial class TreeviewBase<Tvalue>:ComponentBase
    {

        [Parameter]
        public List<Tvalue> DataSource { get; set; }
        [Parameter]
        public string Id { get; set; }
        [Parameter]
        public string ParentId { get; set; }
        [Parameter]
        public string HasChildren { get; set; }
        [Parameter]
        public string Text { get; set; }
        [Parameter]
        public string Expanded { get; set; }

        protected List<Tvalue> AllItems;
        protected Dictionary<int, bool> _caretDown= new Dictionary<int, bool>();
        protected Dictionary<int, string> _caretcss=new Dictionary<int,string>();
        protected Dictionary<int, string> _nestedcss=new Dictionary<int,string>();
       
        protected override Task OnInitializedAsync()
        {
            //asigning to its new instance to avoid exceptions.
            AllItems = new List<Tvalue>();
            AllItems = DataSource.ToArray().ToList();

            if (AllItems != null)
            {
                foreach (var item in AllItems)
                {
                     var _id = Convert.ToInt32(GetPropertyValue(item, Id));
                    
                    //initializing fields with default value.
                    _caretDown.Add(_id, true);
                    _caretcss.Add(_id, "caret");
                    _nestedcss.Add(_id, "nested");
                }

            }


            return base.OnInitializedAsync();
        }


        protected override Task OnParametersSetAsync()
        {
            //This will check if the first item in the
            // list/collection has a "parentId" then remove the "parentId" from it. 
            //Because we use the first item as a reference in the razor file, so it must not have "parentId".

            var Parem = AllItems.First();
            switch (GetPropertyType(Parem, ParentId))
            {
                case "Int32":
                    if (Convert.ToInt32(GetPropertyValue(Parem, ParentId)) > 0)
                    {
                        SetPropertyValue<int>(Parem, ParentId, 0);
                    }
                    break;
                case "String":
                    if (GetPropertyValue(Parem, ParentId) != "")
                    {
                        SetPropertyValue<string>(Parem, ParentId, "");
                    }

                    break;
                default:
                    break;
            }

            return base.OnParametersSetAsync();
        }



        protected void SpanToggle(Tvalue item)
        {
           var _clckdItemid = Convert.ToInt32(GetPropertyValue(item, Id));

            _caretcss[_clckdItemid] = _caretDown[_clckdItemid] ? "caret caret-down" : "caret";
            _nestedcss[_clckdItemid] = _caretDown[_clckdItemid] ? "active" : "nested";
            _caretDown[_clckdItemid] = !_caretDown[_clckdItemid];
        }

        #region reflection methodes to get your property type, propert value and also set property value 
        protected string GetPropertyValue(Tvalue item, string Property)
        {

            if (item != null)
            {
                return item.GetType().GetProperty(Property).GetValue(item, null).ToString();
            }
            return "";

        }

        protected void SetPropertyValue<T>(Tvalue item, string Property, T value)
        {
            if (item != null)
            {
                item.GetType().GetProperty(Property).SetValue(item, value);
            }
        }

        protected string GetPropertyType(Tvalue item, string Property)
        {

            if (item != null)
            {
           return item.GetType().GetProperty(Property).PropertyType.Name;

            }
            return null;
        }
        #endregion
    }
Run Code Online (Sandbox Code Playgroud)

这是 Blazor 中通用 Treeview 组件背后的逻辑。

请点击此图片查看工作示例:

请点击此图片查看工作示例