在 slot 上执行 js

Executing js on slot

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

有很多 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 内容进行格式化。我知道我可以使用道具,组件看起来像这样:

Tooltip.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>

Parent.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 函数?

如果我没理解错的话,你正在寻找scoped slots这里。

这些将允许您将信息(包括方法)从 child 组件(具有 <slot> 元素的组件)传递回 parents(填充这些组件的组件)插槽),允许 parents 直接在 slotted-in 内容中使用所选信息。

在这种情况下,我们可以授予 parents 对 formatContent() 的访问权限,这将允许他们传入直接使用它的内容。这使我们能够通过 props 的数据传递来保持插槽的灵活性。

为了将此添加到您的示例中,我们在 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>

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

<!-- 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 }">

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

<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>