03创建Vue项目并实现全球化
03创建Vue项目并实现全球化
创建Vue项目
vue create client-vue
使用Vuex作为状态管理,用于保存从后台获取的应用程序配置ApplicationConfigurationDto
,该对象包含本地化的所有数据。
安装Vue-Cookies
npm install vue-cookies --force
vue-cookies
用于管理cookie,用户选择的语言类型存放在cookie中。
在main.ts
中添加以下代码:
import Cookies from 'vue-cookies'
.use(Cookies)
安装nswag
npm install nswag --force
配置nswag
使用nswag
生成客户端,在package.json
文件中添加以下代码
"scripts": { "generate-client": "nswag openapi2tsclient /input:https://localhost:7027/swagger/v1/swagger.json /Template:Fetch /UseGetBaseUrlMethod:true /GenerateClientClasses:true /operationGenerationMode:MultipleClientsFromPathSegments /useTransformOptionsMethod:true /useTransformResultMethod:true /clientBaseClass:ClientBase /configurationClass:IConfig /ImportRequiredTypes:true /ExtensionCode:\"import { ClientBase, IConfig } from './clientBase'\" /output:src/api-client/client.ts" },
/Key:value 为命令参数 详情请见
openapi2tsclient
:从Swagger/OpenAPI规范生成TypeScript客户端代码。
input
: 数据或JSON数据本身的文件路径或URL。
Template
: 异步处理的类型('JQueryCallbacks', 'JQueryPromises', 'AngularJS', 'Angular', 'Fetch', 'Aurelia')
UseGetBaseUrlMethod
:指定是否使用基类中的'getBaseUrl(defaultUrl: string)'方法(默认值:false)
GenerateClientClasses
:指定是否生成客户端类。
operationGenerationMode
:操作生成方式('SingleClientFromOperationId' or 'MultipleClientsFromPathSegments').")]
clientBaseClass
客户端代码的基类
configurationClass
客户端代码的配置类
ImportRequiredTypes
:指定是否应该导入所需的类型(默认值:true)。
ExtensionCode
生成的客户端TS文件中的扩展代码,参数为字符串或文件路径
useTransformOptionsMethod
启用请求参数转换方法
useTransformResultMethod
启用响应结果转换方法
output
:输出文件路径(可选)。
nswag 为node_modules\.bin
中的可执行程序,如果没有配置node_modules
文件夹的环境变量,则这里需要用node_modules/.bin/
替代nswag
执行命令
npm run generate-client
创建ClientBase.ts
在api-client
文件夹中创建ClientBase.ts
文件,添加以下代码
/** * Configuration class needed in base class. * The config is provided to the API client at initialization time. * API clients inherit from #ClientBase and provide the config. */ import packageConfig from '../../package.json' import Cookies from 'vue-cookies' export class IConfig { public static readonly acceptLanguageKey = 'acceptLanguage' /** * Returns a valid value for the Authorization header. * Used to dynamically inject the current auth header. */ public getAuthorization (): string { return '' // return 'the-authentication-token' } // 从cookie中获取当前语言 public getAcceptLanguage (): string { const cookies: any = Cookies const acceptLanguage = cookies.get(IConfig.acceptLanguageKey) return acceptLanguage || 'zh-Hans' } } export class ClientBase { private readonly config: IConfig; protected constructor (config: IConfig) { this.config = config } // 请求参数转换方法 protected transformOptions (options: RequestInit): Promise<RequestInit> { options.headers = { ...options.headers, Authorization: this.config.getAuthorization(), myHeader: 'myValue', 'accept-language': this.config.getAcceptLanguage() || '' // 在请求头中添加当前语言 } // 设置跨域请求发送cookie options.credentials = 'include' // 指示请求将使用CORS options.mode = 'cors' options.cache = 'default' console.log('transformOptions', 'options:', options) return Promise.resolve(options) } // 响应结果转换方法 protected transformResult (url: string, response: Response, processor: (response: Response) => Promise<any>): Promise<any> { console.log('transformResult', 'url:', url, response) if (response === null) return Promise.resolve() // 判断响应头内容类型为 text/plain 则直接返回响应文本 const contentType = response.headers.get('content-type') if (contentType != null && contentType.indexOf('text/plain') >= 0) { return response.text() } // 调用回调函数 return processor(response) } // 基类中的 getBaseUrl 用于 client 类拼接API请求地址 protected getBaseUrl (defaultUrl: string, baseUrl?: string): string { if (baseUrl && baseUrl.length > 0) return baseUrl if (defaultUrl && defaultUrl.length > 0) return defaultUrl // 从package.json文件中获取baseUrl return packageConfig.baseUrl } }
从
.json
配置文件读取配置信息必须在shims-vue.ts
文件中添加以下配置
declare module '*.json' { const value: any; export default value; }
实现状态管理
在store
文件夹中添加文件夹Modules\ApplicationConfiguration
。在store\Modules\ApplicationConfiguration
中添加文件interfaces.ts
,添加以下代码
import { ApplicationConfigurationDto } from '@/api-client/client' export default interface Configuration{ applicationConfiguration: ApplicationConfigurationDto // 应用程序配置数据 }
在store\Modules\ApplicationConfiguration
中添加文件index.ts
,添加以下代码
import { AbpClient, ApplicationConfigurationDto } from '@/api-client/client' import { IConfig } from '@/api-client/clientBase' import RootStateTypes from '@/store/interfaces' import { Module } from 'vuex' import Configuration from './interfaces' const ConfigurationModule: Module<Configuration, RootStateTypes> = { namespaced: true, state: { applicationConfiguration: new ApplicationConfigurationDto() }, getters: { getLocalization (state) { return state.applicationConfiguration.localization }, l: (state) => (key:string) => { // 全球化的方法,通过该方法显示各国对应的语言 const localization = state.applicationConfiguration.localization if (localization?.values && localization?.defaultResourceName) { return localization?.values[localization.defaultResourceName][key] } return key } }, mutations: { Set_ApplicationConfiguration (state, data: ApplicationConfigurationDto) { state.applicationConfiguration = data } }, actions: { // 初始化应用程序配置 initApplicationConfiguration (store): Promise<ApplicationConfigurationDto> { if (store.state.applicationConfiguration.timing) { return Promise.resolve(store.state.applicationConfiguration) } const client = new AbpClient(new IConfig()) // 获取应用程序配置,并更新状态 return client.applicationConfiguration() .then(result => { this.commit('ConfigurationModule/Set_ApplicationConfiguration', result) return Promise.resolve(store.state.applicationConfiguration) }) }, // 重置应用程序配置 resetApplicationConfiguration (store): Promise<ApplicationConfigurationDto> { store.state.applicationConfiguration.timing = undefined return this.dispatch('ConfigurationModule/initApplicationConfiguration') } } } export default ConfigurationModule
在store\interfaces.ts
文件的代码给为:
import Configuration from './Modules/ApplicationConfiguration/interfaces' // 定义根状态类型 export default interface RootStateTypes { isLogin: boolean } // 扩展更状态类型 export interface AllStateTypes extends RootStateTypes { // 应用程序配置 ConfigurationModule: Configuration // other state type }
修改store\index.ts
文件的代码为:
import { InjectionKey } from 'vue' import { createStore, Store, useStore as baseUseStore } from 'vuex' import RootStateTypes, { AllStateTypes } from './interfaces' import ConfigurationModule from './Modules/ApplicationConfiguration' export default createStore<RootStateTypes>({ state: { isLogin: false }, getters: {}, mutations: { // }, actions: {}, modules: { ConfigurationModule } }) export const key: InjectionKey<Store<RootStateTypes>> = Symbol('CA3227F5-D73C-4E65-AA3F-BA781CA32231') export function useStore<T = AllStateTypes> (): Store<T> { return baseUseStore<T>(key) }
在main.ts
中添加以下代码:
import store, { key } from '@/store/index'
.use(store, key)
main.ts
完整代码:
import { createApp } from 'vue' import App from './App.vue' import router from './router' import store, { key } from '@/store/index' import Cookies from 'vue-cookies' createApp(App) .use(store, key) .use(router) .use(Cookies) .mount('#app')
在App.vue
里初始化应用程序配置,添加以下代码:
<script lang="ts"> import { defineComponent } from 'vue' import { useStore } from './store' export default defineComponent({ mounted () { const store = useStore() store.dispatch('ConfigurationModule/initApplicationConfiguration') } }) </script>
修改AboutView.vue
文件的代码为:
<template> <div class="about"> <h1>This is an about page</h1> <div> {{ l('LongWelcomeMessage') }} <!--显示对应的语言信息 --> </div> </div> </template> <script lang="ts"> import { defineComponent } from 'vue' import { mapGetters } from 'vuex' export default defineComponent({ components: { // }, data () { return { } }, beforeMount () { // }, mounted () { // }, computed: { // 从状态管理Vuex中映射Get方法到计算属性l中 // 对应的是 `store\Modules\ApplicationConfiguration\index.ts`中Getters中的 l ...mapGetters({ l: 'ConfigurationModule/l' }) }, methods: { // } }) </script>
到此Vue中实现全球化初步完成,还缺语言的切换,现在是默认的中文。
语言选择
在components\selects
文件夹中添加文件LanguageSelect.vue
,添加以下代码:
<template> <select @change="change"> <option v-for="item in options" :key="item.cultureName" :value="item.cultureName" :selected="isSelected(item)" > {{ item.displayName }} </option> </select> </template> <script lang="ts"> import { LanguageInfo } from '@/api-client/client' import { IConfig } from '@/api-client/clientBase' import { useStore } from '@/store' import { defineComponent } from 'vue' export default defineComponent({ setup () { // }, data () { return { data: this.value } }, emits: ['onchange'], watch: { // }, computed: { store () { return useStore() }, // 当前语言 currentCulture () { return this.store.state.ConfigurationModule.applicationConfiguration.localization?.currentCulture?.cultureName }, // 支持的语言项 options () { return this.store.state.ConfigurationModule.applicationConfiguration.localization?.languages || new Array<LanguageInfo>() }, isSelected () { return (item: LanguageInfo) => { return item.cultureName === this.currentCulture } } }, mounted () { // }, methods: { // 当选项更改时,将更改后的值保存进cookie中,并重置应用程序配置 change (event: any) { console.log(event, this.store) this.data = event.target.value // 将选择的语言保存进cookie中 this.$cookies.set(IConfig.acceptLanguageKey, this.data) // 状态管理重置应用程序配置 this.store.dispatch('ConfigurationModule/resetApplicationConfiguration') this.$emit('onchange', this.data) } } }) </script>
将LanguageSelect.vue
组件添加进AboutView.vue
,就可自由切换想显示的语言了。
如此全球化实现完成
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异