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
相关产品推荐
相关产品推荐

