Як автоматизувати текстову область за допомогою прототипу?


121

Зараз я працюю над додатком для внутрішніх продажів компанії, в якій працюю, і у мене є форма, яка дозволяє користувачеві змінювати адресу доставки.

Тепер я думаю, що це буде виглядати набагато приємніше, якби текстові області, які я використовую для основних деталей адреси, просто займуть область тексту в ньому та автоматично змінять розмір, якщо текст буде змінено.

Ось скріншот на даний момент.

Адреса ISO

Будь-які ідеї?


@Chris

Хороший момент, але є причини, за які я хочу його змінити. Я хочу, щоб область, яку вона займає, була зоною інформації, що міститься в ній. Як ви можете бачити на знімку екрана, якщо у мене фіксований текстовий пояс, це займає неабиякий запас вертикального простору.

Я можу зменшити шрифт, але мені потрібно, щоб адреса була великою і читабельною. Тепер я можу зменшити розмір області тексту, але тоді у мене виникають проблеми з людьми, які мають адресний рядок, який займає 3 або 4 (один займає 5) рядків. Необхідність використання користувачем смуги прокрутки - це головне, що немає.

Я думаю, я повинен бути трохи більш конкретним. Я після вертикального розміру, і ширина не має великого значення. Єдина проблема, яка трапляється з цим, - це номер ISO (великий "1"), який підписується під адресою, коли ширина вікна занадто мала (як ви бачите на скріншоті).

Справа не в тому, щоб мати трюк; йдеться про наявність текстового поля, який користувач може редагувати, що не займе зайвого місця, але покаже весь текст у ньому.

Хоча якщо хтось придумує інший спосіб підійти до проблеми, я також до цього відкритий.


Я трохи змінив код, тому що він діяв трохи дивно. Я змінив його, щоб активувати клавішу, оскільки він не брав би до уваги щойно введеного символу.

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

Чи можете ви створити демонстраційний сайт, де ми можемо бачити це на роботі?
Ейнар Ólafsson

3
цей плагін здається гарним jacklmoore.com/autosize
Gaurav Shah

Чи існує версія JQuery? Як отримати доступ до команд і рядків TextArea у JQuery?
Зак

Майже те ж саме, але з явним вимогою , яке повинно стати менше , коли текст буде видалений: stackoverflow.com/questions/454202 / ...
Чіро Сантіллі郝海东冠状病六四事件法轮功

Відповіді:


75

Facebook робить це, коли ви пишете на стінах людей, але розмір лише вертикально.

Горизонтальний розмір вважає мене безладним через перенесення слів, довгі рядки тощо, але вертикальний розмір здається досить безпечним і приємним.

Жоден із Facebook-новачків, яких я знаю, ніколи про це не згадував і не плутався. Я використовую це як анекдотичні докази, щоб сказати: "вперед, впроваджуй це".

Якийсь код JavaScript, щоб зробити це, використовуючи прототип (адже саме з цим я знайомий):

<!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: Очевидно, що цей код JavaScript дуже наївний і недостатньо перевірений, і ви, мабуть, не хочете його використовувати в текстових полях з романами, але ви отримуєте загальну думку.


2
Це передбачає, що браузер перерве будь-який символ, що є неправильним. Спробуйте <textarea cols='5'>0 12345 12345 0</textarea>. (Я написав майже однакову реалізацію, і не вдавав це лише через місяць використання.) Він також не відповідає порожнім рядкам.
st-boost

Чи існує для цього версія JQuery?
смарагдовий

Нахил в $ A (str.split ("\ n")) потребує іншого. (Моя редакція вищезгаданої відповіді чомусь не збереглася.)
gherson

67

Одне уточнення деяких із цих відповідей - дозволити CSS робити більше роботи.

Основним маршрутом, здається, є:

  1. Створіть елемент контейнера для зберігання textarea та прихованогоdiv
  2. За допомогою Javascript зберігайте textarea "вміст s синхронізованого з div
  3. Нехай браузер виконує роботу з обчисленням висоти цього дільника
  4. Оскільки браузер обробляє відображення / розмір прихованого div, ми уникаємо явного встановлення textareaвисоти.

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
Це дивовижне рішення! Єдине застереження полягає в тому, що браузери, які не підтримують розмір коробки (IE <7), не будуть належним чином обчислювати ширину, і тому ви втратите деяку точність, але якщо ви залишите на межі вартості місця в кінці, ти все одно маєш гаразд. Однозначно люблю це за простоту.
Антоніо Салазар Кардозо,

4
Я взяв на себе реалізацію цього рішення як самостійний, простий у використанні плагін jQuery, без розмітки чи стилізації. xion.io/jQuery.xarea на випадок, якщо хтось може ним скористатися :)
Xion

2
встановлення textCopy на приховане все ще дозволяє прихованому div зайняти місце в розмітці, так що вміст textCopy збільшиться, ви зрештою отримаєте смугу прокрутки по всій довжині вашої сторінки ...
topwik

1
Ще один приємний твіст до цього; var text = $("#textArea").val().replace(/\n/g, '<br/>') + '&nbsp;';гарантує, що ви не матимете ривкової поведінки, переходячи від нового порожнього рядка в кінці текстової області до не порожнього, оскільки прихований div обов'язково переходить до nbsp.
невідомо

1
@unwitting чудовий дзвінок про додавання "& nbsp;" щоб позбутися того раптового збільшення розміру, коли ви додаєте першу букву в новий рядок - для мене це порушено без цього - це слід додати до відповіді!
davnicwil

40

Ось ще одна техніка автоматизації текстової області.

  • Використовує висоту пікселя замість висоти рядка: точніше обробляти обертання рядків, якщо використовується пропорційний шрифт.
  • Приймає ідентифікатор або елемент як вхідний
  • Приймає необов'язковий параметр максимальної висоти - корисний, якщо ви бажаєте не допустити, щоб область тексту перевищувала певний розмір (тримайте все це на екрані, уникайте зламу макета тощо).
  • Тестовано на Firefox 3 та Internet Explorer 6

Код: (звичайний ванільний JavaScript)

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

Демонстрація: (використовує jQuery, цілі на текстовій області, яку я зараз набираю - якщо у вас встановлена Firebug , вставте обидва зразки в консоль і протестуйте на цій сторінці)

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

@SMB - це, мабуть, не буде занадто складно реалізувати, просто додайте ще один умовний
Джейсон

@Jason: Коли текст у полі не заповнює його, clientHeightі scrollHeightвони рівні, тому ви не можете використовувати цей метод, якщо ви хочете, щоб ваші текстові області скорочувалися, а також зростали.
Brant Bobby

Щоб просто зменшити його, вам просто потрібно додати цей код перед рядком 6:if (text.clientHeight == text.scrollHeight) text.style.height = "20px";
Gapipro

14

Мабуть, найкоротше рішення:

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

Таким чином, вам не потрібні приховані діви чи щось подібне.

Примітка: можливо, вам доведеться грати, this.style.height = (this.scrollHeight) + "px";залежно від того, як ви стилюєте текстові області (висота лінії, оббивка та подібні речі).


Найкраще рішення, якщо ви не заперечуєте блимати смугою прокрутки.
cfillol

Було б достатньо, щоб наздогнати лише подію клавіатури. Ви не думаєте так?
cfillol

2
Встановіть властивість переповнення текстової області "прихованою", щоб уникнути моргання смуги прокрутки.
cfillol

keyupмогло б вистачити, але я не впевнений. Я був такий щасливий, що зрозумів це, що перестав пробувати все інше.
Едуард Лука

Я все ще намагаюся дізнатися, чому ви додали this.style.height = "1px"; або this.style.height = "авто"; раніше. Я знаю, що textarea не змінить розмір, коли ми видалимо вміст, якщо ми не додамо цей рядок. Може хтось потурбується пояснити?
Баласубрамані M

8

Ось версія прототипу щодо зміни розміру текстової області, яка не залежить від кількості стовпців у текстовій області. Це чудова методика, оскільки вона дозволяє контролювати область тексту за допомогою CSS, а також мати текстові області змінної ширини. Крім того, ця версія відображає кількість символів, що залишилися. Хоча це не вимагається, це досить корисна функція і легко видаляється, якщо небажана.

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

Створіть віджет, зателефонувавши new Widget.Textarea('element_id'). Параметри за замовчуванням можна змінити, передавши їх як об'єкт, наприклад new Widget.Textarea('element_id', { max_length: 600, min_height: 50}). Якщо ви хочете створити його для всіх текстових областей на сторінці, зробіть щось на кшталт:

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

7

Ось рішення з JQuery:

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

abcє а teaxtarea.


5

Перевірте посилання нижче: 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

Щойно переглянувши це, я зробив це трохи охайніше (хоча хтось, хто має повний флакон на Prototype / JavaScript, може запропонувати поліпшення?).

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

Просто дзвінок із:

new TextAreaResize('textarea_id_name_here');

3

Я зробив щось досить легко. Спочатку я поклав TextArea у DIV. По-друге, я закликав цю readyфункцію до цього сценарію.

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

Простий. Це максимальна висота діва, як тільки він виведений, поділений на висоту одного TextArea одного ряду.


2

Мені ця функція була потрібна для мене, але жоден із них не працював так, як мені потрібно.

Тому я використав код Оріона і змінив його.

Я додав мінімальну висоту, щоб на деструкт не потрапив занадто малий.

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

Як і відповідь @memical.

Однак я знайшов деякі поліпшення. Ви можете використовувати функцію jQuery height(). Але пам’ятайте про пікселі на нижній та нижній частині. В іншому випадку ваша текстарія буде рости занадто швидко.

$(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

Моє рішення про використання jQuery (оскільки іноді вони не повинні бути однаковими) нижче. Хоча це було протестовано лише в Internet Explorer 7 , тож спільнота може вказати на всі причини цього неправильно:

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

Поки мені дуже подобається, як це працює, і я не переймаюся іншими браузерами, тому, мабуть, застосую це до всіх моїх текстових областей:

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

Ось розширення віджета "Прототип", який Джеремі опублікував 4 червня:

Це не дозволяє користувачеві вводити більше символів, якщо ви використовуєте обмеження в текстових областях. Він перевіряє, чи залишилися символи. Якщо користувач копіює текст у текстову область, текст обрізається на макс. довжина:

/**
 * 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 мав приголомшливе рішення для встановлення висоти textarea на завантаженні сторінки за допомогою jQuery, але для мого застосування я хотів мати можливість збільшити висоту textarea, оскільки користувач додав більше вмісту. Я створив рішення пам'яті з наступного:

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

Це не дуже гладко, але це також не клієнтська програма, тому гладкість насправді не має значення. (Якби це було орієнтовано на клієнта, я, мабуть, просто би використав плагін автоматичного розміру jQuery.)


1

Для тих, хто кодує IE і стикається з цією проблемою. IE має невелику хитрість, що робить його 100% CSS.

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

Ви можете навіть надати значення для рядків = "n", яке IE буде ігнорувати, але інші браузери будуть використовувати. Я дуже ненавиджу кодування, яке реалізує хакі IE, але це дуже корисно. Можливо, що він працює лише в режимі Quirks.


1

Користувачі Internet Explorer, Safari, Chrome і Opera повинні пам’ятати, щоб чітко встановити значення CSS у висоті лінії. Я роблю таблицю стилів, яка встановлює початкові властивості для всіх текстових полів наступним чином.

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

1

Ось функція, яку я щойно написав у jQuery, щоб виконати її - ви можете перенести її до прототипу перенести , але вони не підтримують "живучість" jQuery, тому елементи, додані запитами Ajax, не відповідатимуть.

Ця версія не тільки розширюється, але й стискається при натисканні на видалення або зворотній простір.

Ця версія спирається на jQuery 1.4.2.

Насолоджуйтесь;)

http://pastebin.com/SUKeBtnx

Використання:

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

або (наприклад, будь-який селектор jQuery)

$("textarea").textareacontrol();

Він був протестований на Internet Explorer 7 / Internet Explorer 8 , Firefox 3.5 та Chrome. Все працює чудово.


1

Використовуючи ASP.NET, просто зробіть це:

<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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.