Como detecto "shift + enter" e giro uma nova linha na Textarea?

145

Atualmente, se a pessoa pressionar enterdentro da área de texto, o formulário será enviado.
Bom, eu quero isso.

Mas quando eles digitam shift+ enter, quero que a área de texto passe para a próxima linha:\n

Como posso fazer isso no JQueryJavaScript simples ou o mais simples possível?

TIMEX
fonte
3
Oh, como eu odeio esse comportamento alterado ... ^^ Por que você faria isso? Se você escrever uma carta em palavras, esperaria que ele salve o texto em um arquivo ao pressionar Enter ou deve iniciar uma nova linha?
Andreas
18
Estou construindo uma sala de bate-papo. É assim que o Skype se senta.
TIMEX 16/05
10
Verifique se há e.shiftKey.
Thai
6
Tudo o que você precisa fazer é encontrar o código que impede o Enter de enviar o formulário e verificar a shiftKeypropriedade do evento .
Tim Down
3
Shift ENTER para uma nova linha em um campo de texto não é um comportamento "alterado". Esse comportamento é esperado nos anos do burro, para todo tipo de coisa. Eu o usei décadas atrás ao inserir texto em planilhas.
Relaxando em Chipre

Respostas:

81

Melhor usar solução mais simples:

A solução de Tim abaixo é melhor, sugiro usar isso: https://stackoverflow.com/a/6015906/4031815


Minha solução

Eu acho que você pode fazer algo assim ..

EDIT: O código foi alterado para funcionar independentemente da posição do sinal de intercalação

A primeira parte do código é obter a posição do cursor.

Ref: Como obter a posição da coluna de sinal de intercalação (não pixels) em uma área de texto, em caracteres, desde o início?

function getCaret(el) { 
    if (el.selectionStart) { 
        return el.selectionStart; 
    } else if (document.selection) { 
        el.focus();
        var r = document.selection.createRange(); 
        if (r == null) { 
            return 0;
        }
        var re = el.createTextRange(), rc = re.duplicate();
        re.moveToBookmark(r.getBookmark());
        rc.setEndPoint('EndToStart', re);
        return rc.text.length;
    }  
    return 0; 
}

E, em seguida, substituindo o valor da área de texto adequadamente quando Shift+ Enterjuntos, envie o formulário se Enterfor pressionado sozinho.

$('textarea').keyup(function (event) {
    if (event.keyCode == 13) {
        var content = this.value;  
        var caret = getCaret(this);          
        if(event.shiftKey){
            this.value = content.substring(0, caret - 1) + "\n" + content.substring(caret, content.length);
            event.stopPropagation();
        } else {
            this.value = content.substring(0, caret - 1) + content.substring(caret, content.length);
            $('form').submit();
        }
    }
});

Aqui está uma demonstração

Jishnu AP
fonte
Isso não funcionará se o cursor não estiver no final do conteúdo da área de texto.
Tim Down
Além disso, há um erro de digitação (você quer dizer event.keyCode == 13) e eu acho que você provavelmente também queria event.preventDefault()e não event.stopPropagation().
Tim Down
Eu mudei isso. Agora funcionará independentemente da posição do cursor. E event.stopPropagation()eu pretendia interromper algum outro código que ele possa ter escrito para enviar o formulário.
Jishnu AP
7
Essa função de posição do cursor é defeituosa (veja meu comentário e resposta sobre a questão da posição do cursor vinculada) e você não precisa da posição do cursor para fazer isso de qualquer maneira. Veja minha resposta aqui. Re event.stopPropagation(), isso impedirá que o evento borbulhe ainda mais no DOM, mas não impedirá que o pressionamento de tecla faça sua ação padrão de inserir uma quebra de linha (embora, na verdade, na keyupminha sugestão de event.preventDefault()não o faça).
Tim Down
2
Embora ele funcionou bem, mas deu erro que carentnão está definido, se eu mudá-lo para acento circunflexo ele adiciona 2 novas linhas
Aamir Mahmood
164

Solução fácil e elegante:

Primeiro, pressionar Enterdentro de uma área de texto não envia o formulário, a menos que você tenha um script para fazê-lo. Esse é o comportamento que o usuário espera e eu recomendo que não seja alterado. No entanto, se você precisar fazer isso, a abordagem mais fácil seria encontrar o script que está Enterenviando o formulário e alterá-lo. O código terá algo como

if (evt.keyCode == 13) {
    form.submit();
}

... e você pode simplesmente mudar para

if (evt.keyCode == 13 && !evt.shiftKey) {
    form.submit();
}

Por outro lado, se você não tiver acesso a esse código por algum motivo, faça o seguinte para fazê-lo funcionar em todos os principais navegadores, mesmo que o cursor não esteja no final do texto:

jsFiddle: http://jsfiddle.net/zd3gA/1/

Código:

function pasteIntoInput(el, text) {
    el.focus();
    if (typeof el.selectionStart == "number"
            && typeof el.selectionEnd == "number") {
        var val = el.value;
        var selStart = el.selectionStart;
        el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd);
        el.selectionEnd = el.selectionStart = selStart + text.length;
    } else if (typeof document.selection != "undefined") {
        var textRange = document.selection.createRange();
        textRange.text = text;
        textRange.collapse(false);
        textRange.select();
    }
}

function handleEnter(evt) {
    if (evt.keyCode == 13 && evt.shiftKey) {
        if (evt.type == "keypress") {
            pasteIntoInput(this, "\n");
        }
        evt.preventDefault();
    }
}

// Handle both keydown and keypress for Opera, which only allows default
// key action to be suppressed in keypress
$("#your_textarea_id").keydown(handleEnter).keypress(handleEnter);
Tim Down
fonte
42

A maioria dessas respostas complica isso demais. Por que não tentar dessa maneira?

$("textarea").keypress(function(event) {
        if (event.keyCode == 13 && !event.shiftKey) {
         submitForm(); //Submit your form here
         return false;
         }
});

Não é necessário mexer na posição de cursor ou empurrar a linha para o JS. Basicamente, a função não funcionará se a tecla Shift estiver sendo pressionada, permitindo que a tecla Enter / Return execute sua função normal.

Matt Goodwin
fonte
Isto é exatamente o que eu queria. Obrigado.
Taku Yoshi
18

Por que não apenas

$(".commentArea").keypress(function(e) {
    var textVal = $(this).val();
    if(e.which == 13 && e.shiftKey) {

    }
    else if (e.which == 13) {
       e.preventDefault(); //Stops enter from creating a new line
       this.form.submit(); //or ajax submit
    }
});
Liam Hall
fonte
2
Você pode usar apenas uma condição como (event.keyCode == 13 &&! Event.shiftKey). Apenas uma dica: se você usa knockoutjs, precisa desfocar o textarea primeiro para atualizar o valor: jQuery (this) .blur ();
23713 Justin
4

Use o plug-in de teclas de atalho jQuery e este código

jQuery(document).bind('keydown', 'shift+enter', 
         function (evt){ 
             $('textarea').val($('#textarea').val() + "\n");// use the right id here
             return true;
         }
);
Thariama
fonte
3

Aqui está uma solução AngularJS usando ng-keyup se alguém tiver o mesmo problema usando o AngularJS.

ng-keyup="$event.keyCode == 13 && !$event.shiftKey && myFunc()"
Tombery
fonte
3

Usando o ReactJS ES6, aqui está a maneira mais simples

shift+ enterNova linha em qualquer posição

enter Bloqueado

class App extends React.Component {

 constructor(){
    super();
    this.state = {
      message: 'Enter is blocked'
    }
  }
  onKeyPress = (e) => {
     if (e.keyCode === 13 && e.shiftKey) {
        e.preventDefault();
        let start = e.target.selectionStart,
            end = e.target.selectionEnd;
        this.setState(prevState => ({ message:
            prevState.message.substring(0, start)
            + '\n' +
            prevState.message.substring(end)
        }),()=>{
            this.input.selectionStart = this.input.selectionEnd = start + 1;
        })
    }else if (e.keyCode === 13) { // block enter
      e.preventDefault();
    }
    
  };

  render(){
    return(
      <div>
      New line with shift enter at any position<br />
       <textarea 
       value={this.state.message}
       ref={(input)=> this.input = input}
       onChange={(e)=>this.setState({ message: e.target.value })}
       onKeyDown={this.onKeyPress}/>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='root'></div>

Shrroy
fonte
2

Encontrei este tópico procurando uma maneira de controlar Shift + qualquer tecla. Eu colei outras soluções para fazer essa função combinada realizar o que eu precisava. Espero que ajude alguém.

function () {
    return this.each(function () {
    $(this).keydown(function (e) {
        var key = e.charCode || e.keyCode || 0;
        // Shift + anything is not desired
        if (e.shiftKey) {
            return false;
        }
        // allow backspace, tab, delete, enter, arrows, numbers 
        //and keypad numbers ONLY
        // home, end, period, and numpad decimal
        return (
            key == 8 ||
            key == 9 ||
            key == 13 ||
            key == 46 ||
            key == 110 ||
            key == 190 ||
            (key >= 35 && key <= 40) ||
            (key >= 48 && key <= 57) ||
            (key >= 96 && key <= 105));
    });
});
Spencer Sullivan
fonte
1

Caso alguém ainda esteja se perguntando como fazer isso sem o jQuery.

HTML

<textarea id="description"></textarea>

Javascript

const textarea = document.getElementById('description');

textarea.addEventListener('keypress', (e) => {
    e.keyCode === 13 && !e.shiftKey && e.preventDefault(); 
})

JS de baunilha

var textarea = document.getElementById('description');

textarea.addEventListener('keypress', function(e) {
    if(e.keyCode === 13 && !e.shiftKey) {
      e.preventDefault();
    }
})
Jaco Ahmad
fonte
1

Eu uso div, adicionando contenteditable true em vez de usar a área de texto.

A esperança pode ajudá-lo.

$("#your_textarea").on('keydown', function(e){//textarea keydown events
  if(e.key == "Enter")
  {
    if(e.shiftKey)//jump new line
    {
     // do nothing
    }
    else  // do sth,like send message or else
    {
       e.preventDefault();//cancell the deafult events
    }
  }
})
Hsinhsin Hung
fonte
1

Isso funciona para mim!

$("#your_textarea").on('keydown', function(e){
    if(e.keyCode === 13 && !e.shiftKey) 
    {

          $('form').submit();

    }
});
Mȍhǟmmǟd Șamȋm
fonte
0

usando a ng-keyupdiretiva no angularJS, envie apenas uma mensagem ao pressionar a Entertecla e Shift+Enterterá apenas uma nova linha.

ng-keyup="($event.keyCode == 13&&!$event.shiftKey) ? sendMessage() : null"
Abdallah Okasha
fonte