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

Next.js三语言切换器开发:如何实现三个数组项位置交换?

问题根因

现有代码存在两个核心问题导致位置置换失效:

  • 硬编码绑定locales[1]、locales[2]作为下拉选项,没有根据当前选中状态动态调整语言列表顺序
  • 仅维护了当前选中语言的单个状态,没有维护整个语言列表的排序状态,无法记录各语言的位置变化
    另外代码中存在语法笔误(locales[1)缺少右方括号),且初始选中值没有和Next.js路由当前的locale对齐,也没有调用路由API完成实际的语言切换。
实现方案

核心逻辑是维护一个排序后的语言列表状态,始终将当前激活语言放在列表首位,下拉选项渲染列表除首位外的剩余元素:

  • 初始化时,将当前路由匹配的locale放在列表首位,剩余语言按默认顺序补全
  • 点击下拉项时,将点击的语言移到首位作为新激活项,原激活项放到被点击语言的原位置,其余语言位置保持不变
  • 切换语言时同步调用Next.js路由API更新页面locale,关闭下拉面板
修复后完整代码
import { useState } from "react";
import { IoMdArrowDropup, IoMdArrowDropdown } from "react-icons/io";
import { useRouter } from "next/router";

const LanguageSwitcher = () => {
  const router = useRouter();
  const allLocales = router.locales || [];
  const currentLocale = router.locale || allLocales[0];
  
  // 维护排序后的语言列表,首位为当前激活语言
  const [sortedLocales, setSortedLocales] = useState<string[]>(() => {
    const restLocales = allLocales.filter(locale => locale !== currentLocale);
    return [currentLocale, ...restLocales];
  });
  const [showLG, setShowLG] = useState(false);

  const handleSwitchLocale = (targetLocale: string, targetPositionInDropdown: number) => {
    // 被点击项在完整排序列表中的索引 = 下拉内索引 + 1(下拉不渲染首位激活项)
    const targetIndexInList = targetPositionInDropdown + 1;
    const originalActiveLocale = sortedLocales[0];

    // 生成新排序列表
    const newSortedList: string[] = [targetLocale];
    for (let i = 1; i < sortedLocales.length; i++) {
      if (i === targetIndexInList) {
        // 原激活项放到被点击语言的原位置
        newSortedList.push(originalActiveLocale);
        continue;
      }
      const currentItem = sortedLocales[i];
      if (currentItem !== targetLocale) {
        newSortedList.push(currentItem);
      }
    }

    setSortedLocales(newSortedList);
    // 同步Next.js路由,保留当前页面路径切换语言
    router.push(router.pathname, router.asPath, { locale: targetLocale });
    setShowLG(false);
  };

  return (
    <div className="z-50 relative">
      <div
        onClick={() => setShowLG(!showLG)}
        className="w-16 p-4 bg-white text-sm font-medium leading-none text-gray-800 flex items-center justify-between cursor-pointer"
      >
        {sortedLocales[0].toUpperCase()}
        <div>
          {showLG ? (
            <IoMdArrowDropup size="15" />
          ) : (
            <IoMdArrowDropdown size="15" />
          )}
        </div>
      </div>
      {showLG && (
        <div className="w-16 mt-2 p-4 bg-white shadow rounded absolute top-11">
          {sortedLocales.slice(1).map((locale, idx) => (
            <p
              key={locale}
              onClick={() => handleSwitchLocale(locale, idx)}
              className={`text-sm leading-normal text-gray-800 ${idx !== 0 ? 'mt-4' : ''} cursor-pointer hover:text-gray-600`}
            >
              {locale.toUpperCase()}
            </p>
          ))}
        </div>
      )}
    </div>
  );
};
export default LanguageSwitcher;
逻辑验证(以三语en/zh/ja为例)
  • 初始状态:激活en,列表顺序为['en','zh','ja'],下拉显示次级zh、三级ja
  • 点击三级位置的ja:新激活为ja,原激活en移动到ja原属的三级位置,新列表为['ja','zh','en'],下拉显示次级zh、三级en
  • 再点击次级位置的zh:新激活为zh,原激活ja移动到zh原属的次级位置,新列表为['zh','ja','en'],下拉显示次级ja、三级en
    完全符合你需要的位置置换规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:48:44