首页 > 解决方案 > 在插槽上执行 js

问题描述

我是网络开发的初学者,我正在尝试帮助朋友重新启动旧游戏。我负责工具提示组件,但我碰壁了......

有很多 Vue 组件,其中很多我想调用一个名为 Tooltip 的子组件,我使用它vue-tippy来轻松配置。这是组件:

<template>
    <tippy class="tippy-tooltip">
      <slot name='tooltip-trigger'></slot>

      <template #content>
          <slot name='tooltip-content'>
          </slot>
      </template>
    </tippy>
</template>

<script>
import { formatText } from "@/utils/formatText";

    export default {
    name: "Tooltip",
    methods:{
        formatContent(value) {
            if (! value) return '';
            return formatText(value.toString());
            }
        },
    }
</script>

在其他组件之一中,我尝试使用工具提示:

<template>
    <a class="action-button" href="#">
        <Tooltip>
            <template #tooltip-trigger>
                <span v-if="action.movementPointCost > 0">{{ action.movementPointCost }}<img src="@/assets/images/pm.png" alt="mp"></span>
                <span v-else-if="action.actionPointCost > 0">{{ action.actionPointCost }}<img src="@/assets/images/pa.png" alt="ap"></span>
                <span v-if="action.canExecute">{{ action.name }}</span>
                <span v-else><s>{{ action.name }}</s></span>
                <span v-if="action.successRate < 100" class="success-rate"> ({{ action.successRate }}%)</span>
            </template>
            <template #tooltip-content>
                <h1>{{action.name}}</h1>
                <p>{{action.description}}</p>
            </template>
        </Tooltip>
    </a>
</template>

<script>
import Tooltip from "@/components/Utils/ToolTip";

export default {
    props: {
        action: Object
    },
    components: {Tooltip}
};
</script>

从这里一切都很好,工具提示以正确的内容正确显示。

问题是,文本中的文本{{ named.description }}需要与formatContent内容一起格式化。我知道我可以使用道具,组件看起来像这样:

工具提示.vue

<template>
    <tippy class="tippy-tooltip">
      <slot name='tooltip-trigger'></slot>

      <template #content>
          <h1 v-html="formatContent(title)" />
          <p v-html="formatContent(content)"/>
      </template>
    </tippy>
</template>

<script>
import { formatText } from "@/utils/formatText";

    export default {
    name: "Tooltip",
    methods:{
        formatContent(value) {
            if (! value) return '';
            return formatText(value.toString());
            }
        },
    props: {
        title: { 
            type: String,
            required: true
            },
        content: { 
            type: Array,
            required: true
            }
        }
    }
</script>

父.vue


<template>
    <a class="action-button" href="#">
        <Tooltip :title="action.name" :content="action.description">
            <template v-slot:tooltip-trigger>
                <span v-if="action.movementPointCost > 0">{{ action.movementPointCost }}<img src="@/assets/images/pm.png" alt="mp"></span>
                <span v-else-if="action.actionPointCost > 0">{{ action.actionPointCost }}<img src="@/assets/images/pa.png" alt="ap"></span>
                <span v-if="action.canExecute">{{ action.name }}</span>
                <span v-else><s>{{ action.name }}</s></span>
                <span v-if="action.successRate < 100" class="success-rate"> ({{ action.successRate }}%)</span>
            </template>
        </Tooltip>
    </a>
</template>

<script>
import Tooltip from "@/components/Utils/ToolTip";

export default {
    props: {
        action: Object
    },
    components: {Tooltip}
};
</script>

但我需要在工具提示组件中使用一个插槽,因为我们将有一些带有v-for.

有没有办法将数据从插槽传递到 JS 函数?

标签: vue.jsvue-componentvue-slot

解决方案


如果我对您的理解正确,那么您正在这里寻找作用域插槽

这些将允许您将信息(包括方法)从子组件(带有<slot>元素的组件)传递回父组件(填充这些插槽的组件),允许父组件直接在插入的内容中使用选择的信息。

在这种情况下,我们可以让父母访问formatContent(),这将允许他们传递直接使用它的内容。这让我们可以通过 props 的数据传递来保持 slot 的灵活性。

要将其添加到您的示例中,我们将一些“范围”添加到您的内容槽中Tooltip.vue<slot>这只是意味着我们为您的元素提供一个或多个属性,在这种情况下, formatContent

<!-- Tooltip.vue -->
<template>
    <tippy class="tippy-tooltip">
      <slot name='tooltip-trigger'></slot>

      <template #content>
          <!-- Attributes we add or bind to this slot (eg. formatContent) -->
          <!-- become available to components using the slot -->
          <slot name='tooltip-content' :formatContent="formatContent"></slot>
      </template>
    </tippy>
</template>

<script>
import { formatText } from "@/utils/formatText";

export default {
    name: "Tooltip",
    methods: {
        formatContent(value) {
            // Rewrote as a ternary, but keep what you're comfortable with
            return !value ? '' : formatText(value.toString());
        }
    },
}
</script>

现在我们已经为插槽添加了一些范围,用内容填充插槽的父母可以通过调用插槽的“范围”来使用它:

<!-- Parent.vue -->
<template>
    <a class="action-button" href="#">
        <Tooltip>
            . . .
            <template #tooltip-content="{ formatContent }">
                <!-- Elements in this slot now have access to 'formatContent' -->
                <h1>{{ formatContent(action.name) }}</h1>
                <p>{{ formatContent(action.description) }}</p>
            </template>
        </Tooltip>
    </a>
</template>

. . . 

旁注:我更喜欢对插槽范围使用解构语法,因为我觉得它更清晰,并且您只需公开您实际使用的内容:

<template #tooltip-content="{ formatContent }">

但是,如果您愿意,也可以在此处使用变量名称,这将成为一个对象,其中包含您的所有插槽内容作为属性。例如。:

<template #tooltip-content="slotProps">
    <!-- 'formatContent' is now a property of 'slotProps' -->
    <h1>{{ slotProps.formatContent(action.name) }}</h1>
    <p>{{ slotProps.formatContent(action.description) }}</p>
</template>

如果您仍然需要v-html渲染,您仍然可以在插槽中执行此操作:

<template #tooltip-content="{ formatContent }">
    <h1 v-html="formatContent(title)" />
    <p v-html="formatContent(content)"/>
</template>

推荐阅读