asp.net mvc - 实现“自动完成”博客的标签选择?

发布于 2024-10-09 18:36:17 字数 99 浏览 5 评论 0原文

我正在开发一个供我自己使用的博客系统,并且想要实现自动完成标签选择(类似于 stackoverflow),我将如何实现这样的东西?任何示例或教程链接将不胜感激。

谢谢。

I'm working on a blog system for my own use, and would like to implement an auto-complete tags selection (similar to stackoverflow), how would I implement something like this? Any example or links to a tutorial would be greatly appreciated.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

与往事干杯 2024-10-16 18:36:17

在这里查看我的问题 Jquery,使用 json 自动完成,id 与显示值

我们实际上“借用”(读取复制和粘贴)SO 的自动完成 JavaScript,然后稍微调整它 - 例如重命名它,这样它就不会干扰 jquery ui 的自动完成e.

两者实际上非常相似,但我们特别想要一个像 SO 这样的标签系统。

您可以将我使用的代码从 http://pastebin.com/t29RCCZg 中删除

,这是我们的示例操作用于标签

public ActionResult ProfileTags(string prefix, int? limit)
    {
        if (!limit.HasValue)
            limit = ConfigurationHelper.Paging.TagList;

        if (String.IsNullOrEmpty(prefix))
            prefix = String.Empty;

        ProfileTagModel model = new ProfileTagModel()
        {
            Tags = profileTagRepository.GetList(new ProfileTagsByPrefixQuery(prefix)).OrderBy(x => x.Name).Take<ProfileTag>(limit.Value)
        };

        return View(model);
    }

视图看起来像这样

<%@ Page Language="C#" ContentType="text/html" Inherits="System.Web.Mvc.ViewPage<ProfileTagModel>" %>

<% if(Model.Tags != null) { %>
    <% foreach (ProfileTag tag in Model.Tags) { %>
        <%= tag.Name + ((tag.ProfileCount > 0) ? " (" + tag.ProfileCount.ToString() + ")" : String.Empty) %>
    <% } %>
<% } %>

然后我们在页面上的用法看起来像这样

$().ready(function () {
    $("#ProfileTags").troppinautocomplete('<%= Url.Action("ProfileTags", "Filter") %>', {
        max: 10,
        highlightItem: true,
        multiple: true,
        multipleSeparator: " ",
        matchContains: false,
        scroll: true,
        scrollHeight: 300,
        dataType: "html"
    });


})

不过,您不必这样做。您可以使操作方法以 json 形式返回对象数组,然后通过更改自动完成的声明方式,您实际上可以格式化标签以显示图标或其他功能。

这是一个采用 json 进行格式化外观的示例

$('#troppinSearch').troppinautocomplete(url, {
        dataType: 'json',
        parse: function (data) {
            var rows = new Array();
            if (data != null) {
                for (var i = 0; i < data.length; i++) {
                    rows[i] = { data: data[i], value: data[i].Id, result: data[i].Title };
                }
            }
            return rows;
        },
        formatItem: function (row, i, n) {

            return '<table><tr><td valign="top"><img height="28" width="28" src="' + row.ImageUrl + '" /></td><td valign="top" style="padding:0px 0px 0px 6px;"><div>' + row.Title + '</div><div><small>' + row.ResultType + '</small></div></td></tr></table>';
        },
        formatResult: function (row, i, n) {
            return row.Id;
        },
        width: 336,
        max: 20,
        highlightItem: true,
        multiple: false,
        matchContains: true,
        scroll: true,
        scrollHeight: 300
    }).result(function (event, data, formatted) {
        var type = data.ResultType.toLowerCase();
        var id = data.Id;

        if (type == "product") {
            window.location.href = '/Shop/Product/' + id;
        } else {
            window.location.href = '/Profile/Index/' + id;
        }
    });

,操作如下所示

public ActionResult Search(string contentType, string prefix, int? limit)
    {
        if (!limit.HasValue)
            limit = ConfigurationHelper.Paging.ProfileList;

        SearchResponse response = GetSearchResults(contentType, prefix);

        var dropDownResults = (from r in response.Results
                              select new
                              {
                                  Id = r.Id,
                                  Title = r.Name,
                                  ImageUrl = r.DefaultImage,
                                  ResultType = r.ResultType.ToString()
                              }).Distinct().Take(limit.Value);

        return Json(dropDownResults.ToList(), JsonRequestBehavior.AllowGet);
    }

当您这样做时,您不需要视图。自动完成器接收 json 数据并神奇地完成一切。最后的 .Result 函数允许您设置在做出选择时发生的事件。在这种情况下,它实际上将用户发送到另一个页面,但我们使用它在隐藏字段中设置一个值。

编辑

我忘记了此代码的内置 CSS 类。这是一个 CSS 示例。

.ac_results{
padding:0;
border:1px solid #4c4c4c;
background-color:#ffffff;
overflow:hidden;
z-index:99999;
text-align:left;
font-size: 14px; line-height:14px;
color: #333333;
}

.ac_highlight{
font-weight:bold;
text-decoration:underline;
background-color: #ff6600;
color: #ffffff;
}

.ac_results ul{
width:100%;
list-style-position:outside;
list-style:none;
padding:0;
margin:0;

}

.ac_results li{
margin:0;
padding:3px 6px 3px 6px;
cursor:default;
display:block;
line-height:14px;
overflow:hidden;
}

.ac_loading{
background:#fff url(/Content/images/loading.gif) right center no-repeat;

}

.ac_over{
background-color:#ff6600;
color:#ffffff;

}

See my question here Jquery, Autocomplete using json, id's vs display values

We actually "borrowed" (read copy and pasted) SO's autocomplete javascript and then tweaked it slightly - such as renaming it so it won't interfere with jquery ui's autocomplete.

The two are actually very similar, but we wanted specifically to have a tag system like SO.

you can yank the code I used off http://pastebin.com/t29RCCZg

and here is a sample action we used for tags

public ActionResult ProfileTags(string prefix, int? limit)
    {
        if (!limit.HasValue)
            limit = ConfigurationHelper.Paging.TagList;

        if (String.IsNullOrEmpty(prefix))
            prefix = String.Empty;

        ProfileTagModel model = new ProfileTagModel()
        {
            Tags = profileTagRepository.GetList(new ProfileTagsByPrefixQuery(prefix)).OrderBy(x => x.Name).Take<ProfileTag>(limit.Value)
        };

        return View(model);
    }

And the view looks like this

<%@ Page Language="C#" ContentType="text/html" Inherits="System.Web.Mvc.ViewPage<ProfileTagModel>" %>

<% if(Model.Tags != null) { %>
    <% foreach (ProfileTag tag in Model.Tags) { %>
        <%= tag.Name + ((tag.ProfileCount > 0) ? " (" + tag.ProfileCount.ToString() + ")" : String.Empty) %>
    <% } %>
<% } %>

And then our usage on the page looks something like this

$().ready(function () {
    $("#ProfileTags").troppinautocomplete('<%= Url.Action("ProfileTags", "Filter") %>', {
        max: 10,
        highlightItem: true,
        multiple: true,
        multipleSeparator: " ",
        matchContains: false,
        scroll: true,
        scrollHeight: 300,
        dataType: "html"
    });


})

You don't have to do it this way, though. You can make the action method return an array of objects as json, and then by altering how your autocomplete is declared, you can actually format the tags in to display with an icon or other features.

Heres a sample that took in json for a formatted look

$('#troppinSearch').troppinautocomplete(url, {
        dataType: 'json',
        parse: function (data) {
            var rows = new Array();
            if (data != null) {
                for (var i = 0; i < data.length; i++) {
                    rows[i] = { data: data[i], value: data[i].Id, result: data[i].Title };
                }
            }
            return rows;
        },
        formatItem: function (row, i, n) {

            return '<table><tr><td valign="top"><img height="28" width="28" src="' + row.ImageUrl + '" /></td><td valign="top" style="padding:0px 0px 0px 6px;"><div>' + row.Title + '</div><div><small>' + row.ResultType + '</small></div></td></tr></table>';
        },
        formatResult: function (row, i, n) {
            return row.Id;
        },
        width: 336,
        max: 20,
        highlightItem: true,
        multiple: false,
        matchContains: true,
        scroll: true,
        scrollHeight: 300
    }).result(function (event, data, formatted) {
        var type = data.ResultType.toLowerCase();
        var id = data.Id;

        if (type == "product") {
            window.location.href = '/Shop/Product/' + id;
        } else {
            window.location.href = '/Profile/Index/' + id;
        }
    });

And the action looks like this

public ActionResult Search(string contentType, string prefix, int? limit)
    {
        if (!limit.HasValue)
            limit = ConfigurationHelper.Paging.ProfileList;

        SearchResponse response = GetSearchResults(contentType, prefix);

        var dropDownResults = (from r in response.Results
                              select new
                              {
                                  Id = r.Id,
                                  Title = r.Name,
                                  ImageUrl = r.DefaultImage,
                                  ResultType = r.ResultType.ToString()
                              }).Distinct().Take(limit.Value);

        return Json(dropDownResults.ToList(), JsonRequestBehavior.AllowGet);
    }

When you do it this way, you don't need a view. The autocompleter takes in the json data and does everything magically. The .Result function on the end lets you set up an event that occurs when a selection is made. in this case it's actually sending the user to another page, but we have used it to set a value in a hidden field.

EDIT

I forgot the built in CSS classes for this code. Here's a sample CSS.

.ac_results{
padding:0;
border:1px solid #4c4c4c;
background-color:#ffffff;
overflow:hidden;
z-index:99999;
text-align:left;
font-size: 14px; line-height:14px;
color: #333333;
}

.ac_highlight{
font-weight:bold;
text-decoration:underline;
background-color: #ff6600;
color: #ffffff;
}

.ac_results ul{
width:100%;
list-style-position:outside;
list-style:none;
padding:0;
margin:0;

}

.ac_results li{
margin:0;
padding:3px 6px 3px 6px;
cursor:default;
display:block;
line-height:14px;
overflow:hidden;
}

.ac_loading{
background:#fff url(/Content/images/loading.gif) right center no-repeat;

}

.ac_over{
background-color:#ff6600;
color:#ffffff;

}
帅气尐潴 2024-10-16 18:36:17

我决定尝试一下 jQuery UI 自动完成,它似乎很简单:) 这是 javascript 代码:

$(document).ready(function () {
    function split(val) {
        return val.split(/,\s*/);
    }
    function extractLast(term) {
        return split(term).pop();
    }

    $("#TagsString")
    // don't navigate away from the field on tab when selecting an item
            .bind("keydown", function (event) {
                if (event.keyCode === $.ui.keyCode.TAB &&
                        $(this).data("autocomplete").menu.active) {
                    event.preventDefault();
                }
            })
            .autocomplete({
                source: function (request, response) {
                    $.get("/Blog/GetTags", { term: extractLast(request.term) }, function (data) {
                        response($.map(data.tags, function (item) {
                            return {
                                label: item.Name,
                                value: item.Id
                            }
                        }))
                    }, "json");
                },
                minLength: 2,
                dataType: 'json',
                focus: function () {
                    // prevent value inserted on focus
                    return false;
                },
                select: function (event, ui) {
                    var terms = split(this.value);
                    // remove the current input
                    terms.pop();
                    // add the selected item
                    terms.push(ui.item.label);
                    // add placeholder to get the comma-and-space at the end
                    terms.push("");
                    this.value = terms.join(", ");
                    return false;
                }
            });
});

这是 HTML:

<p>
            @Html.TextBoxFor(Model => Model.TagsString, new { @tabindex = "2", @size = "22", @value = "", @class = "text_input" })
            <label for="TagsString">
                <strong class="leftSpace">Tags</strong></label></p>
<style>
    .ui-autocomplete-loading
    {
        background: white url('/Content/Images/ui-anim_basic_16x16.gif') right center no-repeat;
    }
</style>

这是操作:

[HttpGet]
        public virtual JsonResult GetTags(string term)
        {
            var getTags = _tag.All().Where(t => t.Name.ToLower().Contains(term.ToLower())).OrderBy(t => t.Name).ToList();

            TagViewModel model = new TagViewModel()
            {
                Tags = Mapper.Map<List<Tag>, List<TagModel>>(getTags)
            };

            return Json(new
            {
                tags = model.Tags
            }, JsonRequestBehavior.AllowGet);
        }

效果非常好:)

I've decided to give jQuery UI Autocomplete a try and it seems to be easy enough :) Here's the javascript code:

$(document).ready(function () {
    function split(val) {
        return val.split(/,\s*/);
    }
    function extractLast(term) {
        return split(term).pop();
    }

    $("#TagsString")
    // don't navigate away from the field on tab when selecting an item
            .bind("keydown", function (event) {
                if (event.keyCode === $.ui.keyCode.TAB &&
                        $(this).data("autocomplete").menu.active) {
                    event.preventDefault();
                }
            })
            .autocomplete({
                source: function (request, response) {
                    $.get("/Blog/GetTags", { term: extractLast(request.term) }, function (data) {
                        response($.map(data.tags, function (item) {
                            return {
                                label: item.Name,
                                value: item.Id
                            }
                        }))
                    }, "json");
                },
                minLength: 2,
                dataType: 'json',
                focus: function () {
                    // prevent value inserted on focus
                    return false;
                },
                select: function (event, ui) {
                    var terms = split(this.value);
                    // remove the current input
                    terms.pop();
                    // add the selected item
                    terms.push(ui.item.label);
                    // add placeholder to get the comma-and-space at the end
                    terms.push("");
                    this.value = terms.join(", ");
                    return false;
                }
            });
});

Here's the HTML:

<p>
            @Html.TextBoxFor(Model => Model.TagsString, new { @tabindex = "2", @size = "22", @value = "", @class = "text_input" })
            <label for="TagsString">
                <strong class="leftSpace">Tags</strong></label></p>
<style>
    .ui-autocomplete-loading
    {
        background: white url('/Content/Images/ui-anim_basic_16x16.gif') right center no-repeat;
    }
</style>

And here's the action:

[HttpGet]
        public virtual JsonResult GetTags(string term)
        {
            var getTags = _tag.All().Where(t => t.Name.ToLower().Contains(term.ToLower())).OrderBy(t => t.Name).ToList();

            TagViewModel model = new TagViewModel()
            {
                Tags = Mapper.Map<List<Tag>, List<TagModel>>(getTags)
            };

            return Json(new
            {
                tags = model.Tags
            }, JsonRequestBehavior.AllowGet);
        }

Works really well :)

美男兮 2024-10-16 18:36:17

我使用 jQuery UI 的自动完成功能,但我事先加载了数据;

视图:

@Html.TextBoxFor(Model => Model.Tags, new { @class = "txtbox-long" })
@Html.Resource(@<link href="@Url.Content("~/Content/CSS/flick/jquery-ui-1.8.11.css")" rel="stylesheet" type="text/css" />, "css")
@Html.Resource(@<script src="@Url.Content("~/Content/JS/jquery-ui-1.8.11.min.js")" type="text/javascript" language="javascript"></script>, "js")
@Html.Resource(
    @<script type="text/javascript" language="javascript">
         $(document).ready(function () {
             var tags; $.getJSON("/Thread/GetTags", function (data) { tags = data; });

             function split(val) { return val.split(/ \s*/); }
             function extractLast(term) { return split(term).pop(); }

             $("#Tags")
             // don't navigate away from the field on tab when selecting an item
                .bind("keydown", function (event) {
                    if (event.keyCode === $.ui.keyCode.TAB && $(this).data("autocomplete").menu.active) event.preventDefault();
                })
                .autocomplete({
                    delay: 0,
                    minLength: 0,
                    source: function (request, response) {
                        response($.ui.autocomplete.filter(tags, extractLast(request.term)));
                    },
                    focus: function () {
                        // prevent value inserted on focus
                        return false;
                    },
                    select: function (event, ui) {
                        var terms = split(this.value);
                        // remove the current input
                        terms.pop();
                        // add the selected item
                        terms.push(ui.item.value);
                        // add placeholder to get the space at the end
                        terms.push("");
                        this.value = terms.join(" ");

                        return false;
                    }
                });
         });
    </script>
, "js")

控制器:

[Classes.Attributes.Ajax]
public JsonResult GetTags()
{
    return Json(
        TagService.GetTags().Select(x => x.Name),
        "text/plain",
        JsonRequestBehavior.AllowGet
    );
}

工作得非常好,并且由于使用客户端搜索而保存了对数据库的多次调用。我在一个小项目中使用它,所以不会有那么多标签。

I use jQuery UI's autocomplete but I load the data beforehand;

View:

@Html.TextBoxFor(Model => Model.Tags, new { @class = "txtbox-long" })
@Html.Resource(@<link href="@Url.Content("~/Content/CSS/flick/jquery-ui-1.8.11.css")" rel="stylesheet" type="text/css" />, "css")
@Html.Resource(@<script src="@Url.Content("~/Content/JS/jquery-ui-1.8.11.min.js")" type="text/javascript" language="javascript"></script>, "js")
@Html.Resource(
    @<script type="text/javascript" language="javascript">
         $(document).ready(function () {
             var tags; $.getJSON("/Thread/GetTags", function (data) { tags = data; });

             function split(val) { return val.split(/ \s*/); }
             function extractLast(term) { return split(term).pop(); }

             $("#Tags")
             // don't navigate away from the field on tab when selecting an item
                .bind("keydown", function (event) {
                    if (event.keyCode === $.ui.keyCode.TAB && $(this).data("autocomplete").menu.active) event.preventDefault();
                })
                .autocomplete({
                    delay: 0,
                    minLength: 0,
                    source: function (request, response) {
                        response($.ui.autocomplete.filter(tags, extractLast(request.term)));
                    },
                    focus: function () {
                        // prevent value inserted on focus
                        return false;
                    },
                    select: function (event, ui) {
                        var terms = split(this.value);
                        // remove the current input
                        terms.pop();
                        // add the selected item
                        terms.push(ui.item.value);
                        // add placeholder to get the space at the end
                        terms.push("");
                        this.value = terms.join(" ");

                        return false;
                    }
                });
         });
    </script>
, "js")

Controller:

[Classes.Attributes.Ajax]
public JsonResult GetTags()
{
    return Json(
        TagService.GetTags().Select(x => x.Name),
        "text/plain",
        JsonRequestBehavior.AllowGet
    );
}

Works really well and saves multiple calls to the database as it uses client side searching. I'm using it in a small project so there won't be that many tags.

千里故人稀 2024-10-16 18:36:17

您可以调用一个操作方法,该方法将获取他们当前输入的文本并返回一个包含可能标签的填充列表的视图。

您的操作方法可能如下所示:

public ActionResult GetTags(string tag)
{
    List<string> tags = // get AutoComplete data from somewhere

    return View(tags);
}

您的自动完成视图可能只是:

<%@ Page Language="C#" Inherits="ViewPage<IList<string>>" %>

<ul>
    <% foreach(string tag in Model) { %>
    <li><%=tag %></li>
    <% } %>
</ul>

如果您使用的是 jQuery,您可以尝试:

$.ajax({
    url: "Autocomplete/GetTags/" + tag,
    cache: false,
    success: function(html) {
        $("#autocomplete").html(html);
    }
});

You could call an Action Method that would take the text they're currently entering and return a View with a populated list of possible tags.

Your Action Method could look like this:

public ActionResult GetTags(string tag)
{
    List<string> tags = // get AutoComplete data from somewhere

    return View(tags);
}

And your Autocomplete View could simply be:

<%@ Page Language="C#" Inherits="ViewPage<IList<string>>" %>

<ul>
    <% foreach(string tag in Model) { %>
    <li><%=tag %></li>
    <% } %>
</ul>

And if you're using jQuery, you could try:

$.ajax({
    url: "Autocomplete/GetTags/" + tag,
    cache: false,
    success: function(html) {
        $("#autocomplete").html(html);
    }
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文