English 中文(简体)
自动扩展案文a
原标题:Auto-expanding textarea
  • 时间:2011-10-12 19:52:42
  •  标签:
  • javascript

I m试图做简单的自动扩展文本处理。 这是我的法典:

textarea.onkeyup = function () {
  textarea.style.height = textarea.clientHeight +  px ;
}

但是,案文只是随着您的类型而无限期地增长。

我知道有多霍和少花钱,但不必使用。 我审视了这些建议的执行情况,最初使用的是scrollHels/code>,但情况相同。

你们可以开始回答你们的回答,并在文本中发挥作用。

最佳回答

在使用<代码>scrollH8之前重新定位,以便正确地扩大/缩小案文。 <>Math.min(>可用于对文本区域高度设定限制。

Code:

var textarea = document.getElementById("textarea");
var heightLimit = 200; /* Maximum height: 200px */

textarea.oninput = function() {
  textarea.style.height = ""; /* Reset the height*/
  textarea.style.height = Math.min(textarea.scrollHeight, heightLimit) + "px";
};

Fiddle:

Note: The input event is not supported by IE8 and earlier. Use keydown or keyup with onpaste and/or oncut if you want to support this ancient browser as well.

问题回答

2022 Vanilla JS Solution

Note: I have only tested this in Chrome but it should work everywhere.

This will handle pasting, deleting, text-wrapping, manual returns, etc. & accounts for padding and box-sizing issues.

How it Works

  1. Forces resize and all height properties to auto/none/0 etc to prevent interference with the event code.
  2. Resets the rows attribute to 1 to get accurate scrollHeight.
  3. Sets overflow to hidden and hard locks the current computed width (minus left/right border width and left/right padding widths), then forces box-sizing to content-box to get an accurate line-height and scrollHeight reading. border-width and padding-inline is also removed to keep the textarea width consistent when switching box-sizing. This all helps keep the math accurate when dealing with text wrapping.
  4. Grabs the computed line-height and top/bottom-padding pixel values.
  5. Obtains the scrollHeight pixel value (rounded since chrome rounds and we re hoping to handle all browsers consistently).
  6. Removes overflow, box-sizing, width, padding-inline and border-width overrides.
  7. Subtracts block_padding from scroll_height then divides that by the line_height to get the needed rows. The rows value is rounded to the nearest integer since it will always be within ~.1 of the correct whole number.
  8. The calculated rows value is applied as the rows attribute unless the row_limit is smaller, then the row_limit is used instead.

Edit / Update Details

我删除了用于数字的左翼法,因为我得以在大约1个所需行数中核实分公式的数学。 因此,一个简单的<代码>Math.round()确保浏览量准确。 我无法在测试中打破这种差距,如果它变成错的话,那么我会感到有自由建议。

I also ran into issues when line-height is not explicitly set on the text area as in that case the computed value for line-height comes back as "normal" and not the actual computed value. This new version accounts for this eventuality and handles it properly as well.

Layout Shift Possibility

我没有将<代码>textarea至position: final;在打上. Box-sizing/code>,因为我在测试时没有注意到需要。 值得一提,因为我假定,如果这些细微改动可能会造成布局的转变,这取决于该页的风格,如果情况发生的话,你可以补充,然后将它与箱子化压倒一切的去除。

Sample Code

(仅需要一份联合材料功能,其他一切都只是为了去除)

function autosize(textarea_id, row_limit) {
  // Set default for row_limit parameter
  row_limit = parseInt(row_limit ??  5 );
  if (!row_limit) {
    row_limit = 5;
  }

  // Get the element
  const textarea = document.getElementById(textarea_id);

  // Set required styles for this to function properly.
  textarea.style.setProperty( resize ,  none );
  textarea.style.setProperty( min-height ,  0 );
  textarea.style.setProperty( max-height ,  none );
  textarea.style.setProperty( height ,  auto );

  // Set rows attribute to number of lines in content
  textarea.oninput = function() {

    // Reset rows attribute to get accurate scrollHeight
    textarea.setAttribute( rows ,  1 );

    // Get the computed values object reference
    const cs = getComputedStyle(textarea);

    // Force content-box for size accurate line-height calculation
    // Remove scrollbars, lock width (subtract inline padding and inline border widths)
    // and remove inline padding and borders to keep width consistent (for text wrapping accuracy)
    const inline_padding = parseFloat(cs[ padding-left ]) + parseFloat(cs[ padding-right ]);
    const inline_border_width = parseFloat(cs[ border-left-width ]) + parseFloat(cs[ border-right-width ]);
    textarea.style.setProperty( overflow ,  hidden ,  important );
    textarea.style.setProperty( width , (parseFloat(cs[ width ]) - inline_padding - inline_border_width) +  px );
    textarea.style.setProperty( box-sizing ,  content-box );
    textarea.style.setProperty( padding-inline ,  0 );
    textarea.style.setProperty( border-width ,  0 );
    
    // Get the base line height, and top / bottom padding.
    const block_padding = parseFloat(cs[ padding-top ]) + parseFloat(cs[ padding-bottom ]);
    const line_height =
      // If line-height is not explicitly set, use the computed height value (ignore padding due to content-box)
      cs[ line-height ] ===  normal  ? parseFloat(cs[ height ])
      // Otherwise (line-height is explicitly set), use the computed line-height value.
      : parseFloat(cs[ line-height ]);

    // Get the scroll height (rounding to be safe to ensure cross browser consistency)
    const scroll_height = Math.round(textarea.scrollHeight);

    // Undo overflow, width, border-width, box-sizing & inline padding overrides
    textarea.style.removeProperty( width );
    textarea.style.removeProperty( box-sizing );
    textarea.style.removeProperty( padding-inline );
    textarea.style.removeProperty( border-width );
    textarea.style.removeProperty( overflow );

    // Subtract block_padding from scroll_height and divide that by our line_height to get the row count.
    // Round to nearest integer as it will always be within ~.1 of the correct whole number.
    const rows = Math.round((scroll_height - block_padding) / line_height);

    // Set the calculated rows attribute (limited by row_limit)
    textarea.setAttribute("rows", "" + Math.min(rows, row_limit));
  };

  // Trigger the event to set the initial rows value
  textarea.dispatchEvent(new Event( input , {
    bubbles: true
  }));
}

autosize( textarea );
* {
  box-sizing: border-box;
}

textarea {
  width: 100%;
  max-width: 30rem;
  font-family: sans-serif;
  font-size: 1rem;
  line-height: 1.5rem;
  padding: .375rem;
}
<body>
  <textarea id="textarea" placeholder="enter some text here :)"></textarea>
</body>

...and if you need an infinitely expanding textarea (as I did), just do this:

var textarea = document.getElementById("textarea");

textarea.oninput = function() {
  textarea.style.height = ""; /* Reset the height*/
  textarea.style.height = textarea.scrollHeight + "px";
};

using

<div content Editable></div>

也可以做同样的工作,扩大工作本身,无需打碎。

与已接受的答复不同的是,我的职能涉及<条码>穿戴-{,底层}和<条码>,边界------上,底层}-width。 它有许多参数。 请注意,其t setwindow.addEventListener ( resize )

Function:

// @author Arzet Ro, 2021 <arzeth0@gmail.com>
// @license CC0 (Creative Commons Zero v1.0 Universal) (i.e. Public Domain)
// @source https://stackoverflow.com/a/70341077/332012
// Useful for elements with overflow-y: scroll and <textarea>
// Tested only on <textarea> in desktop Firefox 95 and desktop Chromium 96.
export function autoResizeScrollableElement (
    el: HTMLElement,
    {
        canShrink = true,
        minHeightPx = 0,
        maxHeightPx,
        minLines,
        maxLines,
    }: {
        canShrink?: boolean,
        minHeightPx?: number,
        maxHeightPx?: number,
        minLines?: number,
        maxLines?: number,
    } = {}
): void
{
    const FN_NAME =  autoResizeScrollableElement 
    if (
        typeof minLines !==  undefined 
        && minLines !== null
        && Number.isNaN(+minLines)
    )
    {
        console.warn(
             %O(el=%O):: minLines (%O) as a number is NaN ,
            FN_NAME, el, minLines
        )
    }
    if (
        typeof maxLines !==  undefined 
        && maxLines !== null
        && Number.isNaN(+maxLines)
    )
    {
        console.warn(
             %O(el=%O):: maxLines (%O) as a number is NaN ,
            FN_NAME, el, maxLines
        )
    }
    canShrink = (
        canShrink === true
        ||
        // @ts-ignore
        canShrink === 1 || canShrink === void 0 || canShrink === null
    )

    const style = window.getComputedStyle(el)
    const unpreparedLineHeight = style.getPropertyValue( line-height )
    if (unpreparedLineHeight ===  normal )
    {
        console.error( %O(el=%O):: line-height is unset , FN_NAME, el)
    }
    const lineHeightPx: number = (
        unpreparedLineHeight ===  normal 
        ? 1.15 * parseFloat(style.getPropertyValue( font-size )) // 1.15 is a wrong number
        : parseFloat(unpreparedLineHeight)
    )

    // @ts-ignore
    minHeightPx = parseFloat(minHeightPx || 0) || 0
    //minHeight = Math.max(lineHeightPx, parseFloat(style.getPropertyValue( min-height )))
    // @ts-ignore
    maxHeightPx = parseFloat(maxHeightPx || 0) || Infinity
    minLines = (
        minLines
        ? (
            Math.round(+minLines || 0) > 1
            ? Math.round(+minLines || 0)
            : 1
        )
        : 1
    )
    maxLines = (
        maxLines
        ? (Math.round(+maxLines || 0) || Infinity)
        : Infinity
    )
    //console.log( %O:: old ov.x=%O ov.y=%O, ov=%O , FN_NAME, style.getPropertyValue( overflow-x ), style.getPropertyValue( overflow-y ), style.getPropertyValue( overflow ))
    /*if (overflowY !==  scroll  && overflowY ===  hidden )
    {
        console.warn( %O:: setting overflow-y to scroll , FN_NAME)
    }*/
    if (minLines > maxLines)
    {
        console.warn(
             %O(el=%O):: minLines (%O) > maxLines (%O),  
            +  therefore both parameters are ignored ,
            FN_NAME, el, minLines, maxLines
        )
        minLines = 1
        maxLines = Infinity
    }
    if (minHeightPx > maxHeightPx)
    {
        console.warn(
             %O(el=%O):: minHeightPx (%O) > maxHeightPx (%O),  
            +  therefore both parameters are ignored ,
            FN_NAME, el, minHeightPx, maxHeightPx
        )
        minHeightPx = 0
        maxHeightPx = Infinity
    }
    const topBottomBorderWidths: number = (
        parseFloat(style.getPropertyValue( border-top-width ))
        + parseFloat(style.getPropertyValue( border-bottom-width ))
    )
    let verticalPaddings: number = 0
    if (style.getPropertyValue( box-sizing ) ===  border-box )
    {
        verticalPaddings += (
            parseFloat(style.getPropertyValue( padding-top ))
            + parseFloat(style.getPropertyValue( padding-bottom ))
            + topBottomBorderWidths
        )
    }
    else
    {
        console.warn(
             %O(el=%O):: has `box-sizing: content-box` 
            +   which is untested; you should set it to border-box. Continuing anyway. ,
            FN_NAME, el
        )
    }
    const oldHeightPx = parseFloat(style.height)
    if (el.tagName ===  TEXTAREA )
    {
        el.setAttribute( rows ,  1 )
        //el.style.overflowY =  hidden 
    }
    // @ts-ignore
    const oldScrollbarWidth: string|void = el.style.scrollbarWidth
    el.style.height =   

    // Even when there is nothing to scroll,
    // it causes an extra height at the bottom in the content area (tried Firefox 95).
    // scrollbar-width is present only on Firefox 64+,
    // other browsers use ::-webkit-scrollbar
    // @ts-ignore
    el.style.scrollbarWidth =  none 

    const maxHeightForMinLines = lineHeightPx * minLines + verticalPaddings // can be float
    // .scrollHeight is always an integer unfortunately
    const scrollHeight = el.scrollHeight + topBottomBorderWidths
    /*console.log(
         %O:: lineHeightPx=%O * minLines=%O + verticalPaddings=%O, el.scrollHeight=%O, scrollHeight=%O ,
        FN_NAME, lineHeightPx, minLines, verticalPaddings,
        el.scrollHeight, scrollHeight
    )*/
    const newHeightPx = Math.max(
        canShrink === true ? minHeightPx : oldHeightPx,
        Math.min(
            maxHeightPx,
            Math.max(
                maxHeightForMinLines,
                Math.min(
                    Math.max(scrollHeight, maxHeightForMinLines)
                    - Math.min(scrollHeight, maxHeightForMinLines) < 1
                    ? maxHeightForMinLines
                    : scrollHeight,
                    (
                        maxLines > 0 && maxLines !== Infinity
                        ? lineHeightPx * maxLines + verticalPaddings
                        : Infinity
                    )
                )
            )
        )
    )
    // @ts-ignore
    el.style.scrollbarWidth = oldScrollbarWidth
    if (!Number.isFinite(newHeightPx) || newHeightPx < 0)
    {
        console.error(
             %O(el=%O):: BUG:: Invalid return value: `%O` ,
            FN_NAME, el, newHeightPx
        )
        return
    }
    el.style.height = newHeightPx +  px 
    //console.log( %O:: height: %O → %O , FN_NAME, oldHeightPx, newHeightPx)
    /*if (el.tagName ===  TEXTAREA  && el.scrollHeight > newHeightPx)
    {
        el.style.overflowY =  scroll 
    }*/
}

使用重读(图文):

<textarea
    onKeyDown={(e) => {
        if (!(e.key ===  Enter  && !e.shiftKey)) return true
        e.preventDefault()
        // send the message, then this.scrollToTheBottom()
        return false
    }}
    onChange={(e) => {
        if (this.state.isSending)
        {
            e.preventDefault()
            return false
        }
        this.setState({
            pendingMessage: e.currentTarget.value
        }, () => {
            const el = this.chatSendMsgRef.current!
            engine.autoResizeScrollableElement(el, {maxLines: 5})
        })
        return true
    }}
/>

React onChange See also oninput in RUS5, so if You no t use React, when use the input.


其中一个答案是:rows attribute (instead of CSS s h 8,, as my Code above do),这里有一个备选实施,在变数之外使用(BUT, 仅像这一答案一样,有节点:rows<>/code> is temporaily set to 1, a me末ase with <html> scroll> scroll 可在以下时间浏览:

// @author Arzet Ro, 2021 <arzeth0@gmail.com>
// @license CC0 (Creative Commons Zero v1.0 Universal) (i.e. Public Domain)
// @source https://stackoverflow.com/a/70341077/332012
function autoResizeTextareaByChangingRows (
    el,
    {minLines, maxLines}
)
{
    const FN_NAME =  autoResizeTextareaByChangingRows 
    if (
        typeof minLines !==  undefined 
        && minLines !== null
        && Number.isNaN(+minLines)
    )
    {
        console.warn( %O:: minLines (%O) as a number is NaN , FN_NAME, minLines)
    }
    if (
        typeof maxLines !==  undefined 
        && maxLines !== null
        && Number.isNaN(+maxLines)
    )
    {
        console.warn( %O:: maxLines (%O) as a number is NaN , FN_NAME, maxLines)
    }
    minLines = (
        minLines
        ? (
            Math.round(+minLines || 0) > 1
            ? Math.round(+minLines || 0)
            : 1
        )
        : 1
    )
    maxLines = (
        maxLines
        ? (Math.round(+maxLines || 0) || Infinity)
        : Infinity
    )
    el.setAttribute(
         rows ,
         1 ,
    )
    const style = window.getComputedStyle(el)
    const unpreparedLineHeight = style.getPropertyValue( line-height )
    if (unpreparedLineHeight ===  normal )
    {
        console.error( %O:: line-height is unset for %O , FN_NAME, el)
    }
    const rows = Math.max(minLines, Math.min(maxLines,
        Math.round(
            (
                el.scrollHeight
                - parseFloat(style.getPropertyValue( padding-top ))
                - parseFloat(style.getPropertyValue( padding-bottom ))
            ) / (
                unpreparedLineHeight ===  normal 
                ? 1.15 * parseFloat(style.getPropertyValue( font-size )) // 1.15 is a wrong number
                : parseFloat(unpreparedLineHeight)
            )
        )
   ))
    el.setAttribute(
         rows ,
        rows.toString()
    )
}

const textarea = document.querySelector( textarea )
textarea.oninput = function ()
{
    autoResizeTextareaByChangingRows(textarea, {maxLines: 5})
}

对于使用安热器和有相同问题的人,使用

<textarea cdkTextareaAutosize formControlName="description" name="description" matInput placeholder="Description"></textarea>

此处的关键是cdkTextareaAutosize,其中将自动使案文领域与内容相适应。

我希望这能帮助某人。

安装有新线管的阵列,将其长度定为<条码>。

textarea.addEventListener( input , 
    e => e.target.rows = e.target.value.split( 
 ).length
);




相关问题
selected text in iframe

How to get a selected text inside a iframe. I my page i m having a iframe which is editable true. So how can i get the selected text in that iframe.

How to fire event handlers on the link using javascript

I would like to click a link in my page using javascript. I would like to Fire event handlers on the link without navigating. How can this be done? This has to work both in firefox and Internet ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Clipboard access using Javascript - sans Flash?

Is there a reliable way to access the client machine s clipboard using Javascript? I continue to run into permissions issues when attempting to do this. How does Google Docs do this? Do they use ...

javascript debugging question

I have a large javascript which I didn t write but I need to use it and I m slowely going trough it trying to figure out what does it do and how, I m using alert to print out what it does but now I ...

Parsing date like twitter

I ve made a little forum and I want parse the date on newest posts like twitter, you know "posted 40 minutes ago ","posted 1 hour ago"... What s the best way ? Thanx.