Pergunta

Atualmente estou trabalhando em um aplicativo de vendas interno da empresa onde trabalho e possuo um formulário que permite ao usuário alterar o endereço de entrega.

Agora acho que ficaria muito melhor se a área de texto que estou usando para os detalhes do endereço principal ocupasse apenas a área do texto e redimensionasse automaticamente se o texto fosse alterado.

Aqui está uma captura de tela dele atualmente.

ISO Address

Alguma ideia?


@Chris

Um bom argumento, mas há motivos pelos quais quero redimensioná-lo.Quero que a área que ele ocupa seja a área das informações nele contidas.Como você pode ver na captura de tela, se eu tiver uma área de texto fixa, ela ocupará bastante espaço vertical.

Posso reduzir a fonte, mas preciso que o endereço seja grande e legível.Agora posso reduzir o tamanho da área de texto, mas tenho problemas com pessoas que têm uma linha de endereço que ocupa 3 ou 4 (uma leva 5) linhas.A necessidade de que o usuário use uma barra de rolagem é uma grande impossibilidade.

Acho que deveria ser um pouco mais específico.Estou atrás de redimensionamento vertical e a largura não importa tanto.O único problema que acontece com isso é que o número ISO (o grande "1") é colocado abaixo do endereço quando a largura da janela é muito pequena (como você pode ver na imagem).

Não se trata de ter um artifício;trata-se de ter um campo de texto que o usuário possa editar e que não ocupe espaço desnecessário, mas que mostre todo o texto nele contido.

Embora se alguém encontrar outra maneira de abordar o problema, também estou aberto a isso.


Modifiquei um pouco o código porque ele estava agindo de forma um pouco estranha.Mudei para ativar no keyup, pois não levaria em consideração o caractere que acabou de ser digitado.

resizeIt = function() {
  var str = $('iso_address').value;
  var cols = $('iso_address').cols;
  var linecount = 0;

  $A(str.split("\n")).each(function(l) {
    linecount += 1 + Math.floor(l.length / cols); // Take into account long lines
  })

  $('iso_address').rows = linecount;
};
Foi útil?

Solução

O Facebook faz isso quando você escreve nas paredes das pessoas, mas apenas redimensiona verticalmente.

O redimensionamento horizontal me parece uma bagunça, devido à quebra de linha, linhas longas e assim por diante, mas o redimensionamento vertical parece ser bastante seguro e agradável.

Nenhum dos novatos que usam o Facebook que conheço jamais mencionou algo sobre isso ou ficou confuso.Eu usaria isso como evidência anedótica para dizer 'vá em frente, implemente'.

Algum código JavaScript para fazer isso, usando Protótipo (porque é com isso que estou familiarizado):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <script src="http://www.google.com/jsapi"></script>
        <script language="javascript">
            google.load('prototype', '1.6.0.2');
        </script>
    </head>

    <body>
        <textarea id="text-area" rows="1" cols="50"></textarea>

        <script type="text/javascript" language="javascript">
            resizeIt = function() {
              var str = $('text-area').value;
              var cols = $('text-area').cols;

              var linecount = 0;
              $A(str.split("\n")).each( function(l) {
                  linecount += Math.ceil( l.length / cols ); // Take into account long lines
              })
              $('text-area').rows = linecount + 1;
            };

            // You could attach to keyUp, etc. if keydown doesn't work
            Event.observe('text-area', 'keydown', resizeIt );

            resizeIt(); //Initial on load
        </script>
    </body>
</html>

PS:Obviamente, esse código JavaScript é muito ingênuo e não foi bem testado, e você provavelmente não deseja usá-lo em caixas de texto com romances, mas essa é a ideia geral.

Outras dicas

Um refinamento para algumas dessas respostas é permitir que o CSS faça mais trabalho.

A rota básica parece ser:

  1. Crie um elemento contêiner para armazenar o textarea e um escondido div
  2. Usando Javascript, mantenha o textareaconteúdo sincronizado com o divé
  3. Deixe o navegador fazer o trabalho de calcular a altura dessa div
  4. Porque o navegador lida com a renderização/dimensionamento do oculto div, evitamos definir explicitamente o textareaé a altura.

document.addEventListener('DOMContentLoaded', () => {
    textArea.addEventListener('change', autosize, false)
    textArea.addEventListener('keydown', autosize, false)
    textArea.addEventListener('keyup', autosize, false)
    autosize()
}, false)

function autosize() {
    // Copy textarea contents to div browser will calculate correct height
    // of copy, which will make overall container taller, which will make
    // textarea taller.
    textCopy.innerHTML = textArea.value.replace(/\n/g, '<br/>')
}
html, body, textarea {
    font-family: sans-serif;
    font-size: 14px;
}

.textarea-container {
    position: relative;
}

.textarea-container > div, .textarea-container > textarea {
    word-wrap: break-word; /* make sure the div and the textarea wrap words in the same way */
    box-sizing: border-box;
    padding: 2px;
    width: 100%;
}

.textarea-container > textarea {
    overflow: hidden;
    position: absolute;
    height: 100%;
}

.textarea-container > div {
    padding-bottom: 1.5em; /* A bit more than one additional line of text. */ 
    visibility: hidden;
    width: 100%;
}
<div class="textarea-container">
    <textarea id="textArea"></textarea>
    <div id="textCopy"></div>
</div>

Aqui está outra técnica para dimensionar automaticamente uma área de texto.

  • Usa altura de pixel em vez de altura de linha:manipulação mais precisa da quebra de linha se uma fonte proporcional for usada.
  • Aceita ID ou elemento como entrada
  • Aceita um parâmetro opcional de altura máxima - útil se você preferir não deixar a área de texto crescer além de um determinado tamanho (manter tudo na tela, evitar quebrar o layout, etc.)
  • Testado no Firefox 3 e Internet Explorador 6

Código:(JavaScript simples e simples)

function FitToContent(id, maxHeight)
{
   var text = id && id.style ? id : document.getElementById(id);
   if (!text)
      return;

   /* Accounts for rows being deleted, pixel value may need adjusting */
   if (text.clientHeight == text.scrollHeight) {
      text.style.height = "30px";
   }

   var adjustedHeight = text.clientHeight;
   if (!maxHeight || maxHeight > adjustedHeight)
   {
      adjustedHeight = Math.max(text.scrollHeight, adjustedHeight);
      if (maxHeight)
         adjustedHeight = Math.min(maxHeight, adjustedHeight);
      if (adjustedHeight > text.clientHeight)
         text.style.height = adjustedHeight + "px";
   }
}

Demonstração:(usa jQuery, tem como alvo a área de texto que estou digitando agora - se você tiver Bug de fogo instalado, cole os dois exemplos no console e teste nesta página)

$("#post-text").keyup(function()
{
   FitToContent(this, document.documentElement.clientHeight)
});

Provavelmente a solução mais curta:

jQuery(document).ready(function(){
    jQuery("#textArea").on("keydown keyup", function(){
        this.style.height = "1px";
        this.style.height = (this.scrollHeight) + "px"; 
    });
});

Dessa forma, você não precisa de divs ocultos ou algo parecido.

Observação:você pode ter que brincar com this.style.height = (this.scrollHeight) + "px"; dependendo de como você estiliza a área de texto (altura da linha, preenchimento e esse tipo de coisa).

Aqui está um Protótipo versão de redimensionamento de uma área de texto que não depende do número de colunas na área de texto.Esta é uma técnica superior porque permite controlar a área de texto via CSS, bem como ter textarea de largura variável.Além disso, esta versão exibe o número de caracteres restantes.Embora não seja solicitado, é um recurso bastante útil e pode ser facilmente removido se indesejado.

//inspired by: http://github.com/jaz303/jquery-grab-bag/blob/63d7e445b09698272b2923cb081878fd145b5e3d/javascripts/jquery.autogrow-textarea.js
if (window.Widget == undefined) window.Widget = {}; 

Widget.Textarea = Class.create({
  initialize: function(textarea, options)
  {
    this.textarea = $(textarea);
    this.options = $H({
      'min_height' : 30,
      'max_length' : 400
    }).update(options);

    this.textarea.observe('keyup', this.refresh.bind(this));

    this._shadow = new Element('div').setStyle({
      lineHeight : this.textarea.getStyle('lineHeight'),
      fontSize : this.textarea.getStyle('fontSize'),
      fontFamily : this.textarea.getStyle('fontFamily'),
      position : 'absolute',
      top: '-10000px',
      left: '-10000px',
      width: this.textarea.getWidth() + 'px'
    });
    this.textarea.insert({ after: this._shadow });

    this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
    this.textarea.insert({after: this._remainingCharacters});  
    this.refresh();  
  },

  refresh: function()
  { 
    this._shadow.update($F(this.textarea).replace(/\n/g, '<br/>'));
    this.textarea.setStyle({
      height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
    });

    var remaining = this.options.get('max_length') - $F(this.textarea).length;
    this._remainingCharacters.update(Math.abs(remaining)  + ' characters ' + (remaining > 0 ? 'remaining' : 'over the limit'));
  }
});

Crie o widget chamando new Widget.Textarea('element_id').As opções padrão podem ser substituídas passando-as como um objeto, por exemplo. new Widget.Textarea('element_id', { max_length: 600, min_height: 50}).Se você quiser criá-lo para todas as áreas de texto da página, faça algo como:

Event.observe(window, 'load', function() {
  $$('textarea').each(function(textarea) {
    new Widget.Textarea(textarea);
  });   
});

Aqui está uma solução com JQuery:

$(document).ready(function() {
    var $abc = $("#abc");
    $abc.css("height", $abc.attr("scrollHeight"));
})

abc é um teaxtarea.

Verifique o link abaixo:http://james.padolsey.com/javascript/jquery-plugin-autoresize/

$(document).ready(function () {
    $('.ExpandableTextCSS').autoResize({
        // On resize:
        onResize: function () {
            $(this).css({ opacity: 0.8 });
        },
        // After resize:
        animateCallback: function () {
            $(this).css({ opacity: 1 });
        },
        // Quite slow animation:
        animateDuration: 300,
        // More extra space:
        extraSpace:20,
        //Textarea height limit
        limit:10
    });
});

Apenas revisitando isso, deixei-o um pouco mais arrumado (embora alguém que esteja com a garrafa cheia Protótipo/JavaScript poderia sugerir melhorias?).

var TextAreaResize = Class.create();
TextAreaResize.prototype = {
  initialize: function(element, options) {
    element = $(element);
    this.element = element;

    this.options = Object.extend(
      {},
      options || {});

    Event.observe(this.element, 'keyup',
      this.onKeyUp.bindAsEventListener(this));
    this.onKeyUp();
  },

  onKeyUp: function() {
    // We need this variable because "this" changes in the scope of the
    // function below.
    var cols = this.element.cols;

    var linecount = 0;
    $A(this.element.value.split("\n")).each(function(l) {
      // We take long lines into account via the cols divide.
      linecount += 1 + Math.floor(l.length / cols);
    })

    this.element.rows = linecount;
  }
}

Basta ligar com:

new TextAreaResize('textarea_id_name_here');

Eu fiz algo muito fácil.Primeiro coloquei o TextArea em um DIV.Em segundo lugar, liguei para o ready função para este script.

<div id="divTable">
  <textarea ID="txt" Rows="1" TextMode="MultiLine" />
</div>

$(document).ready(function () {
  var heightTextArea = $('#txt').height();
  var divTable = document.getElementById('divTable');
  $('#txt').attr('rows', parseInt(parseInt(divTable .style.height) / parseInt(altoFila)));
});

Simples.É a altura máxima do div depois de renderizado, dividida pela altura de um TextArea de uma linha.

Eu precisava dessa função para mim, mas nenhuma daqui funcionou como eu precisava.

Então usei o código do Orion e mudei.

Adicionei uma altura mínima, para que no destruct não fique muito pequeno.

function resizeIt( id, maxHeight, minHeight ) {
    var text = id && id.style ? id : document.getElementById(id);
    var str = text.value;
    var cols = text.cols;
    var linecount = 0;
    var arStr = str.split( "\n" );
    $(arStr).each(function(s) {
        linecount = linecount + 1 + Math.floor(arStr[s].length / cols); // take into account long lines
    });
    linecount++;
    linecount = Math.max(minHeight, linecount);
    linecount = Math.min(maxHeight, linecount);
    text.rows = linecount;
};

Curta a resposta de @memical.

No entanto, encontrei algumas melhorias.Você pode usar o jQuery height() função.Mas esteja ciente dos pixels de preenchimento superior e inferior.Caso contrário, sua área de texto crescerá muito rápido.

$(document).ready(function() {
  $textarea = $("#my-textarea");

  // There is some diff between scrollheight and height:
  //    padding-top and padding-bottom
  var diff = $textarea.prop("scrollHeight") - $textarea.height();
  $textarea.live("keyup", function() {
    var height = $textarea.prop("scrollHeight") - diff;
    $textarea.height(height);
  });
});

Minha solução para não usar jQuery (porque às vezes não precisa ser a mesma coisa) está abaixo.Embora só tenha sido testado em Internet Explorador 7, para que a comunidade possa apontar todos os motivos pelos quais isso está errado:

textarea.onkeyup = function () { this.style.height = this.scrollHeight + 'px'; }

Até agora eu realmente gosto de como está funcionando e não me importo com outros navegadores, então provavelmente irei aplicá-lo a todas as minhas áreas de texto:

// Make all textareas auto-resize vertically
var textareas = document.getElementsByTagName('textarea');

for (i = 0; i<textareas.length; i++)
{
    // Retain textarea's starting height as its minimum height
    textareas[i].minHeight = textareas[i].offsetHeight;

    textareas[i].onkeyup = function () {
        this.style.height = Math.max(this.scrollHeight, this.minHeight) + 'px';
    }
    textareas[i].onkeyup(); // Trigger once to set initial height
}

Aqui está uma extensão do widget Prototype que Jeremy postou em 4 de junho:

Impede que o usuário insira mais caracteres se você estiver usando limites em áreas de texto.Ele verifica se ainda restam caracteres.Se o usuário copiar o texto na área de texto, o texto será cortado no máximo.comprimento:

/**
 * Prototype Widget: Textarea
 * Automatically resizes a textarea and displays the number of remaining chars
 * 
 * From: http://stackoverflow.com/questions/7477/autosizing-textarea
 * Inspired by: http://github.com/jaz303/jquery-grab-bag/blob/63d7e445b09698272b2923cb081878fd145b5e3d/javascripts/jquery.autogrow-textarea.js
 */
if (window.Widget == undefined) window.Widget = {}; 

Widget.Textarea = Class.create({
  initialize: function(textarea, options){
    this.textarea = $(textarea);
    this.options = $H({
      'min_height' : 30,
      'max_length' : 400
    }).update(options);

    this.textarea.observe('keyup', this.refresh.bind(this));

    this._shadow = new Element('div').setStyle({
      lineHeight : this.textarea.getStyle('lineHeight'),
      fontSize : this.textarea.getStyle('fontSize'),
      fontFamily : this.textarea.getStyle('fontFamily'),
      position : 'absolute',
      top: '-10000px',
      left: '-10000px',
      width: this.textarea.getWidth() + 'px'
    });
    this.textarea.insert({ after: this._shadow });

    this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
    this.textarea.insert({after: this._remainingCharacters});  
    this.refresh();  
  },

  refresh: function(){ 
    this._shadow.update($F(this.textarea).replace(/\n/g, '<br/>'));
    this.textarea.setStyle({
      height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
    });

    // Keep the text/character count inside the limits:
    if($F(this.textarea).length > this.options.get('max_length')){
      text = $F(this.textarea).substring(0, this.options.get('max_length'));
        this.textarea.value = text;
        return false;
    }

    var remaining = this.options.get('max_length') - $F(this.textarea).length;
    this._remainingCharacters.update(Math.abs(remaining)  + ' characters remaining'));
  }
});

@memical tinha uma solução incrível para definir a altura da área de texto no carregamento de página com jQuery, mas para meu aplicativo eu queria poder aumentar a altura da área de texto à medida que o usuário adicionasse mais conteúdo.Eu desenvolvi a solução da memical com o seguinte:

$(document).ready(function() {
    var $textarea = $("p.body textarea");
    $textarea.css("height", ($textarea.attr("scrollHeight") + 20));
    $textarea.keyup(function(){
        var current_height = $textarea.css("height").replace("px", "")*1;
        if (current_height + 5 <= $textarea.attr("scrollHeight")) {
            $textarea.css("height", ($textarea.attr("scrollHeight") + 20));
        }
    });
});

Não é muito suave, mas também não é um aplicativo voltado para o cliente, então a suavidade realmente não importa.(Se isso fosse voltado para o cliente, eu provavelmente teria usado apenas um plugin jQuery de redimensionamento automático.)

Para aqueles que estão codificando para o IE e encontram esse problema.O IE tem um pequeno truque que o torna 100% CSS.

<TEXTAREA style="overflow: visible;" cols="100" ....></TEXTAREA>

Você pode até fornecer um valor para rows="n" que o IE irá ignorar, mas outros navegadores usarão.Eu realmente odeio codificação que implementa hacks do IE, mas este é muito útil.É possível que funcione apenas no modo Quirks.

Internet Explorer, Safari, Chrome e Ópera os usuários precisam se lembrar de definir explicitamente o valor da altura da linha em CSS.Eu faço uma folha de estilo que define as propriedades iniciais para todas as caixas de texto da seguinte maneira.

<style>
    TEXTAREA { line-height: 14px; font-size: 12px; font-family: arial }
</style>

Aqui está uma função que acabei de escrever em jQuery para fazer isso - você pode portá-la para Protótipo, mas eles não suportam a "vivacidade" do jQuery, portanto os elementos adicionados pelas solicitações Ajax não responderão.

Esta versão não apenas se expande, mas também se contrai quando delete ou backspace é pressionado.

Esta versão depende do jQuery 1.4.2.

Aproveitar ;)

http://pastebin.com/SUKeBtnx

Uso:

$("#sometextarea").textareacontrol();

ou (qualquer seletor jQuery, por exemplo)

$("textarea").textareacontrol();

Foi testado em Internet Explorador 7/Internet Explorador 8, Firefox 3.5 e Chrome.Tudo funciona bem.

Usando ASP.NET, simplesmente faça o seguinte:

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Automatic Resize TextBox</title>
        <script type="text/javascript">
            function setHeight(txtarea) {
                txtarea.style.height = txtdesc.scrollHeight + "px";
            }
        </script>
    </head>

    <body>
        <form id="form1" runat="server">
            <asp:TextBox ID="txtarea" runat= "server" TextMode="MultiLine"  onkeyup="setHeight(this);" onkeydown="setHeight(this);" />
        </form>
    </body>
</html>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top