JavaScript HERE-doc или другой механизм цитирования?

Есть ли удобный способ процитировать большой блок HTML, который имеет как одинарные, так и двойные кавычки в JavaScript?

Есть ли что-то вроде HERE-doc <<EOF, символа с несколькими кавычками """ или настраиваемых разделителей q{}?

Любые творческие или изобретательные решения этой проблемы?


person Evan Carroll    schedule 01.06.2010    source источник
comment
возможный дубликат Создание многострочных строк в JavaScript   -  person Adam Katz    schedule 14.03.2015
comment
ECMAscript 6, теперь ставший стандартом, позволяет использовать обратные галочки для многострочных строк. Примером этого, притворяясь, что \n является буквальным разрывом строки, может быть var foo = `multi \n line \n string`   -  person Adam Katz    schedule 14.03.2015


Ответы (11)


Некоторым это не нравится, так что будьте готовы к презрению и насмешкам, но есть одна хитрость — свалить «большой блок вещей» в блок <script language="text">:

<script id='blockOfStuff' language="text">
  Hi this is random stuff
  <h1>Including HTML markup</h1>
  And quotes too, or as one man said, "These are quotes, but
  'these' are quotes too."
</script>

Джон Резиг использовал эту технику (или эту мерзость, если хотите) в качестве примера своего механизма шаблонов.

Вы можете получить содержимое с помощью «innerText» или «innerHTML», в зависимости от ситуации, или через службы вашего любимого фреймворка.

редактировать обратите внимание, что через jQuery (вопреки тому, что я сказал в комментарии ниже) .text() не работает, хотя я думаю, что должен. Вместо этого используйте .html().

person Pointy    schedule 01.06.2010
comment
++, я удивлен. Я даже не обиделся. Хотя в этом случае по причинам SEO я бы предпочел не иметь блока текста в html (поскольку динамическое действие приводит его в действие, оно по умолчанию не применимо к странице). - person Evan Carroll; 02.06.2010
comment
В отличие от забавного ответа Энди, это работает в кроссбраузерном режиме? О, и, как я уже много раз говорил в этот день, атрибут language элементов <script> имеет значение устарело. :-П - person Marcel Korpel; 02.06.2010
comment
@Marcel Марсель, я думаю да; Я не проводил много испытаний. Я как бы предположил, что если г-н Резиг использовал его в сообщениях в блогах и т. д., то это, вероятно, было довольно безопасно. Я тоже задаюсь вопросом о языке esp. w.r.t. будущая поддержка HTML5. - person Pointy; 02.06.2010
comment
@Marcel: Я рад, что мой ответ позабавил тебя, я улыбался про себя, когда писал его. Я думаю, что у @Pointy есть единственное жизнеспособное решение здесь, и я не понимаю, почему оно не будет работать во всех браузерах, оно, безусловно, имеет смысл, даже если применяется полностью фиктивный язык или тип пантомимы, пока ни один из них не был пустым или фактически поддерживаемым языком сценариев. - person Andy E; 02.06.2010
comment
@Pointy: не придираться, а innerText() и innerHTML()? Есть ли шутка, которую я не понимаю, или кто-то продвигал эти свойства в функции? :-) - person Andy E; 02.06.2010
comment
@Andy E хорошо, я думаю, что Firefox довольно неуклюж с innerHTML и вернет содержимое файла <script>. Если вы вызовете это в IE для блоков <script> или <style>, вы получите странную ошибку Неизвестного исключения, но я думаю, что innerText() работает. Я не очень уверен, потому что я бы просто вызвал $('#scriptId').text()` :-) (О, конечно же, это не функции!! Извините!) - person Pointy; 02.06.2010
comment
@MatrixFrog, вы также можете сделать script type="text/html". OTOH пытается настроить ваш текст как внешний файл (script src='external.txt' type='text/html'), похоже, не работает. - person LetMyPeopleCode; 10.02.2012

Не поддерживается изначально.

Но поскольку мы говорим о способах заставить это работать, вот один из них (по моему опыту):

<script type="text/javascript">  

    var name = "Mud";

    var str = "\
        My name is " + name + "\
        not to be confused with Bill\
        or Jack or Pete or Dennis\
        my name is " + name + " and it's always been\
    ";

    alert("Les'n one: " + str);

</script>

Эти обратные косые черты сделают свое дело. Просто убедитесь, что все двойные кавычки в вашей строке экранированы обратной косой чертой, так как весь блок заключен в них.

Обратите внимание, что это не сохраняет новые строки, вы должны вставить их вручную как «\ n» перед косой чертой в конце каждой строки. С другой стороны, любой пробел в начале каждой строки будет включен в вывод.

На самом деле это работает лучше всего, когда вам нужно объявить длинную многострочную строку в сценарии (например, XML), но не так хорошо, когда вам нужно сохранить эту строку в точном формате, как вы ее определяете.

Ваше здоровье

person Madbreaks    schedule 30.03.2011

JavaScript не может этого сделать, но CoffeeScript, который представляет собой тонкий слой поверх JavaScript, может.

Перейдите по ссылке и прокрутите вниз до «Многострочные строки и здеки».

person Jakob    schedule 01.06.2010
comment
Ответы, содержащие только ссылку, могут стать недействительными, если связанная страница изменится. ...что и произошло. Вот рабочий URL: coffeescript.org/#strings. - person aidan; 22.10.2015

Я помню, как некоторое время назад видел умное решение, которое использовало многострочные комментарии в функции:

(function () {
   /*
      "This is an example of a multi-line string.  It's really just a mult-line
      comment, and it's wrapped in quote marks.  You might also notice the 
      apostrophe's ;-)"; 
   */
});

Примечание: этот последний апостроф намеренно неверен ;-P

Хитрость заключается в вызове метода toString() функции и анализе многострочного комментария с помощью регулярного выражения. Умно, но очень похоже на предложение Пойнти, немного мерзко.

На самом деле я не думал, что вопрос заключается в поиске серьезного жизнеспособного метода для производственного использования - моя вина в поспешных выводах - я не совсем уверен, почему бы вам просто не избежать соответствующих разделителей строковых литералов. Как отметил Тим Даун в комментариях ниже, третья редакция ECMAScript определяет toString() для функций как зависящую от реализации.

Для забавы я решил проверить совместимость браузера, и этот метод возможен в IE, Opera, Safari и Chrome, но не в Firefox, который не включает комментарии в возвращаемую строку. http://jsfiddle.net/2yvXG/

person Andy E    schedule 01.06.2010
comment
А если серьезно, это действительно хрупко: то, как функция преобразует себя в строку, не указано, и то, что работает в текущих браузерах, может не работать в будущих браузерах. Из спецификации ECMAScript 3: 15.3.4.2 Function.prototype.toString ( ). Возвращается представление функции, зависящее от реализации. Это представление имеет синтаксис FunctionDeclaration. В частности, обратите внимание, что использование и размещение пробелов, разделителей строк и точек с запятой в строке представления зависит от реализации. - person Tim Down; 02.06.2010
comment
У меня не работает Firefox 3.5 javascript:alert ( (function () { /*foo "" '" bar "' '' */ } ).toString() ) - person Evan Carroll; 02.06.2010
comment
@Evan: Признаюсь, я не стал тестировать его в каждом браузере :-) - person Andy E; 02.06.2010
comment
@Tim: Он просил творческие или изобретательные решения, я думаю, что это подходит по крайней мере для одного из них ;-) В любом случае, я не намеревался, чтобы ответ был серьезным предложением для использования в любой производственной среде и, вероятно, должен был где-то это упоминалось! - person Andy E; 02.06.2010
comment
@Evan: кстати, это работает в Opera, Chrome, Safari и IE. Я думаю, это не очень поможет вам, если вы хотите, чтобы он был кросс-браузерным, извините. - person Andy E; 02.06.2010
comment
@Энди: Конечно, это креативно. Никакой критики с моей стороны на этот счет :) По крайней мере, вы прочитали вопрос полностью, а это больше, чем я успел. - person Tim Down; 02.06.2010

ЗдесьДокумент для JavaScript

FuncToHereDoc ("разделитель", невызванная функция с комментарием HEREDOC)

function FuncToHereDoc(here,str) {
    var reobj = new RegExp("/\\*"+here+"\\n[\\s\\S]*?\\n"+here+"\\*/", "m");
    str = reobj.exec(str).toString();
    str = str.replace(new RegExp("/\\*"+here+"\\n",'m'),'').toString();
    return str.replace(new RegExp("\\n"+here+"\\*/",'m'),'').toString();
}

Использование:

FuncToHereDoc("HERE", MyHereDoc);

function MyHereDoc(){
/*HERE
<p>
This is written ing the HEREDOC, notice the multilines :D.
</p>
<p>
HERE
</p>
<p>
And Here
</p>
HERE*/
}
person Zv_oDD    schedule 10.10.2012
comment
Это просто делает предположение, что func.toString(); возвращает исходный код. Это было определено как небезопасное ниже - person Evan Carroll; 11.10.2012
comment
@EvanCarroll предполагает, что вертикальный порядок ответов на SO также небезопасен;) - person Madbreaks; 25.02.2015

ECMAscript 6, теперь ставший стандартом, позволяет использовать обратные кавычки (акценты) для кавычек многострочных литеральных строк. К сожалению, это не поддерживается в IE 11, поэтому его не следует использовать на большинстве веб-сайтов. (Источник: Адам Кац, выше)

Пример:

var str=
`Line 1
Line 2`;
person David Spector    schedule 03.02.2016
comment
На самом деле это самый правильный ответ на исходный вопрос. Проверено это начиная с IE 11.0.45, и оно также работает в этом браузере. - person bearvarine; 24.08.2017

На самом деле я разработал неуклюжий вариант, похожий на user742675, где вы помещаете текст в div, затем отключаете его видимость и извлекаете содержимое. Но простого цитирования большого количества HTML было недостаточно, поэтому я добавил функциональность, которая собирала все переменные, которые вы объявили в своем скрипте, поэтому, если у вас есть var a = 'Steve', любой экземпляр $a в вашем тексте heredoc будет отображаться как 'Стив'.

<script type="text/javascript">
// set variables named andy and handy, which we can use as $andy and $handy in our text

var andy = "Fred Flintstone";
var handy = "Steve Austin";

function hereDoc(divid){
var obj = window; // gets an object containing all the variables
var str = document.getElementById(divid).innerHTML; // gets the HTML block
for(var i in obj){

/* the for loop recurses through all the objects in the page - remember strings are objects in Javascript */

if((typeof(obj[i])=="string")||(typeof(obj[i])=="number")){

/* Type of makes sure it only executes replacement for strings and numbers. The function worked without this test in Firefox and Safari, but threw errors on Opera until it was added. */

myregex = new RegExp('\\$'+i,"g");

/* To replace globally, you need to use a regular expression and use the "g" option, but within the string.replace() method, the regular expression is unquoted, so you can't use a variable in it directly. So we create it and assign it to a RegExp object that works in the string.replace() method. */

str = str.replace(myregex, obj[i]);

/* we replace instances of the variable name with a dollar sign before it with the variable's value */
}
}
return str;

/* and when the loop is done, we return the processed text to be used however needed */

}

function gotoit(){

/* fill the "steve" div with the processed contents of the "randy" div. */

document.getElementById("steve").innerHTML = hereDoc("randy");
}

</script>

<a href="javascript:gotoit();">Run the script</a>
<div id="randy" style="display:none;">
The interesting thing about $andy is that he's not nearly as popular with young kids as $handy.<br><br>

What I really find 'interesting' is that this "multiline" thing works as well as $handy's bionic arm. <br><br>
</div>
<div id="steve"></div>
person LetMyPeopleCode    schedule 10.02.2012

Основываясь на предыдущих ответах и ​​различных вариантах использования, вот небольшой пример:

https://gist.github.com/lavoiesl/5880516

/*!
 * Extract a function's comment, useful to have multiline string
 * @link https://gist.github.com/lavoiesl/5880516
 *
 * Don't forget to use /*! to avoid the comment being removed in minification 
 */

function extractFuncCommentString(func) {
  var matches = func.toString().match(/function\s*\(\)\s*\{\s*\/\*\!?\s*([\s\S]+?)\s*\*\/\s*\}/);
  if (!matches) return false;

  return matches[1];
}

var myString = extractFuncCommentString(function(){/*!
  <p>
    foo bar
  </p>
*/});
person sebastien    schedule 27.06.2013
comment
Это просто делает предположение, что функция func.toString(); возвращает исходный код. Это было определено как небезопасное ниже - person Evan Carroll; 28.06.2013
comment
В нем говорится, что он возвращает зависящее от реализации представление функции, FunctionDefinition, но где пробел не уверен. Моя обертка, кажется, заботится о любых проблемах с пробелами, даже если они сведены к минимуму. - person sebastien; 03.07.2013

Меня заинтересовал этот вопрос, потому что я хочу использовать javascript для добавления новой строки на экран редактирования (например, для нескольких телефонных номеров). (я мог бы использовать для этого ajax, но хотел избежать дополнительного запроса к серверу.)

Мне нравится ответ Pointy об использовании тега для включения блоков html, которые вы хотите использовать:

<script id='blockOfStuff'>
  Hi this is random stuff
  <h1>Including HTML markup</h1>
</script>

Но Firefox и Chrome жаловались на синтаксические ошибки, когда я пробовал это. Мое решение состояло в том, чтобы изменить этот тег «скрипт» на «div», скрыть его отображение от пользователей через css и переместить его в тело. например.:

<div style="display: none;" id="new_row_innerhtml">
  <td><a href="#" onclick="removeCurrentRow(this); return false;">Remove</a></td>
  <input type="hidden" name="id[]" value="new" />
  <td><input name="name[]" type="text" /></td>
</div>

That removed the syntax errors.

Here's how I used that block:

I had an "Add" link that called the appendRow function:
<a href="#" onclick="appendRow(this); return false;">Add</a>

here's the appendRow function:

function appendRow() {
  var tbl = document.getElementById('my_table');
  var row = tbl.insertRow(-1); // add to end of table
}
person durian    schedule 21.08.2014
comment
Я использовал это решение как хороший обходной путь. Это позволило мне без проблем поместить в мое приложение много текста, который вызвал бы все виды сердечной боли JS. - person yougotiger; 24.09.2015

// js heredoc - http://stackoverflow.com/a/32915549/466363
// a function with comment with eval-able string, use it just like regular string

function extractFuncCommentString(func,comments) {
  var matches = func.toString().match(/function\s*\(\)\s*\{\s*\/\*\!?\s*([\s\S]+?)\s*\*\/\s*\}/);
  if (!matches) return undefined;
  var str=matches[1];

   // i have made few flavors of comment removal add yours if you need something special, copy replacement lines from examples below, mix them
  if(comments===1 )
  {
   // keep comments, in order to keep comments  you need to convert /**/ to / * * / to be able to put them inside /**/ like /*    / * * /    */
   return (
    str
   .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */ 
   )
  }
  else if(comments===2)
  {
   // keep comments and replace singleline comment to multiline comment
   return (
    str
   .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */ 
   .replace(/\/\/(.*)/g,"/*$1*/")          //           change   //abc to  /*abc*/
   )
  }
  else if(comments===3)
  {
   // remove comments
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .replace(/\/\/(.*)/g,"")             // match //abc
     )
  }
  else if(comments===4)
  {
   // remove comments and trim and replace new lines with escape codes
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .replace(/\/\/(.*)/g,"")             // match //abc
      .trim() // after removing comments trim and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else if(comments===5)
  {
   // keep comments comments and replace strings, might not suit when there are spaces or comments before and after quotes 
   // no comments allowed before quotes of the string
   // url html links
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */
      .replace(/\/\/(.*)/g,"/*$1*/")          //           change   //abc to  /*abc*/
      .trim() // trim space around quotes to not escape it and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else if(comments===6)
  { // good for html with links
   // remove comments and trim and replace new lines with escape codes
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .trim() // after removing comments trim and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else 
  return str
}

пример

var week=true,b=123;
var q = eval(extractFuncCommentString(function(){/*!

// this is a comment     


'select 

/ * this
is a multiline 
comment * /

 a
,b  // this is a comment  
,c
from `table`
where b='+b+' and monthweek="'+(week?'w':'m')+'" 
//+' where  a=124
order by a asc
'
*/},4));

с кешем: - создайте простую шаблонную функцию и сохраните функцию:

var cache={};
function myfunction(week,a){


    if(!cache.myfunction_sql1) eval('cache.myfunction_sql1=function(week,a){return ('+extractFuncCommentString(function(){/*!
'select 

/ * this
is a multiline 
comment * /

 a
,b  // this is a comment  
,c
from `table`
where b='+b+' and monthweek="'+(week?'w':'m')+'" 
//+' where  a=124
order by a asc

'*/},4)+')}');
    q=cache.myfunction_sql1(week,a);
    console.log(q)
}
myfunction(true,1234)

простой текст (не eval'd):

//var cache={};
function myfunction2(week,a){


    if(!cahce.myfunction_sql2) cahce.myfunction_sql2=extractFuncCommentString(function(){/*!

some multiline text
with <html>
and a link://to.url
and a / * comment * / 
*/},6);
    q=cahce.myfunction_sql2;
    console.log(q)
}
person Shimon Doodkin    schedule 02.10.2015

Вот ваш ответ. В теле вашей страницы сделайте span или div, неважно какой, с уникальным идентификатором и поместите в него весь текст, который вы хотите, со всеми кавычками, которые вы хотите. Сделайте стиль диапазона или div «отображение: нет; видимость: скрытый;». Затем, когда вы захотите, получите объект DOM из идентификатора и извлеките innerHTML, чтобы делать то, что вы хотите.

person John Vonachen    schedule 20.09.2011
comment
Оп попросил решение JS, а не решение DOM. Какой смысл устанавливать visibility:hidden; после того, как вы уже установили display:none;? - person Madbreaks; 04.02.2014