Хорошо Кроссбраузерный флажок три состояния? - PullRequest
0 голосов
/ 30 июля 2009

Привет, ребята, я ищу хороший контроллер флажка с тремя состояниями в JS? Есть что-нибудь, чтобы порекомендовать меня?

Я ищу состояния

  1. Проверено
  2. Неконтролируемый
  3. Безразлично (никогда не проверялось / не проверялось)

Ответы [ 6 ]

1 голос
/ 27 июня 2014

Я разработал это решение, работая над проектом. Он использует неопределенное состояние флажков (атрибут, к которому нельзя получить доступ / установить из разметки). В моем примере у меня есть только один уровень вложенности, но он может быть вложен неопределенно долго, чтобы позволить группам и подгруппам быть un, all или частично выбранными.

Базовая структура вращается вокруг манипулирования неопределенным атрибутом, подобным этому:

<input type="checkbox" value="HasFavoriteColor" name="FavoriteColor" id="myCheckBox" />
<input type="hidden" id="FavoriteColorState" name="FavoriteColorState" /><!-- potential values: 0, 1, -1 -->

<script type="text/javascript">
    //using JQuery
    $("#myCheckBox").prop("indeterminate", true);

    //using pure javascript
    document.getElementById("myCheckBox").setAttribute("indeterminate", true);
</script>

Я использовал его для выбора всего здесь в моем примере, но его можно использовать только для отдельного флажка. Важно знать, что это НЕ сообщает состояние в постбэк на сервер. Размещаемый флажок по-прежнему имеет значение true / false, поэтому неопределенность влияет только на пользовательский интерфейс. Если вам нужно отправить значения обратно, вам придется привязать неопределенное состояние к некоторому скрытому полю, чтобы сохранить значение.

Подробнее о неопределенном состоянии см. В следующих ресурсах:

Вот рабочий пример (внешняя скрипка): http://jsfiddle.net/xDaevax/65wZt/

Рабочий пример (фрагмент кода):

var root = this;
root.selectedCount = 0;
root.totalCount = 0;
root.percentageSelected = 0.0;
root.holdTimer = 0;
jQuery.fn.customSelect = {
    State: 0,
    NextState: function () {
        this.State += 1;
        if (this.State > 2) {
            this.State = 0;
        } // end if
    } // end object
};

function checkAllToggle(parent, toggle) {
    if (parent != null && parent != undefined) {
        parent.find("input[type='checkbox']").prop("checked", toggle);
        for (var i = 0; i < parent.find("input[type='checkbox']").length; i++) {
            $(document).trigger("item-selected", {
                IsSelected: $(parent.find("input[type='checkbox']")[i]).prop("checked")
            });
        } // end for loop
    } // end if
} // end function checkAll
var fadeTimer = setInterval(function () {
    if (root.holdTimer > 0) {
        root.holdTimer -= 1;
    } else {
        root.holdTimer = -2;
    } // end if/else
    if (root.holdTimer == -2) {
        $(".options-status").fadeOut("easeOutBack");
        root.holdTimer = -1;
    } // end if/else
}, 50);
$(function () {
    root.totalCount = $(document).find(".options-list input[type='checkbox']").length;
    $(document).bind("select-state-change", function (e, data) {
        switch (data.State) {
            case 0:
                data.Target.prop("checked", false);
                data.Target.prop("indeterminate", false);
                checkAllToggle($(".options-list"), false);
                break;
            case 1:
                data.Target.prop("indeterminate", true);
                e.preventDefault();
                break;
            case 2:
                data.Target.prop("checked", true);
                data.Target.prop("indeterminate", false);
                checkAllToggle($(".options-list"), true);
                break;
        }

    });
    $(document).bind("item-selected", function (e, data) {
        root.holdTimer = 50;
        if (data != null && data != undefined) {
            if (data.IsSelected) {
                root.selectedCount += 1;
            } else {
                root.selectedCount -= 1;
            } // end if/else
            if (root.selectedCount > root.totalCount) {
                root.selectedCount = root.totalCount;
            } // end if
            if (root.selectedCount < 0) {
                root.selectedCount = 0;
            } // end if
            root.percentageSelected = (100 * (root.selectedCount / root.totalCount));
            root.percentageSelected < 50 && root.percentageSelected >= 0 ? $(".options-status").removeClass("finally-there").removeClass("almost-there").addClass("not-there", 200) : false;
            root.percentageSelected < 100 && root.percentageSelected >= 50 ? $(".options-status").removeClass("not-there").removeClass("finally-there").addClass("almost-there", 200) : false;
            root.percentageSelected == 100 ? $(".options-status").removeClass("not-there").removeClass("almost-there").addClass("finally-there", 200) : false;
            $(".options-status .output").text(root.percentageSelected + "%");
            setTimeout(function () {
                $(".options-status").fadeIn("easeInBack");
            }, 100);
        } // end if
    });
    $("#select-all").click(function (e) {
        var checkbox = $(this);
        if (checkbox.prop("checked") == true) {
            checkbox.customSelect.State = 2;
        } else {
            checkbox.customSelect.State = 0;
        } // end if/else
        $(document).trigger("select-state-change", {
            State: checkbox.customSelect.State,
            Target: $("#select-all")
        });
    });
    $("input[name='options']").each(function () {
        $(this).click(function () {
            if ($(this).prop("checked") == true) {
                $(document).trigger("item-selected", {
                    IsSelected: true
                });
                if ($(this).parent().parent().find("input[type='checkbox']:checked").length == $(this).parent().parent().find("input[type='checkbox']").length) {
                    $(document).trigger("select-state-change", {
                        State: 2,
                        Target: $("#select-all")
                    });
                } else {
                    $(document).trigger("select-state-change", {
                        State: 1,
                        Target: $("#select-all")
                    });
                } // end if/else
            } else {
                $(document).trigger("item-selected", {
                    IsSelected: false
                });
                if ($(this).parent().parent().find("input[type='checkbox']:checked").length <= 0) {
                    $(document).trigger("select-state-change", {
                        State: 0,
                        Target: $("#select-all")
                    });
                } else {
                    $(document).trigger("select-state-change", {
                        State: 1,
                        Target: $("#select-all")
                    });
                } // end if/else
            } // end if/else
        });
    });
});
body {
    font-family: Helvetica, Verdana, Sans-Serif;
    font-size: small;
    color: #232323;
    background-color: #efefef;
    padding: 0px;
    margin: 0px;
}
H1 {
    margin-top: 2px;
    text-align: center;
}
LEGEND {
    margin-bottom: 6px;
}
.content-wrapper {
    padding: 2px;
    margin: 3px auto;
    width: 100%;
    max-width: 500px;
    min-width: 250px;
}
.wrapper {
    padding: 3px;
    margin: 2px;
}
.container {
    border-right: solid 1px #788967;
    border-bottom: solid 1px #677867;
    border-top: solid 1px #89ab89;
    border-left: solid 1px #89ab89;
}
.rounded {
    border-radius: 2px;
}
.contents {
    background: linear-gradient(rgba(255, 255, 255, 1), rgba(180, 180, 180, .2));
}
.header {
    padding: 4px;
    border: solid 1px #000000;
    background-color: rgba(200, 200, 230, .8);
    font-size: 123%;
    background-image: linear-gradient(rgba(220, 220, 255, .8), rgba(200, 200, 230, .8));
}
#options-chooser {
    margin-top: 30px;
    display: block;
}
#options-chooser .options-list > LABEL {
    display: table-row;
    height: 26px;
}
.red {
    color: red;
}
.blue {
    color: blue;
}
.green {
    color: green;
}
.black {
    color: black;
}
.options-status {
    float: right;
    right: 3%;
    clear: both;
    display: none;
    margin-top: -20px;
}
.output {
    font-weight: bold;
}
.not-there {
    border-color: rgba(190, 190, 190, .3);
    background-color: rgba(190, 190, 190, .1);
}
.almost-there {
    border-color: rgba(220, 220, 50, .6);
    background-color: rgba(220, 220, 50, .3);
}
.finally-there {
    border-color: rgba(50, 190, 50, .3);
    background-color: rgba(50, 190, 50, .1);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.js"></script>
<div class="content-wrapper">
    <div class="wrapper container rounded">
        <div class="contents">
             <h1 class="header rounded">Partial Select All Example</h1>

            <p>This example demonstrates how to implement a tri-state checkbox with options.</p>
            <form name="options-chooser" id="options-chooser" method="post">
                <fieldset class="rounded options">
                    <legend class="rounded header">Options
                        <input type="checkbox" value="options-all" name="selectAll" id="select-all" title="Select All" />
                    </legend> <span class="options-status rounded container wrapper">Items Selected: <span class="output"></span></span>
                    <div class="options-list">
                        <label class="blue">
                            <input type="checkbox" name="options" value="1" />Blue</label>
                        <label class="green">
                            <input type="checkbox" name="options" value="2" />Green</label>
                        <label class="red">
                            <input type="checkbox" name="options" value="3" />Red</label>
                        <label class="black">
                            <input type="checkbox" name="options" value="4" />Black</label>
                    </div>
                </fieldset>
            </form>
        </div>
    </div>
</div>
1 голос
/ 30 июля 2009

Возможно, вы захотите взглянуть на EXTJS.

У них есть большое сообщество, которое часто создает подобные вещи, и я уверен, что если вы погуглите на одном, это может подойти. На самом деле, вы можете внести некоторые изменения в это и заставить его работать так, как вы хотите:

http://extjs.net/forum/showthread.php?t=28096

Надеюсь, это поможет!

1 голос
/ 30 июля 2009

Используйте радио кнопки.

<input type="radio" name="tristate" value="checked" />Checked
<input type="radio" name="tristate" value="unchecked" />Unchecked

Если нет, если радиоприемники включены, значит у вас есть третье состояние "безразлично" или ноль.

0 голосов
/ 19 марта 2015

У меня есть решение, использующее встроенный флажок и неопределенное свойство и сохраняющее пользовательский атрибут в флажке, чтобы захватить текущее состояние для достижения эффективного флажка тройного состояния.

Это решение хорошо зарекомендовало себя на последних версиях Chrome и Firefox и chromium (nw.js) для Linux и IE 11, Firefox и Chrome на Windohs.

Я отправил это решение на JSFiddle .

Вот утилита-синглтон, которую я использовал:

tscb$ = {
     STATE_UNCHECKED: 0
    ,STATE_CHECKED: 1
    ,STATE_INDETER: 2
    ,setState:  function(o,iState){
        var t=this;
        if(iState==t.STATE_UNCHECKED){
            o.indeterminate=false; o.checked=false;
        } else if(iState==t.STATE_CHECKED){
            o.indeterminate=false; o.checked=true;
        } else if(iState==t.STATE_INDETER){
            o.checked=false; o.indeterminate=true;
        } else {
            throw new Error("Invalid state passed: `"+iState+"`")
        }
        o.setAttribute("tscbState", iState);
    }
    // Event to call when the cb is clicked to toggle setting.
    ,toggleOnClick:  function(o){
        var t=this, iNextState=t.getNextState(o)
        if(iNextState==t.STATE_UNCHECKED){
            o.checked=false;
        } else if(iNextState==t.STATE_CHECKED){
            o.checked=true;
        } else if(iNextState==t.STATE_INDETER){
            o.indeterminate=true;
        }
        o.setAttribute("tscbState", iNextState);
    }
    // For retrieval of next state 
    ,getNextState: function(o){
        var t=this, iState=t.getState(o)
        if(iState==t.STATE_UNCHECKED){
            return t.STATE_INDETER;
        } else if(iState==t.STATE_CHECKED){
            return t.STATE_UNCHECKED;
        } else if(iState==t.STATE_INDETER){
            return t.STATE_CHECKED;
        }
    }
    ,getState: function(o){
        return parseInt(o.getAttribute("tscbState"))
    }

}

Использование:

  • tscb $ .setState () используется для инициализации или переопределения параметра для флажка
  • tscb $ .toggleOnClick () используется при нажатии элемента для перехода в следующее состояние
  • tscb $ .getState () - для получения текущего состояния
  • tscb $ .getNextState () - для получения следующего состояния

Удивительно, насколько эффективным может быть флажок с тройным состоянием для сохранения компактности пользовательского интерфейса при одновременной уникальной функциональности фильтрации. Это очень эффективно для динамической фильтрации результатов поиска, где фильтр может быть True / False / Off только с одним элементом управления

0 голосов
/ 29 сентября 2012
0 голосов
/ 30 июля 2009

Если вам нужно более двух состояний, используйте 3 переключателя.

Не думайте, что пользователь ничего не выбрал, чтобы обозначать третье состояние. Что если пользователь пропустил вопрос все вместе или нажал кнопку отправить по ошибке?

Если вы хотите 3 состояния, тогда 3 состояния!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...