123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- <template>
- <!-- <div class="block">
- <header class="simple-header van-hairline--bottom" :style="{ position: isFixed ? 'fixed' : 'relative' }">
- <i v-if="!isback" class="nbicon nbfanhui" @click="goBack"></i>
- <i v-else></i>
- <div class="simple-header-name">{{ name }}</div>
- <i class="nbicon nbmore moreIcon"></i>
- </header>
- </div> -->
- <van-nav-bar v-if="!isback" :title="name" :border="isBorder" left-arrow @click-left="onClickLeft" :style="barStyle">
- <!-- 右侧语言切换 -->
- <template #right>
- <div class="nav-language">
- <van-button round size="small" class="lang-trigger" @click="showPopover = true">
- <div class="current-lang">
- <img :src="currentLang.flag" class="current-flag" />
- <span class="lang-code">{{ currentLang.code.toUpperCase() }}</span>
- </div>
- </van-button>
- <van-popover v-model:show="showPopover" :offset="[0, 8]" placement="bottom-end" class="lang-popover">
- <van-cell-group>
- <van-cell v-for="lang in languages" :key="lang.code"
- :class="['lang-item', { active: lang.code === currentLang.code }]" @click="handleChangeLanguage(lang)">
- <template #icon>
- <img :src="lang.flag" class="flag" :alt="lang.code">
- </template>
- <div class="lang-content">
- <span class="lang-label">{{ lang.label }}</span>
- <span class="lang-code">{{ lang.code.toUpperCase() }}</span>
- </div>
- </van-cell>
- </van-cell-group>
- </van-popover>
- </div>
- </template>
- </van-nav-bar>
- <van-nav-bar v-else :title="name">
- <!-- 右侧语言切换 -->
- <template #right>
- <div class="nav-language">
- <van-button round size="small" class="lang-trigger" @click="showPopover = true">
- <div class="current-lang">
- <img :src="currentLang.flag" class="current-flag" />
- <span class="lang-code">{{ currentLang.code.toUpperCase() }}</span>
- </div>
- </van-button>
- <van-popover v-model:show="showPopover" :offset="[0, 8]" placement="bottom-end" class="lang-popover">
- <van-cell-group>
- <van-cell v-for="lang in languages" :key="lang.code"
- :class="['lang-item', { active: lang.code === currentLang.code }]" @click="handleChangeLanguage(lang)">
- <template #icon>
- <img :src="lang.flag" class="flag" :alt="lang.code">
- </template>
- <div class="lang-content">
- <span class="lang-label">{{ lang.label }}</span>
- <span class="lang-code">{{ lang.code.toUpperCase() }}</span>
- </div>
- </van-cell>
- </van-cell-group>
- </van-popover>
- </div>
- </template>
- </van-nav-bar>
- </template>
- <script>
- import { ref } from 'vue'
- import { useRouter } from 'vue-router'
- import { useI18n } from 'vue-i18n';
- import { Locale } from 'vant';
- // 引入英文语言包
- import enUS from "vant/es/locale/lang/en-US";
- // 引入简体中文语言包
- import zhCN from "vant/es/locale/lang/zh-CN";
- import jaJP from "vant/es/locale/lang/ja-JP";
- // 引入俄语语言包
- import ruRU from "vant/es/locale/lang/ru-RU";
- // 引入法语语言包
- import frFR from "vant/es/locale/lang/fr-FR";
- // 引入西班牙语语言包
- import esES from "vant/es/locale/lang/es-ES";
- // 引入葡萄牙语语言包
- import ptBR from "vant/es/locale/lang/pt-BR";
- // 引入乌克兰语语言包
- import ukUA from "vant/es/locale/lang/uk-UA";
- export default {
- props: {
- name: {
- type: String,
- default: ''
- },
- back: {
- type: String,
- default: ''
- },
- noback: {
- type: Boolean,
- default: false
- },
- // 是否固定在顶部
- isFixed: {
- type: Boolean,
- default: true
- },
- // 锁定要跳转的页面路径
- targetPath: {
- type: String,
- default: ''
- },
- // 是否显示下边框
- isBorder: {
- type: Boolean,
- default: true
- },
- barStyle: {
- type: Object,
- default: () => ({})
- }
- },
- emits: ['callback'],
- setup(props, ctx) {
- const isback = ref(props.noback)
- const router = useRouter()
- const goBack = () => {
- if (props.targetPath) {
- router.replace({ path: props.targetPath })
- } else if (!props.back) {
- router.go(-1)
- } else {
- router.push({ path: props.back })
- }
- ctx.emit('callback')
- }
- const { locale } = useI18n();
- // 可用语言列表
- const languages = ref([
- { code: 'zh', label: '简体中文', vant: zhCN, flag: 'https://flagcdn.com/cn.svg' },
- { code: 'en', label: 'English', vant: enUS, flag: 'https://flagcdn.com/us.svg' },
- { code: 'ja', label: '日本語', vant: jaJP, flag: 'https://flagcdn.com/jp.svg' },
- { code: 'ru', label: 'Русский', vant: ruRU, flag: 'https://flagcdn.com/ru.svg' },
- { code: 'fr', label: 'Français', vant: frFR, flag: 'https://flagcdn.com/fr.svg' },
- { code: 'es', label: 'Español', vant: esES, flag: 'https://flagcdn.com/es.svg' },
- { code: 'pt', label: 'Português', vant: ptBR, flag: 'https://flagcdn.com/pt.svg' },
- { code: 'uk', label: 'Українська', vant: ukUA, flag: 'https://flagcdn.com/ua.svg' }
- ]);
- // 当前语言
- const currentLang = ref(languages.value.find(l => l.code === locale.value) || languages.value[0]);
- const showPopover = ref(false);
- // 切换语言
- const handleChangeLanguage = async (lang) => {
- currentLang.value = lang;
- locale.value = lang.code;
- // 1. 切换应用语言
- locale.value = lang.code
- // 2. 切换 Vant 语言
- Locale.use(lang.code, lang.vant)
- showPopover.value = false;
- // 3. (可选) 持久化存储
- localStorage.setItem('curLang', lang.code)
- };
- const onClickLeft = () => history.back();
- return {
- goBack,
- isback,
- onClickLeft,
- handleChangeLanguage,
- showPopover,
- languages,
- currentLang
- }
- }
- }
- </script>
- <style lang="less" scoped>
- @import '../common/style/mixin';
- .simple-header {
- // position: fixed;
- top: 0;
- left: 0;
- z-index: 999;
- .fj();
- .wh(100%, 44px);
- line-height: 44px;
- padding: 0 10px;
- .boxSizing();
- color: #404d74;
- background: #fff;
- .simple-header-name {
- white-space: nowrap;
- font-size: 16px;
- font-weight: 600;
- }
- }
- .block {
- width: 100%;
- height: 44px;
- }
- .moreIcon {
- visibility: hidden;
- }
- .current-lang {
- display: flex;
- align-items: center;
- gap: 6px;
- padding: 2px;
- }
- .current-flag {
- width: 20px;
- height: 15px;
- border-radius: 2px;
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
- }
- .lang-code {
- font-size: 14px;
- font-weight: 500;
- color: #333;
- margin-top: 1px;
- }
- .nav-language {
- margin-right: -8px;
- }
- .lang-trigger {
- padding: 4px 8px;
- background: rgba(255, 255, 255, 0.9);
- border: 1px solid #eee;
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
- border: 1px solid #eee;
- /* 边框颜色 */
- color: #2c87c8;
- /* 文字颜色 */
- &:hover {
- border-color: #2c87c8;
- color: #2c87c8;
- background: rgba(77, 106, 221, 0.05);
- }
- }
- /* 点击状态 */
- .lang-trigger:active {
- border-color: #2c87c8;
- color: #2c87c8;
- background: rgba(77, 106, 221, 0.1);
- }
- .globe-icon {
- font-size: 16px;
- color: #666;
- margin-right: 6px;
- }
- .lang-text {
- font-size: 14px;
- font-weight: 500;
- color: #333;
- }
- .lang-popover {
- --van-popover-arrow-size: 8px;
- }
- .lang-item {
- padding: 10px 16px;
- &.active {
- background: #f5f8ff;
- .lang-label {
- color: #2c87c8;
- }
- }
- }
- /* 调整后的样式 */
- .van-cell {
- --cell-vertical-padding: 12px;
- /* 统一垂直间距 */
- display: flex;
- align-items: center;
- /* 主轴线居中 */
- }
- .flag {
- width: 22px;
- height: 16px;
- border-radius: 2px;
- margin-right: 12px;
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
- vertical-align: middle;
- /* 行内元素垂直对齐 */
- position: relative;
- top: -1px;
- /* 微调视觉平衡 */
- }
- .lang-content {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .lang-label {
- line-height: 24px;
- font-size: 14px;
- color: #333;
- gap: 8px;
- }
- .lang-code {
- font-size: 12px;
- color: #2c87c8;
- font-weight: 600;
- /* 增加字重提升可读性 */
- letter-spacing: 0.5px;
- }
- /* 国旗悬停动画 */
- .lang-trigger:hover .current-flag {
- filter: brightness(0.9);
- }
- </style>
|