2

Going through the Vue online guide, I ran into something that looks like a quote escaping problem. More specifically, I am toying around with the example provided in chapter components->events.

The template in my component looks like

    "<div class=\"blog-post\">\
        <h3>{{ post.title }}</h3>\
        <button  @click=\"$emit(\\\"enlarge-text\\\")\"  >Enlarge text</button>\
        <div v-text=\"post.content\"></div>\
    </div>"

And instead of the expected button, I get the string ")" >Enlarge text

I managed to circumvent my issue by replacing the two occurrences of the double escape \\\" by single quotes, but I have the feeling there is something I am missing here. Can you help me to understand what is happening here or provide me pointers towards the relevant doc? Any explanation is welcome.

tony19
  • 125,647
  • 18
  • 229
  • 307
  • Why don't you save yourself some pain, and use backticks (template literal: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Multi-line_strings) – Stuart Oct 03 '19 at 12:40

3 Answers3

2

As I'm sure you're aware, escaping is used to include characters literally within text that would otherwise be interpreted as having a special meaning. Establishing which characters have special meaning requires us to look at the 'channels' that will be interpreting that text and then select a suitable escaping mechanism for those channels.

In this case the text will be interpreted by 3 channels...

  1. As a JavaScript string literal.
  2. By the Vue template compiler, which has a format very similar to HTML.
  3. Expressions within the template, such as binding expressions, will be treated as JavaScript, potentially including yet more JavaScript string literals.

JavaScript string literals use the \ character to introduce escape sequences. However, the HTML-like syntax used for Vue templates do not. As for HTML they use entities prefixed with &.

So, working backwards, we first need to consider how we escape the expressions within the template. In this case that is $emit("enlarge-text"). As the string "enlarge-text" doesn't contain any special characters we don't need to apply any escaping. Easy so far.

Then we need to escape the template 'HTML'. Now we do run into problems because the @click attribute is delimited with double-quotes and its value contains double-quotes. Obviously we could dodge the issue by using different types of quotes but if we instead hit the problem head-on we'd need to use & entities to escape those quotes. i.e. &quot; for ". That gives us:

<button @click="$emit(&quot;enlarge-text&quot;)">Enlarge text</button>

I believe this is where the escaping in the question goes wrong as it attempts to use \ escaping to escape the attribute value.

If we were using SFCs then that would be sufficient. But for a template written as a string literal we've still got one more level of escaping to apply, using \. The original quotes around enlarge-text are no longer present so they don't require any further escaping but we still have the quotes around the attribute. That gives us:

"<button @click=\"$emit(&quot;enlarge-text&quot;)\">Enlarge text</button>"

However, all that said, the usual conventions when specifying string templates are:

  1. Use backticks for the template string itself, giving better multi-line support.
  2. Use double-quotes around attributes.
  3. Use single-quotes for strings within expressions.

Obviously there are cases where that isn't possible, such as if you want to use backticks within an expression, but if you stick to those conventions as much as possible you usually won't need to escape anything. When you do it'll also be a lot simpler to perform the escaping as you aren't using the same delimiters at all three levels.

skirtle
  • 27,868
  • 4
  • 42
  • 57
  • Thanks a lot for your very detailed and enlightening answer.I am very new to web development. I wasn't even aware of the necessity for escaping quotes in HTML (found something on the subject [here](https://stackoverflow.com/questions/25916943/uses-for-the-quot-entity-in-html)). Thanks also for the conventions. On the same Vue page, in the comments of the [previous example](https://vuejs.org/v2/guide/components.html#A-Single-Root-Element) there is a warning about using backticks. It seems I took it too seriously, I guess everybody uses transpilers nowadays and this is not that important. – Benjamin schwarz Oct 03 '19 at 14:41
1

You could use template literal / template string for this:

let tpl = `<div class="blog-post">
    <h3>{{ post.title }}</h3>
    <button  @click="$emit('enlarge-text')">Enlarge text</button>
    <div v-text="post.content"></div>
</div>`;

Not only does it read better, it is way more maintanable than multiple escaped quotes.

Stuart
  • 6,630
  • 2
  • 24
  • 40
0

You can wrap enlarge-text with single quotes. Like this:

<button @click=\"$emit('enlarge-text')\">Enlarge text</button>
protestator
  • 311
  • 1
  • 15