You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何简化Wix Mega Menu代码,点击主菜单直接加载过滤后的分类数据

Wix Velo 超级菜单实现问题及解决方案

问题背景

我正在开发一个Wix网站,目前卡在超级菜单的逻辑调整上。现有4个内容管理器数据库存储菜单相关数据:

  • 第一个数据库为mainMenu,用于填充站点顶部的主菜单按钮,点击按钮可展开对应分类的子菜单
  • 第二个数据库名为subMenu,根据点击的主菜单按钮过滤数据,展示子分类名称的独立菜单,当前逻辑下点击子菜单按钮才会打开超级菜单
  • 第三个数据库为productsMenu,用于填充超级菜单展示的所有产品分类,根据点击的子菜单按钮过滤数据
  • 第四个数据库为newMenu,仅用于填充超级菜单右侧的图片和文本

当前逻辑

点击主菜单按钮 → 展开过滤后的子菜单 → 点击子菜单按钮 → 展开过滤后的超级菜单

期望效果

点击主菜单项 → 直接展开对应该主分类的过滤后超级菜单,子菜单标题作为不同列的表头

现有效果截图:
现有效果:点击「CLOTHING」再点击「WOMEN'S」才会展示超级菜单

期望效果截图:
期望效果:点击「CLOTHING」后直接展示超级菜单,subMenu数据库中的不同子分类作为列标题,productsMenu数据库中的对应分类在列下展示

原有代码

前端页面代码

import { getMenus } from 'backend/data.jsw';

// ID: 5119D613F3A02481B7F825C8A883DE93

let menusData, repeaters;

let selectionState = {
    currMain: null,
    currSub: null,
};

const colors = {
    mainUnselected: 'white',
    subUnselected: 'black',
    selected: 'red'
}

$w.onReady(async function () {
    await iniPage();
});

async function iniPage() {
    try {
        const menus = await getMenus();
        repeaters = menus.menusNames.map(id => ({ menuId: id, repeaterSelector: $w('#' + id + 'Repeater') }));
        menusData = menus.menusData;
        $w('#mainMenuRepeater').data = menusData.mainMenu;
        connectDataToRepeatersItems();
        selectMenu('mainMenu');
    } catch (err) {
        console.error('error ', err);
    }
}

function connectDataToRepeatersItems() {

    repeaters.forEach(({ menuId, repeaterSelector }) => {
        repeaterSelector.onItemReady(($item, itemData) => {
            const $itemBtn = $item('#' + menuId + 'Button');
            if (itemData.name) $itemBtn.label = itemData.name;
            if (itemData.image) $item('#' + menuId + 'Image').src = itemData.image;
            if (itemData.link) $itemBtn.link = itemData.link;
            else $itemBtn.onClick(() => {
                resetColorForPrevSelection(menuId);
                if (menuId === 'mainMenu') {
                    selectionState.currMain = $itemBtn;
                    selectionState.currSub = null;
                } else {
                    selectionState.currSub = $itemBtn;
                }
                $itemBtn.style.color = colors.selected;
                selectMenu(menuId, itemData._id)
            });
        });
    });
}

function resetColorForPrevSelection(menuId) {
    if (menuId === 'mainMenu' && selectionState.currMain) {
        selectionState.currMain.style.color = colors.mainUnselected;
    } else if (selectionState.currSub) {
        selectionState.currSub.style.color = colors.subUnselected;
    }
}

function selectMenu(menu, clickedElementId) {
    let nestedMenus;
    if (menu === 'mainMenu') {
        nestedMenus = ['subMenu'];
        $w('#megaMenuStrip').collapse();
    } else if (menu === 'subMenu') {
        nestedMenus = ['productMenu', 'rangeMenu', 'newMenu'];
        $w('#megaMenuStrip').expand();
    }
    nestedMenus.forEach(nestedMenu => {
        $w('#' + nestedMenu + 'Repeater').data = filterRepeaterData(menu, nestedMenu, clickedElementId);
    });
}

function filterRepeaterData(clickedMenu, nestedMenu, elementId) {
    return menusData[nestedMenu].filter(item => item[clickedMenu] === elementId);
}

后端data.jsw代码

import wixData from 'wix-data';

const menusNames = ['mainMenu', 'subMenu', 'productMenu', 'newMenu'];

export async function getMenus() {

    const collectionsNames = menusNames;
    const promises = [];

    collectionsNames.forEach(collection => {
        promises.push(wixData.query(collection).find());
    });

    const resolvedData = await Promise.all(promises);
    const menusData = {
        'mainMenu': resolvedData[0].items,
        'subMenu': resolvedData[1].items,
        'productMenu': resolvedData[2].items,
        'newMenu': resolvedData[3].items
    };
    return {
        menusNames,
        menusData
    };
}

解决方案

后端代码无需修改,仅调整前端页面的selectMenu和filterRepeaterData两个函数即可实现需求。

修改后完整前端代码

import { getMenus } from 'backend/data.jsw';

// ID: 5119D613F3A02481B7F825C8A883DE93

let menusData, repeaters;

let selectionState = {
    currMain: null,
    currSub: null,
};

const colors = {
    mainUnselected: 'white',
    subUnselected: 'black',
    selected: 'red'
}

$w.onReady(async function () {
    await iniPage();
});

async function iniPage() {
    try {
        const menus = await getMenus();
        repeaters = menus.menusNames.map(id => ({ menuId: id, repeaterSelector: $w('#' + id + 'Repeater') }));
        menusData = menus.menusData;
        $w('#mainMenuRepeater').data = menusData.mainMenu;
        connectDataToRepeatersItems();
        selectMenu('mainMenu');
    } catch (err) {
        console.error('error ', err);
    }
}

function connectDataToRepeatersItems() {

    repeaters.forEach(({ menuId, repeaterSelector }) => {
        repeaterSelector.onItemReady(($item, itemData) => {
            const $itemBtn = $item('#' + menuId + 'Button');
            if (itemData.name) $itemBtn.label = itemData.name;
            if (itemData.image) $item('#' + menuId + 'Image').src = itemData.image;
            if (itemData.link) $itemBtn.link = itemData.link;
            else $itemBtn.onClick(() => {
                resetColorForPrevSelection(menuId);
                if (menuId === 'mainMenu') {
                    selectionState.currMain = $itemBtn;
                    selectionState.currSub = null;
                } else {
                    selectionState.currSub = $itemBtn;
                }
                $itemBtn.style.color = colors.selected;
                selectMenu(menuId, itemData._id)
            });
        });
    });
}

function resetColorForPrevSelection(menuId) {
    if (menuId === 'mainMenu' && selectionState.currMain) {
        selectionState.currMain.style.color = colors.mainUnselected;
    } else if (selectionState.currSub) {
        selectionState.currSub.style.color = colors.subUnselected;
    }
}

// 调整主菜单点击逻辑,直接加载全部菜单数据并展开超级菜单
function selectMenu(menu, clickedElementId) {
    let nestedMenus;
    if (menu === 'mainMenu') {
        nestedMenus = ['subMenu', 'productMenu', 'newMenu'];
        $w('#megaMenuStrip').expand();
    } else if (menu === 'subMenu') {
        nestedMenus = ['productMenu', 'newMenu'];
    }
    nestedMenus.forEach(nestedMenu => {
        $w('#' + nestedMenu + 'Repeater').data = filterRepeaterData(menu, nestedMenu, clickedElementId);
    });
}

// 新增主菜单维度的产品过滤逻辑
function filterRepeaterData(clickedMenu, nestedMenu, elementId) {
    if (clickedMenu === 'mainMenu' && nestedMenu === 'productMenu') {
        // 先筛选当前主菜单对应的所有子菜单ID
        const relatedSubIds = menusData.subMenu
            .filter(sub => sub.mainMenu === elementId)
            .map(sub => sub._id);
        // 过滤出所有关联子菜单对应的产品
        return menusData[nestedMenu].filter(item => relatedSubIds.includes(item.subMenu));
    }
    return menusData[nestedMenu].filter(item => item[clickedMenu] === elementId);
}

布局调整说明

需要将原来独立的subMenu Repeater移入超级菜单容器#megaMenuStrip中,设置为横向列布局,每个子菜单项作为列头,下方绑定对应筛选后的productMenu Repeater即可实现期望的多列展示效果。


内容的提问来源于stack exchange,提问作者niclozano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 21:06:04