Actualización 2018
Como esta es una respuesta bastante popular, decidí actualizarla y embellecerla un poco agregando el selector de nodo de texto a jQuery como complemento.
En el fragmento a continuación, puede ver que defino una nueva función jQuery que obtiene todos (y solo) los textNodes. También puede encadenar esta función con, por ejemplo, la first()
función. Hago un recorte en el nodo de texto y verifico si no está vacío después del recorte porque los espacios, pestañas, nuevas líneas, etc. también se reconocen como nodos de texto. Si también necesita esos nodos, simplemente elimínelos de la declaración if en la función jQuery.
Agregué un ejemplo de cómo reemplazar el primer nodo de texto y cómo reemplazar todos los nodos de texto.
Este enfoque facilita la lectura del código y facilita su uso varias veces y con diferentes propósitos.
La Actualización 2017 (adrach) también debería funcionar si lo prefiere.
Como extensión jQuery
//Add a jQuery extension so it can be used on any jQuery object
jQuery.fn.textNodes = function() {
return this.contents().filter(function() {
return (this.nodeType === Node.TEXT_NODE && this.nodeValue.trim() !== "");
});
}
//Use the jQuery extension
$(document).ready(function(){
$('#replaceAll').on('click', () => {
$('#testSubject').textNodes().replaceWith('Replaced');
});
$('#replaceFirst').on('click', () => {
$('#testSubject').textNodes().first().replaceWith('Replaced First');
});
});
p {
margin: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="testSubject">
**text to change**
<p>text that should not change</p>
<p>text that should not change</p>
**also text to change**
<p>text that should not change</p>
<p>text that should not change</p>
**last text to change**
</div>
<button id="replaceFirst">Replace First</button>
<button id="replaceAll">Replace All</button>
Equivalente de Javascript (ES)
//Add a new function to the HTMLElement object so it cna be used on any HTMLElement
HTMLElement.prototype.textNodes = function() {
return [...this.childNodes].filter((node) => {
return (node.nodeType === Node.TEXT_NODE && node.nodeValue.trim() !== "");
});
}
//Use the new HTMLElement function
document.addEventListener('DOMContentLoaded', () => {
document.querySelector('#replaceAll').addEventListener('click', () => {
document.querySelector('#testSubject').textNodes().forEach((node) => {
node.textContent = 'Replaced';
});
});
document.querySelector('#replaceFirst').addEventListener('click', function() {
document.querySelector('#testSubject').textNodes()[0].textContent = 'Replaced First';
});
});
p {
margin: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="testSubject">
**text to change**
<p>text that should not change</p>
<p>text that should not change</p>
**also text to change**
<p>text that should not change</p>
<p>text that should not change</p>
**last text to change**
</div>
<button id="replaceFirst">Replace First</button>
<button id="replaceAll">Replace All</button>
Actualización 2017 (adrach):
Parece que varias cosas han cambiado desde que se publicó. Aquí hay una versión actualizada
$("div").contents().filter(function(){ return this.nodeType == 3; }).first().replaceWith("change text");
Respuesta original (no funciona para versiones actuales)
$("div").contents().filter(function(){ return this.nodeType == 3; })
.filter(':first').text("change text");
Fuente: http://api.jquery.com/contents/