记一个简易的全局tooltip指令

238 阅读2分钟
  • 你是否也会因为el-tooltip组件的繁琐使用而想要一个简单易用的指令呢?
  • 你是否想要一个类似el-tableshow-overflow-tooltip文字溢出功能的独立tooltip呢?

那就开始今日份v-tooltip指令的封装吧~

  1. 在项目目录中的自定义指令文件夹directive里添加 tooltip.js
import { createApp, ref, h } from 'vue'
import { ElTooltip } from 'element-plus';

// 初始化配置
const INIT_CONFIG = {
    isCommon: false,
    visible: false,
    triggeringRef: {}, 
    placement: 'top',
    content: '',
    effect: 'light',
    offset: 6,
    showArrow: true,
    rawContent: false
}

// 可修改配置
const CONFIG = ref({
    visible: false,
    triggeringRef: {}, 
    placement: 'top',
    content: '',
    effect: 'light',
    offset: 0,
    showArrow: true,
    rawContent: false,
    disabled: false
})

const synopsis = createApp({
    setup() {
        return () => h(ElTooltip, {
            ref: 'elTooltipRef',
            isCommon: CONFIG.value.isCommon,                // 设置为普通的tooltip,无需溢出再触发
            visible: CONFIG.value.visible,                 // 手动触发显示
            virtualTriggering: true,                // 是否开启虚拟触发元素【这里默认开启状态】
            virtualRef: CONFIG.value.triggeringRef,        // 虚拟触发元素
            placement: CONFIG.value.placement,             // 提示框位置
            content: CONFIG.value.content,                 // 提示框内容
            effect: CONFIG.value.effect,                   // 提示框主题
            offset: CONFIG.value.offset,                    // 提示框偏移量
            showArrow: CONFIG.value.showArrow,                              // 是否显示箭头
            rawContent: CONFIG.value.rawContent,      // 是否开启内容显示为html
            disabled: CONFIG.value.disabled,                    // 是否禁用
        });
    }
});
const DIV = document.createElement("div")
const tipInstance = synopsis.mount(DIV)
document.body.appendChild(tipInstance.$el);

function tipMouseenterHandler (el) {
    const binding = this.binding;
    if (binding.value.isCommon || el.target.scrollWidth > el.target.offsetWidth || el.target.scrollHeight > el.target.offsetHeight) {
        // 强制指定 arg 是 placement
        binding.arg ? CONFIG.value.placement = binding.arg : INIT_CONFIG.placement;

        // 当 binding.value 是对象时,将 binding.value 合并到 CONFIG.value 中,如果是字符串,则直接赋值给 CONFIG.value.content
        if (binding.value) {
            if (Object.prototype.toString.call(binding.value) === '[object Object]') {
                Object.keys(CONFIG.value).forEach(key => CONFIG.value[key] = binding.value[key] !== undefined ? binding.value[key] : INIT_CONFIG[key]);
            } else {
                CONFIG.value.content = binding.value;
            }
        }

        CONFIG.value.visible = true;
        CONFIG.value.triggeringRef = el.target;
    }
}

function tipMouseleaveHandler (el) {
    CONFIG.value.visible = false;
    CONFIG.value.triggeringRef = null;
}

function tipClickHandler(el) {
    const binding = this.binding;
    if (binding.value.isCommon || el.target.scrollWidth > el.target.offsetWidth || el.target.scrollHeight > el.target.offsetHeight) {
        // 强制指定 arg 是 placement
        binding.arg ? CONFIG.value.placement = binding.arg : INIT_CONFIG.placement;

        // 当 binding.value 是对象时,将 binding.value 合并到 CONFIG.value 中,如果是字符串,则直接赋值给 CONFIG.value.content
        if (binding.value) {
            if (Object.prototype.toString.call(binding.value) === '[object Object]') {
                Object.keys(CONFIG.value).forEach(key => CONFIG.value[key] = binding.value[key] ? binding.value[key] : INIT_CONFIG[key]);
                if (binding.value.content === undefined) {
                    const content = [...this.children].find(item => item.classList.contains('el-tooltip__popper'));
                    CONFIG.value.content = content.innerHTML;
                }
            } else {
                CONFIG.value.content = binding.value;
            }
        }

        CONFIG.value.visible = true;
        CONFIG.value.triggeringRef = el.target;
    }
}

export default {
    install(app) {
        app.directive('tooltip', {
            mounted(el, binding) {
                el.binding = binding;
                el.addEventListener('mouseenter', tipMouseenterHandler);
                el.addEventListener('mouseleave', tipMouseleaveHandler, false);
            },
            updated(el, binding) {
                el.binding = binding;
            },
            beforeUnmount(el) {
                el.removeEventListener('mouseenter', tipMouseenterHandler);
                el.removeEventListener('mouseleave', tipMouseleaveHandler);
            }
        })
    }
}
  1. main.js 配置
import { GlobDirective, ToolTip } from './directive/tooltip.js';

const app = createApp(App)
    .use(ToolTip);
  1. 使用方式
  • 最简单的传递字符串(文字溢出时移入提示)
<div style="padding: 100px;background-color: #fff;">
    <p v-tooltip="'你是最牛逼的前端开发工程师'" style="width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap">你是最牛逼的前端开发工程师</p>
</div>

image.png

  • 完整配置(无论何时都可移入显示提示)
<div style="padding: 100px;background-color: #fff;">
    <p v-tooltip="{
        content: `<div style='font-size: 20px;color: pink;'>Your are the best~</div>`,
        isCommon: true,
        placement: 'bottom',
        effect: 'dark',
        offset: 10,
        showArrow: false,
        rawContent: true,
        disabled: false
    }" style="width: fit-content;">你是最牛逼的前端开发工程师</p>
</div>

image.png