2

我想使用VueUse 的可组合虚拟滚动器来呈现HeadlessUI 的列表框内容。

这是我尝试过的:

<Listbox v-model="selectedIcon">
  <div class="relative mt-1">
    <ListboxButton class="bg-white rounded-lg cursor-default shadow-md text-left w-full py-2 pr-10 pl-3 relative sm:text-sm focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-white focus-visible:ring-2 focus-visible:ring-opacity-75 focus-visible:ring-offset-orange-300 focus-visible:ring-offset-2">
      <span class="block truncate">test</span>
      <span class="flex pr-2 inset-y-0 right-0 absolute items-center pointer-events-none">
        <SelectorIcon class="h-5 text-gray-400 w-5" aria-hidden="true" />
      </span>
    </ListboxButton>

    <ListboxOptions v-bind="containerProps" class="bg-white rounded-md shadow-lg ring-black mt-1 text-base w-full max-h-60 h-full py-1 ring-1 ring-opacity-5 absolute overflow-auto sm:text-sm focus:outline-none">
      <div v-bind="wrapperProps">
        <ListboxOption v-slot="{ active, selected }" v-for="icon in list" :key="icon.data.name" :value="icon">
          <li>
            <span>{{ icon.data.name }}</span>
          </li>
        </ListboxOption>
      </div>
    </ListboxOptions>
  </div>
</Listbox>

这是可组合的虚拟滚动条:

const { list, containerProps, wrapperProps } = useVirtualList(icons, { itemHeight: 40 })

问题是,当我尝试打开列表框时,出现此错误:

Uncaught (in promise) TypeError: Failed to execute 'observe' on 'ResizeObserver': parameter 1 is not of type 'Element'.
    at watch.immediate (index.mjs:1322)
    at callWithErrorHandling (runtime-core.esm-bundler.js:6737)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js:6746)
    at Array.job (runtime-core.esm-bundler.js:7154)
    at flushPostFlushCbs (runtime-core.esm-bundler.js:6938)
    at flushJobs (runtime-core.esm-bundler.js:6983)
    at flushJobs (runtime-core.esm-bundler.js:6991)

我也收到此警告:

[Vue warn]: Unhandled error during execution of watcher callback 
  at <ApplicationIconSelector key=0 > 
  at <Anonymous as="template" enter="ease-out duration-300" enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"  ... > 
  at <ForcePortalRoot force=false > 
  at <PortalGroup target= <div class=​&quot;fixed z-10 inset-0 overflow-y-auto" id=​&quot;headlessui-dialog-4" role=​&quot;dialog" aria-modal=​&quot;true" aria-labelledby=​&quot;headlessui-dialog-title-8">​…​&lt;/div>​&lt;div class=​&quot;flex min-h-screen text-center px-4 pt-4 pb-20 items-end justify-center sm:​p-0 sm:​block">​&lt;div id=​&quot;headlessui-dialog-overlay-6" aria-hidden=​&quot;true" class=​&quot;bg-gray-975 bg-opacity-85 inset-0 transition-opacity fixed">​&lt;/div>​&lt;!-- This element is to trick the browser into centering the modal contents. --><span class=​&quot;hidden sm:​h-screen sm:​inline-block sm:​align-middle" aria-hidden=​&quot;true">​&amp;ZeroWidthSpace;​&lt;/span>​&lt;div class=​&quot;rounded-lg shadow-xl text-left transform transition-all text-gray-850 inline-block align-bottom sm:​max-w-lg sm:​my-8 sm:​w-full sm:​align-middle dark:​text-gray-200">​&lt;div class=​&quot;rounded-t-lg bg-gray-25 px-4 pt-5 pb-4 sm:​p-6 sm:​pb-4 dark:​bg-gray-925">​…​&lt;/div>​&lt;div class=​&quot;bg-gray-75 py-3 px-3 sm:​flex sm:​flex-row-reverse dark:​bg-gray-900">​…​&lt;/div>​flex<button class=​&quot;flex-y-center justify-center p-2 px-3 font-medium text-sm transition duration-75 select-none cursor-pointer focus:​outline-none rounded-md bg-gray-75 text-gray-850 hover:​bg-gray-100 active:​bg-gray-175 dark:​text-gray-250 dark:​bg-gray-875 dark:​hover:​bg-gray-850 dark:​active:​bg-gray-825 w-full">​…​&lt;/button>​flex</div>​&lt;/div>​&lt;/div>​&lt;/div>​ > 
  at <Portal> 
  at <ForcePortalRoot force=true > 
  at <Dialog as="div" class="fixed z-10 inset-0 overflow-y-auto" ref="el"  ... > 
  at <Anonymous onBeforeEnter=fn<onBeforeEnter> onAfterEnter=fn<onAfterEnter> onBeforeLeave=fn<onBeforeLeave>  ... > 
  at <Anonymous as="template" show=true data=null > 
  at <AddEditApplication modelValue=true onUpdate:modelValue=fn data=null > 
  at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy {__v_skip: true} > > 
  at <RouterView> 
  at <App>
4

1 回答 1

0

Uncaught (in promise) TypeError: Failed to execute 'observe' on 'ResizeObserver': parameter 1 is not of type 'Element'.

看起来它正在尝试将自己绑定到本机 DOM 元素以外的东西。在 VueUse 网站上的示例中,它们显示带有v-bind指令的原生 DOM 元素。但是,您的代码v-bind在非本地 DOM 元素上使用,您将它放在 VNode(ListBox 组件)上。

即使查看源代码,您也可以看到绑定containerProps期望一个HTMLElement.

const containerRef: Ref = ref<HTMLElement | null>()

我以前没有使用过 HeadlessUI,但是查看ListBoxOptions组件的源代码,它似乎不会呈现任何传递到其默认插槽之外的元素;又名你的<div v-bind="wrapperProps">。您的课程列表甚至可以渲染任何东西吗?如果没有示例,很难说出您的代码是如何运行的。

我建议创建另一个div嵌套在 中的ListBoxOptions包裹<div v-bind="wrapperProps">元素。在这个新div的移动中,v-bind="containerProps"从它ListBoxOptions到它;见下文。

<ListboxOptions>
  <div v-bind="containerProps" class="bg-white rounded-md shadow-lg ring-black mt-1 text-base w-full max-h-60 h-full py-1 ring-1 ring-opacity-5 absolute overflow-auto sm:text-sm focus:outline-none">
    <div v-bind="wrapperProps">
      <ListboxOption v-slot="{ active, selected }" v-for="icon in list" :key="icon.data.name" :value="icon">
        <li>
          <span>{{ icon.data.name }}</span>
        </li>
      </ListboxOption>
    </div>
  </div>
</ListboxOptions>

我认为这可能会解决您的问题。

于 2022-01-03T18:27:31.797 回答