【问题标题】:how to show selected item in react js?如何在反应js中显示选定的项目?
【发布时间】:2021-07-06 02:57:11
【问题描述】:

我有一个项目列表(示例名称)。我正在尝试在列表中显示所选项目。 .Selected 项目有一个selected 类,它将为该元素添加一个边框。

.selected {
  border: 1px solid blue;
}

选择的项目用变量const selectedItem = 1;决定,如果1,它将选择second项目。如果const selectedItem = 0;,它将选择第一个元素。

问题与陈述

  1. 我有包装器 div className="container",其宽度为 200px。它将包含尽可能多的列表元素。这取决于项目宽度。

示例 list Item(参见示例 1,它仅显示三个 Item,因为所有文本都很小。)

const data = [
  { title: "xahsdha" },
  { title: "hello" },
  { title: "hessllo" },
  { title: "hesslssslo" },
  { title: "navveiii" }
];

带有新数据的示例 2:请参阅第一个项目文本很大。它只显示一项。

const data = [
  { title: "xahsdhaadasdasdasdass" },
  { title: "hello" },
  { title: "hessllo" },
  { title: "hesslssslo" },
  { title: "navveiii" }
];

问题

我无法选择超出容器的项目。

示例给定数据

const data = [
  { title: "xahsdh" },
  { title: "hello" },
  { title: "hessllo" },
  { title: "hesslssslo" },
  { title: "navveiii" }
];

如果我给 const selectedItem = 1;

我的输出和预期输出是一样的。看到我能够显示选定的项目

但是如果我给 const selectedItem = 3; 相同的数据集 我的输出是这样的

但预期的输出是这样的

如果隐藏元素被选中,我们可以向前移动它吗?

场景 2

  1. 我们还需要注意隐藏元素的宽度。所以选定的项目宽度取决于我将在容器中显示多少项目。

例如如果我们通过const selectedItem = 3; 有了这个数据集

const data = [
  { title: "xahsdh" },
  { title: "hello" },
  { title: "hessllo" },
  { title: "hesslsssloasdasdasdasdasdsa" },
  { title: "navveiii" }
];

预期的输出是这样的

这个功能可行吗?

这是我的代码 https://codesandbox.io/s/unruffled-hellman-hswdl?file=/src/App.js

import "./styles.css";
import React, { createRef, useMemo, useRef } from "react";
const data = [
  { title: "xahsdh" },
  { title: "hello" },
  { title: "hessllo" },
  { title: "hesslssslo" },
  { title: "navveiii" }
];
const selectedItem = 1;
export default function App() {
  const arrLength = data.length;
  const [defaultState, setDefaultState] = React.useState(true);

  const elRefs = useMemo(
    () => Array.from({ length: data.length }).map(() => createRef()),
    []
  );
  const [state, setState] = React.useState({
    total: 0,
    tabWidth: 0,
    dimension: {}
  });
  const ulRef = useRef(null);

  React.useEffect(() => {
    setDimention();
  }, []);

  const setDimention = () => {
    let total = ulRef.current.offsetWidth,
      dimension = {},
      tabWidth = 0;
    console.log(total);
    elRefs.forEach((item, i) => {
      dimension[i] = item.current?.offsetWidth || 0;
      tabWidth += item.current?.offsetWidth || 0;
    });
    console.log({
      total,
      dimension,
      tabWidth
    });
    setDefaultState(false);
    setState({
      total,
      dimension,
      tabWidth
    });
  };

  const getTabs = () => {
    const { tabWidth, dimension, total } = state;
    var visible = [],
      avaiable = total,
      hidden = [];
    if (defaultState) {
      return {
        visible,
        hidden
      };
    }
    data.forEach((element, index) => {
      if (avaiable - dimension[index] > 0) {
        visible.push(element);
        avaiable = avaiable - dimension[index];
      } else {
        hidden.push(element);
      }
    });
    return {
      visible,
      hidden
    };
  };
  const { visible = [], hidden = [] } = getTabs();
  return (
    <div className="container" ref={ulRef}>
      <ul id="dummy">
        {visible.length === 0 &&
          hidden.length === 0 &&
          data.map((el, i) => (
            <li
              className={i === selectedItem ? "selected" : ""}
              ref={elRefs[i]}
              key={i}
            >
              {el.title}
            </li>
          ))}
      </ul>
      <ul id="visible">
        {visible.map((el, i) => (
          <li className={i === selectedItem ? "selected" : ""} key={i}>
            {el.title}
          </li>
        ))}
      </ul>
      <ul id="hidden">
        {hidden.map((el, i) => (
          <li className="hide" key={i}>
            {el.title}
          </li>
        ))}
      </ul>
    </div>
  );
}

注意和更新:我不想要可滚动列表。我希望优先考虑“选定”项目,如果有可用空间,请在前面添加其他元素。

有什么建议吗?

在 jQuery 中是可能的。所以确定我们是否在 react 中实现了这一点。我检查了这个 jQuery 示例选择的项目在最后,但它仍然在视图中

https://codepen.io/naveennsit/pen/poPJOPM?editors=1010

【问题讨论】:

  • 也许你可以让 div 水平滚动,然后以编程方式滚动到被选中的元素
  • @RishabhGupta 我不想滚动列表..举个例子,如果selectedIndex=4 .it 将显示元素 3(具有多个排列 elem 1 + elm 2 )或元素 3(elem 1)

标签: javascript reactjs


【解决方案1】:

我认为这里的主要问题是弄清楚当从头开始渲染时应该显示哪些元素。

我建议从当前选定的项目开始计算可见和隐藏元素的数组,以及可见的偏移量。首先逆向计算移动到数组front的可见/隐藏元素,然后从元素after 选定的项目向数组的移动。

const getTabs = () => {
  const { dimension, total } = state;

  const visible = [];
  const hidden = [];

  let offset = 0;
  let available = total;

  if (!initialRender) {
    // check forward
    for (let i = selectedItem; i >= 0; i--) {
      if (available > dimension[i]) {
        visible.unshift(data[i]);
        available -= dimension[i];
      } else {
        hidden.unshift(data[i]);
        offset++;
      }
    }

    // check aft
    for (let i = selectedItem + 1; i < arrLength; i++) {
      if (available > dimension[i]) {
        visible.push(data[i]);
        available -= dimension[i];
      } else {
        hidden.push(data[i]);
      }
    }
  }

  return {
    hidden,
    offset,
    visible
  };
};

在渲染可见和隐藏数组时,只需将当前映射的索引+偏移量与当前选中的项索引进行比较即可。

<ul id="visible">
  {visible.map((el, i) => (
    <li
      className={i + offset === selectedItem ? "selected" : ""}
      key={i}
    >
      {el.title}
    </li>
  ))}
</ul>
<ul id="hidden">
  {hidden.map((el, i) => (
    <li className="hide" key={i}>
      {el.title}
    </li>
  ))}
</ul>

编辑

由于想法是在可见区域中拥有当前选定的项目,然后只有数组中从数组开头的那些元素仍然合适,也可见,我们可以将上述解决方案修改为假设当前选择的项目总是合适的。

首先从可用性中减去所选项目的大小,然后从数组的开头进行迭代。如果当前索引与当前选定的索引不匹配,则将当前元素推入可见数组,如果合适则从可用性中减去。如果当前正在查看所选项目,请将其推入可见数组。

对于这个算法和渲染,我为每个项目添加了一个 GUID。

const data = [
  { title: "xahsdh", id: uuidV4() },
  { title: "hello", id: uuidV4() },
  { title: "hessllo", id: uuidV4() },
  { title: "hesslssslo", id: uuidV4() },
  { title: "navveiii", id: uuidV4() },
];

...

const getTabs = () => {
  const { dimension, total } = state;

  const visible = [];
  const hidden = [];

  const selectedIndex = data.findIndex((el) => el.id === selectedItem);
  if (!initialRender && selectedIndex !== -1) {
    let available = total - dimension[selectedIndex];

    data.forEach((el, i) => {
      if (i === selectedIndex) {
        visible.push(el);
        return;
      }
      if (available > dimension[i]) {
        visible.push(el);
        available -= dimension[i];
      } else {
        hidden.push(el);
      }
    });
  }

  return {
    hidden,
    visible
  };
};

渲染时检查 GUID。

<ul id="visible">
  {visible.map((el, i) => (
    <li
      className={el.id === selectedItem ? "selected" : ""}
      key={el.id}
    >
      {el.title}
    </li>
  ))}
</ul>
<ul id="hidden">
  {hidden.map((el, i) => (
    <li className="hide" key={el.id}>
      {el.title}
    </li>
  ))}
</ul>

【讨论】:

  • 谢谢@drew 你能分享codehandbox链接吗
  • Drew ,我也尝试过我的方法是不同的方法,但它也有效,但有时调试失败...codesandbox.io/s/jovial-proskuriakova-tcr2t?file=/src/…
  • @user5711656 啊,当然,没有意识到你会这么快看到这个……我已经在添加我的分叉沙箱了。用链接更新了我的答案。
  • drew ,谢谢,但我认为您正在滚动...请参阅我的代码框。这就是我在看codesandbox.io/s/…
  • @user5711656 不,再次检查,不涉及滚动。我正在移动适合的元素的可见“窗口”,如果那是你所指的。
猜你喜欢
  • 2021-09-22
  • 2021-03-10
  • 2019-03-17
  • 1970-01-01
  • 2013-09-11
  • 1970-01-01
  • 2021-08-22
  • 2021-10-10
  • 1970-01-01
相关资源
最近更新 更多