根据用户选择的第一个条件(如一级分类),动态加载并更新第二个条件(如二级分类或标签)的可选项,并根据最终的选择来展示内容。
下面我将通过一个“产品专题页”的例子,为你提供一个完整、可操作的步骤指南。
场景设定
假设我们要做一个“智能家居”专题页,包含以下筛选条件:
- 一级分类: 智能安防、智能照明、智能家电
- 二级分类:
- 智能安防:智能门锁、摄像头、传感器
- 智能照明:智能灯泡、灯带、开关
- 智能家电:智能音箱、扫地机器人、空调
- 筛选结果: 根据用户选择的“一级分类”和“二级分类”,展示对应的产品列表。
实现步骤
整个过程分为四个主要部分:
- 数据准备: 在后台正确设置好栏目和文章(产品)。
- 模板制作: 编写包含筛选表单和结果列表的HTML模板。
- JS联动逻辑: 编写JavaScript代码实现“一级分类”选择后,“二级分类”的动态加载。
- PHP数据处理: 编织织梦的标签,根据筛选条件查询并展示结果。
第一步:数据准备
-
创建一级分类栏目:
- 在织梦后台【栏目管理】中,创建一个顶级栏目,智能家居专题”。
- 在“智能家居专题”下,创建三个子栏目,分别对应一级分类:
智能安防(栏目ID假设为2)智能照明(栏目ID假设为3)智能家电(栏目ID假设为4)
-
创建二级分类栏目:
- 进入“智能安防”栏目,创建其子栏目:
智能门锁(栏目ID假设为5)摄像头(栏目ID假设为6)传感器(栏目ID假设为7)
- 同理,为“智能照明”和“智能家电”创建各自的二级分类子栏目。
- 进入“智能安防”栏目,创建其子栏目:
-
添加产品内容:
- 将所有产品文章发布到对应的最末级的二级分类栏目中,一个“小米智能门锁”的文章,就应该发布到“智能安防”下的“智能门锁”栏目中。
关键点: 筛选的核心就是利用织梦的栏目ID,一级分类的值是其栏目ID,二级分类的值也是其栏目ID。
第二步:模板制作
在专题页模板文件(通常是 templets/plus/list_special_专题ID.htm 或你自定义的模板文件)中,编写如下HTML结构。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">智能家居专题</title>
<script src="{dede:global.cfg_cmspath/}/static/js/jquery.min.js"></script> <!-- 确保引入了jQuery -->
</head>
<body>
<h1>智能家居专题</h1>
<!-- 筛选表单开始 -->
<div class="filter-form">
<form id="filterForm" action="" method="get">
<!-- 隐藏字段,用于传递专题ID,方便PHP获取 -->
<input type="hidden" name="tid" value="{dede:geturl typeid='0'}" />
<!-- 一级分类选择 -->
<div class="filter-item">
<label for="cat_1">一级分类:</label>
<select name="cat_1" id="cat_1">
<option value="0">请选择</option>
{dede:channel type='son' typeid='1'}
<option value="{dede:field.id/}">{dede:field.typename/}</option>
{/dede:channel}
</select>
</div>
<!-- 二级分类选择(初始为空,由JS动态填充) -->
<div class="filter-item">
<label for="cat_2">二级分类:</label>
<select name="cat_2" id="cat_2">
<option value="0">请先选择一级分类</option>
</select>
</div>
<!-- 提交按钮(可以省略,用JS监听change事件) -->
<button type="submit">筛选</button>
</form>
</div>
<!-- 筛选表单结束 -->
<!-- 结果列表开始 -->
<div class="result-list">
<!-- 这里将由织梦的列表标签填充内容 -->
{dede:list pagesize='10'}
<div class="item">
<a href="[field:arcurl/]">[field:title/]</a>
</div>
{/dede:list}
<!-- 分页 -->
<div class="page">
{dede:pagelist listsize='4'/}
</div>
</div>
<!-- 结果列表结束 -->
</body>
</html>
代码解释:
{dede:channel type='son' typeid='1'}:这个标签用于输出一级分类。typeid='1'指定了父栏目的ID(即“智能家居专题”的ID),type='son'表示只输出其直接子栏目。name="cat_1"和name="cat_2":这两个是表单提交时的字段名,PHP端会通过它们获取用户选择的值。value="{dede:field.id/}":一级分类的option值是其栏目的ID。id="cat_1"和id="cat_2":给select元素设置ID,方便JS进行操作。{dede:list}:这是标准的织梦列表标签,用于显示筛选后的结果。
第三步:JS联动逻辑
在模板的</body>标签之前,添加以下JavaScript代码。
<script type="text/javascript">
$(document).ready(function(){
// 一级分类选择框
var cat1Select = $('#cat_1');
// 二级分类选择框
var cat2Select = $('#cat_2');
// 当一级分类的值发生改变时
cat1Select.change(function(){
// 获取选中项的栏目ID
var parent_id = $(this).val();
// 如果用户选择了“请选择”(值为0),则清空二级分类并返回
if (parent_id == 0) {
cat2Select.empty();
cat2Select.append('<option value="0">请先选择一级分类</option>');
return;
}
// 清空二级分类下拉框,并显示一个加载提示
cat2Select.empty();
cat2Select.append('<option value="0">加载中...</option>');
// 发送AJAX请求,请求服务器获取二级分类
$.ajax({
type: 'POST',
url: '{dede:global.cfg_cmspath/}/plus/ajax_channel.php', // 织梦获取栏目的标准接口
data: {
'parentid': parent_id, // 传递一级分类的ID
'type': 'sun', // 获取子栏目
'_ajax': 1 // 标记为AJAX请求
},
dataType: 'json', // 期望返回JSON数据
success: function(data){
// 请求成功,清空加载提示
cat2Select.empty();
// 如果返回的数据不为空,则循环生成option
if (data && data.length > 0) {
cat2Select.append('<option value="0">请选择</option>');
$.each(data, function(i, item){
cat2Select.append('<option value="' + item.id + '">' + item.typename + '</option>');
});
} else {
// 如果没有子分类,则显示提示
cat2Select.append('<option value="0">暂无二级分类</option>');
}
},
error: function(){
// 请求失败,显示错误信息
cat2Select.empty();
cat2Select.append('<option value="0">加载失败</option>');
}
});
});
// 可选:当二级分类改变时,自动提交表单
cat2Select.change(function(){
// 确保一级和二级都选择了有效的值
if (cat1Select.val() != '0' && $(this).val() != '0') {
$('#filterForm').submit();
}
});
});
</script>
代码解释:
$('#cat_1').change(...):监听一级分类下拉框的change事件。$.ajax(...):这是核心,当一级分类选择后,通过AJAX请求{dede:global.cfg_cmspath/}/plus/ajax_channel.php这个文件。'parentid': parent_id:将选中的一级分类ID作为参数传递过去。'type': 'sun':告诉接口我们要获取子栏目。dataType: 'json':织梦的这个接口会返回一个JSON格式的栏目列表,如[{"id":5,"typename":"智能门锁"}, {"id":6,"typename":"摄像头"}]。success: function(data){...}:在AJAX请求成功后,解析返回的JSON数据,并动态地创建<option>元素,填充到二级分类下拉框中。cat2Select.change(function(){ $('#filterForm').submit(); });:这是一个很好的用户体验优化,当用户选择完二级分类后,表单会自动提交,无需再点击“筛选”按钮。
第四步:PHP数据处理
现在需要修改 {dede:list} 标签,让它能够根据URL参数 cat_1 和 cat_2 来筛选内容。
织梦的 {dede:list} 和 {dede:arclist} 标签本身不支持直接传入自定义的WHERE条件,我们需要使用更灵活的 {dede:sql} 标签来手动构建SQL查询。
将模板中的 {dede:list} 部分替换为以下代码:
<!-- 结果列表开始 -->
<div class="result-list">
<?php
// 获取URL参数
$cat_1 = isset($_GET['cat_1']) ? intval($_GET['cat_1']) : 0;
$cat_2 = isset($_GET['cat_2']) ? intval($_GET['cat_2']) : 0;
// 构建SQL查询条件
$where = " WHERE arc.arcrank > -1 "; // 默认条件:已审核
$typeid = 0; // 默认查询所有栏目
if ($cat_2 > 0) {
// 如果选择了二级分类,则直接按二级分类的ID查询
$typeid = $cat_2;
} elseif ($cat_1 > 0) {
// 如果只选择了一级分类,则按一级分类的ID查询
$typeid = $cat_1;
}
// 如果typeid不为0,则添加到查询条件中
if ($typeid > 0) {
$where .= " AND arc.typeid = '$typeid' ";
}
?>
{dede:sql sql='SELECT arc.id, arc.title, arc.litpic, arc.typeid, tp.typename
FROM dede_archives arc
LEFT JOIN dede_arctype tp ON arc.typeid = tp.id
[!--上面构建的where条件--]
ORDER BY arc.sortrank DESC, arc.id DESC
LIMIT 0, 10'}
<div class="item">
<a href="[field:arcurl/]">[field:title/]</a>
<span>分类:[field:typename/]</span>
</div>
{/dede:sql}
<!-- 分页 -->
<!-- 注意:使用sql标签后,默认的分页标签 {dede:pagelist} 会失效,分页功能需要更复杂的PHP代码来实现,这里先省略。 -->
<div class="page">
<!-- 分页代码 -->
</div>
</div>
<!-- 结果列表结束 -->
代码解释:
<?php ... ?>:在织梦模板中嵌入PHP代码。isset($_GET['cat_1']):获取通过URL传递过来的筛选参数。intval(...):对获取的参数进行整数化处理,防止SQL注入。$where变量:这是SQL查询的WHERE子句,我们初始化了一个基本条件arc.arcrank > -1(只显示审核通过的文章)。- 逻辑判断:
- 优先判断
$cat_2,如果用户选择了二级分类,$typeid就等于二级分类的ID。 $cat_2为空,但$cat_1不为空,$typeid就等于一级分类的ID。- 如果两者都为空,
$typeid保持为0,表示不按栏目筛选。
- 优先判断
{dede:sql}:sql='...':这里直接编写完整的SQL查询语句。[!--上面构建的where条件--]:这是一个占位符,我们需要将PHP变量$where的值插入到这里,在织梦模板中,更规范的写法是直接将PHP逻辑放在标签外面,然后构建完整的SQL字符串。
- 分页问题:使用
{dede:sql}实现分页比较麻烦,因为它不会自动计算总数和生成分页代码,对于数据量大的情况,建议使用{dede:list}并通过修改其底层list.php文件来实现动态筛选,但这涉及到文件修改,更复杂,对于专题页这种数据量通常不大的情况,手动分页或“加载更多”是更简单的方案。
最终优化与总结
- URL美化:默认提交的URL可能是
...?tid=1&cat_1=2&cat_2=5,你可以通过织梦的“伪静态”或“路由”功能,将其美化成.../cat_2/5/这样的形式,但这需要额外的配置。 - 无刷新筛选:上面的JS代码已经实现了无刷新加载二级分类,并且通过
change事件实现了自动提交,整个筛选过程对用户来说是流畅的。 - 扩展性:这个方法可以轻松扩展到三级分类甚至更多,只需要在JS中再嵌套一层AJAX请求,PHP中再增加一个
cat_3的判断逻辑即可。 - 性能:如果产品(文章)数量非常庞大,直接在
dede_archives表里用typeid查询可能会变慢,可以考虑为typeid字段建立索引。
通过以上四个步骤,你就可以在织梦专题页中实现一个功能完善、用户体验良好的联动筛选功能了。
