浏览代码

feat(语言切换): 优化语言切换逻辑和URL参数验证

本次提交主要进行了以下修改:
1. 在 `LanguageSwitcher.vue` 中更新了语言切换逻辑,使用新的URL构建方式替代页面重载,提升用户体验。
2. 在 `products/index.vue` 中添加了URL参数的有效性验证,确保分类和标签参数的正确性,避免无效参数影响页面状态。
3. 更新了路由逻辑,使用 `router.replace` 方法清除无效的分类和标签参数,优化了用户的导航体验。

这些改动旨在提升多语言支持的流畅性和产品页面的可用性。
master
lizhuang 3 个月前
父节点
当前提交
b95826bbdd
共有 2 个文件被更改,包括 106 次插入7 次删除
  1. 11
    1
      components/LanguageSwitcher.vue
  2. 95
    6
      pages/products/index.vue

+ 11
- 1
components/LanguageSwitcher.vue 查看文件

*/ */
import { ref, computed, onMounted, onBeforeUnmount } from "vue"; import { ref, computed, onMounted, onBeforeUnmount } from "vue";
import { useI18n } from "#imports"; import { useI18n } from "#imports";
import { useRouter } from "vue-router";


// 定义语言代码的类型,应该与 i18n 配置中的一致 // 定义语言代码的类型,应该与 i18n 配置中的一致
type LocaleCode = "zh" | "en" | "ja"; // 你需要根据你的 i18n 配置更新这个类型 type LocaleCode = "zh" | "en" | "ja"; // 你需要根据你的 i18n 配置更新这个类型


const { locale, locales, setLocale } = useI18n(); const { locale, locales, setLocale } = useI18n();
const router = useRouter();
const currentLocale = computed(() => locale.value); const currentLocale = computed(() => locale.value);
const isDropdownOpen = ref(false); const isDropdownOpen = ref(false);
const dropdownContainerRef = ref(null); const dropdownContainerRef = ref(null);
try { try {
// 使用类型断言,确保 langCode 是有效的 LocaleCode // 使用类型断言,确保 langCode 是有效的 LocaleCode
await setLocale(langCode as LocaleCode); await setLocale(langCode as LocaleCode);
window.location.reload();
// 获取当前路径(不包含查询参数)
const path = window.location.pathname;
// 构建新URL,不包含任何查询参数
const newUrl = `${window.location.origin}${path}`;
// 使用新URL替换当前URL并刷新页面
window.location.href = newUrl;
} catch (error) { } catch (error) {
console.error("Failed to set locale:", error); console.error("Failed to set locale:", error);
// 这里可以添加用户反馈,例如显示一个错误提示 // 这里可以添加用户反馈,例如显示一个错误提示

+ 95
- 6
pages/products/index.vue 查看文件

</div> </div>


<div <div
v-if="getCategoryTags(category)?.length > 0 && selectedCategory"
v-if="
getCategoryTags(category)?.length > 0 &&
selectedCategory
"
class="flex flex-wrap gap-4" class="flex flex-wrap gap-4"
> >
<span <span
usages.value = uniqueUsages.value; usages.value = uniqueUsages.value;
categories.value = categoryTitles.value; categories.value = categoryTitles.value;
filteredProducts.value = paginatedProducts.value; filteredProducts.value = paginatedProducts.value;

// 验证URL参数中的分类和标签是否有效
if (selectedCategory.value) {
const categoryExists = allCategories.value.some(
(c: Category) => c.title === selectedCategory.value
);

if (!categoryExists) {
// 如果分类不存在于当前语言环境,清除分类和标签参数
selectedCategory.value = "";
selectedTag.value = "all";

// 更新路由,移除无效的参数
router.replace({
query: {
...route.query,
category: undefined,
tag: undefined,
},
});
} else if (selectedTag.value !== "all") {
// 检查标签是否在当前分类中存在
const categoryTags = getCategoryTags(selectedCategory.value);
if (!categoryTags.includes(selectedTag.value)) {
selectedTag.value = "all";

// 更新路由,移除无效的标签参数
router.replace({
query: {
...route.query,
tag: undefined,
},
});
}
}
}
} catch (err) { } catch (err) {
console.error("Error processing data:", err); console.error("Error processing data:", err);
error.value = new Error(t("products.processError")); error.value = new Error(t("products.processError"));
selectedTag.value = "all"; selectedTag.value = "all";
currentPage.value = 1; // 重置页码 currentPage.value = 1; // 重置页码
filteredProducts.value = paginatedProducts.value; filteredProducts.value = paginatedProducts.value;
// 更新路由,移除tag参数 // 更新路由,移除tag参数
router.push({ router.push({
query: { query: {
...route.query, ...route.query,
category: category, category: category,
tag: undefined, // 清除tag参数 tag: undefined, // 清除tag参数
page: currentPage.value > 1 ? currentPage.value.toString() : undefined
}
page: currentPage.value > 1 ? currentPage.value.toString() : undefined,
},
}); });
} }


watch( watch(
() => route.query, () => route.query,
(newQuery) => { (newQuery) => {
// 先保存当前的值,方便后续比较变化
const prevCategory = selectedCategory.value;
const prevTag = selectedTag.value;

// 更新本地状态
selectedCategory.value = newQuery.category?.toString() || ""; selectedCategory.value = newQuery.category?.toString() || "";
selectedUsage.value = newQuery.usage?.toString() || ""; selectedUsage.value = newQuery.usage?.toString() || "";
selectedTag.value = newQuery.tag?.toString() || "all"; selectedTag.value = newQuery.tag?.toString() || "all";
if (page !== currentPage.value) { if (page !== currentPage.value) {
currentPage.value = page; currentPage.value = page;
} }

// 如果数据已加载完成,则验证URL参数的有效性
if (allCategories.value.length > 0 && allProducts.value.length > 0) {
// 检查分类是否有效
if (selectedCategory.value && prevCategory !== selectedCategory.value) {
const categoryExists = allCategories.value.some(
(c: Category) => c.title === selectedCategory.value
);

if (!categoryExists) {
// 如果分类不存在,重置选择并更新路由
selectedCategory.value = "";
selectedTag.value = "all";

// 使用replace而不是push,避免在历史记录中添加新条目
router.replace({
query: {
...route.query,
category: undefined,
tag: undefined,
},
});
return; // 提前退出,因为后续更新将由新的路由触发
}
}

// 检查标签是否有效(仅当有选中分类时)
if (
selectedCategory.value &&
selectedTag.value !== "all" &&
prevTag !== selectedTag.value
) {
const categoryTags = getCategoryTags(selectedCategory.value);
if (!categoryTags.includes(selectedTag.value)) {
selectedTag.value = "all";

router.replace({
query: {
...route.query,
tag: undefined,
},
});
}
}
}
}, },
{ deep: true } { deep: true }
); );
router.push({ router.push({
query: { query: {
...route.query, ...route.query,
tag: tag === "all" ? undefined : tag
}
tag: tag === "all" ? undefined : tag,
},
}); });
} }



正在加载...
取消
保存