mirror of
				https://github.com/pure-admin/vue-pure-admin.git
				synced 2025-11-03 13:44:47 +08:00 
			
		
		
		
	feat(ReText): 新增ReText组件,支持自动省略显示Tooltip功能, 支持多行省略, 高可复用性 (#898)
				
					
				
			* feat(ReText): 新增ReText组件 - 基于El-Text, 增加自动省略显示Tooltip功能, 高可复用性
This commit is contained in:
		
							parent
							
								
									c62731df5b
								
							
						
					
					
						commit
						f6eaa8d6d8
					
				@ -44,6 +44,7 @@ menus:
 | 
				
			|||||||
  hsmap: Map
 | 
					  hsmap: Map
 | 
				
			||||||
  hsdraggable: Draggable
 | 
					  hsdraggable: Draggable
 | 
				
			||||||
  hssplitPane: Split Pane
 | 
					  hssplitPane: Split Pane
 | 
				
			||||||
 | 
					  hsText: Text Ellipsis
 | 
				
			||||||
  hsElButton: Button
 | 
					  hsElButton: Button
 | 
				
			||||||
  hsbutton: Button Animation
 | 
					  hsbutton: Button Animation
 | 
				
			||||||
  hsCheckButton: Check Button
 | 
					  hsCheckButton: Check Button
 | 
				
			||||||
 | 
				
			|||||||
@ -44,6 +44,7 @@ menus:
 | 
				
			|||||||
  hsmap: 地图
 | 
					  hsmap: 地图
 | 
				
			||||||
  hsdraggable: 拖拽
 | 
					  hsdraggable: 拖拽
 | 
				
			||||||
  hssplitPane: 切割面板
 | 
					  hssplitPane: 切割面板
 | 
				
			||||||
 | 
					  hsText: 文本省略
 | 
				
			||||||
  hsElButton: 按钮
 | 
					  hsElButton: 按钮
 | 
				
			||||||
  hsCheckButton: 可选按钮
 | 
					  hsCheckButton: 可选按钮
 | 
				
			||||||
  hsbutton: 按钮动效
 | 
					  hsbutton: 按钮动效
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,3 @@
 | 
				
			|||||||
@import "tippy.js/themes/light.css";
 | 
					 | 
				
			||||||
@import "cropperjs/dist/cropper.css";
 | 
					@import "cropperjs/dist/cropper.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.re-circled {
 | 
					.re-circled {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								src/components/ReText/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/components/ReText/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					import reText from "./src/index.vue";
 | 
				
			||||||
 | 
					import { withInstall } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 支持`Tooltip`提示的文本省略组件 */
 | 
				
			||||||
 | 
					export const ReText = withInstall(reText);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ReText;
 | 
				
			||||||
							
								
								
									
										62
									
								
								src/components/ReText/src/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/components/ReText/src/index.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					<script lang="ts" setup>
 | 
				
			||||||
 | 
					import { h, onMounted, ref, useSlots } from "vue";
 | 
				
			||||||
 | 
					import { useTippy, type TippyOptions } from "vue-tippy";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const props = defineProps({
 | 
				
			||||||
 | 
					  // 行数
 | 
				
			||||||
 | 
					  lineClamp: {
 | 
				
			||||||
 | 
					    type: [String, Number]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  tippyProps: {
 | 
				
			||||||
 | 
					    type: Object as PropType<TippyOptions>,
 | 
				
			||||||
 | 
					    default: () => ({})
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const $slots = useSlots();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const textRef = ref();
 | 
				
			||||||
 | 
					const tippyFunc = ref();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const isTextEllipsis = (el: HTMLElement) => {
 | 
				
			||||||
 | 
					  if (!props.lineClamp) {
 | 
				
			||||||
 | 
					    // 单行省略判断
 | 
				
			||||||
 | 
					    return el.scrollWidth > el.clientWidth;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // 多行省略判断
 | 
				
			||||||
 | 
					    return el.scrollHeight > el.clientHeight;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getTippyProps = () => ({
 | 
				
			||||||
 | 
					  content: h($slots.content || $slots.default),
 | 
				
			||||||
 | 
					  ...props.tippyProps
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function handleHover(event: MouseEvent) {
 | 
				
			||||||
 | 
					  if (isTextEllipsis(event.target as HTMLElement)) {
 | 
				
			||||||
 | 
					    tippyFunc.value.setProps(getTippyProps());
 | 
				
			||||||
 | 
					    tippyFunc.value.enable();
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    tippyFunc.value.disable();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onMounted(() => {
 | 
				
			||||||
 | 
					  tippyFunc.value = useTippy(textRef.value?.$el, getTippyProps());
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <el-text
 | 
				
			||||||
 | 
					    v-bind="{
 | 
				
			||||||
 | 
					      truncated: !lineClamp,
 | 
				
			||||||
 | 
					      lineClamp,
 | 
				
			||||||
 | 
					      ...$attrs
 | 
				
			||||||
 | 
					    }"
 | 
				
			||||||
 | 
					    ref="textRef"
 | 
				
			||||||
 | 
					    @mouseover.self="handleHover"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <slot />
 | 
				
			||||||
 | 
					  </el-text>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
@ -3,10 +3,12 @@ import path from "path";
 | 
				
			|||||||
import { getConfig } from "@/config";
 | 
					import { getConfig } from "@/config";
 | 
				
			||||||
import { menuType } from "../../types";
 | 
					import { menuType } from "../../types";
 | 
				
			||||||
import extraIcon from "./extraIcon.vue";
 | 
					import extraIcon from "./extraIcon.vue";
 | 
				
			||||||
 | 
					import { useDark } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					import { ReText } from "@/components/ReText";
 | 
				
			||||||
import { useNav } from "@/layout/hooks/useNav";
 | 
					import { useNav } from "@/layout/hooks/useNav";
 | 
				
			||||||
import { transformI18n } from "@/plugins/i18n";
 | 
					import { transformI18n } from "@/plugins/i18n";
 | 
				
			||||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
					import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
				
			||||||
import { ref, toRaw, PropType, nextTick, computed, CSSProperties } from "vue";
 | 
					import { type CSSProperties, type PropType, computed, ref, toRaw } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ArrowUp from "@iconify-icons/ep/arrow-up-bold";
 | 
					import ArrowUp from "@iconify-icons/ep/arrow-up-bold";
 | 
				
			||||||
import EpArrowDown from "@iconify-icons/ep/arrow-down-bold";
 | 
					import EpArrowDown from "@iconify-icons/ep/arrow-down-bold";
 | 
				
			||||||
@ -14,6 +16,7 @@ import ArrowLeft from "@iconify-icons/ep/arrow-left-bold";
 | 
				
			|||||||
import ArrowRight from "@iconify-icons/ep/arrow-right-bold";
 | 
					import ArrowRight from "@iconify-icons/ep/arrow-right-bold";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { layout, isCollapse, tooltipEffect, getDivStyle } = useNav();
 | 
					const { layout, isCollapse, tooltipEffect, getDivStyle } = useNav();
 | 
				
			||||||
 | 
					const { isDark } = useDark();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					const props = defineProps({
 | 
				
			||||||
  item: {
 | 
					  item: {
 | 
				
			||||||
@ -29,13 +32,6 @@ const props = defineProps({
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getSpanStyle = computed((): CSSProperties => {
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    width: "100%",
 | 
					 | 
				
			||||||
    textAlign: "center"
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const getNoDropdownStyle = computed((): CSSProperties => {
 | 
					const getNoDropdownStyle = computed((): CSSProperties => {
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    display: "flex",
 | 
					    display: "flex",
 | 
				
			||||||
@ -43,15 +39,7 @@ const getNoDropdownStyle = computed((): CSSProperties => {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getMenuTextStyle = computed(() => {
 | 
					const getSubMenuIconStyle = computed((): CSSProperties => {
 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    overflow: "hidden",
 | 
					 | 
				
			||||||
    textOverflow: "ellipsis",
 | 
					 | 
				
			||||||
    outline: "none"
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const getsubMenuIconStyle = computed((): CSSProperties => {
 | 
					 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    display: "flex",
 | 
					    display: "flex",
 | 
				
			||||||
    justifyContent: "center",
 | 
					    justifyContent: "center",
 | 
				
			||||||
@ -65,43 +53,6 @@ const getsubMenuIconStyle = computed((): CSSProperties => {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getSubTextStyle = computed((): CSSProperties => {
 | 
					 | 
				
			||||||
  if (!isCollapse.value) {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      width: "210px",
 | 
					 | 
				
			||||||
      display: "inline-block",
 | 
					 | 
				
			||||||
      overflow: "hidden",
 | 
					 | 
				
			||||||
      textOverflow: "ellipsis"
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      width: ""
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const getSubMenuDivStyle = computed((): any => {
 | 
					 | 
				
			||||||
  return item => {
 | 
					 | 
				
			||||||
    return !isCollapse.value
 | 
					 | 
				
			||||||
      ? {
 | 
					 | 
				
			||||||
          width: "100%",
 | 
					 | 
				
			||||||
          display: "flex",
 | 
					 | 
				
			||||||
          alignItems: "center",
 | 
					 | 
				
			||||||
          justifyContent: "space-between",
 | 
					 | 
				
			||||||
          overflow: "hidden"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      : {
 | 
					 | 
				
			||||||
          width: "100%",
 | 
					 | 
				
			||||||
          textAlign:
 | 
					 | 
				
			||||||
            item?.parentId === null
 | 
					 | 
				
			||||||
              ? "center"
 | 
					 | 
				
			||||||
              : layout.value === "mix" && item?.pathList?.length === 2
 | 
					 | 
				
			||||||
                ? "center"
 | 
					 | 
				
			||||||
                : ""
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const expandCloseIcon = computed(() => {
 | 
					const expandCloseIcon = computed(() => {
 | 
				
			||||||
  if (!getConfig()?.MenuArrowIconNoTransition) return "";
 | 
					  if (!getConfig()?.MenuArrowIconNoTransition) return "";
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
@ -113,41 +64,6 @@ const expandCloseIcon = computed(() => {
 | 
				
			|||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const onlyOneChild: menuType = ref(null);
 | 
					const onlyOneChild: menuType = ref(null);
 | 
				
			||||||
// 存放菜单是否存在showTooltip属性标识
 | 
					 | 
				
			||||||
const hoverMenuMap = new WeakMap();
 | 
					 | 
				
			||||||
// 存储菜单文本dom元素
 | 
					 | 
				
			||||||
const menuTextRef = ref(null);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function hoverMenu(key) {
 | 
					 | 
				
			||||||
  // 如果当前菜单showTooltip属性已存在,退出计算
 | 
					 | 
				
			||||||
  if (hoverMenuMap.get(key)) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  nextTick(() => {
 | 
					 | 
				
			||||||
    // 如果文本内容的整体宽度大于其可视宽度,则文本溢出
 | 
					 | 
				
			||||||
    menuTextRef.value?.scrollWidth > menuTextRef.value?.clientWidth
 | 
					 | 
				
			||||||
      ? Object.assign(key, {
 | 
					 | 
				
			||||||
          showTooltip: true
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      : Object.assign(key, {
 | 
					 | 
				
			||||||
          showTooltip: false
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    hoverMenuMap.set(key, true);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 左侧菜单折叠后,当菜单没有图标时只显示第一个文字并加上省略号
 | 
					 | 
				
			||||||
function overflowSlice(text, item?: any) {
 | 
					 | 
				
			||||||
  const newText =
 | 
					 | 
				
			||||||
    (text?.length > 1 ? text.toString().slice(0, 1) : text) + "...";
 | 
					 | 
				
			||||||
  if (item && !(isCollapse.value && item?.parentId === null)) {
 | 
					 | 
				
			||||||
    return layout.value === "mix" &&
 | 
					 | 
				
			||||||
      item?.pathList?.length === 2 &&
 | 
					 | 
				
			||||||
      isCollapse.value
 | 
					 | 
				
			||||||
      ? newText
 | 
					 | 
				
			||||||
      : text;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return newText;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function hasOneShowingChild(children: menuType[] = [], parent: menuType) {
 | 
					function hasOneShowingChild(children: menuType[] = [], parent: menuType) {
 | 
				
			||||||
  const showingChildren = children.filter((item: any) => {
 | 
					  const showingChildren = children.filter((item: any) => {
 | 
				
			||||||
@ -194,7 +110,7 @@ function resolvePath(routePath) {
 | 
				
			|||||||
    <div
 | 
					    <div
 | 
				
			||||||
      v-if="toRaw(props.item.meta.icon)"
 | 
					      v-if="toRaw(props.item.meta.icon)"
 | 
				
			||||||
      class="sub-menu-icon"
 | 
					      class="sub-menu-icon"
 | 
				
			||||||
      :style="getsubMenuIconStyle"
 | 
					      :style="getSubMenuIconStyle"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <component
 | 
					      <component
 | 
				
			||||||
        :is="
 | 
					        :is="
 | 
				
			||||||
@ -205,51 +121,34 @@ function resolvePath(routePath) {
 | 
				
			|||||||
        "
 | 
					        "
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <span
 | 
					    <el-text
 | 
				
			||||||
      v-if="
 | 
					      v-if="
 | 
				
			||||||
        !props.item?.meta.icon &&
 | 
					        (!props.item?.meta.icon &&
 | 
				
			||||||
          isCollapse &&
 | 
					          isCollapse &&
 | 
				
			||||||
          layout === 'vertical' &&
 | 
					          layout === 'vertical' &&
 | 
				
			||||||
        props.item?.pathList?.length === 1
 | 
					          props.item?.pathList?.length === 1) ||
 | 
				
			||||||
      "
 | 
					        (!onlyOneChild.meta.icon &&
 | 
				
			||||||
      :style="getSpanStyle"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      {{ overflowSlice(transformI18n(onlyOneChild.meta.title)) }}
 | 
					 | 
				
			||||||
    </span>
 | 
					 | 
				
			||||||
    <span
 | 
					 | 
				
			||||||
      v-if="
 | 
					 | 
				
			||||||
        !onlyOneChild.meta.icon &&
 | 
					 | 
				
			||||||
          isCollapse &&
 | 
					          isCollapse &&
 | 
				
			||||||
          layout === 'mix' &&
 | 
					          layout === 'mix' &&
 | 
				
			||||||
        props.item?.pathList?.length === 2
 | 
					          props.item?.pathList?.length === 2)
 | 
				
			||||||
      "
 | 
					      "
 | 
				
			||||||
      :style="getSpanStyle"
 | 
					      truncated
 | 
				
			||||||
 | 
					      class="!px-4 !text-inherit"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      {{ overflowSlice(transformI18n(onlyOneChild.meta.title)) }}
 | 
					      {{ transformI18n(onlyOneChild.meta.title) }}
 | 
				
			||||||
    </span>
 | 
					    </el-text>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <template #title>
 | 
					    <template #title>
 | 
				
			||||||
      <div :style="getDivStyle">
 | 
					      <div :style="getDivStyle">
 | 
				
			||||||
        <span v-if="layout === 'horizontal'">
 | 
					        <ReText
 | 
				
			||||||
          {{ transformI18n(onlyOneChild.meta.title) }}
 | 
					          :tippyProps="{
 | 
				
			||||||
        </span>
 | 
					            offset: [0, -10],
 | 
				
			||||||
        <el-tooltip
 | 
					            theme: !isDark ? tooltipEffect : undefined
 | 
				
			||||||
          v-else
 | 
					          }"
 | 
				
			||||||
          placement="top"
 | 
					          class="!text-inherit"
 | 
				
			||||||
          :effect="tooltipEffect"
 | 
					 | 
				
			||||||
          :offset="-10"
 | 
					 | 
				
			||||||
          :disabled="!onlyOneChild.showTooltip"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <template #content>
 | 
					 | 
				
			||||||
            {{ transformI18n(onlyOneChild.meta.title) }}
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
          <span
 | 
					 | 
				
			||||||
            ref="menuTextRef"
 | 
					 | 
				
			||||||
            :style="getMenuTextStyle"
 | 
					 | 
				
			||||||
            @mouseover="hoverMenu(onlyOneChild)"
 | 
					 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          {{ transformI18n(onlyOneChild.meta.title) }}
 | 
					          {{ transformI18n(onlyOneChild.meta.title) }}
 | 
				
			||||||
          </span>
 | 
					        </ReText>
 | 
				
			||||||
        </el-tooltip>
 | 
					 | 
				
			||||||
        <extraIcon :extraIcon="onlyOneChild.meta.extraIcon" />
 | 
					        <extraIcon :extraIcon="onlyOneChild.meta.extraIcon" />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
@ -264,48 +163,38 @@ function resolvePath(routePath) {
 | 
				
			|||||||
    <template #title>
 | 
					    <template #title>
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
        v-if="toRaw(props.item.meta.icon)"
 | 
					        v-if="toRaw(props.item.meta.icon)"
 | 
				
			||||||
        :style="getsubMenuIconStyle"
 | 
					        :style="getSubMenuIconStyle"
 | 
				
			||||||
        class="sub-menu-icon"
 | 
					        class="sub-menu-icon"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <component
 | 
					        <component
 | 
				
			||||||
          :is="useRenderIcon(props.item.meta && toRaw(props.item.meta.icon))"
 | 
					          :is="useRenderIcon(props.item.meta && toRaw(props.item.meta.icon))"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <span v-if="layout === 'horizontal'">
 | 
					      <ReText
 | 
				
			||||||
        {{ transformI18n(props.item.meta.title) }}
 | 
					 | 
				
			||||||
      </span>
 | 
					 | 
				
			||||||
      <div
 | 
					 | 
				
			||||||
        v-if="
 | 
					        v-if="
 | 
				
			||||||
          !(
 | 
					          !(
 | 
				
			||||||
 | 
					            layout === 'vertical' &&
 | 
				
			||||||
            isCollapse &&
 | 
					            isCollapse &&
 | 
				
			||||||
            toRaw(props.item.meta.icon) &&
 | 
					            toRaw(props.item.meta.icon) &&
 | 
				
			||||||
            props.item.parentId === null
 | 
					            props.item.parentId === null
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        "
 | 
					        "
 | 
				
			||||||
        :style="getSubMenuDivStyle(props.item)"
 | 
					        :tippyProps="{
 | 
				
			||||||
 | 
					          offset: [0, -10],
 | 
				
			||||||
 | 
					          theme: !isDark ? tooltipEffect : undefined
 | 
				
			||||||
 | 
					        }"
 | 
				
			||||||
 | 
					        :class="{
 | 
				
			||||||
 | 
					          '!text-inherit': true,
 | 
				
			||||||
 | 
					          '!px-4':
 | 
				
			||||||
 | 
					            layout !== 'horizontal' &&
 | 
				
			||||||
 | 
					            isCollapse &&
 | 
				
			||||||
 | 
					            !toRaw(props.item.meta.icon) &&
 | 
				
			||||||
 | 
					            props.item.parentId === null
 | 
				
			||||||
 | 
					        }"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <el-tooltip
 | 
					 | 
				
			||||||
          v-if="layout !== 'horizontal'"
 | 
					 | 
				
			||||||
          placement="top"
 | 
					 | 
				
			||||||
          :effect="tooltipEffect"
 | 
					 | 
				
			||||||
          :offset="-10"
 | 
					 | 
				
			||||||
          :disabled="!props.item.showTooltip"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <template #content>
 | 
					 | 
				
			||||||
        {{ transformI18n(props.item.meta.title) }}
 | 
					        {{ transformI18n(props.item.meta.title) }}
 | 
				
			||||||
          </template>
 | 
					      </ReText>
 | 
				
			||||||
          <span
 | 
					 | 
				
			||||||
            ref="menuTextRef"
 | 
					 | 
				
			||||||
            :style="getSubTextStyle"
 | 
					 | 
				
			||||||
            @mouseover="hoverMenu(props.item)"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            {{
 | 
					 | 
				
			||||||
              overflowSlice(transformI18n(props.item.meta.title), props.item)
 | 
					 | 
				
			||||||
            }}
 | 
					 | 
				
			||||||
          </span>
 | 
					 | 
				
			||||||
        </el-tooltip>
 | 
					 | 
				
			||||||
      <extraIcon v-if="!isCollapse" :extraIcon="props.item.meta.extraIcon" />
 | 
					      <extraIcon v-if="!isCollapse" :extraIcon="props.item.meta.extraIcon" />
 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <sidebar-item
 | 
					    <sidebar-item
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										10
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/main.ts
									
									
									
									
									
								
							@ -31,7 +31,7 @@ Object.keys(directives).forEach(key => {
 | 
				
			|||||||
  app.directive(key, (directives as { [key: string]: Directive })[key]);
 | 
					  app.directive(key, (directives as { [key: string]: Directive })[key]);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 全局注册`@iconify/vue`图标库
 | 
					// 全局注册@iconify/vue图标库
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  IconifyIconOffline,
 | 
					  IconifyIconOffline,
 | 
				
			||||||
  IconifyIconOnline,
 | 
					  IconifyIconOnline,
 | 
				
			||||||
@ -45,13 +45,11 @@ app.component("FontIcon", FontIcon);
 | 
				
			|||||||
import { Auth } from "@/components/ReAuth";
 | 
					import { Auth } from "@/components/ReAuth";
 | 
				
			||||||
app.component("Auth", Auth);
 | 
					app.component("Auth", Auth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 全局注册`vue-tippy`
 | 
					// 全局注册vue-tippy
 | 
				
			||||||
import "tippy.js/dist/tippy.css";
 | 
					import "tippy.js/dist/tippy.css";
 | 
				
			||||||
import "tippy.js/animations/perspective.css";
 | 
					import "tippy.js/themes/light.css";
 | 
				
			||||||
import VueTippy from "vue-tippy";
 | 
					import VueTippy from "vue-tippy";
 | 
				
			||||||
app.use(VueTippy, {
 | 
					app.use(VueTippy);
 | 
				
			||||||
  defaultProps: { animation: "perspective" }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
getPlatformConfig(app).then(async config => {
 | 
					getPlatformConfig(app).then(async config => {
 | 
				
			||||||
  setupStore(app);
 | 
					  setupStore(app);
 | 
				
			||||||
 | 
				
			|||||||
@ -91,6 +91,15 @@ export default {
 | 
				
			|||||||
        title: $t("menus.hssegmented")
 | 
					        title: $t("menus.hssegmented")
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      path: "/components/text",
 | 
				
			||||||
 | 
					      name: "PureText",
 | 
				
			||||||
 | 
					      component: () => import("@/views/components/text.vue"),
 | 
				
			||||||
 | 
					      meta: {
 | 
				
			||||||
 | 
					        title: $t("menus.hsText"),
 | 
				
			||||||
 | 
					        extraIcon: "IF-pure-iconfont-new svg"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      path: "/components/el-button",
 | 
					      path: "/components/el-button",
 | 
				
			||||||
      name: "PureButton",
 | 
					      name: "PureButton",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										164
									
								
								src/views/components/text.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/views/components/text.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,164 @@
 | 
				
			|||||||
 | 
					<script lang="ts" setup>
 | 
				
			||||||
 | 
					import dayjs from "dayjs";
 | 
				
			||||||
 | 
					import { ref } from "vue";
 | 
				
			||||||
 | 
					import { ReText } from "@/components/ReText";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineOptions({
 | 
				
			||||||
 | 
					  name: "PureText"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const customContent = ref("自定义tooltip内容");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const changeTooltipContent = () => {
 | 
				
			||||||
 | 
					  customContent.value =
 | 
				
			||||||
 | 
					    "现在的时间是: " + dayjs().format("YYYY-MM-DD HH:mm:ss");
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <el-card shadow="never">
 | 
				
			||||||
 | 
					    <template #header>
 | 
				
			||||||
 | 
					      <div class="card-header">
 | 
				
			||||||
 | 
					        <span class="font-medium">
 | 
				
			||||||
 | 
					          文本省略,基于
 | 
				
			||||||
 | 
					          <el-link
 | 
				
			||||||
 | 
					            href="https://element-plus.org/zh-CN/component/text.html"
 | 
				
			||||||
 | 
					            target="_blank"
 | 
				
			||||||
 | 
					            style="margin: 0 4px 5px; font-size: 16px"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            el-text
 | 
				
			||||||
 | 
					          </el-link>
 | 
				
			||||||
 | 
					          和
 | 
				
			||||||
 | 
					          <el-link
 | 
				
			||||||
 | 
					            href="https://vue-tippy.netlify.app/basic-usage"
 | 
				
			||||||
 | 
					            target="_blank"
 | 
				
			||||||
 | 
					            style="margin: 0 4px 5px; font-size: 16px"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            VueTippy
 | 
				
			||||||
 | 
					          </el-link>
 | 
				
			||||||
 | 
					          自动省略后显示 Tooltip 提示, 支持多行省略
 | 
				
			||||||
 | 
					        </span>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <p class="mb-2">基础用法</p>
 | 
				
			||||||
 | 
					    <el-space wrap>
 | 
				
			||||||
 | 
					      <ul class="content">
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <ReText>
 | 
				
			||||||
 | 
					            测试文本,这是一个稍微有点长的文本,过长省略后,鼠标悬浮会有tooltip提示
 | 
				
			||||||
 | 
					          </ReText>
 | 
				
			||||||
 | 
					          <ReText :lineClamp="2">
 | 
				
			||||||
 | 
					            测试文本,这是一个稍微有点长的文本,lineClamp参数为2,即两行过长省略后,鼠标悬浮会有tooltip提示
 | 
				
			||||||
 | 
					          </ReText>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					    </el-space>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <el-divider />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <p class="mb-2">自定义 Tooltip 内容</p>
 | 
				
			||||||
 | 
					    <div class="mb-2">
 | 
				
			||||||
 | 
					      <el-button @click="changeTooltipContent">
 | 
				
			||||||
 | 
					        点击切换下方 Tooltip 内容
 | 
				
			||||||
 | 
					      </el-button>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <el-space wrap>
 | 
				
			||||||
 | 
					      <ul class="content">
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <ReText :tippyProps="{ content: customContent }">
 | 
				
			||||||
 | 
					            props写法 -
 | 
				
			||||||
 | 
					            测试文本,这是一个稍微有点长的文本,过长省略后,鼠标悬浮会有tooltip提示
 | 
				
			||||||
 | 
					          </ReText>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <ReText>
 | 
				
			||||||
 | 
					            <template #content>
 | 
				
			||||||
 | 
					              <div>
 | 
				
			||||||
 | 
					                <b>这是插槽写法: </b>
 | 
				
			||||||
 | 
					                <div>{{ customContent }}</div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            插槽写法 -
 | 
				
			||||||
 | 
					            测试文本,这是一个稍微有点长的文本,过长省略后,鼠标悬浮会有tooltip提示
 | 
				
			||||||
 | 
					          </ReText>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					    </el-space>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <el-divider />
 | 
				
			||||||
 | 
					    <p class="mb-2">自定义 el-text 配置</p>
 | 
				
			||||||
 | 
					    <el-space wrap>
 | 
				
			||||||
 | 
					      <ul class="content">
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <ReText type="primary" size="large">
 | 
				
			||||||
 | 
					            测试文本,这是一个稍微有点长的文本,过长省略后,鼠标悬浮会有tooltip提示
 | 
				
			||||||
 | 
					          </ReText>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <ReText :lineClamp="4" type="info">
 | 
				
			||||||
 | 
					            测试文本,这是一个非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长的文本,lineClamp参数为4,即四行过长省略后,鼠标悬浮会有tooltip提示
 | 
				
			||||||
 | 
					          </ReText>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					    </el-space>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <el-divider />
 | 
				
			||||||
 | 
					    <p class="mb-2">自定义 VueTippy 配置</p>
 | 
				
			||||||
 | 
					    <el-space wrap>
 | 
				
			||||||
 | 
					      <ul class="content">
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <ReText
 | 
				
			||||||
 | 
					            :tippyProps="{ offset: [0, -20], theme: 'light', arrow: false }"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            偏移白色无箭头 -
 | 
				
			||||||
 | 
					            测试文本,这是一个稍微有点长的文本,过长省略后,鼠标悬浮会有tooltip提示
 | 
				
			||||||
 | 
					          </ReText>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <ReText :lineClamp="4" :tippyProps="{ followCursor: true }">
 | 
				
			||||||
 | 
					            鼠标跟随 -
 | 
				
			||||||
 | 
					            测试文本,这是一个非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长,非常非常长的文本,lineClamp参数为4,即四行过长省略后,鼠标悬浮会有tooltip提示
 | 
				
			||||||
 | 
					          </ReText>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					    </el-space>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <el-divider />
 | 
				
			||||||
 | 
					    <p class="mb-2">组件嵌套: 不需要省略的需设置 truncated 为 false</p>
 | 
				
			||||||
 | 
					    <el-space wrap>
 | 
				
			||||||
 | 
					      <ul class="content">
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <ReText tag="p" :lineClamp="2">
 | 
				
			||||||
 | 
					            This is a paragraph. Paragraph start
 | 
				
			||||||
 | 
					            <ReText :truncated="false">
 | 
				
			||||||
 | 
					              【 This is ReText
 | 
				
			||||||
 | 
					              <ReText tag="sup" size="small" :truncated="false">
 | 
				
			||||||
 | 
					                superscript 】
 | 
				
			||||||
 | 
					              </ReText>
 | 
				
			||||||
 | 
					            </ReText>
 | 
				
			||||||
 | 
					            <el-text>
 | 
				
			||||||
 | 
					              【 This is El-Text
 | 
				
			||||||
 | 
					              <el-text tag="sub" size="small"> subscript 】 </el-text>
 | 
				
			||||||
 | 
					            </el-text>
 | 
				
			||||||
 | 
					            <el-text tag="ins">【Inserted】</el-text>
 | 
				
			||||||
 | 
					            <el-text tag="del">【Deleted】</el-text>
 | 
				
			||||||
 | 
					            <el-text tag="mark">【Marked】</el-text>
 | 
				
			||||||
 | 
					            Paragraph end.
 | 
				
			||||||
 | 
					          </ReText>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					    </el-space>
 | 
				
			||||||
 | 
					  </el-card>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
 | 
					.content {
 | 
				
			||||||
 | 
					  width: 400px;
 | 
				
			||||||
 | 
					  padding: 15px;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  resize: horizontal;
 | 
				
			||||||
 | 
					  background-color: var(--el-color-info-light-9);
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user