关于vue-i18n:Vue-中英文转换-vuei18n-的使用

一、装置 npm install vue-i18n二、应用 在 src 下创立 lang 文件夹。 1、筹备语言包本例我筹备了两种语言包,别离是中文和英文:zn、en。在 lang 下创立两个文件,zn.js 和 en.js。 // zn.jsexport default { main:{ message:"音讯", display:"展现" }};// en.jsexport default { main:{ message:"message", display:"display" }}2、筹备翻译的语言环境在 lang 下创立 index.js,应用如上的两种语言包 import Vue from "vue";import VueI18n from 'vue-i18n'import zn from "./zn"import en from "./en"Vue.use(VueI18n); // 全局注册国际化包 // 筹备翻译的语言环境信息const i18n = new VueI18n({ locale: "zn", // 初始化中文 messages: { "zn":zn, "en":en }}); export default i18n3、实现语言翻译在 main.js 中将 i18n 注入 vue 中 ...

January 4, 2023 · 1 min · jiezi

关于vue-i18n:vuei18n国际化

这两天手头的工作是给一个商城我的项目增加多语言。这个商城宏大且简单,是用uniapp+uview ui实现的。商城类的我的项目要增加多语言,不可避免要做大量的文本替换的工作,这么庞杂的一个我的项目怎么能力高效的实现多语言国际化是这篇文章次要要写的货色。 引入vue-i18nvue-i18n是一个vue插件,次要作用就是让我的项目反对国际化多语言,首先咱们在我的项目引入这个插件: cnpm vue-i18nyarn install main.jsimport VueI18n from 'vue-i18n' 增加lang语言文件夹新建zh-cn.json 和 ug.json 封装i18n不便咱们应用新建lang/index.js import Vue from 'vue'import VueI18n from 'vue-i18n'Vue.use(VueI18n);const i18n = new VueI18n({ locale:'zh', messages:{ 'zh':require('@/lang/zh-cn.json'), 'en':require('@/lang/ug.json'), }});if (uni.getStorageSync('locale')) { i18n.locale = uni.getStorageSync('locale')} else { i18n.locale = 'zh-cn'}Vue.prototype._i18n = i18n;export default i18nvue中应用 mounted() { if (uni.getStorageSync('locale')) { this.$i18n.locale = uni.getStorageSync('locale') } else { this.$i18n.locale = 'zh-cn' } this.langobj= this.$t('goods'); },js中应用**import i18n from '../../lang/index'**export default { // 手机号 mobile: [{ required: true, message: i18n.t('shopro.qingshurushoujihao'), trigger: ['change', 'blur'] }, { validator: (rule, value, callback) => { return test.mobile(value); }, message: **i18n.t('shopro.shoujihaomageshibuzhengque'),** trigger: ['change', 'blur'] } ],多语言切换js ...

December 17, 2021 · 1 min · jiezi

Vue2.0 + ElementUI 手写权限管理系统后台模板(三)——页面搭建

框架布局本章只介绍基础布局,和一些主要的js,页面上基本上都是些交互事件,项目代码上都有注释,不懂的地方debug跑一变就知道了,只是这些事件基本上没有独立存在的,相互之间都有关联框架风格新建页面:/src/views/layout/layout.vue<!– layout.vue –><template> <div id=“loyout”> <el-container> <layoutAside></layoutAside> <el-container> <layoutHeader></layoutHeader> <el-main id=“elmain”> <transition name=“main” mode=“out-in”> <router-view></router-view> </transition> </el-main> <el-footer> <Bottom></Bottom> </el-footer> </el-container> </el-container> </div></template>aside 无限级菜单组件新建页面:/src/views/layout/aside/aside.vue<!– aside.vue –><template> <div> <el-aside id=“asideNav”> <div class=“logo-name”> <p v-if="$store.getters.logoShow">XU</p> <p v-else>vue-xuAdmin后台模板</p> </div> <!– el-menu的属性查看官方文档 –> <el-menu :default-active="$route.path" class=“el-menu-vertical” @select=“selectmenu” :collapse="$store.getters.isCollapse" background-color="#03152A" text-color=“rgba(255,255,255,.7)” active-text-color="#ffffff" :router="$store.getters.uniquerouter" :unique-opened="$store.getters.uniquerouter" :collapse-transition=“true” > <!– 遍历根据权限生成的路由表生成菜单列表 –> <template v-for="(item,index) in $store.getters.routers" v-if="!item.hidden"> <!– 检查是否带有alone属性的一级菜单类似“主页”,还有子菜单的个数 –> <el-submenu v-if="!item.alone && item.children.length>0" :index=“index+’’"> <template slot=“title”> <!– 如果没有设置图标将会采用默认图标‘fa fa-server’ –> <i :class=“item.iconCls?item.iconCls:[fa,fa-server]"></i> <span slot=“title”>{{ $t(routeNmae.${item.name}) }}</span> </template> <!– 子菜单组件 –> <menu-tree :menuData=“item.children”></menu-tree> </el-submenu> <!– 一级菜单 –> <el-menu-item :index=“item.path” v-else> <i :class=“item.iconCls?item.iconCls:[fa,fa-file]"></i> <span slot=“title”>{{ $t(routeNmae.${item.name}) }}</span> </el-menu-item> </template> </el-menu> </el-aside> </div></template>点击菜单// aside.vuewatch: { // 监听浏览器直接输入路由,将此路由添加到tabnavBox ‘$route.path’: function (val) { this.selectmenu(val) } }, // 点击菜单把当前菜单的name和path添加到tabNavBox容器,生成tabNav标签页菜单selectmenu (key) { // 获取当前权限路由表 let router = this.$store.getters.routers let name = ’’ // 查找路由的name属性 let navTitle = function (path, routerARR) { for (let i = 0; i < routerARR.length; i++) { if (routerARR[i].children.length > 0 || routerARR[i].path === path) { if (routerARR[i].path === path && routerARR[i].children.length < 1) { name = routerARR[i].name break } // 递归查找 navTitle(path, routerARR[i].children) } } return name } // tabNavBox添加数据 this.$store.dispatch(‘addTab’, { title: navTitle(key, router), path: key }) }子菜单组件 menu-true新建页面:/src/views/layout/aside/menuTree.vue<!– menuTree.vue –><template> <div> <template v-for="(child,index) in menuData”> <el-submenu v-if=“child.children.length > 0” :index=“child.path”> <template slot=“title”> <i :class=“child.iconCls?child.iconCls:[fa,fa-file]"></i> <span slot=“title”>{{ $t(routeNmae.${child.name}) }}</span> </template> <!– 通过递归 menu-tree 生成无限级菜单 –> <menu-tree :menuData=“child.children”></menu-tree> </el-submenu> <el-menu-item v-else :index=“child.path”> <i :class=“child.iconCls?child.iconCls:[fa,fa-file]"></i> <span slot=“title”>{{ $t(routeNmae.${child.name}) }}</span> </el-menu-item> </template> </div></template>header头部这里没啥好说的,都是html布局,tabnav接下来说, i18n后面会讲新建页面:/src/views/layout/header/header.vue<!– header.vue –><template> <div> <el-header id=“header”> <span class=“hideAside” @click=“collapse”><i class=“fa fa-indent fa-lg”></i></span> <ul class=“personal”> <li class=“fullScreen” @click=“fullScreen”> <el-tooltip class=“item” effect=“dark” content=“全屏” placement=“bottom”><i class=“fa fa-arrows-alt fa-lg”></i></el-tooltip> </li> <li> <langSelect></langSelect> </li> <li>{{ $t(role.${this.$store.getters.info.role}) }}</li> <li> <el-dropdown @command=“handleCommand”> <span class=“el-dropdown-link”> 夏洛克丶旭<i class=“el-icon-arrow-down el-icon–right”></i> </span> <el-dropdown-menu slot=“dropdown”> <el-dropdown-item command=“a”>{{ $t(‘userDropdownMenu.basicInfor’) }}</el-dropdown-item> <el-dropdown-item command=“b”>{{ $t(‘userDropdownMenu.changePassword’) }}</el-dropdown-item> <el-dropdown-item command=“logout” divided>{{ $t(‘userDropdownMenu.logout’) }}</el-dropdown-item> </el-dropdown-menu> </el-dropdown> </li> <li class=“icon”><img :src=“avatar”/></li> </ul> </el-header> <!– tabNav 组件,标签页菜单 –> <tabNav></tabNav> </div></template>tabNav 组件这里的tabNav标签动画和页面的动画是一样的,都是官方的demo稍微改一下,,只不过页面有mode=“out-in"所以动画时间需要快一点新建页面:/src/views/layout/header/tabNav.vue<!– tabNav.vue –><template> <div> <div class=“tabnavBox”> <transition-group name=“list” tag=“ul”> <!– tabnavBox 是存储所有tabNav的数据容器,每次点击左侧菜单就会把数据添加到tabnavBox –> <li v-for="(item, index) in $store.getters.tabnavBox” @contextmenu.prevent=“openMenu(item,$event,index)” :key=“item.title” class=“tabnav” :class=”{ active: $route.path === item.path }"> <router-link :to=“item.path”>{{ $t(routeNmae.${item.title}) }}</router-link> <i @click=“removeTab(item)” class=“el-icon-error” v-if=“index !== 0”></i> </li> </transition-group> </div> <!– 右击菜单 –> <ul v-show=“this.rightMenuShow” :style="{left:this.left+‘px’,top:this.top+‘px’}” class=“menuBox”> <li @click=“removeTab($store.getters.rightNav)"><i class=“fa fa-remove”></i>{{ $t(‘rightMenu.close’) }}</li> <li @click=“removeOtherTab($store.getters.rightNav)">{{ $t(‘rightMenu.closeOther’) }}</li> <li @click=“removeAllTab”>{{ $t(‘rightMenu.closeAll’) }}</li> </ul> </div></template> ...

December 17, 2018 · 2 min · jiezi

Vue2.0 + ElementUI 手写权限管理系统后台模板(二)——权限管理

权限验证页面级别权限路由:默认挂载不需要权限的路由,例如:登录、主页。需要权限的页面通过 router.addRoutes(点击查看官方文档) 动态添加更多的路由规则,404拦截页面需要放在路由表的最后,否则 /404 后面的路由会被404拦截,通过路由元信息meta(点击查看官方文档)记录路由需要的权限。为了菜单列表可以被翻译,路由表的 name 属性值通过 i18n 的英文对照表来获取,也可以直接写英文名称,如 name: routeNmae.builtInIcon 可以直接写成 name: “builtInIcon”,凭个人喜好// src/router/index.jsimport en from ‘../i18n/lang/en’ // 路由名字 name import Vue from ‘vue’import Router from ‘vue-router’import CommerViews from ‘@/views/commerViews’import Login from ‘@/views/login/index’import Layout from ‘@/views/layout/layout’import HomeMain from ‘@/views/index/mainIndex’// 不是必须加载的组件使用懒加载const Icon = () => import(’@/views/icon/index’)const Upload = () => import(’@/views/upload/upload’)const Markdown = () => import(’@/views/markdown/markdownView’)const NotFound = () => import(’@/page404’)Vue.use(Router)let routeNmae = en.routeNmae// 不需要权限的路由let defaultRouter = [ { path: ‘/’, redirect: ‘/index’, hidden: true, children: [] }, { path: ‘/login’, component: Login, name: ‘’, hidden: true, children: [] }, { path: ‘/index’, iconCls: ‘fa fa-dashboard’, // 菜单图标,直接填写字体图标的 class name: routeNmae.home, component: Layout, alone: true, children: [ { path: ‘/index’, iconCls: ‘fa fa-dashboard’, name: ‘主页’, component: HomeMain, children: [] } ] }, { path: ‘/404’, component: NotFound, name: ‘404’, hidden: true, children: [] },]// 需要 addRouters 动态加载的路由 let addRouter = [ { path: ‘/’, iconCls: ‘fa fa-server’, name: routeNmae.multiDirectory, component: Layout, children: [ { path: ‘/erji1’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu2-1’], component: Erji, children: [] }, { path: ‘/erji3’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu2-3’], component: CommerViews, // 无限极菜单的容器 超过三级菜单父级容器需要使用 CommerViews children: [ { path: ‘/sanji2’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu3-2’], component: Sanji2, children: [] }, { path: ‘/sanji3’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu3-3’], component: CommerViews, children: [ { path: ‘/siji’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu4-1’], component: Siji, children: [] }, { path: ‘/siji1’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu4-2’], component: CommerViews, children: [ { path: ‘/wuji’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu5-1’], component: Wuji, children: [] } ] } ] } ] } ] }, { path: ‘/’, iconCls: ’el-icon-edit’, // 图标样式class name: routeNmae.editor, component: Layout, meta: {role: [‘superAdmin’, ‘admin’]}, // 需要权限 ‘superAdmin’, ‘admin’。meta属性可以放在父级,验证父级和所有子菜单,也可以放在子级单独验证某一个子菜单 children: [ { path: ‘/markdown’, iconCls: ‘fa fa-file-code-o’, // 图标样式class name: routeNmae.markdown, component: Markdown, children: [] } ] }, { path: ‘*’, redirect: ‘/404’, hidden: true, children: [] },]export default new Router({ routes: defaultRouter})export {defaultRouter, addRouter}然后通过 token 获取当前登录用户的个人信息,在router被挂载到Vue之前和需要权限的路由表做对比,筛选出当前角色的动态路由表,// main.js// 获取角色信息,根据用户权限动态加载路由router.beforeEach((to, from, next) => { if (store.getters.token) { // 查看 token 是否存在 store.dispatch(‘setToken’, store.getters.token) // 每次操作都重新写入 token,延长有效会话时间 if (to.path === ‘/login’) { next({path: ‘/’}) } else { if (!store.getters.info.role) { // 查看是否有当前用户角色,如果没有则获取角色信息 !async function getAddRouters () { await store.dispatch(‘getInfo’, store.getters.token) // 通过token获取角色信息 await store.dispatch(’newRoutes’, store.getters.info.role) // 通过权限筛选新路由表 await router.addRoutes(store.getters.addRouters) // 动态加载新路由表 next({path: ‘/index’}) }() } else { let is404 = to.matched.some(record => { // 404页面拦截 if(record.meta.role){ // 没有权限的页面,跳转的404页面 return record.meta.role.indexOf(store.getters.info.role) === -1 } }) if(is404){ next({path: ‘/404’}) return false } next() } } } else { if (to.path === ‘/login’) { next() } next({path: ‘/login’}) }})actions: getInfo// src/vuex/modules/role.jsstate: { info: ’’ // 每次刷新都要通过token请求个人信息来筛选动态路由 }, mutations: { getInfo (state, token) { // 省略 axios 请求代码 通过 token 向后台请求用户权限等信息,这里用假数据赋值 state.info = { role: ‘superAdmin’, permissions: ‘超级管理员’ } // 将 info 存储在 sessionStorage里, 按钮指令权限将会用到 sessionStorage.setItem(‘info’, JSON.stringify(store.getters.info)) }, setRole (state, options) { // 切换角色,测试权限管理 state.info = { role: options.role, permissions: options.permissions } sessionStorage.setItem(‘info’, JSON.stringify(store.getters.info)); // 权限切换后要根据新权限重新获取新路由,再走一遍流程 store.dispatch(’newRoutes’, options.role) router.addRoutes(store.getters.addRouters) } }, actions: { getInfo ({commit}, token) { commit(‘getInfo’, token) }, setRole ({commit}, options){// 切换角色,测试权限管理,不需要可以删除 commit(‘setRole’, options) } }actions: newRoutes// src/vuex/modules/routerData.jsimport {defaultRouter, addRouter} from ‘@/router/index’const routerData = {state: { routers: [], addRouters: [] }, mutations: { setRouters: (state, routers) => { state.addRouters = routers // 保存动态路由用来addRouter state.routers = defaultRouter.concat(routers) // 所有有权限的路由表,用来生成菜单列表 } }, actions: { newRoutes ({commit}, role) { // 通过递归路由表,删除掉没有权限的路由 function eachSelect (routers, userRole) { for (let j = 0; j < routers.length; j++) { if (routers[j].meta && routers[j].meta.role.length && routers[j].meta.role.indexOf(userRole) === -1) { // 如果没有权限就删除该路由,如果是父级路由没权限,所有子菜单就更没权限了,所以一并删除 routers.splice(j, 1) j = j !== 0 ? j - 1 : j // 删除掉没有权限的路由后,下标应该停止 +1,保持不变,如果下标是 0的话删除之后依然等于0 } if (routers[j].children && routers[j].children.length) { // 如果包含子元素就递归执行 eachSelect(routers[j].children, userRole) } } } // 拷贝这个数组是因为做权限测试的时候可以从低级切回到高级角色,仅限演示,正式开发时省略这步直接使用 addRouter // 仅限演示 let newArr = […addRouter] eachSelect(newArr, role) commit(‘setRouters’, newArr) // 正式开发 // eachSelect(addRouter, role) // commit(‘setRouters’, addRouter) } }}export default routerData按钮级别权限验证通过自定义指令获取当前按钮所需的有哪些权限,然后和当前用户的权限对比,如果没有权限则删除按钮// btnPermission.jsimport Vue from ‘vue’Vue.directive(‘roleBtn’,{ bind:function (el,binding) { let roleArr = binding.value; // 获取按钮所需权限 let userRole = JSON.parse(sessionStorage.getItem(‘info’)).role // 获取当前用户权限 if (roleArr && roleArr.indexOf(userRole) !== -1) { return false } else { el.parentNode.removeChild(el); } }})export default Vue使用自定义指令权限<el-button type=“primary” plain size=“medium”>查看</el-button><el-button type=“primary” plain size=“medium” v-role-btn="[‘admin’]">添加</el-button><el-button type=“danger” plain size=“medium” v-role-btn="[‘superAdmin’]">删除</el-button><el-button type=“primary” plain size=“medium” v-role-btn="[‘superAdmin’,‘admin’]">修改</el-button> ...

December 17, 2018 · 4 min · jiezi

Vue2.0 + ElementUI 手写权限管理系统后台模板(四)——组件结尾

i18n国际化多语言翻译使用框架采用vue-i18n版本 8.4.0,使用npm安装新建文件夹src/i18n,目录如下i18n.js//i18n.jsimport Vue from ‘vue’import locale from ’element-ui/lib/locale’import VueI18n from ‘vue-i18n’import messages from ‘./lang’Vue.use(VueI18n)const i18n = new VueI18n({ locale: localStorage.lang || ‘cn’, messages})locale.i18n((key, value) => i18n.t(key, value))export default i18ni18n/lang/index.js//index.jsimport en from ‘./en’import cn from ‘./cn’export default { en, cn}i18n/lang/cn.jscn.js和en.js 需要要翻译的内容要一一对照,我这里这是参考示例只写了一部分//cn.jsimport zhLocale from ’element-ui/lib/locale/lang/zh-CN’const cn = { home: ‘主页’, routeNmae: { home: ‘主页’, article: ‘文章管理’, ‘menu2-2’: ‘二级-2’, ‘menu2-3’: ‘二级-3’, }, rightMenu: { close: ‘关闭’, closeOther: ‘关闭其他’, closeAll: ‘全部关闭’ } …zhLocale // 合并element-ui内置翻译}export default cni18n/lang/en.js//en.jsimport enLocale from ’element-ui/lib/locale/lang/en’const en = { home: ‘home’, routeNmae: { home: ‘home’, article: ‘article’, ‘menu2-2’: ‘menu2-2’, ‘menu2-3’: ‘menu2-3’ }, rightMenu: { close: ‘close’, closeOther: ‘closeOther’, closeAll: ‘closeAll’ } …enLocale // 合并element-ui内置翻译}export default en多语言切换组件新建src/components/lang/langSelect.vue<!– langSelect.vue –><template> <el-dropdown class=‘international’ @command=“handleSetLanguage”> <div> <span class=“el-dropdown-link”><i class=“fa fa-language fa-lg”></i>&nbsp;{{language}}<i class=“el-icon-arrow-down el-icon–right”></i> </span> </div> <el-dropdown-menu slot=“dropdown”> <el-dropdown-item command=“cn”>中文</el-dropdown-item> <el-dropdown-item command=“en”>English</el-dropdown-item> </el-dropdown-menu> </el-dropdown></template>main.jsimport Vue from ‘./btnPermission’import ElementUI from ’element-ui’import ’element-ui/lib/theme-chalk/index.css’import ‘font-awesome/css/font-awesome.css’import App from ‘./App.vue’import router from ‘./router’import store from ‘./vuex’import i18n from ‘./i18n/i18n’new Vue({ el: ‘#app’, router, store, i18n, render: h => h(App), components: {App}, template: ‘<App/>’})使用:<!– 翻译使用 –><p>message: {{ $t(‘home’) }}</p><p>message: {{ $t(‘routeNmae.article’) }}</p><!– 多语言切换组件调用 –><langSelect></langSelect>vue中使用ECharts具体使用方法可以查看ECharts官网,需要注意的地方就是响应屏幕大小代码如下,在调用组件的页面 mounted () { this.selfAdaption() }, methods: { // echart自适应 selfAdaption () { let that = this setTimeout(() => { window.onresize = function () { if (that.$refs.echarts) { that.$refs.echarts.chart.resize() } } }, 10) } }编辑器-markdown框架目前只封装了markdown,实时获取markdown,html,text三种格式文本,支持内容回填,默认初始值,可以编辑已发布的文章或者草稿引用的Editor.md,点击查看插件更多的使用方法结束vue-xuAdmin 只注重框架基础功能,这几个组件是我最近用到的,更多的组件内容根据项目需求可以自己去封装。如果你感觉这个框架或者这几篇文章对你有所帮助,请去项目git上给个星点个star,感谢!orz项目地址:github:https://github.com/Nirongxu/v…码云:https://gitee.com/nirongxu/xu… ...

December 17, 2018 · 1 min · jiezi