Blazor 自动完成标记

Blazor autocomplete tagging

this question类似,我正在寻找一个组件来向Whosebug中的对象添加标签,这意味着标签的自动完成文本字段。我正在寻找本机组件或包装 JS 解决方案的方法,以便它可以在 blazor 中使用。

另一个想法是像 中讨论的那样带有复选框的多 select 组件, 但我不太喜欢这个主意。

理想情况下,我会提供所有标签的列表,并绑定到为其设置标签的项目的列表。

通常,共享完整代码是不正确的做法,因为 SO 不是代码共享站点,而且通常会询问 到目前为止您尝试了什么?。然而,由于 Blazor 是一项新技术,因此初学者很难在网络上找到一个好的解决方案或插件来满足他们的要求,因此我认为这是一个例外。

现在回答您的问题创建用于添加标签的新组件。您可以使用我在我正在处理的项目之一中创建的以下解决方案。这不需要任何 JS,只需使用 C# 即可创建标签。您还可以在 fiddle 上查看我为您准备的 Blazor Fiddle 解决方案。希望这就是您要找的。

@using System;
@using System.Collections.Generic;
@using System.Linq;
@using System.Text.RegularExpressions;

<style>

.suggestion-container {
    position: relative;
}

.tagsinput, .tagsinput * {
    box-sizing: border-box
}

.tagsinput {
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-flex-wrap: wrap;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    background: #fff;
    font-size: 14px;
    line-height: 20px;
    color: #556270;
    padding: 5px 5px 0;
    border: 1px solid #e6e6e6;
    border-radius: 2px
}

    .tagsinput.focus {
        border-color: #ccc
    }

    .tagsinput .tag {
        position: relative;
        background: #556270;
        display: block;
        max-width: 100%;
        word-wrap: break-word;
        color: #fff;
        padding: 5px 30px 5px 5px;
        border-radius: 2px;
        margin: 0 5px 5px 0
    }

        .tagsinput .tag .tag-remove {
            position: absolute;
            background: 0 0;
            display: block;
            width: 30px;
            height: 30px;
            top: 0;
            right: 0;
            cursor: pointer;
            text-decoration: none;
            text-align: center;
            color: #ff6b6b;
            line-height: 30px;
            padding: 0;
            border: 0
        }

            .tagsinput .tag .tag-remove:after, .tagsinput .tag .tag-remove:before {
                background: #ff6b6b;
                position: absolute;
                display: block;
                width: 10px;
                height: 2px;
                top: 14px;
                left: 10px;
                content: ''
            }

            .tagsinput .tag .tag-remove:before {
                -webkit-transform: rotateZ(45deg);
                transform: rotateZ(45deg)
            }

            .tagsinput .tag .tag-remove:after {
                -webkit-transform: rotateZ(-45deg);
                transform: rotateZ(-45deg)
            }

    .tagsinput div {
        -webkit-box-flex: 1;
        -webkit-flex-grow: 1;
        -ms-flex-positive: 1;
        flex-grow: 1
    }

        .tagsinput div input {
            background: 0 0;
            display: block;
            width: 100%;
            font-size: 14px;
            line-height: 20px;
            padding: 5px;
            border: 0;
            margin: 0 5px 5px 0
        }

            .tagsinput div input:focus {
                color: #495057;
                background-color: #fff;
                border-color: #80bdff;
                outline: 0;
                box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
            }

            .tagsinput div input.error {
                color: #ff6b6b
            }

            .tagsinput div input::-ms-clear {
                display: none
            }

            .tagsinput div input::-webkit-input-placeholder {
                color: #ccc;
                opacity: 1
            }

            .tagsinput div input:-moz-placeholder {
                color: #ccc;
                opacity: 1
            }

            .tagsinput div input::-moz-placeholder {
                color: #ccc;
                opacity: 1
            }

            .tagsinput div input:-ms-input-placeholder {
                color: #ccc;
                opacity: 1
            }
</style>

<div class="suggestion-container w-75">
    <div id="@($"{Id}_tagsinput")" class="tagsinput">

        @if (Tags != null && Tags.Any())
        {
            @foreach (var tag in Tags)
            {
                <span class="tag">
                    <span class="tag-text">@tag</span>
                    <span class="tag-remove" @onclick="() => DeleteTag(tag)" />
                </span>
            }
        }

        <div id="@($"{Id}_addTag")">
            <div class="@(IsContainSpecialCharacter ? "tag-tooltip" : string.Empty)">
                <input id="@($"{Id}_tag")"
                       class="tag-input"
                       placeholder="Add tags"
                       autocomplete="off"
                       @bind-value="Value"
                       @bind-value:event="oninput"
                       @onkeyup="AddTags" />

                @if (IsContainSpecialCharacter)
                {
                    <div class="error-right d-inline-flex p-2">
                        <i class="oi oi-warning text-warning p-1"></i>
                        <p class="text-left m-0 p-1">Special characters not allowed.</p>
                        <i></i>
                    </div>
                }
            </div>
        </div>
    </div>
</div>

@code{

    private Guid Id => Guid.NewGuid();
    protected string Value { get; set; }
    protected bool MenuVisibility { get; set; }
    protected bool IsContainSpecialCharacter { get; set; }
    protected List<string> Tags { get; set; } = new List<string>();

        protected void AddTags(KeyboardEventArgs eventArgs)
        {
            IsContainSpecialCharacter = false;

            if (!String.IsNullOrEmpty(Value))
            {
                if (eventArgs.Key.Equals("Enter"))
                {
                    var regex = new Regex(@"[^a-zA-Z0-9\s]");
                    if (!regex.IsMatch(Value))
                    {
                        if (!Tags.Exists(t => t.Equals(Value, StringComparison.CurrentCultureIgnoreCase)))
                        {
                            Tags.Add(Value);
                        }

                        Value = string.Empty;
                    }
                    else
                    {
                        IsContainSpecialCharacter = true;
                    }
                }
            }       
        }
    
        protected void DeleteTag(string value)
        {
            if (String.IsNullOrEmpty(value)) return;

            var tag = Tags.FirstOrDefault(t => t == value);
            if (tag == null) return;

            Tags.Remove(tag);
        }
}

P.S. 我在这里分享的只是构建标签的代码片段,它不包含具有自动完成选项的标签,因为它需要是时候用假数据在 fiddle 上创建一个完整的解决方案了。因此,由于时间限制,我避免了这种情况。