You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Vue 2.6与DevExtreme构建可复用组件以避免代码重复?

解决Vue2.6+DevExtreme图标与Tooltip的封装问题

问题背景

使用Vue 2.6和DevExtreme开发时,图标搭配Tooltip的逻辑存在大量重复(如控制显示状态的变量、鼠标事件),尝试封装v-icon-tooltip组件但未生效,需要实现可复用的图标+Tooltip组件。

现有重复代码(工作状态)

模板部分

<div>
    ...
        <template #icon>
            <i
                id="icon1"
                class="dx-icon-refresh icon-cursor"
                @click="getReferralLink"
                readonly
                @mouseenter="toggleDefault1"
                @mouseleave="toggleDefault1"
            />
            <v-dx-tool-tip :visible="defaultVisible1" :hide-on-outside-click="false" target="#icon1">Get link</v-dx-tool-tip>
            <i
                id="icon2"
                class="dx-icon-copy icon-cursor"
                @click="copyReferralLink"
                readonly
                @mouseenter="toggleDefault2"
                @mouseleave="toggleDefault2"
            />
            <v-dx-tool-tip :visible="defaultVisible2" :hide-on-outside-click="false" target="#icon2">Copy to clipboard</v-dx-tool-tip>
        </template>
    ...
</div>

脚本部分

import { DxTooltip } from 'devextreme-vue/tooltip';

@Component({
    components: {
        'v-dx-tool-tip': DxTooltip,
    },
})
export default class ExtendedDetailAccountComponent extends mixins(CurrentUserMixin) {
    ...
    defaultVisible1 = false;
    defaultVisible2 = false;

    toggleDefault1() {
        this.defaultVisible1 = !this.defaultVisible1;
    }

    toggleDefault2() {
        this.defaultVisible2 = !this.defaultVisible2;
    }

    async getReferralLink() {
        // 业务逻辑
    }

    copyReferralLink() {
        // 业务逻辑
    }
    ...
}

未成功的封装尝试

父组件使用代码

<div>
    ...
        <template #icon>
            <v-icon-tooltip :id="icon1" class="dx-icon-refresh icon-cursor" tooltipText="Get link" @click="getReferralLink" />
            <v-icon-tooltip :id="icon2" class="dx-icon-copy icon-cursor" tooltipText="Copy to clipboard" @click="copyReferralLink" />
        </template>
    </v-text-input>
</div>

组件注册代码

import VIconTooltip from './v-icon-tooltip.vue';

@Component({
    components: {
        VIconTooltip,
    },
})
export default class ExtendedDetailAccountComponent extends mixins(CurrentUserMixin) {
    ...
    async getReferralLink() {
        // 业务逻辑
    }

    copyReferralLink() {
        // 业务逻辑
    }
    ...
}

待修正的v-icon-tooltip.vue组件

<template>
    <div>
        <i :id="id" v-bind="$attrs" readonly @mouseenter="toggle" @mouseleave="toggle" v-on="$listeners" />
        <DxTooltip :visible="visible" :hide-on-outside-click="false" target="id">{{ tooltipText }}</DxTooltip>
    </div>
</template>

<script>
import { DxTooltip } from 'devextreme-vue/tooltip';

export default {
    inheritAttrs: false,
    components: {
        DxTooltip,
    },
    props: {
        id: {
            type: String
        },
        tooltipText: {
            type: String
        },
    },
    data() {
        return {
            visible: false,
        }
    },
    methods: {
        toggle() {
            this.visible = !this.visible;
        }
    }
}
</script>

修正后的组件实现

问题点分析

  1. Tooltip目标绑定错误:DxTooltip的target属性需要带#前缀(CSS选择器格式),原代码直接写target="id"未绑定变量且缺少前缀。
  2. 属性绑定优先级问题:readonly直接写在标签上会被v-bind="$attrs"覆盖,需要调整位置确保生效。
  3. id传参错误:父组件中:id="icon1"会将icon1解析为变量,应改为字符串形式id="icon1"。

修正后的v-icon-tooltip.vue

<template>
    <div>
        <i 
            :id="id" 
            v-bind="$attrs" 
            v-on="$listeners"
            readonly 
            @mouseenter="toggle" 
            @mouseleave="toggle" 
        />
        <DxTooltip 
            :visible="visible" 
            :hide-on-outside-click="false" 
            :target="`#${id}`"
        >
            {{ tooltipText }}
        </DxTooltip>
    </div>
</template>

<script>
import { DxTooltip } from 'devextreme-vue/tooltip';

export default {
    inheritAttrs: false,
    components: {
        DxTooltip,
    },
    props: {
        id: {
            type: String,
            required: true // 强制传入id,避免绑定错误
        },
        tooltipText: {
            type: String,
            required: true
        },
    },
    data() {
        return {
            visible: false,
        }
    },
    methods: {
        toggle() {
            this.visible = !this.visible;
        }
    }
}
</script>

修正后的父组件使用代码

<div>
    ...
        <template #icon>
            <v-icon-tooltip id="icon1" class="dx-icon-refresh icon-cursor" tooltipText="Get link" @click="getReferralLink" />
            <v-icon-tooltip id="icon2" class="dx-icon-copy icon-cursor" tooltipText="Copy to clipboard" @click="copyReferralLink" />
        </template>
    </v-text-input>
</div>

效果说明

修正后组件可独立管理自身Tooltip的显示状态,父组件无需维护多个visible变量和toggle方法,完全复用图标+Tooltip的交互逻辑,代码简洁性和可维护性大幅提升。

内容的提问来源于stack exchange,提问作者tesicg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:17:56