模拟SO标签编辑器

时间:2013-06-22 23:52:15

标签: javascript jquery html css dom

我正在尝试在我的应用中实现“标记编辑器”字段,就像SO一样。 现在我得到了这个:

编辑:我已将其编码为jQuery插件: https://github.com/fernandotenorio/tagme.git

小提琴

http://jsfiddle.net/FernandoTen/PnYuF/

HTML

<div style="margin-left: auto; margin-right: auto; width: 400px;">      
            <span style='color: #333; font-size: small'>
                Tags [a-z A-Z 0-9 # + . -]
            </span>

            <div id='tags_container'>   
                <span id='tags_queue'></span>   
                <input type='text' id='tf' />
            </div>
</div>

JS

$(document).ready(function () {

var rexp = /[^a-zA-Z0-9#+\.\-]/
var left = 37;
var right = 39;
var del = 8;
var space = 32;
var comma = 188;
var minlen = 3;
var maxlen = 15;
var current_tag = null

$('#tf').focus().attr('maxlength', maxlen)

$('#tags_container').click(function () {
    $('#tf').focus()
})

$('#tf').keydown(function (e) {

    var code = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode;
    var txt = $(this).val().trim()

    // handle navigation between tags
    if ((code === left || code === right) && txt.length === 0) {

        if (!current_tag) 
        {
            if (code === left) 
                current_tag = $('#tags_queue span').last()
            else 
                current_tag = $('#tags_queue span').first()

            if (current_tag.length > 0) current_tag.css('background-color', '#9FC2D6')
        } else //current tag exists
        {
            if (code === left) 
                current_tag = current_tag.css('background-color', '#B8D0DE').prev()
            else 
                current_tag = current_tag.css('background-color', '#B8D0DE').next()

            if (current_tag.length > 0) 
                current_tag.css('background-color', '#9FC2D6')
            // hit last/first, clean current_tag
            else
            {                    
                current_tag.css('background-color', '#B8D0DE')
                current_tag = null
            }
        }            
    }
});

$('#tf').keypress(function (e) {
    var token = String.fromCharCode(e.which)
    var code = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode;

    if (token.match(rexp) && (code !== del) && (code !== left) && (code !== right)) 
        return false;                               
});


$('#tf').keyup(function (e) {
    var code = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode;
    var txt = $(this).val().trim()

    if (code === del && txt.length === 0 && current_tag) {
        current_tag.remove()
        current_tag = null
        return
    }

    // clean current_tag, user is typing
    if (current_tag && (code !== left) && (code != right))
    {
        current_tag.css('background-color', '#B8D0DE')
        current_tag = null          
    }

    if (txt.length > maxlen) txt = txt.substring(0, maxlen)

    if (txt.match(rexp)) {-
        $(this).val("")
        return
    } else if (code === space || code === comma) {

        if (txt.length < minlen) return;

        var tag = $('<span></span>', {
            'class': 'tag'
        }).html(txt).append($('<a></a>', {
            'class': 'close_tag',
            html: '&times',
            click: function () {                    
                $(this).parent().fadeOut(function(){
                    $(this).remove()
                    current_tag.css('background-color', '#B8D0DE')
                    current_tag = null
                })                    
            }
        }))

        $('#tags_queue').append(tag)
        $(this).val("")
    }
});

})

CSS

div#tags_container {
        border: 1px solid #ccc;
        padding-bottom: 5px;
        border-radius: 5px;
        background-color: beige;
        overflow: hidden;                                           
    }
    input#tf {
        border: 1px solid orange !important;
        outline: none !important;
        background-color: transparent !important;
        height: 30px;   
        margin-top: 2px;
        padding-left: 5px;

    }
    a.close_tag {
        margin-left: 5px;
        color: #fff;
    }
    a.close_tag:hover {
        cursor: pointer;
    }
    span.tag {
        background-color: #B8D0DE;
        color: #111;
        margin-left: 5px;
        margin-top: 5px;
        padding: 5px;
        float: left;
        border-radius: 5px;
    }
    span.tag:hover {
        background-color: #9FC2D6;
    }
    span#tags_queue {           
        margin-right: 5px;
        vertical-align: middle;
    }

问题是,我如何使用箭头键处理'隐藏'内容,SO的方式如何?看起来我必须处理文本字段中的光标位置,并观察箭头左和右箭头事件......还有点击已完成的标签。

我可以想到以下(反SO设计)解决方案:

  1. white-space: nowrap div中删除 tags_container ,然后让 当用户添加更多标签时,div'成长'。

  2. overflow: scroll 添加到 tags_container div(非常难看!)

  3. 所以,我很欣赏有关如何近似 SO标签编辑器行为的任何新想法。 谢谢!

1 个答案:

答案 0 :(得分:3)

重新发明轮子是一种不好的做法:看看优秀的Tag-it jQuery插件代码,它实现了你正在处理的东西。