ECSHOP 本身只支持二级分类(一级分类和二级分类),要实现三级菜单,我们需要对 PHP 代码CSS 样式模板文件 进行修改。

ecshop 三级菜单 模板
(图片来源网络,侵删)

下面我将提供一个完整、详细的步骤,并附上代码示例,你可以直接套用。


实现思路

  1. PHP 逻辑修改

    • 修改获取分类数据的函数,使其能够读取并处理三级分类。
    • 修改传递给模板的分类数据结构,确保模板能正确识别和显示三级分类。
  2. 模板文件修改

    • library/page_header.lbi 文件中,修改循环输出分类的代码,增加一个层级来判断和输出三级分类。
  3. CSS 样式调整

    ecshop 三级菜单 模板
    (图片来源网络,侵删)

    添加新的 CSS 样式来美化三级菜单,使其能够正确悬停和显示,并与一、二级菜单风格保持一致。


第一步:PHP 逻辑修改

这一步是核心,目的是让 ECSHOP 能“认识”并“提供”三级分类的数据。

修改 includes/lib_goods.php 文件

这个文件包含了获取商品分类的主要函数,我们需要修改 get_categories_tree() 函数。

操作步骤:

ecshop 三级菜单 模板
(图片来源网络,侵删)
  1. 打开 includes/lib_goods.php 文件。
  2. 找到 get_categories_tree() 函数。
  3. 找到 if ($categories[$row['cat_id']]['parent_id'] == $parent_id) 这一行。
  4. 在它下面,递归调用函数 get_categories_tree() 的代码块中,进行修改。

修改前(原始代码片段):

// ... 函数内部 ...
foreach ($db->query($sql) as $row) {
    // ...
    if ($categories[$row['cat_id']]['parent_id'] == $parent_id) {
        // ...
        // 递归获取子分类
        $children = get_categories_tree($categories[$row['cat_id']]['cat_id'], $level + 1);
        if ($children) {
            $categories[$row['cat_id']]['children'] = $children;
        } else {
            $categories[$row['cat_id']]['children'] = '';
        }
        // ...
    }
}
// ...

修改后(支持三级分类):

我们需要确保递归调用能一直进行下去,直到没有子分类为止,ECSHOP 的原始代码逻辑上已经支持无限级,但问题出在数据读取和模板处理上,我们这里主要是确保数据结构完整。

关键在于,你需要确保你的数据库中,三级分类的 parent_id 指向了正确的二级分类 ID。

更稳妥的修改方式:

直接替换整个 get_categories_tree() 函数,这个函数在 ECSHOP 2.7.3 和其他版本中基本通用。

/**
 * 获取分类树
 * @param int $parent_id 父分类ID
 * @param int $level 层级
 * @return array 分类树数组
 */
function get_categories_tree($parent_id = 0, $level = 0)
{
    $sql = "SELECT cat_id, cat_name, parent_id, is_show, grade, style, keywords, cat_desc " .
           "FROM " . $GLOBALS['ecs']->table('category') .
           " WHERE parent_id = '$parent_id' AND is_show = 1 ORDER BY sort_order ASC, cat_id ASC";
    $res = $GLOBALS['db']->getAll($sql);
    $arr = array();
    foreach ($res AS $row) {
        // 如果当前分类有子分类,则递归获取
        if (get_categories_count($row['cat_id']) > 0) {
            $row['children'] = get_categories_tree($row['cat_id'], $level + 1);
        } else {
            $row['children'] = ''; // 标记为叶子节点
        }
        $arr[] = $row;
    }
    return $arr;
}

这个版本的函数能正确地构建一个包含无限层级的分类树,如果你的分类结构是 一级 -> 二级 -> 三级$row['children'] 就会包含三级分类的数组。


第二步:模板文件修改

现在数据已经准备好了,我们只需要在模板中把它显示出来。

修改 themes/你的模板名称/library/page_header.lbi 文件

这是网站头部文件,通常主导航菜单都在这里。

操作步骤:

  1. 打开 themes/你的模板名称/library/page_header.lbi 文件。
  2. 找到输出分类的 foreach 循环代码,它通常看起来像这样:
<!-- {foreach from=$categories item=cat} -->
    <li class="nav-item">
        <a href="{$cat.url}">{$cat.cat_name}</a>
        <!-- {if $cat.children} -->
        <div class="sub-category">
            <!-- {foreach from=$cat.children item=child} -->
            <a href="{$child.url}">{$child.cat_name}</a>
            <!-- {/foreach} -->
        </div>
        <!-- {/if} -->
    </li>
<!-- {/foreach} -->

修改后(支持三级菜单):

我们需要在二级分类的循环内部,再增加一个循环来判断和输出三级分类。

<!-- {foreach from=$categories item=cat} -->
    <li class="nav-item">
        <a href="{$cat.url}">{$cat.cat_name}</a>
        <!-- {if $cat.children} -->
        <div class="sub-category">
            <!-- 循环二级分类 -->
            <!-- {foreach from=$cat.children item=child} -->
            <div class="second-level">
                <a href="{$child.url}">{$child.cat_name}</a>
                <!-- {if $child.children} -->
                <div class="third-level">
                    <!-- 循环三级分类 -->
                    <!-- {foreach from=$child.children item=grandchild} -->
                    <a href="{$grandchild.url}">{$grandchild.cat_name}</a>
                    <!-- {/foreach} -->
                </div>
                <!-- {/if} -->
            </div>
            <!-- {/foreach} -->
        </div>
        <!-- {/if} -->
    </li>
<!-- {/foreach} -->

代码解释:

  • 我们给二级分类的外层 div 添加了 class="second-level"
  • 在二级分类的循环中,我们通过 <!-- {if $child.children} --> 判断当前二级分类下是否有三级分类。
  • 如果有,我们就创建一个新的 div 并赋予 class="third-level",然后在这个 div 内部用另一个 foreach 循环输出所有三级分类。

第三步:CSS 样式美化

为了让三级菜单看起来更专业,我们需要添加 CSS 样式,你可以将这些样式添加到你的模板主 CSS 文件中(themes/你的模板名称/style.css)。

/* 1. 隐藏所有二级和三级菜单,默认只显示一级 */
.sub-category, .third-level {
    display: none;
    position: absolute;
    left: 100%; /* 让三级菜单出现在二级菜单的右侧 */
    top: 0;
    background-color: #fff;
    border: 1px solid #ddd;
    padding: 10px;
    min-width: 160px;
    z-index: 1000;
}
/* 2. 当鼠标悬停在一级菜单上时,显示对应的二级菜单 */
.nav-item:hover .sub-category {
    display: block;
}
/* 3. 二级菜单项的样式 */
.second-level {
    position: relative; /* 为三级菜单定位提供参考 */
    padding: 5px 10px;
    white-space: nowrap; /* 防止文字换行 */
}
.second-level a {
    display: block;
    color: #333;
    text-decoration: none;
    padding: 5px 0;
}
.second-level a:hover {
    color: #ff6600;
    text-decoration: underline;
}
/* 4. 三级菜单的样式 */
.third-level {
    /* 样式已经在上面定义,这里可以补充或覆盖 */
    left: 100%; /* 确保在二级菜单右侧显示 */
    top: 0;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.third-level a {
    display: block;
    padding: 3px 10px;
    color: #666;
    text-decoration: none;
    font-size: 14px;
}
.third-level a:hover {
    color: #ff6600;
    background-color: #f9f9f9;
}

CSS 样式说明:

  • display: none;: 默认隐藏二级和三级菜单。
  • hover: 这是 CSS 的核心,当鼠标悬停在 .nav-item (一级菜单) 上时,它的子元素 .sub-category (二级菜单) 会显示 (display: block;)。
  • position: absolute;left: 100%;: 这两个属性是让三级菜单“飞”到二级菜单右侧的关键。absolute 让它脱离文档流,left: 100% 让它的左边框对准父级元素的右边框。
  • .second-level: 为每个二级分类项添加了 position: relative,这样里面的 .third-level 就能相对于它来定位。
  • z-index: 确保菜单显示在其他页面元素之上。

总结与注意事项

  1. 检查分类数据:在动手修改代码前,请务必去 ECSHOP 后台 -> 商品分类 -> 分类管理,确保你的分类层级关系是正确的(手机 -> 品牌 -> 苹果)。
  2. 清除缓存:修改完 PHP 和模板文件后,一定要去 ECSHOP 后台 -> 清除缓存,否则看不到效果。
  3. 模板兼容性:不同的 ECSHOP 模板(如官方默认模板、第三方模板)其 page_header.lbi 文件的结构可能略有不同,请根据你实际文件中的代码进行修改,核心逻辑(嵌套 foreach)不变。
  4. 浏览器兼容性:上述 CSS 代码在现代浏览器中(Chrome, Firefox, Edge, Safari)都能很好地工作,如果需要支持非常古老的浏览器(如 IE),可能需要添加一些额外的 hack 或调整。

按照以上三个步骤,你就可以成功地在你的 ECSHOP 网站上实现一个功能完善、样式美观的三级菜单了。