iview-admin之showTitle改造与useI18n

iview-admin之showTitle与useI18n

越来越被自己的无知征服,写了这么长时间的iview-admin竟然不知道useI18n的用途,为什么要说这个呢?还是源于一个需求,就是不同的模块有相同的功能项,比如说个人中心和流程管理里面都有我的流程这个子页面,这时点击任何一个我的流程菜单项都会跳转到位置靠前的路由里面,后面的不会跳转,这是为什么呢?看到这你肯定会说这不合理啊,菜单的名字虽然相同但是对应的跳转路由应该不同啊?是啊,我也是这么想的,因为是从别人手里接受的项目,所以就沿用之前人的写法,而之前人的useI18n设置的是true,这种设置会导致什么结果呢?嗯,没错,会导致你的菜单显示的名字大概率会是你router.js里面的name属性的值(为什么说是大概率呢,后面揭晓),而这个值就是路由跳转的标识,所以就出现了之前的那种状况,即使你的meta.title设置了也不会显示,这也是我纳闷的地方,这种情况我早就发现了,但是原来没有这种同名子菜单的情况,所以就把他给忽略了(按理说name应该起个英文名,但我为了显示中文,苟且的给这个name属性值全都赋了中文值),如今不得不把他给解决掉,在写了一下午bug后兜兜转转的发现了useI18n的秘密,也算是没瞎干一场。

你肯定会问我:干了一下午都干什么了呢?嗯,我告诉你,我是怎么干的,你可不许笑话我,既然meta里的title不好使,那我索性就把每个路由加上一个title属性,赋成中文值,也就是之前name里的值,再把name属性赋了唯一的英文名,像这样

 
/*router.js*/
{
        path: 'split_pane_page',
        name: 'split_pane_page',
        title:'分割窗口'
        meta: {
          icon: 'md-pause',
          title: '分割窗口'
        },
        component: () => import('@/view/components/split-pane/split-pane.vue')
  },

用来做路由标识然后把showtitle方法做了个改造(改造方法放后面),稀里糊涂的改了好长时间也就是在这个过程中对这个useI18n产生了兴趣,于是仔细地读了一下代码,并发现了useI18n的秘密。

这个useI18n到底是干什么的呢?,其实原来我原来看过这个东东,在这个地方@/config/index.js

 * @description 是否使用国际化,默认为false
   *              如果不使用,则需要在路由中给需要在菜单中展示的路由设置meta: {title: 'xxx'}
   *              用来在菜单中显示文字
   */
  useI18n: true,
 

我一看国际化三个字就直接绕过了,这三个字和我实在没什么关系,但实际上却是大有关系,注释里只是说用来在菜单里显示文字,这里说的很笼统只说了如果设置了false就需要设置meta里的title,而且也没说不设置会怎样(会显示name里的文字),也没说设置为true之后会怎样,只给出了三个字‘国际化’,(大概率还是菜单里显示name里的文字,后面揭晓原因)呵呵。那这个useI18n是怎么决定菜单文字显示的呢,没错就是这个showTitle

现在让我们来好好的看一下这个showTitle,让真相彻底大白吧

之前为什么说设置为true大概率会显示name里的文字,看我手写的true下面的前两个if,第一个

  if (title.includes('{{') && title.includes('}}') && useI18n)

这种情况对应的是

  {
        path: 'i18n_page',
        name: 'i18n_page',
        meta: {
          icon: 'md-planet',
          title: 'i18n - {{ i18n_page }}'
        },
        component: () => import('@/view/i18n/i18n-page.vue')
   }

meta里的title是一个带插值的字符串的情况然后执行这个

title = title.replace(/({{[\s\S]+?}})/, (m, str) => str.replace(/{{([\s\S]*)}}/, (m, _) => vm.$t(_.trim())))

用这个$t来实现国际化也就是语言的切换
 

第二个

  else if (__titleIsFunction__) title = item.meta.title

这种情况对应的是

  {
        path: 'params/:id',
        name: 'params',
        meta: {
          icon: 'md-flower',
          title: route => `{{ params }}-${route.params.id}`,
          notCache: true,
          beforeCloseName: 'before_close_normal'
        },
        component: () => import('@/view/argu-page/params.vue')
  },

title是一个函数的运算结果

也就是路由传参的情况,

以上这两种很少用到,所以我说是大概率会是下面这种

 else title = vm.$t(item.name)
也就造成了菜单显示文字和路由的名字混而为一的情况

再看false这种情况

 else title = (item.meta && item.meta.title) || item.name

熟悉js的同学应该能看懂(我就不解释了,看不懂的去看一下js逻辑运算中的短路相关知识点)

如果存在meta和meta.title的话就显示meta.title里的文字,否则显示name里的文字

也就是说我的需求到这就可以实现了,那为什么还要改造呢?

再说回我的改造过程,如果只给路由添加title属性(我自己加的那个name下面的title,不是meta里的)是没用的还需要改一个地方@/libs/util.js


export const getMenuByRouter = (list, access) => {
  let res = []
  forEach(list, item => {
    if (!item.meta || (item.meta && !item.meta.hideInMenu)) {
      let obj = {
        icon: (item.meta && item.meta.icon) || '',
        name: item.name,
        meta: item.meta,
        //我添加的
        title:item.title
      }
      if ((hasChild(item) || (item.meta && item.meta.showAlways)) && showThisMenuEle(item, access)) {
        obj.children = getMenuByRouter(item.children, access)
      }
      if (item.meta && item.meta.href) obj.href = item.meta.href
      if (showThisMenuEle(item, access)) res.push(obj)
    }
  })
  return res
}

故名思意,这个方法是用来生成菜单的,通过谁生成呢,通过Router,所以要再把title引出去,看到这你肯定会说你这不是脱了那啥那啥吗?人家meta里的title已经可以用来做菜单显示文字了,你这简直是多此一举。是的,但是你忽略了一点,就是这个showTitle不仅用来生成菜单的文字,还有其他两个用途------windows标签和导航栏里的标签

菜单因为有父级菜单所以相同的子菜单不会造成混淆,但是标签是没有父级标签的,(如果不看面包屑的话)

所以我这种改造方法真正的意义在这里-----就是让标签和菜单里的文字不同,如何做到呢?还是继续看代码

看菜单模块

/*side-Menu-item*/
<template>
  <Submenu :name="`${parentName}`">
    <template slot="title">
      <common-icon :type="parentItem.icon || ''"/>
      <span>{{ showTitle(parentItem) }}</span>
    </template>
    <template v-for="item in children">
      <template v-if="item.children && item.children.length === 1">
        <side-menu-item v-if="showChildren(item)" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
        <menu-item v-else :name="getNameOrHref(item, true)" :key="`menu-${item.children[0].name}`"><common-icon :type="item.children[0].icon || ''"/><span>{{ showTitle(item.children[0]) }}</span></menu-item>
      </template>
      <template v-else>
        <side-menu-item v-if="showChildren(item)" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
        <menu-item v-else :name="getNameOrHref(item)" :key="`menu-${item.name}`"><common-icon :type="item.icon || ''"/><span>{{ showTitle(item) }}</span></menu-item>
      </template>
    </template>
  </Submenu>
</template>

 

/*side-Menu*/
<template>
  <div class="side-menu-wrapper">
    <slot></slot>
    <Menu ref="menu" v-show="!collapsed" :active-name="activeName" :open-names="openedNames" :accordion="accordion" :theme="theme" width="auto" @on-select="handleSelect">
      <template v-for="item in menuList">
        <template v-if="item.children && item.children.length === 1">
          <side-menu-item v-if="showChildren(item)" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
          <menu-item v-else :name="getNameOrHref(item, true)" :key="`menu-${item.children[0].name}`"><common-icon :type="item.children[0].icon || ''"/><span>{{ showTitle(item.children[0]) }}</span></menu-item>
        </template>
        <template v-else>
          <side-menu-item v-if="showChildren(item)" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
          <menu-item v-else :name="getNameOrHref(item)" :key="`menu-${item.name}`"><common-icon :type="item.icon || ''"/><span>{{ showTitle(item) }}</span></menu-item>
        </template>
      </template>
    </Menu>
    <div class="menu-collapsed" v-show="collapsed" :list="menuList">
      <template v-for="item in menuList">
        <collapsed-menu v-if="item.children && item.children.length > 1" @on-click="handleSelect" hide-title :root-icon-size="rootIconSize" :icon-size="iconSize" :theme="theme" :parent-item="item" :key="`drop-menu-${item.name}`"></collapsed-menu>
        <Tooltip transfer v-else :content="showTitle(item.children && item.children[0] ? item.children[0] : item)" placement="right" :key="`drop-menu-${item.name}`">
          <a @click="handleSelect(getNameOrHref(item, true))" class="drop-menu-a" :style="{textAlign: 'center'}"><common-icon :size="rootIconSize" :color="textColor" :type="item.icon || (item.children && item.children[0].icon)"/></a>
        </Tooltip>
      </template>
    </div>
  </div>
</template>

你看显示什么其实靠的就是showTitle,所以我的方法其实就是加一个showTItlemine方法只不过show的是我加的这个title,把这两个模块里的所有showTitle替换成showTItlemine方法

export const showTitlemine = (item, vm) => {
  let { title, __titleIsFunction__ } = item.meta
  if (!title) return
  if (useI18n) {
    if (title.includes('{{') && title.includes('}}') && useI18n) title = title.replace(/({{[\s\S]+?}})/, (m, str) => str.replace(/{{([\s\S]*)}}/, (m, _) => vm.$t(_.trim())))
    else if (__titleIsFunction__) title = item.meta.title
    //else title = vm.$t(item.name)改成
    else title = vm.$t(item.Title)
  //} else title = (item.meta && item.meta.title) || item.name改成
  } else title = (item.meta && item.meta.title) || item.title
return title
}

这样就达到了增加一个显示的目的(不影响windows标签和导航栏标签)。(以上纯属个人行为请勿模仿,如有闪失概不负责)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值