如何在NiceGUI插槽中复用函数且避免客户端代码重复?
这个问题确实戳中了NiceGUI里复用客户端逻辑的痛点——重复写内联代码不仅冗余,还特别不好维护。我给你两个亲测可行的方案,解决起来很顺畅:
方案一:注册Vue全局方法(最直接的复用方式)
因为NiceGUI基于Vue 3,我们可以把格式化函数注册到Vue的全局属性里,这样所有组件的插槽模板都能直接调用它,完全不用重复代码。
步骤1:定义全局函数并注册到Vue
用ui.add_head_html在页面头部添加脚本,等Vue应用初始化完成后,把我们的自定义函数挂载到Vue全局属性上:
from nicegui import ui # 在页面头部添加脚本,注册全局格式化函数 ui.add_head_html(""" <script> document.addEventListener('DOMContentLoaded', () => { // 获取NiceGUI的Vue应用实例 const vueApp = document.querySelector('#app').__vue__; // 注册全局格式化函数,这里可以写任意复杂的逻辑 vueApp.config.globalProperties.getBadgeColor = (value) => { if (value < 21) return 'red'; if (value < 65) return 'green'; if (value > 100) return 'purple'; return 'orange'; }; }); </script> """)
步骤2:在插槽里调用全局函数
之后在任何组件的插槽中,都可以用$前缀调用这个全局函数(Vue会自动把全局属性挂载到组件上下文):
# 示例:在Table的age列插槽中使用全局函数 table.add_slot('body-cell-age', ''' <q-td key="age" :props="props"> <q-badge :color="$getBadgeColor(props.value)"> {{ props.value }} </q-badge> </q-td> ''')
这样不管你有多少个插槽需要用这个格式化逻辑,只需要调用$getBadgeColor就行,完全不会有代码重复。
方案二:封装成可复用Vue组件(适合UI+逻辑绑定的场景)
如果你的格式化不仅是颜色判断,还需要配合特定的UI结构(比如自定义徽章样式、图标等),把逻辑和UI封装成一个自定义Vue组件会更合适,而且能彻底解决你之前遇到的props不填充的问题。
步骤1:定义带props的自定义Vue组件
在自定义组件里用defineProps明确声明需要接收的参数,然后把格式化逻辑写在组件内部:
from nicegui import ui # 封装可复用的年龄徽章组件,包含格式化逻辑 AgeBadge = ui.vue(""" <template> <q-badge :color="getBadgeColor(value)" class="custom-badge"> {{ value }} </q-badge> </template> <script setup> // 明确声明组件需要接收的props const props = defineProps(['value']); // 自定义格式化逻辑 const getBadgeColor = (value) => { if (value < 21) return 'red'; if (value < 65) return 'green'; return 'blue'; }; </script> <style scoped> .custom-badge { font-weight: bold; padding: 4px 8px; } </style> """)
步骤2:在插槽里使用自定义组件
之后在任何插槽中,直接调用这个组件并传递props.value就行,组件会自动接收并处理参数:
# 在Table的age列插槽中使用自定义组件 table.add_slot('body-cell-age', ''' <q-td key="age" :props="props"> <AgeBadge :value="props.value" /> </q-td> ''')
之前你遇到的props不填充问题,就是因为没有在自定义组件里用defineProps声明需要的参数,加上之后就完全正常了。
补充:为什么之前挂window的方法没生效?
Vue的模板表达式默认运行在组件的局部上下文里,不是全局window对象。如果一定要用window挂载的方法,需要在插槽里显式加window.前缀,比如window.getBadgeColor(props.value),但这种方式不符合Vue的生态规范,还是推荐用上面两种方案。
备注:内容来源于stack exchange,提问作者Konrad Jamrozik

