在写代码的时候,偶然遇到了这个问题。
Slot "default" invoked outside of the render function: this will not track dependencies used in the slot. Invoke the slot function inside the render function instead.
看样子是关于插槽的问题。
最后发现了问题所在:useSlots 返回的 slots 是一个代理对象,也就是说它是具有响应式的。
定义一个父组件。它会动态改变 msg,来使插槽改变。
它使用了一个 v-button 组件。
<script setup lang="ts">
import { ref } from 'vue';
import vButton from './components/button.vue'
const msg = ref('123')
</script>
<template>
<input type="text" v-model="msg" />
<br />
<v-button>{{msg}}</v-button>
</template>
<style lang="scss" scoped>
</style>
v-button 中使用 computed 动态计算 slot 的内容
我们有一个子组件 button.vue。
如果像一开始那样写,相当于只是给 isShowIcon 赋了一个初始值。
如果想要具有响应式,需要放在 computed 计算属性里。(因为计算返回的是一个引用地址,引用地址始终没变,所以不会重新触发 computed 计算函数。)
<script setup lang="ts">
import { computed, useSlots } from 'vue';
/** 获取插槽 */
const slots = useSlots()
- // const isShowIcon = !(slots.default && slots.default() && slots.default()[0].children)
+ const isShowIcon = computed(() => {
+ return !(slots.default && slots.default() && slots.default()[0].children)
+ })
</script>
<template>
<button>
<span v-show="isShowIcon">🤩</span>
<slot />
</button>
</template>
<style lang="scss" scoped>
</style>
v-button 中直接模板上使用 $slots
除了在 computed 中使用 slot,也可以直接再模板上使用 $slots。
注意前缀 $
<template>
<button>
<span v-show="!($slots.default && $slots.default() && $slots.default()[0].children)">🤩</span>
<slot />
</button>
</template>
总结
只有这样,当动态输入改变 msg,按钮上的内容为 "" 时,“icon”文字就会显示了。
结尾来张动图。当输入框内的内容为空时,按钮的 icon 就会显示。