Come ridimensionare automaticamente un'area di testo usando Prototype?


121

Attualmente sto lavorando a un'applicazione di vendita interna per l'azienda per cui lavoro e ho un modulo che consente all'utente di modificare l'indirizzo di consegna.

Ora penso che sarebbe molto più bello, se l'area di testo che sto usando per i dettagli dell'indirizzo principale occupasse solo l'area del testo al suo interno e si ridimensionasse automaticamente se il testo è stato modificato.

Eccone uno screenshot al momento.

Indirizzo ISO

Qualche idea?


@Chris

Un buon punto, ma ci sono ragioni per cui voglio che venga ridimensionato. Voglio che l'area che occupa sia l'area delle informazioni in essa contenute. Come puoi vedere nella schermata, se ho un'area di testo fissa, occupa una discreta quantità di spazio verticale.

Posso ridurre il carattere, ma ho bisogno che l'indirizzo sia grande e leggibile. Ora posso ridurre la dimensione dell'area di testo, ma poi ho problemi con le persone che hanno una riga dell'indirizzo che richiede 3 o 4 (una richiede 5) righe. La necessità che l'utente utilizzi una barra di scorrimento è una delle principali no-no.

Credo che dovrei essere un po 'più specifico. Sto cercando il ridimensionamento verticale e la larghezza non ha molta importanza. L'unico problema che si verifica è che il numero ISO (il grande "1") viene inserito sotto l'indirizzo quando la larghezza della finestra è troppo piccola (come puoi vedere nello screenshot).

Non si tratta di avere un gimick; si tratta di avere un campo di testo che l'utente può modificare che non occuperà spazio non necessario, ma mostrerà tutto il testo al suo interno.

Tuttavia, se qualcuno propone un altro modo per affrontare il problema, sono aperto anche a quello.


Ho modificato un po 'il codice perché si comportava in modo un po' strano. L'ho cambiato per attivarlo su keyup, perché non avrebbe preso in considerazione il carattere appena digitato.

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;
};

Puoi creare un sito dimostrativo in cui possiamo vederlo all'opera?
Einar Ólafsson

3
questo plugin sembra buono jacklmoore.com/autosize
Gaurav Shah

Esiste una versione JQuery? Come accedere a colonne e righe di una TextArea in JQuery?
Zach

Quasi la stessa, ma con obbligo esplicito che dovrebbe diventare più piccolo quando il testo viene rimosso: stackoverflow.com/questions/454202/...
Ciro Santilli郝海东冠状病六四事件法轮功

Risposte:


75

Facebook lo fa, quando scrivi sui muri delle persone, ma si ridimensiona solo verticalmente.

Il ridimensionamento orizzontale mi sembra un disastro, a causa del ritorno a capo automatico, delle linee lunghe e così via, ma il ridimensionamento verticale sembra essere abbastanza sicuro e piacevole.

Nessuno dei neofiti che usano Facebook che conosco ha mai menzionato qualcosa al riguardo o è stato confuso. Lo userei come prova aneddotica per dire "vai avanti, implementalo".

Un po 'di codice JavaScript per farlo, usando Prototype (perché è quello con cui ho familiarità):

<!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: Ovviamente questo codice JavaScript è molto ingenuo e non ben testato, e probabilmente non vuoi usarlo su caselle di testo con romanzi al loro interno, ma hai un'idea generale.


2
Ciò presuppone che il browser si interrompa a qualsiasi carattere, il che non è corretto. Provalo <textarea cols='5'>0 12345 12345 0</textarea>. (Ho scritto un'implementazione quasi identica e non l'ho presa fino a dopo un mese di utilizzo.) Inoltre non funziona per le righe vuote.
st-boost

Esiste una versione di JQuery per questo?
emeraldhieu

La barra rovesciata in $ A (str.split ("\ n")) necessita di un'altra. (La mia modifica alla risposta di cui sopra non è sopravvissuta per qualche motivo.)
gherson

67

Un perfezionamento di alcune di queste risposte è lasciare che CSS faccia più lavoro.

Il percorso di base sembra essere:

  1. Crea un elemento contenitore per contenere il textareae un nascostodiv
  2. Utilizzando Javascript, mantieni textareai contenuti sincronizzati con divi file
  3. Lascia che sia il browser a calcolare l'altezza di quel div
  4. Poiché il browser gestisce il rendering / dimensionamento del nascosto div, evitiamo di impostare esplicitamente l' textareaaltezza di.

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;
}
<div class="textarea-container">
    <textarea id="textArea"></textarea>
    <div id="textCopy"></div>
</div>


5
Questa è una soluzione fantastica! L'unico avvertimento è che i browser che non supportano il dimensionamento del riquadro (IE <7) non calcoleranno correttamente la larghezza e quindi perderai un po 'di precisione, ma se lasci lo spazio di una riga alla fine, dovresti comunque stare bene. Sicuramente lo adoro per la semplicità.
Antonio Salazar Cardozo

4
Mi sono preso la libertà di implementare questa soluzione come plug-in jQuery autonomo, semplice da usare, senza markup o stili richiesti. xion.io/jQuery.xarea nel caso in cui qualcuno potesse usarlo :)
Xion

2
l'impostazione di textCopy su hidden consente comunque al div nascosto di occupare spazio nel markup in modo che il contenuto di textCopy si ingrandisca, alla fine otterrai una barra di scorrimento lungo l'intera lunghezza della pagina ...
topwik

1
Un altro bel ritocco a questo; var text = $("#textArea").val().replace(/\n/g, '<br/>') + '&nbsp;';si assicura di non ottenere un comportamento a scatti quando si passa da una nuova riga vuota alla fine dell'area di testo a una non vuota, poiché il div nascosto si assicura di andare a capo al nbsp.
inconsapevole

1
@Grande invito inaspettato per l'aggiunta di "& nbsp;" per sbarazzarti di quell'improvviso aumento di dimensioni quando aggiungi la prima lettera a una nuova riga - per me è rotta senza questo - questo dovrebbe essere aggiunto alla risposta!
davnicwil

40

Ecco un'altra tecnica per ridimensionare automaticamente un'area di testo.

  • Utilizza l'altezza in pixel anziché l'altezza della riga: gestione più accurata del ritorno a capo automatico se viene utilizzato un carattere proporzionale.
  • Accetta ID o elemento come input
  • Accetta un parametro di altezza massima opzionale, utile se preferisci non lasciare che l'area di testo si estenda oltre una certa dimensione (tienilo tutto sullo schermo, evita di interrompere il layout, ecc.)
  • Testato su Firefox 3 e Internet Explorer 6

Codice: (JavaScript semplice vaniglia)

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";
   }
}

Demo: (usa jQuery, target nell'area di testo in cui sto digitando in questo momento - se hai installato Firebug , incolla entrambi i campioni nella console e prova su questa pagina)

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

@SMB - probabilmente non sarebbe troppo difficile da implementare, basta aggiungere un altro condizionale
Jason

@ Jason: Quando il testo nella casella non lo riempie clientHeighte scrollHeightsono uguali, quindi non puoi usare questo metodo se vuoi che la tua textarea si restringa oltre che cresca.
Brant Bobby

Per ridurlo semplicemente a, devi solo aggiungere questo codice prima della riga 6:if (text.clientHeight == text.scrollHeight) text.style.height = "20px";
Gapipro

14

Probabilmente la soluzione più breve:

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

In questo modo non hai bisogno di div nascosti o qualcosa del genere.

Nota: potresti dover giocare a this.style.height = (this.scrollHeight) + "px";seconda di come modifichi l'area di testo (altezza della riga, padding e quel tipo di cose).


La soluzione migliore se non ti dispiace che la barra di scorrimento lampeggi.
cfillol

Sarebbe sufficiente catturare solo l'evento keyup. Non credi?
cfillol

2
Imposta la proprietà textarea overflow su "hidden" per evitare che la barra di scorrimento lampeggi.
cfillol

keyuppotrebbe essere sufficiente, ma non ne sono sicuro. Ero così felice di averlo capito, che ho smesso di provare qualcos'altro.
Eduard Luca

Sto ancora cercando di capire perché hai aggiunto this.style.height = "1px"; o this.style.height = "auto"; prima. Lo so, textarea non si ridimensionerà quando rimuoviamo il contenuto se non aggiungiamo questa riga. Qualcuno può preoccuparsi di spiegare?
Balasubramani M

8

Ecco una versione prototipo del ridimensionamento di un'area di testo che non dipende dal numero di colonne nell'area di testo. Questa è una tecnica superiore perché consente di controllare l'area di testo tramite CSS e di avere un'area di testo a larghezza variabile. Inoltre, questa versione mostra il numero di caratteri rimanenti. Sebbene non richiesta, è una funzionalità piuttosto utile e può essere facilmente rimossa se indesiderata.

//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'));
  }
});

Crea il widget chiamando new Widget.Textarea('element_id'). Le opzioni predefinite possono essere sovrascritte passandole come oggetto, ad es new Widget.Textarea('element_id', { max_length: 600, min_height: 50}). Se vuoi crearlo per tutte le aree di testo della pagina, fai qualcosa come:

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

7

Ecco una soluzione con JQuery:

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

abcè un teaxtarea.


5

Controlla il link sottostante: 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
    });
});


3

Solo rivisitando questo, l'ho reso un po 'più ordinato (anche se qualcuno che è pieno di prototipi / JavaScript potrebbe suggerire miglioramenti?).

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 chiamare con:

new TextAreaResize('textarea_id_name_here');

3

Ho fatto qualcosa di abbastanza semplice. Per prima cosa ho inserito TextArea in un DIV. Secondo, ho chiamato la readyfunzione per questo 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)));
});

Semplice. È l'altezza massima del div una volta renderizzato, divisa per l'altezza di una TextArea di una riga.


2

Avevo bisogno di questa funzione per me stesso, ma nessuno di quelli da qui ha funzionato come ne avevo bisogno.

Quindi ho usato il codice di Orion e l'ho cambiato.

Ho aggiunto un'altezza minima, in modo che sulla distruzione non diventi troppo piccolo.

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;
};

2

Come la risposta di @memical.

Tuttavia ho trovato alcuni miglioramenti. Puoi usare la height()funzione jQuery . Ma fai attenzione ai pixel padding-top e padding-bottom. Altrimenti la tua textarea crescerà troppo velocemente.

$(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);
  });
});

2

La mia soluzione per non usare jQuery (perché a volte non devono essere la stessa cosa) è di seguito. Sebbene sia stato testato solo in Internet Explorer 7 , quindi la comunità può sottolineare tutti i motivi per cui questo è sbagliato:

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

Finora mi piace davvero come funziona e non mi interessa degli altri browser, quindi probabilmente lo applicherò a tutte le mie aree di testo:

// 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
}

1

Ecco un'estensione del widget Prototype che Jeremy ha pubblicato il 4 giugno:

Impedisce all'utente di inserire più caratteri se si utilizzano limiti nelle aree di testo. Controlla se sono rimasti caratteri. Se l'utente copia il testo nella textarea, il testo viene tagliato al massimo. lunghezza:

/**
 * 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'));
  }
});

1

@memical aveva una soluzione fantastica per impostare l'altezza della textarea su pageload con jQuery, ma per la mia applicazione volevo essere in grado di aumentare l'altezza della textarea man mano che l'utente aggiungeva più contenuto. Ho costruito la soluzione di Memical con quanto segue:

$(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));
        }
    });
});

Non è molto fluido, ma non è nemmeno un'applicazione per il client, quindi la fluidità non ha molta importanza. (Se fosse stato rivolto al cliente, probabilmente avrei usato un plug-in jQuery a ridimensionamento automatico.)


1

Per coloro che codificano per IE e riscontrano questo problema. IE ha un piccolo trucco che lo rende 100% CSS.

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

Puoi anche fornire un valore per rows = "n" che IE ignorerà, ma verrà utilizzato da altri browser. Odio davvero la codifica che implementa gli hack di IE, ma questa è molto utile. È possibile che funzioni solo in modalità Quirks.


1

Internet Explorer, Safari, Chrome e Opera devono ricordarsi di impostare in modo esplicito il valore dell'altezza della riga in CSS. Faccio un foglio di stile che imposta le proprietà iniziali per tutte le caselle di testo come segue.

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

1

Ecco una funzione che ho appena scritto in jQuery per farlo: puoi portarla su Prototype , ma non supportano la "vivacità" di jQuery, quindi gli elementi aggiunti dalle richieste Ajax non risponderanno.

Questa versione non solo si espande, ma si contrae anche quando si preme Canc o Backspace.

Questa versione si basa su jQuery 1.4.2.

Godere ;)

http://pastebin.com/SUKeBtnx

Uso:

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

o (qualsiasi selettore jQuery per esempio)

$("textarea").textareacontrol();

È stato testato su Internet Explorer 7 / Internet Explorer 8 , Firefox 3.5 e Chrome. Tutto funziona bene.


1

Utilizzando ASP.NET, fai semplicemente questo:

<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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.