admin管理员组

文章数量:1403366

I am using the Line-Clamp property (with a backup max-height) to limit the number of lines to show in a React ponent. I would like to have an optional link afterwards that will expand this content to its full length, but only if the current number of lines is greater than the line-clamp number.

The number of lines is fixed (3) so I guess I could just calculate the current height of the div and then pare it to the expected height of 3 lines at standard text size?

But then if someone decides to put different non text content in it it might not work as intended. Is there a specific way to get the number of lines of text in a container?

 const {useState} = React;

const ClampedDiv = ({ children, showLinkProp }) => {
  const [open, setOpen] = useState(false);

  // This is where I'd do the line number calculation, but it's just
  // using a placeholder instead.
  let showLink = false;
  if (showLinkProp) {
    showLink = true;
  }
  
  let textClass = "text";
  if (open) {
    textClass += " open";
  }

  return <div className="container">
    <span class={textClass}>{children}</span>
    {showLink && !open && (
      <button onClick={() => setOpen(true)}>Open</button>
    )}
  </div>
};

const Component = () => (
  <React.Fragment>
    <ClampedDiv>
      Some content that should not show a read more
    </ClampedDiv>
    <ClampedDiv showLinkProp>
      Some content that should show a read more. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
    </ClampedDiv>
  </React.Fragment>
);

ReactDOM.render(
  <Component />,
  document.body
)
.text {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-height: calc(3 * 1.5 * 14px);
  font-size: 14px;
  line-height: 1.5;
}

.open {
  -webkit-line-clamp: unset;
  max-height: none;
}

.container {
  background-color: crimson;
  color: white;
  margin-bottom: 15px;
  padding: 15px;
}
    <script src=".0.1/umd/react.production.min.js"></script>
    <script src=".0.1/umd/react-dom.production.min.js"></script>
    <div id="react"></div>

I am using the Line-Clamp property (with a backup max-height) to limit the number of lines to show in a React ponent. I would like to have an optional link afterwards that will expand this content to its full length, but only if the current number of lines is greater than the line-clamp number.

The number of lines is fixed (3) so I guess I could just calculate the current height of the div and then pare it to the expected height of 3 lines at standard text size?

But then if someone decides to put different non text content in it it might not work as intended. Is there a specific way to get the number of lines of text in a container?

 const {useState} = React;

const ClampedDiv = ({ children, showLinkProp }) => {
  const [open, setOpen] = useState(false);

  // This is where I'd do the line number calculation, but it's just
  // using a placeholder instead.
  let showLink = false;
  if (showLinkProp) {
    showLink = true;
  }
  
  let textClass = "text";
  if (open) {
    textClass += " open";
  }

  return <div className="container">
    <span class={textClass}>{children}</span>
    {showLink && !open && (
      <button onClick={() => setOpen(true)}>Open</button>
    )}
  </div>
};

const Component = () => (
  <React.Fragment>
    <ClampedDiv>
      Some content that should not show a read more
    </ClampedDiv>
    <ClampedDiv showLinkProp>
      Some content that should show a read more. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
    </ClampedDiv>
  </React.Fragment>
);

ReactDOM.render(
  <Component />,
  document.body
)
.text {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-height: calc(3 * 1.5 * 14px);
  font-size: 14px;
  line-height: 1.5;
}

.open {
  -webkit-line-clamp: unset;
  max-height: none;
}

.container {
  background-color: crimson;
  color: white;
  margin-bottom: 15px;
  padding: 15px;
}
    <script src="https://cdnjs.cloudflare./ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare./ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
    <div id="react"></div>

Share Improve this question asked Mar 23, 2021 at 13:01 James PatersonJames Paterson 2,9253 gold badges32 silver badges43 bronze badges 5
  • may be get the inenerHtml anf then use string.split(" "), which returns the number of texts? – Shyam Kumar Commented Mar 23, 2021 at 13:33
  • 1 Did you check stackoverflow./q/783899/2873538 and this? – Ajeet Shah Commented Mar 24, 2021 at 14:46
  • 1 I've seen them but the first is just base JS - I adapted the solution to React, I'll post my version if I get some time later. – James Paterson Commented Mar 24, 2021 at 16:40
  • The gist of the solution is a div that can expand to any size inside a max-height container. You then measure the height of that box pared to the container and the expected line-height. If it's bigger you show the button. The issue is that using line-clamp automatically limits the size of the box, so you can't use it and have to use max-height on the container instead, which is sad as you don't get the automatic ellipsis. But it does work! – James Paterson Commented Mar 24, 2021 at 16:43
  • 1 @JamesPaterson did ever get a solution to this? – Mateen Kazia Commented Jul 18, 2022 at 8:35
Add a ment  | 

1 Answer 1

Reset to default 3

If you just want to check for hidden content inside your element, you can use the useRef hook to refer to the specific element.

And then, use scrollHeight to get the height of the content of the element.

The Element.scrollHeight read-only property is a measurement of the height of an element's content, including content not visible on the screen due to overflow.

And pare it to the clientHeight to see if there is hidden content.

 const { useState, useRef, useLayoutEffect } = React;

const ClampedDiv = ({ children }) => {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);

  // This is where I'd do the line number calculation, but it's just
  // using a placeholder instead.
  const [showLink, setShowLink] = useState(false);
  
  useLayoutEffect(() => {
      if (ref.current && ref.current.clientHeight < ref.current.scrollHeight) {
        setShowLink(true)
      }
  }, [ref])
  
  let textClass = "text";
  if (open) {
    textClass += " open";
  }

  return <div className="container">
    <span class={textClass} ref={ref}>{children}</span>
    {showLink && !open && (
      <button onClick={() => setOpen(true)}>Open</button>
    )}
  </div>
};

const Component = () => (
  <React.Fragment>
    <ClampedDiv>
      Some content that should not show a read more
    </ClampedDiv>
    <ClampedDiv>
      Some content that should show a read more. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop penter code hereublishing software like Aldus PageMaker including versions of Lorem Ipsum.
    </ClampedDiv>
  </React.Fragment>
);

ReactDOM.render(
  <Component />,
  document.body
)
.text {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-height: calc(3 * 1.5 * 14px);
  font-size: 14px;
  line-height: 1.5;
}

.open {
  -webkit-line-clamp: unset;
  max-height: none;
}

.container {
  background-color: crimson;
  color: white;
  margin-bottom: 15px;
  padding: 15px;
}
    <script src="https://cdnjs.cloudflare./ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare./ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
    <div id="react"></div>

As you can see, now the implementation of the check to show more content is specific to the child ponent and depends on the content passed by the parent ponent.

本文标签: javascriptDetermining the number of lines of text in a div in ReactStack Overflow