JavaScript - 对SELECT选项进行排序

4
使用PHP,我扫描一个目录并列出所有.xml文件。每个XML文件都包含“name”元素和“date”元素。“name”元素在选择列表中列为选项。这很完美,但是每个XML文件中的“date”元素都不同,并包含像这样的日期格式:mm/dd/yyyy。我想知道如何根据日期对项目进行排序,最早的日期在列表中排在第一位,最近的日期在最后一位。
现在假设每个项目的“date”元素具有不同的值。我需要按最早的日期对这些项目进行排序。我不确定如何将“date”元素数据存储在某个地方,以便JavaScript可以处理它。如果我的描述非常模糊,我很抱歉,这已经困扰我一段时间了,而且试图解释也很令人困惑。
更新:
现在,这是我正在使用的内容:
<select name="sel_id" onchange="this.form.submit()" size="20">
<option value="item1">Item 1</option>
<option value="item2">Item 2</option>
<option value="item3">Item 3</option>
<option value="item4">Item 4</option>
</select>

我想有一件事情可以帮上忙,就是知道是否有一种方法可以将日期存储在除了value属性之外的标记中,因为它已经被使用了。日期本身不是问题,我已经解决了这个问题,只是需要将它存储在某个地方,以便可以在客户端调用。

4个回答

7

已更新

你需要:

  • 使用自定义属性来表示日期
  • 使用sort()函数的自定义比较函数参数
  • 将其转换为数组以进行排序
  • 将日期转换为字符串进行比较 (mm/dd/yyyy -> yyyy-mm-dd)

查看演示

[测试通过:IE 5.5+,FF 2+,Chrome 4+,Safari 4+,Opera 9.6+]

HTML:

<select name="sel_id" id="sel_id" size="4">
  <option value="item2" date="02-01-2009">Item 2</option>
  <option value="item3" date="01-05-2010">Item 3</option>
  <option value="item1" date="10-06-2007">Item 1</option>
  <option value="item4" date="04-05-2011">Item 4</option>
</select>

Javascript:

// array functions are not working
// on nodeLists on IE, we need to
// to convert them to array
function toArray( obj ) {
  var i, arr = [];
  for ( i = obj.length; i--; ){
    arr[i] = obj[i];
  }
  return arr;
}

// custom compare function for sorting
// by the hidden date element
function sortByDate( el1, el2 ) {
  var a = convertToDate( el1.getAttribute("date") ),
      b = convertToDate( el2.getAttribute("date") );
  if ( a < b ) return -1;
  else if( a > b ) return 1;
  else return 0;
}

// convert date for string comparison
function convertToDate( date ) {
  date = date.split("-");
  return date[2] + "-" + date[0] + "-" + date[1];
}

// select the elements to be ordered
var itemsId = document.getElementById("sel_id"),
    items   = itemsId.getElementsByTagName("option"),
    len     = items.length;

// convert to array, to make sorting possible
items = toArray( items );

// do the item sorting by their date
items = items.sort( sortByDate );

// append them back to the parent in order
for ( var i = 0; i < len; i++ ) {
  itemsId.appendChild( items[i] );
}

​ ​


这并不是一个选择元素。 - user
当我回答问题时,问题中并没有关于<select>的内容。我重新组织了我的回答。但下次请更具体一些。 - gblazex
谢谢,非常好用。抱歉回复晚了。最后一个问题。我很容易将其转换为函数,以便可以从链接中调用它并且它可以正常工作,但我还尝试实现一个函数来将选项按字母顺序排序。我尝试了几种不同的方法来做到这一点,一开始按日期排序可以工作,然后按名称排序也可以,但之后,两个排序选项都无法正常工作。 - user
我已经为您的需求制作了一个新版本:http://jsbin.com/oraxi4/9/edit。玩得开心! - gblazex
HTML5风格,那个自定义属性应该是'data-date="02-01-2009"'吧?不过Primo的回答真不错,非常好! - ilasno

2
简洁明了。此版本还考虑到日期以mm-dd-yyyy格式为基础,以响应OP的要求。
<form>
  <select id="myList">
    <option value="07-01-2010">Item 2</option>
    <option value="09-21-2009">Item 1</option>
    <option value="08-22-2010">Item 3</option>
  </select>
</form>
<script>
  var list    = document.forms[0].myList,
      opts    = list.options,
      len     = opts.length,
      sorted  = [].slice.call(opts).sort(function(a,b){
        return fixDate(a.value) < fixDate(b.value) ? -1 : 1;
      });

  for (var i=0; i<len; i++) {
    list.appendChild(sorted[i]);
  }

  // convert m-d-y to y-m-d
  function fixDate (d) {
    var a=d.split('-');
    a.unshift(a.pop()); 
    return a.join('-');
  }

</script>

0

我会采用galambalazs上面的答案,但使用数据属性而不是日期属性。因为"data-date"被认为是符合标准的,而"date"只是一个自定义属性。


-1

您可以将日期表示为选项值,或使用数据属性将其存储在选项中。

<option value="2010-07-05">..</option>

或者

<option data-date="2010-07-05">..</option>

假设你的选择列表长这样:
<select id="myList">
    <option value="2010-07-01">Item 1</option>
    <option value="2010-06-21">Item 1</option>
    <option value="2010-08-22">Item 1</option>
    ..
</select>

使用内置的Array.sort函数和自定义比较器来对节点进行排序,一旦排序完成,将它们重新插入到选择列表中。在这里查看示例
/**
 * Sorts option elements by value attribute which holds a date
 *
 * @param {HTMLOptionElement} a first option
 * @param {HTMLOptionElement} b second option
 *
 * @returns {Integer}
 */
var sortByDate = function(a, b) {
    return new Date(a.value) - new Date(b.value);
}

var list = document.getElementById("myList");
var options = list.getElementsByTagName("option");
// NodeList that we get in previous step is an array-like
// object but not actually an array. Some call it a fuck-up,
// but regardless we need to convert it to an array.
var optionsArray = Array.prototype.slice.call(options);

// Now that we have an array, we can use the sort method (in-place sorting)
optionsArray.sort(sortByDate);

// re-insert the sorted nodes
for(var i = 0; i < optionsArray.length; i++) {
    list.appendChild(optionsArray[i]);
}
​

不会起作用。您无法像那样从字符串创建日期,并且在将“排序”选项放入之前,您忘记清除选项了。 - Dagg Nabbit
你可以从字符串中创建一个日期,例如 "yyyy-mm-dd"。在 Chrome 和 Firefox 上都可以使用。如果某些浏览器出现问题,请手动组合日期或使用日期库,例如 Datejs,但这不是问题的主要点。我故意删除了首先清除选项数组的代码,因为那是不必要的。请参阅 DOM 规范的 appendChild - "将节点 newChild 添加到此节点的子节点列表的末尾。如果 newChild 已经在树中,则首先将其删除。" - Anurag
你说得对,我在两个方面都改正了。虽然如果日期字符串格式化为那样,就没有必要转换为日期……字符串比较就足够了。你指出的appendChild的问题非常有趣,谢谢。 (编辑:在审查原始帖子时,我发现他的日期格式为mm / dd / yyyy,因此看来我们仍然有更多工作要做;)) - Dagg Nabbit
使用数据属性吗? <option data-date="2010-07-05">..</option> - Anurag
如果所有的东西都是零填充的,那么“10” < “2”的问题就不重要了,也没有必要转换为日期。不过,仔细想想,数值比较似乎比字符串比较稍微更有效率一些。我稍后会更新我的建议。 - Dagg Nabbit
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接