在 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>
我是 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>