DataV轮播表数据太长内容展示不全的解决方法

解决方法:直接手改源码+使用el-tooltip

注:这里只涉及vue3的版本

第一步下载源码

官方的文档:

Welcome | DataV

git地址

https://github.com/vaemusic/datav-vue3

GitCode - 全球开发者的开源社区,开源代码托管平台

第二步使用源码

在下面的位置找到源码

\datav-vue3-master\packages\datav-vue3\components\ScrollBoard\src\index.vue

直接复制到自己项目中,注意这里有两个引用

import autoResize from 'packages/datav-vue3/utils/autoResize'
import { deepClone, deepMerge } from 'packages/datav-vue3/utils'

解决的方法:对于autoResize,直接创建一个autoResize.ts文件,复制一下内容。deepClone和deepMerge同时也可以复制出来,到自己的创建的文件然后导入使用,但是有一点问题,源码中使用了大量的any,很不友好。

源码内容:

export function deepMerge(target: any, merged: any) {
  for (const key in merged) {
    if (target[key] && typeof target[key] === 'object') {
      deepMerge(target[key], merged[key])

      continue
    }

    if (typeof merged[key] === 'object') {
      target[key] = deepClone(merged[key], true)

      continue
    }

    target[key] = merged[key]
  }

  return target
}

/**
 * @description Clone an object or array
 * @param {object | Array} object Cloned object
 * @param {boolean} recursion   Whether to use recursive cloning
 * @return {object | Array} Clone object
 */
export function deepClone(object: any, recursion: boolean) {
  if (!object)
    return object
  const { parse, stringify } = JSON
  if (!recursion)
    return parse(stringify(object))
  const clonedObj: Record<string, any> = Array.isArray(object) ? [] : {}

  if (object && typeof object === 'object') {
    for (const key in object) {
      if (Object.prototype.hasOwnProperty.call(object, key)) {
        if (object[key] && typeof object[key] === 'object')
          clonedObj[key] = deepClone(object[key], true)

        else
          clonedObj[key] = object[key]
      }
    }
  }

  return clonedObj
}

解决方法:deepClone和deepMerge的作用是深拷贝和合并,可以使用lodash解决。

import { cloneDeep, merge } from "lodash";

第三步使用el-tooltip

下面是源码的部分,传递给dataV的参数会采用v-html的方式渲染出去,新建一个dom元素,然后用el-tooltip包裹一下。

源码

        <div
          v-for="(ceil, ci) in row.ceils"
          :key="`${ceil}${ri}${ci}`"
          class="ceil"
          :style="`width: ${state.widths[ci]}px;`"
          :align="state.aligns[ci]"
          @click="handleClick(ri, ci, row, ceil)"
          @mouseenter="handleHover(true, ri, ci, row, ceil)"
          @mouseleave="handleHover(false)"
          v-html="ceil"
        />

修改后的源码

        <div
          v-for="(ceil, ci) in row.ceils"
          :key="`${ceil}${ri}${ci}`"
          class="ceil"
          :style="`width: ${state.widths[ci]}px;`"
          :align="state.aligns[ci]"
          @click="handleClick(ri, ci, row, ceil)"
          @mouseenter="handleHover(true, ri, ci, row, ceil)"
          @mouseleave="handleHover(false)"
        >
          <ElTooltip
            popper-class="box-item"
            effect="dark"
            placement="top-start"
          >
            <div v-html="ceil" /></div>
            <template #content>
              <div v-html="ceil" />
            </template>
          </ElTooltip>
        </div>

这样就可以使用了。

第四步智能/动态解决tooltip出现的时机

上述代码之后,会对所有的内容都会有气泡的弹出,需要做的对内容是否被遮挡需要弹出气泡做出判断,判断原理来自el-table的show-tooltip的源码

首先是创建一个boolean参数,这个参数用于禁用/启动el-tooltip,其次监听创建的dom元素的鼠标移入和移出事件,当鼠标移入的时候,判断事件的目标(即鼠标下的dom元素)是否被遮挡,(为了有遮挡的效果,需要添加样式),是则boolean参数为false,不禁用el-tooltip,鼠标移入的时会展示气泡

样式:dataV的样式不一定理想

.text-ellipsis {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

vue的template部分

        <div
          v-for="(ceil, ci) in row.ceils"
          :key="`${ceil}${ri}${ci}`"
          class="ceil"
          :style="`width: ${state.widths[ci]}px;`"
          :align="state.aligns[ci]"
          @click="handleClick(ri, ci, row, ceil)"
          @mouseenter="handleHover(true, ri, ci, row, ceil)"
          @mouseleave="handleHover(false)"
        >
          <ElTooltip
            popper-class="box-item"
            effect="dark"
            :disabled="!toolTipFlag"
            placement="top-start"
          >
            <div v-html="ceil"  
                class="text-ellipsis"
                @mouseenter="dealTooltip($event, ceil)"
                @mouseleave="mouseLeaveTooltip" 
            />
            <template #content>
              <div v-html="ceil" />
            </template>
          </ElTooltip>
        </div>

vue的script部分 ,这里判断代码来自el-table的show-tooltip

// 创建参数
const toolTipFlag = ref(false);
// 鼠标移入
const dealTooltip = (el, ceil) => {
  const cellChild = el.target;
  const range = window.document.createRange();
  range.setStart(cellChild, 0);
  range.setEnd(cellChild, cellChild.childNodes.length);
  let rangeWidth = range.getBoundingClientRect().width;
  let rangeHeight = range.getBoundingClientRect().height;
  const offsetWidth = rangeWidth - Math.floor(rangeWidth);
  if (offsetWidth < 0.001) {
    rangeWidth = Math.floor(rangeWidth);
  }
  const offsetHeight = rangeHeight - Math.floor(rangeHeight);
  if (offsetHeight < 0.001) {
    rangeHeight = Math.floor(rangeHeight);
  }

  const { top, left, right, bottom } = getPadding(cellChild);
  const horizontalPadding = left + right;
  const verticalPadding = top + bottom;
  if (
    rangeWidth + horizontalPadding > cellChild.offsetWidth ||
    rangeHeight + verticalPadding > cellChild.offsetHeight ||
    cellChild.scrollWidth > cellChild.offsetWidth
  ) {
    toolTipFlag.value = true;
  }
};
// 鼠标移出
const mouseLeaveTooltip = () => {
  toolTipFlag.value = false;
};

第五步解决el-tooltip太多的问题

当给轮播表传递很多的数据,例如几千个数据,页面会非常的卡,所以需要优化一下,把el-tooltip提取出来,只保留一个,什么地方需要,什么地方使用。

这里需要用到el-tooltip的虚拟触发

第一步创建三个参数

// el-tooltip的虚拟触发时的触发元素
const target = ref();
// el-tooltip渲染的内容
const content = ref();
// el-tooltip组件实例,实调用onOpen和onClose控制显隐
const popperRef = ref();

第二步把上面的dom元素中el-tooltip分开,给el-tooltip的virtual-triggering为true,virtual-ref为上面的创建的target,当鼠标移入的时候判断需要展示气泡了,把el.target赋值给上面创建的target

        <div
          v-for="(ceil, ci) in row.ceils"
          :key="`${ceil}${ri}${ci}`"
          class="ceil"
          :style="`width: ${state.widths[ci]}px;`"
          :align="state.aligns[ci]"
          @click="handleClick(ri, ci, row, ceil)"
          @mouseenter="handleHover(true, ri, ci, row, ceil)"
          @mouseleave="handleHover(false)"
        >
          <div
            v-html="ceil"
            class="text-ellipsis"
            @mouseenter="dealTooltip($event, ceil)"
            @mouseleave="mouseLeaveTooltip"
          />
        </div>

el-tooltip可以放在头部或者尾部,只要不参与dataV的源码中的v-for循环就行

       <ElTooltip
        ref="popperRef"
        popper-class="box-item"
        effect="dark"
        placement="top-start"
        virtual-triggering
        :disabled="!toolTipFlag"
        :virtual-ref="target"
        :teleported="false"
      >
        <template #content>
          <div v-html="content" style="line-height: 1" />
        </template>
      </ElTooltip>

之后通过el-tooltip官方给的onOpen和onClose方法去控制显隐

const dealTooltip = (el, ceil) => {
  const cellChild = el.target;
  const range = window.document.createRange();
  range.setStart(cellChild, 0);
  range.setEnd(cellChild, cellChild.childNodes.length);
  let rangeWidth = range.getBoundingClientRect().width;
  let rangeHeight = range.getBoundingClientRect().height;
  const offsetWidth = rangeWidth - Math.floor(rangeWidth);
  if (offsetWidth < 0.001) {
    rangeWidth = Math.floor(rangeWidth);
  }
  const offsetHeight = rangeHeight - Math.floor(rangeHeight);
  if (offsetHeight < 0.001) {
    rangeHeight = Math.floor(rangeHeight);
  }

  const { top, left, right, bottom } = getPadding(cellChild);
  const horizontalPadding = left + right;
  const verticalPadding = top + bottom;
  if (
    rangeWidth + horizontalPadding > cellChild.offsetWidth ||
    rangeHeight + verticalPadding > cellChild.offsetHeight ||
    cellChild.scrollWidth > cellChild.offsetWidth
  ) {
    toolTipFlag.value = true;
    target.value = el.target;
    content.value = ceil;
    popperRef.value.onOpen();
  }
};

const mouseLeaveTooltip = () => {
  toolTipFlag.value = false;
  target.value = null;
  content.value = null;
  popperRef.value.onClose();
};

这样完成了不论多少个内容需要气泡,当前组件内部只有一个气泡,页面不会卡顿的优化

完整源码

自定义组件ScrollBoard.vue的内容

<template>
  <div ref="scrollBoard" class="dv-scroll-board">
    <div
      v-if="state.header.length && state.mergedConfig"
      class="header"
      :style="`background-color: ${state.mergedConfig.headerBGC};`"
    >
      <div
        v-for="(headerItem, i) in state.header"
        :key="`${headerItem}${i}`"
        v-dompurify-html="headerItem"
        class="header-item"
        :style="`
          height: ${state.mergedConfig.headerHeight}px;
          line-height: ${state.mergedConfig.headerHeight}px;
          width: ${state.widths[i]}px;
        `"
        :align="state.aligns[i]"
      />
    </div>

    <div
      v-if="state.mergedConfig"
      class="rows"
      :style="`height: ${height - (state.header.length ? state.mergedConfig.headerHeight : 0)}px;`"
    >
      <div
        v-for="(row, ri) in state.rows"
        :key="`${row.toString()}${row.scroll}`"
        class="row-item"
        :style="`
          height: ${state.heights[ri]}px;
          line-height: ${state.heights[ri]}px;
          background-color: ${
            state.mergedConfig[row.rowIndex % 2 === 0 ? 'evenRowBGC' : 'oddRowBGC']
          };
        `"
      >
        <div
          v-for="(ceil, ci) in row.ceils"
          :key="`${ceil}${ri}${ci}`"
          class="ceil"
          :style="`width: ${state.widths[ci]}px;`"
          :align="state.aligns[ci]"
          @click="handleClick(ri, ci, row, ceil)"
          @mouseenter="handleHover(true, ri, ci, row, ceil)"
          @mouseleave="handleHover(false)"
        >
          <div
            v-dompurify-html="ceil"
            class="text-ellipsis"
            @mouseenter="dealTooltip($event, ceil)"
            @mouseleave="mouseLeaveTooltip"
          />
        </div>
      </div>
      <ElTooltip
        v-if="state.mergedConfig.showTooltip"
        ref="popperRef"
        popper-class="box-item"
        effect="dark"
        placement="top-start"
        virtual-triggering
        :disabled="!toolTipFlag"
        :virtual-ref="target"
        :teleported="false"
      >
        <template #content>
          <div v-dompurify-html="content" style="line-height: 1" />
        </template>
      </ElTooltip>
    </div>
  </div>
</template>

<script setup>
import { cloneDeep, merge } from "lodash";
import autoResize from "./utils/autoResize";

const props = defineProps({
  config: {
    type: Object,
    default: () => ({}),
  },
});

const emitEvent = defineEmits(["mouseover", "click", "getFirstRow"]);

const scrollBoard = ref(null);
const { width, height } = autoResize(scrollBoard, onResize, afterAutoResizeMixinInit);

const state = reactive({
  defaultConfig: {
    /**
     * @description Board header
     * @type {Array<string>}
     * @default header = []
     * @example header = ['column1', 'column2', 'column3']
     */
    header: [],
    /**
     * @description Board data
     * @type {Array<Array>}
     * @default data = []
     */
    data: [],
    /**
     * @description Row num
     * @type {number}
     * @default rowNum = 5
     */
    rowNum: 5,
    /**
     * @description Header background color
     * @type {string}
     * @default headerBGC = '#00BAFF'
     */
    headerBGC: "#00BAFF",
    /**
     * @description Odd row background color
     * @type {string}
     * @default oddRowBGC = '#003B51'
     */
    oddRowBGC: "#003B51",
    /**
     * @description Even row background color
     * @type {string}
     * @default evenRowBGC = '#003B51'
     */
    evenRowBGC: "#0A2732",
    /**
     * @description Scroll wait time
     * @type {number}
     * @default waitTime = 2000
     */
    waitTime: 2000,
    /**
     * @description Header height
     * @type {number}
     * @default headerHeight = 35
     */
    headerHeight: 35,
    /**
     * @description Column width
     * @type {Array<number>}
     * @default columnWidth = []
     */
    columnWidth: [],
    /**
     * @description Column align
     * @type {Array<string>}
     * @default align = []
     * @example align = ['left', 'center', 'right']
     */
    align: [],
    /**
     * @description Show index
     * @type {boolean}
     * @default index = false
     */
    index: false,
    /**
     * @description index Header
     * @type {string}
     * @default indexHeader = '#'
     */
    indexHeader: "#",
    /**
     * @description Carousel type
     * @type {string}
     * @default carousel = 'single'
     * @example carousel = 'single' | 'page'
     */
    carousel: "single",
    /**
     * @description Pause scroll when mouse hovered
     * @type {boolean}
     * @default hoverPause = true
     * @example hoverPause = true | false
     */
    hoverPause: true,
    /**
     * @description 是否使用气泡
     * @type {boolean}
     * @default hoverPause = true
     * @example showTooltip = true | false
     */
    showTooltip: false,
  },

  mergedConfig: null,

  header: [],

  rowsData: [],

  rows: [],

  widths: [],

  heights: [],

  avgHeight: 0,

  aligns: [],

  animationIndex: 0,

  animationHandler: "",

  updater: 0,

  needCalc: false,
});

watch(
  () => props.config,
  () => {
    stopAnimation();
    // 此处打开后,config发生变化时,会从第一行开始重新轮播
    // state.animationIndex = 0

    calcData();
  },
  { deep: true },
);

onUnmounted(() => {
  stopAnimation();
});

defineExpose({
  updateRows,
});
function handleClick(ri, ci, row, ceil) {
  const { ceils, rowIndex } = row;
  emitEvent("click", {
    row: ceils,
    ceil,
    rowIndex,
    columnIndex: ci,
  });
}
function handleHover(enter, ri, ci, row, ceil) {
  if (enter) {
    const { ceils, rowIndex } = row;
    emitEvent("mouseover", {
      row: ceils,
      ceil,
      rowIndex,
      columnIndex: ci,
    });
  }
  if (!state.mergedConfig.hoverPause) return;

  if (enter) stopAnimation();
  else animation(true);
}
function afterAutoResizeMixinInit() {
  calcData();
}
function onResize() {
  if (!state.mergedConfig) return;

  calcWidths();

  calcHeights();
}
function calcData() {
  mergeConfig();

  calcHeaderData();

  calcRowsData();

  calcWidths();

  calcHeights();

  calcAligns();

  animation(true);
}
function mergeConfig() {
  state.mergedConfig = merge(cloneDeep(state.defaultConfig, true), props.config || {});
}
function calcHeaderData() {
  let { header } = state.mergedConfig;
  const { index, indexHeader } = state.mergedConfig;
  if (!header.length) {
    header = [];

    return;
  }

  header = [...header];
  if (index) header.unshift(indexHeader);

  state.header = header;
}
function calcRowsData() {
  let { data } = state.mergedConfig;
  const { index, headerBGC, rowNum } = state.mergedConfig;
  if (index) {
    data = data.map((row, i) => {
      row = [...row];

      const indexTag = `<span class="index" style="background-color: ${headerBGC};">${
        i + 1
      }</span>`;

      row.unshift(indexTag);

      return row;
    });
  }

  data = data.map((ceils, i) => ({ ceils, rowIndex: i }));

  const rowLength = data.length;

  if (rowLength > rowNum && rowLength < 2 * rowNum) data = [...data, ...data];

  data = data.map((d, i) => ({ ...d, scroll: i }));

  state.rowsData = data;
  state.rows = data;
}
function calcWidths() {
  const { columnWidth, header } = state.mergedConfig;

  const usedWidth = columnWidth.reduce((all, w) => all + w, 0);

  let columnNum = 0;
  if (state.rowsData[0]) columnNum = state.rowsData[0].ceils.length;
  else if (header.length) columnNum = header.length;

  const avgWidth = (width.value - usedWidth) / (columnNum - columnWidth.length);

  const widths = Array.from({ length: columnNum }).fill(avgWidth);

  state.widths = merge(widths, columnWidth);
}
function calcHeights(onresize = false) {
  const { headerHeight, rowNum, data } = state.mergedConfig;

  let allHeight = height.value;

  if (state.header.length) allHeight -= headerHeight;

  const avgHeight = allHeight / rowNum;

  state.avgHeight = avgHeight;

  if (!onresize) state.heights = Array.from({ length: data.length }).fill(avgHeight);
}
function calcAligns() {
  const columnNum = state.header.length;

  const aligns = Array.from({ length: columnNum }).fill("left");

  const { align } = state.mergedConfig;

  state.aligns = merge(aligns, align);
}
async function animation(start = false) {
  if (state.needCalc) {
    calcRowsData();
    calcHeights();
    state.needCalc = false;
  }

  const { waitTime, carousel, rowNum } = state.mergedConfig;
  const { updater } = state;

  const rowLength = state.rowsData.length;

  if (rowNum >= rowLength) return;

  if (start) await new Promise((resolve) => setTimeout(resolve, waitTime));
  if (updater !== state.updater) return;

  const animationNum = carousel === "single" ? 1 : rowNum;

  const rows = state.rowsData.slice(state.animationIndex);
  rows.push(...state.rowsData.slice(0, state.animationIndex));

  state.rows = rows.slice(0, carousel === "page" ? rowNum * 2 : rowNum + 1);
  state.heights = Array.from({ length: rowLength }).fill(state.avgHeight);

  await new Promise((resolve) => setTimeout(resolve, 300));
  if (updater !== state.updater) return;

  state.heights.splice(0, animationNum, ...Array.from({ length: animationNum }).fill(0));

  state.animationIndex += animationNum;

  const back = state.animationIndex - rowLength;
  if (back >= 0) state.animationIndex = back;

  // state.animationIndex = animationIndex
  state.animationHandler = setTimeout(animation, waitTime - 300);

  emitEvent("getFirstRow", rows[1]);
}
function stopAnimation() {
  state.updater = (state.updater + 1) % 999999;
  if (!state.animationHandler) return;

  clearTimeout(state.animationHandler);
}
function updateRows(rows, animationIndex) {
  state.mergedConfig = {
    ...state.mergedConfig,
    data: [...rows],
  };

  state.needCalc = true;

  if (typeof animationIndex === "number") state.animationIndex = animationIndex;
  if (!state.animationHandler) animation(true);
}
// 解决气泡的问题,代码来自el-table的show-tootip
// el-tooltip的虚拟触发时的触发元素
const target = ref();
// el-tooltip渲染的内容
const content = ref();
// el-tooltip组件实例,实调用onOpen和onClose控制显隐
const popperRef = ref();
// 判断是否需要禁用el-tooltip,当内容没被遮挡时禁用
const toolTipFlag = ref(false);
/**
 * 鼠标移入元素的事件
 * @param {Event} el
 * 鼠标移入位置的内容
 * @param {String} ceil
 */
const dealTooltip = (el, ceil) => {
  if (!state.mergedConfig.showTooltip) return;
  const cellChild = el.target;
  // 创建Range对象,通过文本的尺寸和所处的位置的尺寸比较判断是否为被遮挡的
  const range = window.document.createRange();
  range.setStart(cellChild, 0);
  range.setEnd(cellChild, cellChild.childNodes.length);
  let rangeWidth = range.getBoundingClientRect().width;
  let rangeHeight = range.getBoundingClientRect().height;
  const offsetWidth = rangeWidth - Math.floor(rangeWidth);
  if (offsetWidth < 0.001) {
    rangeWidth = Math.floor(rangeWidth);
  }
  const offsetHeight = rangeHeight - Math.floor(rangeHeight);
  if (offsetHeight < 0.001) {
    rangeHeight = Math.floor(rangeHeight);
  }

  const { top, left, right, bottom } = getPadding(cellChild);
  const horizontalPadding = left + right;
  const verticalPadding = top + bottom;
  // 判断也是来自源码,文本被遮挡时显示el-tooltip
  if (
    rangeWidth + horizontalPadding > cellChild.offsetWidth ||
    rangeHeight + verticalPadding > cellChild.offsetHeight ||
    cellChild.scrollWidth > cellChild.offsetWidth
  ) {
    toolTipFlag.value = true;
    target.value = el.target;
    content.value = ceil;
    popperRef.value.onOpen();
  }
};
// 鼠标移出元素时,有关el-tooltip的参数还原,el-tooltip隐藏
const mouseLeaveTooltip = () => {
  if (!state.mergedConfig.showTooltip) return;
  toolTipFlag.value = false;
  target.value = null;
  content.value = null;
  popperRef.value.onClose();
};
/**
 * 获取el元素的css中的paddingLeft等属性值
 * @param {HTMLElement} el
 */
const getPadding = (el) => {
  const style = window.getComputedStyle(el, null);
  const paddingLeft = Number.parseInt(style.paddingLeft, 10) || 0;
  const paddingRight = Number.parseInt(style.paddingRight, 10) || 0;
  const paddingTop = Number.parseInt(style.paddingTop, 10) || 0;
  const paddingBottom = Number.parseInt(style.paddingBottom, 10) || 0;
  return {
    left: paddingLeft,
    right: paddingRight,
    top: paddingTop,
    bottom: paddingBottom,
  };
};
</script>

<style lang="less">
.dv-scroll-board {
  position: relative;
  width: 100%;
  height: 100%;
  color: #fff;

  .text {
    padding: 0 10px;
    box-sizing: border-box;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .header {
    display: flex;
    flex-direction: row;
    font-size: 15px;

    .header-item {
      .text;
      transition: all 0.3s;
    }
  }

  .rows {
    overflow: hidden;

    .row-item {
      display: flex;
      font-size: 14px;
      transition: all 0.3s;
    }

    .ceil {
      .text;
    }

    .index {
      border-radius: 3px;
      padding: 0px 3px;
    }
  }
}
.box-item {
  padding: 0.1rem 0.2rem;
  div {
    span {
      color: #fff !important;
      font-size: 0.225rem;
    }
  }
}
.text-ellipsis {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
</style>

  autoResize.ts

import { nextTick, onActivated, onDeactivated, onMounted, onUnmounted, ref } from "vue";
import { useDebounceFn, useEventListener } from "@vueuse/core";
import type { Ref } from "vue";
/**
 * 创建观察器
 * @param {HTMLElement} dom
 * @param {() => void} callback
 * @returns {window.MutationObserver}
 */
export function observerDomResize(dom: HTMLElement, callback: () => void) {
  const MutationObserver = window.MutationObserver;

  const observer = new MutationObserver(callback);

  observer.observe(dom, { attributes: true, attributeFilter: ["style"], attributeOldValue: true });

  return observer;
}
function autoResize(
  dom: Ref<HTMLElement | null>,
  onResize?: () => void,
  afterAutoResizeMixinInit?: () => void,
) {
  const width = ref(0);
  const height = ref(0);

  let debounceInitWHFun: () => void;
  let domObserver: MutationObserver | null = null;
  let domHtml: HTMLElement | null = null;
  const initWH = (resize = true) => {
    return new Promise((resolve) => {
      nextTick(() => {
        domHtml = dom.value;
        width.value = dom.value ? dom.value.clientWidth : 0;
        height.value = dom.value ? dom.value.clientHeight : 0;

        if (!dom.value)
          console.warn("DataV: Failed to get dom node, component rendering may be abnormal!");
        else if (!width.value || !height.value)
          console.warn("DataV: Component width or height is 0px, rendering abnormality may occur!");

        if (typeof onResize === "function" && resize) onResize();
        resolve(true);
      });
    });
  };
  const getDebounceInitWHFun = () => {
    debounceInitWHFun = useDebounceFn(initWH, 200);
  };
  const bindDomResizeCallback = () => {
    domObserver = observerDomResize(domHtml!, debounceInitWHFun);

    useEventListener(window, "resize", debounceInitWHFun);
  };
  const unbindDomResizeCallback = () => {
    if (!domObserver) return;
    domObserver.disconnect();
    domObserver.takeRecords();
    domObserver = null;
  };
  const autoResizeMixinInit = async () => {
    await initWH(false);

    getDebounceInitWHFun();

    bindDomResizeCallback();

    if (typeof afterAutoResizeMixinInit === "function") afterAutoResizeMixinInit();
  };
  onMounted(() => {
    autoResizeMixinInit();
  });

  onUnmounted(() => {
    unbindDomResizeCallback();
  });
  onActivated(autoResizeMixinInit);

  onDeactivated(unbindDomResizeCallback);

  return {
    width,
    height,
    initWH,
  };
}

export default autoResize;

这里多了一个参数showTooltip,用于控制当前自定义组件是否需要el-tooltip 

另外

可以优化的点:使用v-dompurify-html代替v-html会更安全,替代方法

npm i vue-dompurify-html

在main.ts中引入和使用

// 使用v-dompurify-html替代v-html
import VueDOMPurifyHTML from "vue-dompurify-html";
const vueApp = Vue.createApp(App);
vueApp.use(VueDOMPurifyHTML);

dataV的使用方法:

npm install @kjgl77/datav-vue3
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import DataVVue3 from '@kjgl77/datav-vue3'
createApp(App).use(DataVVue3).mount('#app')
<template>
  <div>
    <dv-decoration-1 :color="['pink','yellow']" style="width:200px;height:50px;" />
  </div>
</template>
<script setup lang="ts">

</script>
<style lang="scss" scoped>
</style>

如有报错,需要安装@dataview/datav-vue3

npm i @dataview/datav-vue3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值