驰骋流程+表单+低代码

Appearance
代码路径:/@/layout/navBars/tagsView
中键鼠标 按下时,判断是鼠标中键就 关闭当前 tasgview
const onMousedownMenu = (v: RouteItem, e: MouseEvent) => {
  if (!v.meta?.isAffix && e.button === 1) {
    const item = Object.assign({}, { contextMenuClickId: 1, ...v });
    onCurrentContextmenuClick(item);
  }
};代码路径:/@/layout/navBars/tagsView/contextmenu.vue,右键菜单与 当前页操作 一样,
onCurrentContextmenuClick 参数包含:
0 刷新当前
1 关闭当前
2 关闭其它
3 关闭全部
4 当前页全屏
具体可查看代码 /@/layout/navBars/tagsView/tagsView.vue 中的 onCurrentContextmenuClick 方法
// 当前项右键菜单点击
const onCurrentContextmenuClick = async (item: RouteItem) => {
  item.commonUrl = transUrlParams(item);
  if (!getCurrentRouteItem(item))
    return ElMessage({
      type: "warning",
      message: "请正确输入路径及完整参数(query、params)",
    });
  const { path, name, params, query, meta, url } = getCurrentRouteItem(item);
  switch (item.contextMenuClickId) {
    case 0:
      // 刷新当前
      if (meta.isDynamic) await router.push({ name, params });
      else await router.push({ path, query });
      refreshCurrentTagsView(route.fullPath);
      break;
    case 1:
      // 关闭当前
      closeCurrentTagsView(getThemeConfig.value.isShareTagsView ? path : url);
      break;
    case 2:
      // 关闭其它
      if (meta.isDynamic) await router.push({ name, params });
      else await router.push({ path, query });
      closeOtherTagsView(path);
      break;
    case 3:
      // 关闭全部
      closeAllTagsView();
      break;
    case 4:
      // 开启当前页面全屏
      openCurrenFullscreen(getThemeConfig.value.isShareTagsView ? path : url);
      break;
  }
};参数说明:0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部 4 当前页全屏。tagsView 只支持对当前页进行操作。
方法说明:onCurrentContextmenuClick 和参数字段名 contextMenuClickId 为固定,只需要传参数 0 - 4
演示地址:/fun/tagsView 操作,只支持 操作当前页,非当前页不可操作。
0) <script setup lang="ts">
  import { useRoute } from "vue-router";
  import mittBus from "/@/utils/mitt";
  // 定义变量内容
  const route = useRoute();
  // 0、刷新当前 tagsView
  const refreshCurrentTagsView = () => {
    mittBus.emit(
      "onCurrentContextmenuClick",
      Object.assign({}, { contextMenuClickId: 0, ...route })
    );
  };
</script>1) <script setup lang="ts">
  import { useRoute } from "vue-router";
  import mittBus from "/@/utils/mitt";
  // 定义变量内容
  const route = useRoute();
  // 1、关闭当前 tagsView
  const refreshCurrentTagsView = () => {
    mittBus.emit(
      "onCurrentContextmenuClick",
      Object.assign({}, { contextMenuClickId: 1, ...route })
    );
  };
</script>2) <script setup lang="ts">
  import { useRoute } from "vue-router";
  import mittBus from "/@/utils/mitt";
  // 定义变量内容
  const route = useRoute();
  // 2、关闭其它 tagsView
  const refreshCurrentTagsView = () => {
    mittBus.emit(
      "onCurrentContextmenuClick",
      Object.assign({}, { contextMenuClickId: 2, ...route })
    );
  };
</script>3) <script setup lang="ts">
  import { useRoute } from "vue-router";
  import mittBus from "/@/utils/mitt";
  // 定义变量内容
  const route = useRoute();
// 3、关闭全部 tagsView
  const refreshCurrentTagsView = () => {
    mittBus.emit(
      "onCurrentContextmenuClick",
      Object.assign({}, { contextMenuClickId: 3, ...route })
    );
  };
</script>4) <script setup lang="ts">
  import { useRoute } from "vue-router";
  import mittBus from "/@/utils/mitt";
  // 定义变量内容
  const route = useRoute();
// 4、开启当前页面全屏
  const refreshCurrentTagsView = () => {
    mittBus.emit(
      "onCurrentContextmenuClick",
      Object.assign({}, { contextMenuClickId: 4, ...route })
    );
  };
</script>内容溢出时,鼠标滚轮 + 鼠标左键
移步 布局配置 -> Tagsview 风格 查看自定义添加更多风格
右上角点击 icon 布局配置图标,界面显示 -> 开启 TagsView 缓存
isCacheTagsView 为 true 时,F5 刷新后,tagsView 数据直接从浏览器 Session Storage 中取
if (Session.get("tagsViewList") && getThemeConfig.value.isCacheTagsView) {
  state.tagsViewList = await Session.get("tagsViewList");
}name 值存入到 keep-alive 的 include 中<keep-alive :include="getKeepAliveNames">F5 刷新时, /src/layout/routerView/parent.vue onMounted 中重新取 name 值放入 cachedViews 数组// 页面加载时
onMounted(() => {
  nextTick(() => {
    setTimeout(() => {
      if (themeConfig.value.isCacheTagsView) {
        let tagsViewArr: RouteItem[] = Session.get("tagsViewList") || [];
        cachedViews.value = tagsViewArr
          .filter((item) => item.meta?.isKeepAlive)
          .map((item) => item.name as string);
      }
    }, 0);
  });
});tagsView 时,当前的路由将清空缓存 // 删除要缓存的路由 names(关闭 Tagsview)
async delCachedView(view: any) {
  const index = this.cachedViews.indexOf(view.name);
  index > -1 && this.cachedViews.splice(index, 1);
}tagsView 时,当前的路由将重新缓存 // 添加要缓存的路由 names(关闭 Tagsview)
async addCachedView(view: any) {
  if (view.meta.isKeepAlive) this.cachedViews?.push(view.name);
}右上角点击 icon 布局配置图标,界面显示 -> 开启 TagsView 拖拽
使用 SortableJS 插件
const initSortable = async () => {
  const el = <HTMLElement>document.querySelector(".layout-navbars-tagsview-ul");
  if (!el) return false;
  state.sortable.el && state.sortable.destroy();
  state.sortable = Sortable.create(el, {
    animation: 300,
    dataIdAttr: "data-url",
    disabled: getThemeConfig.value.isSortableTagsView ? false : true,
    onEnd: () => {
      const sortEndList: RouteItem[] = [];
      state.sortable.toArray().map((val: string) => {
        state.tagsViewList.map((v: RouteItem) => {
          if (v.url === val) sortEndList.push({ ...v });
        });
      });
      addBrowserSetSession(sortEndList);
    },
  });
};const onSortableResize = async () => {
  await initSortable();
  if (other.isMobile()) state.sortable.el && state.sortable.destroy();
};右上角点击 icon 布局配置图标,界面显示 -> 开启 TagsView 共用
代码配置路径:/src/stores/themeConfig.ts
isShareTagsView 为 true 时:
tagsView 只有一个tagsView 有多个isShareTagsView 为 false 时:
tagsView 只有一个tagsView 有多个代码位置:/src/layout/navBars/tagsView/tagsView.vue
// 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化
const setTagsViewNameI18n = computed(() => {
  return (v: RouteItem) => {
    return other.setTagsViewNameI18n(v);
  };
});代码位置:/src/utils/other.ts
/**
 * 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化
 * @param params 路由 query、params 中的 tagsViewName
 * @returns 返回当前 tagsViewName 名称
 */
export function setTagsViewNameI18n(item: any) {
  let tagsViewName: string = "";
  const { query, params, meta } = item;
  // 修复tagsViewName匹配到其他含下列单词的路由
  // https://gitee.com/lyt-top/vue-next-admin/pulls/44/files
  const pattern = /^\{("(zh-cn|en|zh-tw)":"[^,]+",?){1,3}}$/;
  if (query?.tagsViewName || params?.tagsViewName) {
    if (
      pattern.test(query?.tagsViewName) ||
      pattern.test(params?.tagsViewName)
    ) {
      // 国际化
      const urlTagsParams =
        (query?.tagsViewName && JSON.parse(query?.tagsViewName)) ||
        (params?.tagsViewName && JSON.parse(params?.tagsViewName));
      tagsViewName = urlTagsParams[i18n.global.locale.value];
    } else {
      // 非国际化
      tagsViewName = query?.tagsViewName || params?.tagsViewName;
    }
  } else {
    // 非自定义 tagsView 名称
    tagsViewName = i18n.global.t(meta.title);
  }
  return tagsViewName;
}路由跳转 router.push 时,参数必须要加 tagsViewName 字段
演示代码位置:/src/views/params/common/index.vue,可参考里面的写法
注意格式
格式:tagsViewName=xxx
<script setup lang="ts" name="xxx">
  const onGoDetailsClick = () => {
    router.push({
      path: "/params/common/details",
      query: {
        tagsViewName: "我是普通路由测试tagsViewName(非国际化)",
        // 其它参数
        ...
      },
    });
  };
</script>路由跳转 router.push 时,参数必须要加 tagsViewName 字段
演示代码位置:/src/views/params/common/index.vue,可参考里面的写法
注意格式
zh-cn、en、zh-tw 为必填,还需转成字符串 JSON.stringify
格式:tagsViewName=JSON.stringify({"zh-cn":"测试用","en":"test+page","zh-tw":"測試用"})
<script setup lang="ts" name="xxx">
  const tagsViewName = JSON.stringify({
    "zh-cn": "测试用",
    "en": "test page",
    "zh-tw": "測試用",
  });
  const onGoDetailsClick = () => {
    router.push({
      path: "/params/common/details",
      query: {
        tagsViewName,
        // 其它参数
        ...
      },
    });
  };
</script>设置 tagsView 国际化后,去顶栏切换语言查看演示效果。