获取 Svelte 插槽中每个组件的索引

时间:2021-04-27 02:36:11

标签: listview material-design svelte svelte-3 svelte-component

有没有办法遍历 Svelte 组件中的所有子组件?

目标

我正在使用这种语法(理想情况下)在 Svelte 中创建一个列表组件。

<List>
  <ListItem>Item 1</ListItem>
  <ListItem>Item 2</ListItem>
  <ListItem>Item 3</ListItem>
</List>

但是,该列表应该具有相当多的交互性。

  • 用户应该能够点击一个项目并选择它
  • 只有第一项应该是可切换的 (tabindex={0})
  • 用户应该能够使用箭头键/回车键来选择列表项
  • +更多与问题无关的内容

查看Material Design web components for demos

问题

要做到这一点,元素需要知道它们在列表中的“位置”。例如,第一个列表项需要知道它是第一个设置正确的 tabindex。要使用箭头键导航列表,您需要知道“项目 2 处于活动状态”以通过向下箭头切换到“项目 3”。

有没有办法遍历一个组件中的所有子组件?

或者,一种通过组合实现 Material Design 列表行为的方法?

我知道可以通过使用数据道具而不是组合来实现这一点。但对于我的用例,从长远来看,组合可能会好得多。

反应等效

如果您熟悉 React,我正在寻找可以像这个极其简单的示例一样工作的东西。

const List = (props) => {
  return (
    <ul>
      {React.Children.forEach(props.children, (child, index) => (
        child.props.tabIndex = index === 0 ? 0 : -1
      ))}
    </ul>
  )
}

const ListItem = (props) => {
  return <li tabIndex={props.tabIndex}>{props.children}</li>
}

1 个答案:

答案 0 :(得分:1)

我在父级(您的 List 组件)中使用了一个注册函数作为下拉菜单组件。

类似于:

列表组件:

  function nested(nestedText, clicked = false) {
    if (clicked) {
      // clicked and then do something
      ...
    } else {
      // register listItem
      register = [...register, nestedText];
      return register.length - 1;  // itemIdx
    }
  }
  setContext('nested', nested);

项目组件:

let text, itemIdx, thisObj;
const nested = getContext('nested');

onMount(() => {
  text = thisObj.textContent;
  itemIdx = nested(text);  // register item
  ...
});

项目组件html:

<a
  href="..."
  target="..."
  on:click|stopPropagation="{() => {
     nested(text, true);
  }}"
  bind:this={thisObj}>
  <slot />
</a>