我是用 naiveUI 的 datatable 时自己写一个过滤菜单样式,我目前可以按照预期运行,传入 title 还有 value 还有图标的 src 链接. 格式
[{title:'标签名', value:'test', imgSrc='1.jpg'}] 现在我要允许传递一个 h 函数进去,像这样
[{title:'标签名', value:'test', imgSrc:'1.jpg', icon:h('div',null,'我是图标')}] 但是我不知道这个子组件接收到之后怎么把这个 icon 函数放进去 li 标签里面,直接在 h 函数里把 NList 标签用 h 函数来写,像下面的方法,但是他会报错,浏览器全都是下面的报错,我想问下这个要怎么处理才比较好一点
chunk-6SSRW7KQ.js?v=5c5b974b:1543 [Vue warn]: Non-function value encountered for default slot. Prefer function slots for better performance. at <Text> at <ListItem key="peersGettingFromUs" OnClick=fn<onClick> class="padding" > at <List hoverable=true clickable=true showDivider=false > at <List> at <ResizeObserver OnResize=fn<handleContentResize> > at <ResizeObserver OnResize=fn<handleContainerResize> > at <Scrollbar ref="scrollbarInstRef" xScrollable=false theme=undefined ... > at <Scrollbar style= Object > at <Menu optiOns= Array(20) selected= Array(4) onUpdate:modelValue=fn<onUpdate:modelValue> > at <DropdownRenderOption tmNode= Object key="header" > at <DropdownMenu ref=fn class="n-popover-shared n-dropdown" clsPrefix="n" ... > at <BaseTransition OnEnter=fn OnAfterLeave=fn<onAfterLeave> appear=true ... > at <Transition name="popover-transition" appear=true OnEnter=fn<onEnter> ... > at <LazyTeleport show=true to="body" disabled=false > at <Follower ref="followerRef" zIndex=undefined show=true ... > at <PopoverBody theme= Object themeOverrides=undefined builtinThemeOverrides=undefined ... > at <Binder ref="binderInstRef" syncTarget=true syncTargetWithParent=false > at <Popover show=true defaultShow=false showArrow=false ... > at <Dropdown trigger="hover" optiOns= Array(1) > at <Flex> at <HelloWorld> at <App> const mylist = () => { return h(NList, { hoverable: true, clickable: true, showDivider: false, }, props.options.map((item) => { return h(NListItem, { key: item.title, onClick: () => itemClick(item), class: 'padding', }, { prefix: () => { return h(NAvatar, { size: 22, src: item.imgSrc, color: 'white', bordered: true }) }, default: () => { return h(NText, null, item.title) }, suffix: () => { return h(NIcon, { // color: isSelected(item) ? '#1abc9c' : '#bdc3c7' size: 20 }, { default: () => { return h(CheckmarkDoneCircle, null) } } ) } }) }) ) } 
<template> <n-scrollbar style="max-height: 600px"> <!-- <mylist /> --> <n-list hoverable clickable :show-divider="false"> <n-list-item v-for="item in options" @click="itemClick(item)" :class="padding"> <template #prefix v-if="item.imgSrc"> <n-avatar :size="22" :src="item.imgSrc" color="white" :bordered="true" /> </template> {{ item.title ? item.title : empty }} <template #suffix> <n-icon :color="isSelected(item) ? '#1abc9c' : '#bdc3c7'" size="20"> <CheckmarkDoneCircle /> </n-icon> </template> </n-list-item> </n-list> </n-scrollbar> <n-button-group style="width:100%" size="large" :class="btn_width"> <n-button secondary @click="contrary" :disabled="isAll || isEmpty" v-if="contrary_btn"> <template #icon> <n-icon :color="isEmpty ? 'black' : '#00b894'" class="rotate" :style="{ transform: 'rotate(' + target.contrary + 'deg)' }"> <RepeatSharp /> </n-icon> </template> 反选 </n-button> <n-button secondary @click="_submit" :style="'width:' + 1 / 3"> <template #icon> <n-icon> <SaveOutline /> </n-icon> </template> 保存 </n-button> <n-button secondary @click="clear" :disabled="isEmpty" :style="'width:' + 1 / 3"> <template #icon> <n-icon class="rotate" :color="isEmpty ? 'black' : '#e74c3c'"> <TrashBinOutline /> </n-icon> </template> 清空 </n-button> </n-button-group> </template> <script lang="ts" setup> import { computed, h, reactive, ref } from 'vue' import { CheckmarkDoneCircle, TrashBinOutline, RepeatSharp, SaveOutline } from '@vicons/ionicons5' import { NAvatar, NIcon, NList, NListItem, NText } from 'naive-ui'; const props = defineProps({ selected: { type: Array<string | boolean>, required: true }, options: { type: Array<menu>, required: true }, padding: { type: String, required: false, default: 'small' }, contrary_btn: { type: Boolean, required: false, default: true }, // 当 title 为空字符串时显示的文本 empty: { type: String, required: false, default: '(empty)' }, renderIcon: { type: Function, required: false }, }) // 临时数组,用于保存用户已选中但是还未点击提交按钮的勾选值 const tmp_selected = ref<Array<string | boolean>>([...props.selected]) let btn_width = 'two' if (props.contrary_btn) { btn_width = 'there' } // 从传入的选项菜单里提取所有 value const all = props.options.map(item => item.value) const emit = defineEmits(['update:modelValue']); interface menu { title: string value: string | boolean desc?: string imgSrc?: string } const itemClick = (item: menu) => { if (isSelected.value(item)) { tmp_selected.value = tmp_selected.value.filter(o => o !== item.value) } else { tmp_selected.value.push(item.value) } } const _submit = () => { emit('update:modelValue', [...tmp_selected.value]); } const target = reactive({ contrary: 0 }) // 反选函数 const cOntrary= () => { target.contrary += 180; tmp_selected.value = all.filter(item => !tmp_selected.value.includes(item)) console.log(tmp_selected.value) } // 清空函数 const clear = () => { target.cOntrary= 0; tmp_selected.value = [] emit('update:modelValue', []) } const isSelected = computed(() => { return (item: menu) => { return tmp_selected.value.some(o => o === item.value); }; }); const isAll = computed(() => { return tmp_selected.value.length === props.options.length }) const isEmpty = computed(() => { return tmp_selected.value.length === 0 }) </script> <style scoped> .two button { width: 50%; } .there button { width: 33.33%; } .n-list.n-list--hoverable .n-list-item.small { padding: 7px 20px; } .n-list.n-list--hoverable .n-list-item.medium { padding: 10px 20px; } .n-list.n-list--hoverable .n-list-item.large { padding: 15px 20px; } .n-avatar { vertical-align: middle; } .select { background-color: aquamarine; } .rotate { transition: all 0.5s ease; } .rotated { transform: rotate(180deg); } </style> 


