HTML / CSS: что может быть лучше для размещения дерева вложенных элементов, чем вложенных таблиц? - PullRequest
8 голосов
/ 28 января 2009

Хорошо, у меня есть набор флажков для выбора критериев. Ради аргумента скажем, что данные выглядят так:

[] Vehicles
   [] Unpowered
      [] Bicycle
      [] Skateboard
   [] Powered
      [] Two-wheeled
         [] Motorcycle
         [] Scooter
      [] Four-wheeled
etc

[] s представляют флажки.

Игнорируя явно надуманную природу этого примера, идея такова:

  • Для начала виден только флажок Автомобиль;
  • Если пользователь нажимает на флажок «Транспортное средство», происходит переход на следующий уровень («Питание», «Без питания»);
  • Если пользователь выбирает Powered, он открывает следующий уровень (Двухколесный, Четырехколесный);
  • Если пользователь снимает флажок с Powered, этот уровень исчезает.

Теперь это относительно легко настроить, если onclick переключает атрибут CSS отображения между блоком и ни одним.

Это в настоящее время структурировано на странице как:

<table>
<tr>
  <td><input type="checkbox" onclick="toggle('__Vehicles');"></td>
  <td>Vehicles
    <table id="__Vehicles">
    <tr>
      <td><input type="checkbox"></td>
      <td>Unpowered
etc

Я должен указать, прежде чем кто-то спросит: причина, по которой флажок был установлен в ячейке таблицы, заключалась в управлении форматированием. Это облегчало эффективный отступ, так как все в следующей ячейке таблицы будет выстраиваться.

Все это прекрасно работает, но вложение таблиц становится довольно глубоким. Я продолжаю думать, что должен быть лучший способ, чем этот. Он должен иметь возможность легко создаваться динамически и иметь хорошую межбраузерную поддержку для форматирования «дерева».

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

Предложения

Редактировать: Да, стилизация флажка важна, как отмечено в нескольких комментариях. Кроме того, я опубликовал решение этой проблемы на основе полученных ответов в качестве ответа ниже (слишком большой, чтобы добавить его сюда), просто для тех, кому интересно посмотреть пример.

Ответы [ 10 ]

21 голосов
/ 28 января 2009
<ul>
    <li><input type="checkbox" />Vehicles <ul>
        <li><input type="checkbox" />Unpowered</li>
        <li><input type="checkbox" />Bicycle</li>
        <li><input type="checkbox" />Skateboard</li>
    </ul></li>
    <li><input type="checkbox" />Powered <ul>
        <li><input type="checkbox" />Two-wheeled <ul>
            <li><input type="checkbox" />Motorcycle</li>
            <li><input type="checkbox" />Scooter</li>
        </ul></li>
        <li><input type="checkbox" />Four-wheeled</li>
     </ul></li>
</ul>

Редактировать: немного CSS и JS, чтобы показать и скрыть вложенные элементы (без флажков)

li.opened ul {
display: block;
}

li.closed ul {
    display: none;
}

и JS ...

$(document).ready(function() {

$('li input:checkbox').click(function () {
    $(this).parent().toggleClass('opened');
    $(this).parent().toggleClass('closed');
});

$('li').addClass('closed');
});

измените, опять же, потому что Sparr хочет некоторые лучшие стили (при условии, что флажки имеют стиль "флажок"

li input.checkbox { /* input:checkbox is not 100% compatible */
    width: 6px;
    margin: 0 2px;
    /* This makes 10px be the total "width" ofh the checkbox */
}

ul {
    margin: 0 0 0 10px; /* Or whatever your total checkbox width is */
    padding: 0;
}

li {
    padding: 0;
}
10 голосов
/ 28 января 2009

Вы можете сделать это:

<ul>
  <li>
    <input type="checkbox" /> Option 1
    <ul>
      <li><input type="checkbox" /> Option 1 Sub Option A</li>
    </ul>
  </li>
</ul>

Затем вы должны установить отступы / поля для UL на 0 и 0. Затем установите отступ слева от LI на 10 пикселей.

ul {
  margin:0;
  padding:0;
}

li {
  margin:0;
  padding:0 0 0 20px; /* Each nested li will be padded incrementally */
}

Для javascript прикрепите событие к каждому флажку, который определяет, должен ли быть виден родной UL (если таковой существует). Если флажок установлен, покажите его, в противном случае скройте его.

4 голосов
/ 28 января 2009

Вложенные неупорядоченные списки - лучшая практика для такого рода вещей.

<ul>
   <li>Item 1</li>
   <li>Item 2
      <ul>
         <li>Sub Item 1</li>
         <li>Sub Item 2</li>
         <li>Sub Item 3</li>
      </ul>
   </li>
   <li>Item 3</li>
   <li>Item 4
      <ul>
         <li>Sub Item 1</li>
         <li>Sub Item 2</li>
         <li>Sub Item 3</li>
      </ul>
   </li>
</ul>
3 голосов
/ 28 января 2009

Хотите увидеть глубокую магию jQuery?

<ul class="tree">
  <li><input type="checkbox" name="Vehicles" checked>Vehicles
    <ul>
      <li<input type="checkbox" name="Unpowered">Unpowered
        <ul>
          <li><input type="checkbox" name="Bicycle">Bicycle</li>
          <li><input type="checkbox" name="Skateboard">Skateboard</li>
        </ul>
      </li>
      <li><input type="checkbox" name="Powered" checked>Powered
        <ul>
          <li><input type="checkbox" name="Two-wheeled">Two-wheeled
            <ul>
              <li><input type="checkbox" name="Motorcycle" checked>Motorcycle</li>
              <li><input type="checkbox" name="Scooter">Scooter</li>
            </ul>
          </li>
          <li><input type="checkbox" name="Two-Wheeled">Four-wheeled</li>
        </ul>
    </ul>
  </li>
</ul>

Примечание: единственным украшением здесь является класс дерева.

ul.tree {
    list-style-type: none;
    margin: 0 0 0 -22px;
    padding: 0;
}

ul.tree ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
}

ul.tree input {
    margin-right: 6px;
}

ul.tree li {
    padding: 0 0 0 22px;
    margin: 1px;
}

.closed ul {
    display: none;
}

и магия:

$(function() {
    $("ul.tree li:has(ul) > :checkbox").click(function() {
        jQuery(this).parent().toggleClass('closed');
    }).not(":checked").parent().addClass("closed");
});

Это превращает все это в рабочее открывающееся и закрывающееся дерево при нажатии на флажки. Потрясающе.

Спасибо davethegr8, Джонатону Сэмпсону и другим за советы.

2 голосов
/ 28 января 2009

Я должен присоединиться, чтобы предложить вам извлечь javascript из вашей разметки, в дополнение к предложениям выше. Используя такую ​​библиотеку, как lowpro (моя любимая), вы можете создать 1 объект для обработки вашего вложенного поведения флажка и автоматически применять его ненавязчиво. Подобная упаковка вашего кода делает вашу разметку проще в обслуживании, а ваш код легче и быстрее писать, более мощным и более легким в обслуживании.

1 голос
/ 28 января 2009

Хотя плагин jQuery mcDropdown подходит к проблеме с вложенным списком по-другому (без флажков), он может подойти для ваших нужд.

1 голос
/ 28 января 2009

Таблицы для табличных данных. Вместо этого используйте вложенные списки и CSS для форматирования.


Если вы ищете полное решение, вот одно из них, использующее чистый CSS для современных браузеров и JavaScript для IE:

<style>
ul.tree, ul.tree ul {
    position: relative;
    list-style: none;
    margin: 0 0 0 20px;
    padding: 0;
}
ul.tree input {
    position: absolute;
    margin-left: -20px;
}
ul.tree ul {
    display: none;
}
ul.tree input:checked ~ ul {
    display: block;
}
ul.tree label:hover {
    text-decoration: underline;
}
</style>
<ul class="tree">
  <li>
    <input type="checkbox" id="option1">
    <label for="option1">Option 1</label>
    <ul>
      <li>
       <input type="checkbox" id="option1a">
       <label for="option1a">Option 1 Sub Option A</label>
      </li>
      <li>
       <input type="checkbox" id="option1b">
       <label for="option1b">Option 1 Sub Option B</label>
      </li>
    </ul>
  </li>
  <li>
   <input type="checkbox" id="option2">
   <label for="option2">Option 2</label>
  </li>
</ul>
<!--[if lte IE 7]>
<script>
var tree = document.getElementsByTagName('ul')[0];
tree.attachEvent('onclick', function() {
    var src = event.srcElement;

    if(src.nodeName.toLowerCase() === 'label')
        var box = document.getElementById(src.htmlFor);
    else if(src.nodeName.toLowerCase() === 'input')
        var box = src;
    else return;

    for(var current = src.nextSibling;
        current && current.nodeName.toLowerCase() !== 'ul';
        current = current.nextSibling);

    if(current)
        current.style.display = box.checked ? 'block' : 'none';
});
</script>
<![endif]-->

Предполагается, что флажок не шире, чем 20px.

0 голосов
/ 29 января 2009

Если ширина флажков по-прежнему остается проблемой (после всех предыдущих ответов ...), вы можете:

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

Использование предложенной структуры вложенного списка, очевидно.

0 голосов
/ 28 января 2009

Я знаю, что это не очень связано с вопросом, поэтому просьба не голосовать - это просто предложение.

В этом примере из davethegr8:

<ul>
    <li>Vehicles <ul>
        <li>Unpowered</li>
        <li>Bicycle</li>
        <li>Skateboard</li>
    </ul></li>
    <li>Powered <ul>
        <li>Two-wheeled <ul>
            <li>Motorcycle</li>
            <li>Scooter</li>
        </ul></li>
        <li>Four-wheeled</li>
     </ul></li>
</ul>

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

Как

$("li.Two-wheeled").click(function(event){
   $("div.main_wrapper ul.Moto_or_scooter:hidden").slideDown("slow");
}

Просто небольшое предложение, хотя:)

0 голосов
/ 28 января 2009

при создании КБ дать им класс CSS в зависимости от уровня

<input class="LevelXcb" type="checkbox" />

CSS:

.Level0cb{left:4px;}
.Level1cb{left:16px;}
.Level2cb{left:28px;}

если «left» не работает, попробуйте установить «margin-left».

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