织梦的联动类别功能非常强大,常用于地区选择、职位分类、品牌筛选等场景,它的调用方法比普通栏目和文章要稍微复杂一些,核心在于使用 {dede:sql} 标签直接查询数据库。

下面我将分步讲解,从最基础的调用到更复杂的联动菜单实现。
第一步:理解联动类别的数据结构
在调用之前,必须先理解织梦是如何存储联动类别数据的,它主要涉及两个数据表:
#@sys_enum:存储联动类别的“顶级分类”(也就是你在后台添加的“地区”、“职位”等大项)。#@sys_enum:也存储具体的“子分类”,通过evalue字段和ename字段建立层级关系。
evalue:分类的值,同时也是其父分类的ID,顶级分类的evalue通常为0。ename:分类的名称。eorder:排序权重,数字越小越靠前。issign:是否允许前台投稿选择,0为允许,1为不允许。typeid:联动类别ID,这个非常重要,用于区分不同的联动类型(比如地区和职位是不同的typeid)。
示例数据:
假设我们有一个联动类别“地区”,其 typeid 为 1。
| id | ename | evalue | egroup | eorder | issign | typeid |
|---|---|---|---|---|---|---|
| 1 | 顶级分类 | 0 | 0 | 0 | 1 | |
| 2 | 亚洲 | 1 | 1 | 0 | 1 | |
| 3 | 中国 | 2 | 1 | 0 | 1 | |
| 4 | 广东 | 3 | 1 | 0 | 1 | |
| 5 | 北京 | 3 | 2 | 0 | 1 | |
| 6 | 欧洲 | 1 | 2 | 0 | 1 | |
| 7 | 法国 | 6 | 1 | 0 | 1 | |
| 8 | 德国 | 6 | 2 | 0 | 1 |
从上表可以看出:

ename为“亚洲”的记录,其evalue为1。ename为“中国”的记录,其evalue为2,而“亚洲”的id也是2,这说明“中国”的父级是“亚洲”。ename为“广东”的记录,其evalue为3,而“中国”的id也是3,这说明“广东”的父级是“中国”。
理解了这个结构,我们就可以用SQL语句来查询任意层级的数据了。
第二步:基础调用(获取所有顶级分类)
假设我们要调用一个 typeid 为 1 的联动类别的所有顶级分类(亚洲、欧洲、北美洲...)。
在需要调用的模板文件(如 index.htm, list_article.htm 等)中,使用以下代码:
{dede:sql sql="SELECT id, ename FROM `#@__sys_enum` WHERE egroup = 'smalltypes' AND evalue = 0 AND typeid = 1 ORDER BY eorder ASC"}
<li>
<a href="[field:ename function='MakeOneDir(@me)'/]">[field:ename/]</a>
</li>
{/dede:sql}
代码解析:
sql="...":这是SQL查询语句。SELECT id, ename:选择要查询的字段,id用于后续获取子分类,ename是分类名称。FROM#@__sys_enum`指定查询的数据表,#@__`是织梦表前缀的占位符。WHERE egroup = 'smalltypes':重要!egroup字段通常存储的是联动类别的英文标识(如'region', 'job'等),这个值是在你后台添加联动类别时输入的“字段名”,如果你不确定,可以去后台的“核心 -> 联动类别”里查看你添加的类别,找到对应的“字段名”。AND evalue = 0:这是筛选顶级分类的关键条件,因为顶级分类的evalue都为0。AND typeid = 1:指定要调用的联动类别ID,这个ID可以在后台联动类别管理页面看到。ORDER BY eorder ASC:按照后台设置的排序进行升序排列。[field:ename/]:循环输出每个顶级分类的名称。[field:ename function='MakeOneDir(@me)'/]:这是一个函数,用于将分类名转换为拼音或英文,用作URL路径。“亚洲”会变成“ya-zhou”,你也可以直接用[field:id/]来拼接URL。
第三步:递归调用(实现多级联动菜单)
这是最常用也最复杂的情况,比如我们要做一个“省-市-区”三级联动菜单,由于织梦模板本身不支持递归,我们需要借助PHP和JavaScript来实现。
这里我们以一个经典的“省-市-区”三级联动菜单为例,假设联动类别的typeid为1。
在模板文件中放置HTML结构
<!-- 省份选择 -->
<select name="province" id="province">
<option value="0">请选择省份</option>
{dede:sql sql="SELECT id, ename FROM `#@__sys_enum` WHERE egroup = 'smalltypes' AND evalue = 0 AND typeid = 1 ORDER BY eorder ASC"}
<option value="[field:id/]">[field:ename/]</option>
{/dede:sql}
</select>
<!-- 城市选择 -->
<select name="city" id="city">
<option value="0">请先选择省份</option>
</select>
<!-- 区县选择 -->
<select name="district" id="district">
<option value="0">请先选择城市</option>
</select>
编写JavaScript代码处理联动逻辑
在HTML下方,加入以下 <script> 代码:
<script type="text/javascript">
// 获取下拉框元素
var provinceSelect = document.getElementById('province');
var citySelect = document.getElementById('city');
var districtSelect = document.getElementById('district');
// 省份选择改变时,加载对应的城市
provinceSelect.onchange = function() {
var provinceId = this.value;
// 清空城市和区县下拉框
citySelect.innerHTML = '<option value="0">请选择城市</option>';
districtSelect.innerHTML = '<option value="0">请先选择城市</option>';
if (provinceId == 0) return;
// 使用AJAX请求获取城市数据
// 注意:这里需要你创建一个专门用于处理联动请求的PHP文件
var ajax = new XMLHttpRequest();
ajax.open('get', '/plus/get_city.php?pid=' + provinceId, true);
ajax.send();
ajax.onreadystatechange = function() {
if (ajax.readyState == 4 && ajax.status == 200) {
var data = JSON.parse(ajax.responseText);
var html = '<option value="0">请选择城市</option>';
for (var i = 0; i < data.length; i++) {
html += '<option value="' + data[i].id + '">' + data[i].ename + '</option>';
}
citySelect.innerHTML = html;
}
};
};
// 城市选择改变时,加载对应的区县
citySelect.onchange = function() {
var cityId = this.value;
// 清空区县下拉框
districtSelect.innerHTML = '<option value="0">请先选择城市</option>';
if (cityId == 0) return;
// 使用AJAX请求获取区县数据
var ajax = new XMLHttpRequest();
ajax.open('get', '/plus/get_district.php?pid=' + cityId, true);
ajax.send();
ajax.onreadystatechange = function() {
if (ajax.readyState == 4 && ajax.status == 200) {
var data = JSON.parse(ajax.responseText);
var html = '<option value="0">请选择区县</option>';
for (var i = 0; i < data.length; i++) {
html += '<option value="' + data[i].id + '">' + data[i].ename + '</option>';
}
districtSelect.innerHTML = html;
}
};
};
</script>
创建AJAX请求处理文件
上面的JS代码需要两个PHP文件来响应请求:/plus/get_city.php 和 /plus/get_district.php,这两个文件的作用是查询数据库并返回JSON格式的数据。
/plus/get_city.php (获取城市列表)
<?php
require_once(dirname(__FILE__)."/../include/common.inc.php");
// 获取省份ID
$pid = isset($_GET['pid']) ? intval($_GET['pid']) : 0;
// 查询该省份下的所有城市(即evalue等于省份ID的记录)
$sql = "SELECT id, ename FROM `#@__sys_enum` WHERE egroup = 'smalltypes' AND evalue = {$pid} AND typeid = 1 ORDER BY eorder ASC";
$dsql->SetQuery($sql);
$dsql->Execute();
$cities = array();
while ($row = $dsql->GetArray()) {
$cities[] = $row;
}
// 输出JSON格式数据
header('Content-Type: application/json');
echo json_encode($cities);
?>
/plus/get_district.php (获取区县列表)
这个文件的代码和 get_city.php 基本一样,只是注释可以改一下。
<?php
require_once(dirname(__FILE__)."/../include/common.inc.php");
// 获取城市ID
$pid = isset($_GET['pid']) ? intval($_GET['pid']) : 0;
// 查询该城市下的所有区县
$sql = "SELECT id, ename FROM `#@__sys_enum` WHERE egroup = 'smalltypes' AND evalue = {$pid} AND typeid = 1 ORDER BY eorder ASC";
$dsql->SetQuery($sql);
$dsql->Execute();
$districts = array();
while ($row = $dsql->GetArray()) {
$districts[] = $row;
}
// 输出JSON格式数据
header('Content-Type: application/json');
echo json_encode($districts);
?>
将这两个PHP文件上传到网站的 /plus/ 目录下,联动菜单就可以正常工作了。
第四步:高级用法(获取当前文章的联动分类值)
在文章详情页,如果文章使用了联动类别作为自定义字段,如何获取它的值呢?
假设你有一个自定义字段 shengfen (字段名),它关联了typeid为1的联动类别。
在 article_article.htm 模板中:
{dede:field.shengfen/}
这会直接输出分类的evalue(3),这通常不是我们想要的。
我们需要根据evalue去查询ename。
{dede:sql sql="SELECT ename FROM `#@__sys_enum` WHERE id = [field:shengfen/] AND typeid = 1"}
当前省份:<strong>[field:ename/]</strong>
{/dede:sql}
代码解析:
[field:shengfen/]:获取文章自定义字段shengfen的值,也就是evalue。WHERE id = [field:shengfen/]:因为联动分类的id和其父级的evalue是相等的,所以我们可以用id来精确查找。AND typeid = 1:确保查询的是正确的联动类别。[field:ename/]:输出查找到的分类名称。
总结与注意事项
- 核心是
{dede:sql}:调用联动类别的核心方法就是通过编写SQL语句查询#@__sys_enum表。 - 关键参数:
typeid:联动类别的ID,用于区分不同类型。egroup:联动类别的“字段名”,用于区分同一ID下的不同分组(虽然通常一个typeid对应一个egroup)。evalue:用于判断层级,evalue=0是顶级,evalue=父级ID是子级。
- 多级联动:对于多级菜单,最标准的实现方式是“HTML + JS + PHP(AJAX)”的模式,将数据库查询的压力分散到前端交互中。
- 性能考虑:频繁的数据库查询会影响性能,对于不常变动的联动数据(如地区),可以考虑将查询结果缓存,或者一次性加载所有数据然后在前端用JS处理。
- 命名规范:在后台添加联动类别时,给“字段名”起一个有意义且唯一的英文或拼音名称,方便前端调用。
希望这份详细的教程能帮助你完全掌握织梦联动类别的前端调用!
