您有一个下拉菜单,根据用户在该菜单中的选择,第二个下拉菜单将填充相应的选项。我们将介绍三种不同的方法。
标记
在我们的示例中,标记始终相同,只有两个简单的选择元素。第一个有三个选项。第一个只是通知用户选择一个选项,接下来的两个是实际的选择。第二个选择只有一个选项,告诉用户请先从第一个下拉菜单中选择。第二个下拉菜单中的选项将被动态替换。
<select id="first-choice">
<option selected value="base">Please Select</option>
<option value="beverages">Beverages</option>
<option value="snacks">Snacks</option>
</select>
<br>
<select id="second-choice">
<option>Please choose from above</option>
</select>
选项 1:使用文本文件
这篇文章的灵感来自 Robert Young,他写信给我分享了这种技术。这种方法易于使用和理解。并非每个人都希望处理数据库等问题。
为每种可能性准备一个文本文件

在这些文本文件中,准备好用于新选项的替换 HTML
<option>Coffee</option>
<option>Coke</option>
现在,我们将使用 jQuery 来监控第一个选择的更改。所有示例都将使用 jQuery。
$("#first-choice").change(function() {
$("#second-choice").load("textdata/" + $(this).val() + ".txt");
});
这种方法效果很好,确实很容易实现。潜在的缺点是 1) 以这种方式将数据存储在 HTML 标签中可能不是最佳选择,难以将数据重新用于其他目的。2) 可扩展性不强,需要为每种可能性创建新的文本文件。
选项 2:使用 JSON 数据
另一种方法是将所需的数据存储在 JSON 格式中。您可以将其直接放在正在加载的 JavaScript 中,也可以将其保存在外部文件中。对于此演示,我们将使用一个名为 data.json 的外部文件。以下是其内容
{
"beverages": "Coffee,Coke",
"snacks": "Chips,Cookies"
}
我们再次监控第一个选择值的更改,然后加载 JSON 并找出我们需要哪些部分
$("#first-choice").change(function() {
var $dropdown = $(this);
$.getJSON("jsondata/data.json", function(data) {
var key = $dropdown.val();
var vals = [];
switch(key) {
case 'beverages':
vals = data.beverages.split(",");
break;
case 'snacks':
vals = data.snacks.split(",");
break;
case 'base':
vals = ['Please choose from above'];
}
var $secondChoice = $("#second-choice");
$secondChoice.empty();
$.each(vals, function(index, value) {
$secondChoice.append("<option>" + value + "</option>");
});
});
});
这里的优势是我们以一种相当通用的方式存储数据,因此可以很容易地将其用于其他用途。请注意,我们在 JavaScript 本身中添加了 option 标签,这非常灵活。这种方法的缺点是它稍微复杂一些(但实际上并不难)。我们可能需要考虑将 JSON 拆分成单独的文件,这样我们就不需要在每次更改时加载所有数据,但这样一来,我们又会遇到与文本文件相同可扩展性问题。使用数据库返回 JSON 也是一种选择。
选项 3:使用数据库
我们仍然会使用 jQuery 监控第一个选择,并仍然使用 jQuery 的 .load() 函数动态加载新选项。但是要从数据库中提取数据,我们需要一个可以进行数据库交互的中间伙伴(JavaScript 本身无法做到这一点)。因此,我们将使用一个名为“getter.php”的文件,该文件将返回我们需要的内容。
首先,我们需要一个非常简单的数据库来提取数据

CREATE TABLE `dd_vals` (
`index` int(11) NOT NULL,
`category` varchar(255) NOT NULL,
`dd_val` varchar(255) NOT NULL,
UNIQUE KEY `index` (`index`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `dd_vals` (`index`, `category`, `dd_val`) VALUES (1, 'snacks', 'Chips'),
(2, 'snacks', 'Cookies'),
(3, 'beverages', 'Coffee'),
(4, 'beverages', 'Coke');
现在,我们可以查询数据库,在“dd_vals”表中查找类别为零食或饮料的条目,并获取我们想要的内容。我们的查询需要类似于以下内容
SELECT * FROM dd_vals WHERE category='beverages'
因此,让我们创建我们的 getter.php 文件,连接到该数据库,并获取类别选择作为 GET 参数,将其插入查询中,并返回它在 option 标签中找到的内容。
<?php
$username = "username";
$password = "password";
$hostname = "localhost";
$dbhandle = mysql_connect($hostname, $username, $password) or die("Unable to connect to MySQL");
$selected = mysql_select_db("dropdownvalues", $dbhandle) or die("Could not select examples");
$choice = mysql_real_escape_string($_GET['choice']);
$query = "SELECT * FROM dd_vals WHERE category='$choice'";
$result = mysql_query($query);
while ($row = mysql_fetch_array($result)) {
echo "<option>" . $row{'dd_val'} . "</option>";
}
?>
现在我们的 JavaScript 非常简单,我们再次监控第一个下拉菜单的更改,并将 getter.php 文件加载到第二个下拉菜单中。这里的花招是将第一个下拉菜单的值作为 URL 参数传递给 getter.php 文件。
$("#first-choice").change(function() {
$("#second-choice").load("getter.php?choice=" + $("#first-choice").val());
});
对于非常小的网站和孤立的示例,数据库可能感觉工作量很大甚至过头了,但这无疑是最灵活的选择。代码干净,速度快,数据以一种我们可以做任何事情的方式存储等等。
不只是这些?
就像 Web 上的任何东西一样,还有更多方法可以解决这个问题。我们可以将值存储在关联数组中。我们可以使用 MongoDB。我们可以将不同的选择元素准备好放在 HTML 中,并根据需要使用 JavaScript 显示和隐藏它们。每种方法都有其优点和缺点。
注意:我没有将数据库示例包含在下载文件中,因为在您拥有自己的数据库可以连接到并进行所有操作之前,它将无法运行。这样会更简洁明了。
这真是一个很棒的教程,非常有用!感谢 Chris!
棒极了
我最近不得不解决这个问题;最初我使用了 JSON,但事实证明这不是一个好主意。JSON 会给每个操作带来一些延迟,事实证明我的几个用户在断开 Wi-Fi 连接时遇到了问题,并且请求会静默失败;我所做的是将整个选择数据存储在 html 中(json_encode()万岁!),并只更改了我的原始 json 获取函数以使用它。
标记可能不如这种方式干净,但我的用户非常满意,这就是最重要的。
如果我理解正确,那么您并没有使用任何“外部”数据来动态填充表单… 您只是使用了一个预定义的 js 数组/对象,其中包含所有可能的元素…
这可能是一种简单的方法,前提是您只有非常有限的元素数量(如通常情况一样),否则我认为您应该优先考虑使用异步请求的动态解决方案。
@Loige,如果我理解 Crafty_Shadow 的意思,我认为他正在使用外部动态数据。从他的描述来看,他似乎正在使用 PHP 从数据库中提取一个数组,然后将其回显到已服务的页面的原始 HTML 中。这使他能够动态更新数据库中的字段,而无需 AJAX 调用,因为数据库内容已嵌入到原始页面中。
虽然这种解决方案对于少量项目来说是可取的,但如果数据库扩展到成千上万个项目,则可能建议返回到更传统的 AJAX 方法,因为已服务 HTML 文件的大小会不必要地膨胀。
@Benjamin
这正是我想表达的意思!
感谢您提供更清晰的解释!您的英语比我好得多 :P
太酷了。过去要做到这一点需要很多工作和代码。干得好!
非常棒的教程,我已经做了一个类似的脚本,但方式略有不同,但您的脚本非常棒!我学习了一些以前从未见过的函数。
祝您度过愉快的一天
Chris,一如既往的棒,谢谢!
看起来演示中“请选择”选项缺少一个值。
<pre>
<option value=”base”>请从上面选择</option>
</pre>
我真的很喜欢不同的选项。很棒的教程,感谢你的提示。
所有3个示例都使用 $(“#first-choice”).change(function() {…});
在第一个列表更改时触发 $.load。但是当页面重新加载或使用后退按钮时会发生什么?通常,您会在列表 #1 中获得与默认值不同的值,但在列表 #2 中却没有任何选项。
额外的 $(“#first-choice”).change(); 命令将强制脚本在页面加载后立即加载正确的第二个列表。您甚至可以将其附加到主命令的末尾,如下所示
$("#first-choice").change(function() {
$("#second-choice").load("getter.php?choice=" + $("#db-one").val());
}).change();
难道不应该
$("#first-choice").change(function() {
$("#second-choice").load("getter.php?choice=" + $("#db-one").val());
}).trigger("change");
使用
trigger()
方法…是的。jQuery 关于 .change() 的第一句话是
“此方法是第一种变体中 .bind(‘change’, handler) 和第二种变体中 .trigger(‘change’) 的快捷方式。”
所以两种方法都可以。感谢你指出这一点。我一直都在使用 $.click() 或 $.change(),不知道它们是 trigger() 方法的快捷方式。
@Rob Young
感谢你指出…
据我所知,使用 trigger 会真正模拟事件激活(并创建并传递到回调函数的事件对象)。因此,调用会冒泡,并且可以停止传播…
也许我错了,但我认为你不能通过粗略地调用事件函数来做到这一点…
我将深入研究文档以更好地理解库的这个方面;)
对于最后一段代码,$(“#db-one”).val() 不应该是 $(this).val() 或 $(“#first-choice”).val()!?
是的,谢谢你,为了在书面文章中清晰起见,我更改了 ID,但漏掉了。已修复。
你能使用 SQLite 制作一个数据库演示的独立版本吗?
我对 SQLite 不太了解,但这将很棒。如果你能把它弄好,我很乐意写一篇后续文章。
SQLite 与 MySQL 相当。区别在于它没有存储在屏幕背后的主服务器上并从内存中访问,而是 SQLite 数据库是您 FTP 中的单个文件,您可以使用 PHP 打开并在其中进行读写,就像 MySQL 一样。
不过,有一些问题
* 如果它变大了,就会很慢(无论何时需要来自它的数据,都需要从硬盘驱动器“打开”整个文件
* 锁定(两个人不能同时访问)。虽然这种情况在实践中并不常发生,但它确实令人沮丧。
好处是
* 它不需要用户名/密码或任何“后端”内容。创建时间并具有对它的读写访问权限(CHMOD)就足够了,它就可以运行。这意味着如果你正在构建一个轻量级应用程序,你不想让客户在 Phpmyadmin 中设置东西,使用 SQLite 可以上传并运行(PHP 脚本甚至可以创建 SQLite,如果它还不存在)。
PHP5 示例
* http://devzone.zend.com/article/760
* http://www.switchonthecode.com/tutorials/php-tutorial-creating-and-modifying-sqlite-databases
你好,
我创建了数据库和文件,但它不起作用。
谢谢,
我有一个 index.html
我在哪里看到的?;) http://screenr.com/AKZ
非常棒的教程,而且比我想象的容易多了。
不错的方法,
为了进一步防弹功能,你可以使用相同的表在 php 中让整个系统工作
+-------+----------+----------+
| 索引 | 类别 | dd_val |
+-------+----------+----------+
| 1 | 零食 | 薯条 |
| 2 | 零食 | 曲奇 |
| 3 | 饮料 | 可乐 |
| 4 | 饮料 | 咖啡 |
+-------+----------+----------+
在第一个下拉菜单中,你只加载类别,在第二个下拉菜单中,你加载所有 dd_val。用户提交表单后,您交叉检查类别是否与 dd_val 匹配,如果匹配,则按计划进行,否则抛出错误。
一旦这部分工作,您就可以使用 jquery 层根据第一个下拉菜单中选择的类别填充第二个列表中的正确 dd_val。
这样,如果 javascript 不起作用,您就有一个不错的后备方案(无论是因为用户在浏览器中禁用了该功能,还是因为 javascript 本身存在错误)。
我喜欢阅读你的文章。对于 json 部分,我建议
{
"beverages": "Coffee,Coke",
"snacks": "Chips,Cookies"
}
更改为
{
"beverages": ["Coffee", "Coke"],
"snacks": ["Chips", "Cookies"]
}
它使用了一些额外的字符,但更好地捕捉了数据结构的意图。
此外,它消除了调用
split
方法的需要,因为值已经位于数组中。这正是我要说的 :) 使用 JSON 就像预期的那样。
作为一名 javascript 爱好者,我一直都在寻找像你这样的评论,Steven ;) 在该列表中使用数组将允许你编写类似
vals = data[key] || [‘Please choose from above’];
它从数据中通过键获取列表,如果它未定义,则回退到 [‘please choose’]
但这可能与本文无关,本文很好地展示了一些选项。
这太棒了,非常感谢。
几个月前我一直在绞尽脑汁地试图弄清楚这一点……最后放弃了。
感谢你的教程,太棒了,正如大家所说,过去需要大量编码,现在只需两行简单易懂的 jquery 和 php 即可。
PHP 代码容易受到 SQL 注入攻击,因为你没有对 $choice 变量进行转义。此外,你正在使用旧的 MySQL 库(现在已弃用),因此它只适用于 MySQL。我建议将其更改为使用 PDO,它更新且适用于几个数据库(SQLite、PostgreSQL、MySQL 等)。
参见:http://www.webdevrefinery.com/forums/topic/1272-your-mysql-code-sucks/
感谢你发布了一篇关于动态下拉菜单的优秀文章,以及三种方法,一些不错的想法,我们喜欢使用数据库,如所说,是为了灵活、干净的代码和可扩展性。LT
Remy Sharp 已经有一个名为 JQuery Select Chain 的插件,http://remysharp.com/2007/09/18/auto-populate-multiple-select-boxes/,它为该功能提供了一个包装器。
我们经常使用它,我们所要做的就是编写一个 PHP 包装函数,从数组中的值生成一个 JSON 字符串,以便值的来源无关紧要,无论是来自数据库、文件还是 web 服务。
我同意 Steven Albano 的观点,我还会将基本值添加到 json 中,而不是将其保留在代码中。
添加选项不起作用,因为没有函数调用。
检查jsfiddle,看看我如何编写代码。
与其他两种方法相比,MySQL 的方法有点笨拙,有时请求速度非常慢,需要几秒钟才能完成。除非没有其他选择,否则最好不要使用这种方法。
啊.. 我看到过时的 mysql_*-Function。
不过教程很好。
嗨,Chris,很棒的教程。我下载了文件,它运行良好且易于遵循,但在 Google Chrome 上无法运行(在 FF 上运行良好)。只有我遇到这个问题吗?
嗨,
感谢这个很棒的教程;)
我在使用数据库的动态下拉列表时遇到了问题。
我创建了 3 个菜单:第二个菜单依赖于第一个,第三个菜单依赖于第二个。
但是有一个问题。第二个菜单包含一些带空格的元素和一些单个单词的元素。
对于单个单词的元素,一切正常。
但是当我选择一个由两部分组成的元素(包含空格)时,第三个菜单没有显示任何结果!
你怎么认为?空格有什么问题?
我找到了解决方案
你需要为变量添加 escape()!这样空格就不会再有问题了;)
escape($(this).val())
你最好将它添加到你的代码中,使其完美:D
$(“#first-choice”).change(function() {
$(“#second-choice”).load(“textdata/” + $(this).val() + “.txt”);
});
再见,再次感谢
@cristi
我将选项 3:使用数据库上传到这里:http://rapidshare.com/files/428684871/dropdown.rar
将“dropdown”文件夹放到你的“www”文件夹中。在 phpMyAdmin 中创建新数据库并将其命名为“dropdown”。然后导入 dd_vals.sql 文件,该文件可以在 rar 文件中找到,这样你就可以使用了。希望对你有帮助。
很高兴看到如此深入地讨论如此高级的设计主题。我已经做了好几年的网页设计了,我真的希望像这样的资源在我刚开始的时候就存在。如果这样,我的网页设计生涯可能会更进一步。
我也无法使 JSON 示例正常工作(将选择选项推送到 $secondChoice 时缺少函数调用)。David 的 jsfiddle 链接非常有帮助。
您好,关于使用文本文件的方法.. 如何扩展代码以允许超过两个下拉字段?
列表 1 填充列表 2..
列表 2 填充列表 3..
列表 3 填充列表 4..
谢谢。
嗨,
我看到了你的教程。它似乎是一种非常容易处理下拉菜单的方法。但很抱歉地说,我无法获得输出。我收到的错误消息是“Undefined index: choice in”
需要你的帮助。
Ripon
嗨,
你的教程非常有帮助,但我对第三个示例有麻烦。如果你能再次上传(链接已断开)就好了。
如果不过分的话,我想在不创建 getter.php 之类的外部文件的情况下完成所有操作。
抱歉,你如何更改或添加更多选项到这个下拉系统中。
这些示例中的任何一个都可以在本地主机上运行吗?我下载了你的源文件并尝试从本地主机进行测试。文本示例和 Json 都无法从该位置运行。我的本地主机连接正常。谢谢
非常感谢 Chris Coyier,这真的是一个很棒的教程,我想问你一个问题,如何在第三个示例(数据库示例)中使用 PDO