¿Cómo detecto "shift + enter" y genero una nueva línea en Textarea?

145

Actualmente, si la persona presiona enterdentro del área de texto, se enviará el formulario.
Bien, quiero eso

Pero cuando escriben shift+ enter, quiero que el área de texto se mueva a la siguiente línea:\n

¿Cómo puedo hacer eso en JQueryJavaScript o lo más simple posible?

TIMEX
fuente
3
Oh, cómo odio ese cambio de comportamiento ... ^^ ¿Por qué harías eso? Si escribe una letra en palabra, ¿esperaría que guarde el texto en un archivo al presionar enter o debería comenzar una nueva línea?
Andreas
18
Estoy construyendo una sala de chat. Así es como se sienta Skype.
TIMEX
10
Compruebe si hay e.shiftKey.
Tailandés
66
Todo lo que necesita hacer es encontrar el código que impide que Enter envíe el formulario y verificar la shiftKeypropiedad del evento .
Tim Down
3
Shift ENTER para una nueva línea en un campo de texto no es un comportamiento "cambiado". Se ha esperado un comportamiento para los años de burro, para todo tipo de cosas. Lo usé hace décadas cuando ingresaba texto en hojas de cálculo.
Relajarse en Chipre

Respuestas:

81

Mejor usar una solución más simple:

La solución de Tim a continuación es mejor, sugiero usar eso: https://stackoverflow.com/a/6015906/4031815


Mi solución

Creo que puedes hacer algo como esto ...

EDITAR: cambió el código para que funcione independientemente de la posición de intercalación

La primera parte del código es obtener la posición de intercalación.

Ref: ¿Cómo obtener la posición de la columna de intercalación (no píxeles) en un área de texto, en caracteres, desde el principio?

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

Y luego reemplazando el valor del área de texto en consecuencia cuando Shift+ Enterjuntos, envíe el formulario si Enterse presiona solo.

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

Aquí hay una demostración

Jishnu AP
fuente
Eso no funcionará si el cursor no está al final del contenido del área de texto.
Tim Down
Además, hay un error tipográfico (te refieres event.keyCode == 13) y creo que probablemente también quisiste en event.preventDefault()lugar de event.stopPropagation().
Tim Down
Lo cambie. Ahora funcionará independientemente de la posición de caret. Y con la event.stopPropagation()intención de detener algún otro código que él haya escrito para enviar el formulario.
Jishnu AP
77
Esa función de posición de cuidado es defectuosa (vea mi comentario y respuesta sobre la pregunta de posición de cuidado vinculada), y no necesita la posición de cuidado para hacer esto de todos modos. Mira mi respuesta aquí. Re event.stopPropagation(), eso evitará que el evento burbujee más arriba en el DOM, pero no evitará que la pulsación de tecla realice su acción predeterminada de insertar un salto de línea (aunque en realidad, en keyupmi sugerencia event.preventDefault(), tampoco lo hará).
Tim Down
2
A pesar de que funcionó bien, pero dio un error que carentno está definido, si lo cambio para preocuparlo agrega 2 líneas nuevas
Aamir Mahmood
164

Solución fácil y elegante:

Primero, presionar Enterdentro de un área de texto no envía el formulario a menos que tenga una secuencia de comandos para hacerlo. Ese es el comportamiento que el usuario espera y recomendaría no cambiarlo. Sin embargo, si debe hacer esto, el enfoque más fácil sería encontrar el script que está Enterenviando el formulario y cambiarlo. El código tendrá algo como

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

... y podrías cambiarlo a

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

Por otro lado, si no tiene acceso a este código por algún motivo, debe hacer lo siguiente para que funcione en todos los navegadores principales, incluso si el cursor no está al final del 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
fuente
42

La mayoría de estas respuestas complican demasiado esto. ¿Por qué no intentarlo de esta manera?

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

No perder el tiempo con la posición de cuidado o la línea de empuje se rompe en JS Básicamente, la función no se ejecutará si se presiona la tecla shift, por lo tanto, permite que la tecla enter / return realice su función normal.

Matt Goodwin
fuente
Esto es exactamente lo que quería. Gracias.
Taku Yoshi
18

¿Por qué no solo

$(".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
fuente
2
Solo puede usar una condición como (event.keyCode == 13 &&! Event.shiftKey). Solo un consejo: si usa knockoutjs, debe desenfocar el puño del área de texto para actualizar el valor: jQuery (this) .blur ();
Justin
4

Use el complemento jQuery hotkeys y este código

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

Aquí hay una solución AngularJS que usa ng-keyup si alguien tiene el mismo problema al usar AngularJS.

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

Usando ReactJS ES6 esta es la forma más simple

shift+ enterNueva línea en cualquier posición

enter Obstruido

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
fuente
2

Encontré este hilo buscando una forma de controlar Shift + cualquier tecla. Pegué otras soluciones para hacer que esta función combinada lograra lo que necesitaba. Espero que ayude a alguien más.

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
fuente
1

En caso de que alguien todavía se pregunte cómo hacer esto sin jQuery.

HTML

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

Javascript

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

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

Vanilla JS

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

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

Uso div agregando contenteditable true en lugar de usar textarea.

La esperanza te puede ayudar.

$("#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
fuente
1

Esto funciona para mi!

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

          $('form').submit();

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

usando la ng-keyupdirectiva en angularJS, solo envíe un mensaje al presionar la Entertecla y Shift+Entersolo tomará una nueva línea.

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