-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
Description
Note: This post may contain outdated content. Latest reference is now maintained at #1325
Here's yet another long post on the new binding syntax. I know we have gone through a lot of changes during the alpha phase, but please, bear with me - I want to make sure we land on something that is good enough to be called a 1.0 - something that is consistent, explicit, and most importantly, stable. We are going to strictly follow semver post 1.0 - I don't want to have to release 2.0 in a few months ;)
I've been thinking about all the discussion on consistent v-
, and I feel that the new syntax may indeed be a bit too different from what we have in 0.12. Some of the justifications about the additional prefixes was based on the fact that Angular 2 and Aurelia are both introducing custom syntax for bindings; but then I realize Vue is not Angular or Aurelia, because these two are full-stack frameworks, where Vue aims to be flexible in as many use cases as possible.
So, let's take a step back and think about the original problems that we set out to solve with the new syntax, and evaluate what we have so far:
-
Confusion about expressions vs. literals for directives
Example:
<div v-text="msg"></div> <div v-link="/a/b/c"></div>
Here
msg
is an expression buta/b/c
is a literal string. There's no way to tell which should be literal except looking at the directive's documentation.Current solution in alpha.4:
Explicit syntax for literal directives:
v-link#="123"
. This also simplifies implementation of custom directives. I think this is a good change. -
Confusion about where mustaches are allowed.
Example:
<!-- these works... --> <a v-link="/a/b/{{abc}}"></a> <a href="/a/b/{{abc}}"></a> <!-- these don't --> <a v-model="{{abc}}"> <a v-attr="href: 'a/b/{{abc}}'">
The general rule is that mustaches are only allowed in literal strings but not in expressions. But mustaches just make people think in the string template mindset and assume it should work everywhere.
In addition, mustaches inside attributes have some subtle gotchas, for example when used in
src
it causes a 404 error; when used instyle
it causes IE to ignore it.Current solution in alpha.4:
No more mustaches inside attribute values. Attribute bindings use the
bind-
special prefix.As someone pointed out, this introduces an additional prefix and isn't as distinctive and consistent as
v-
. Butv-attr
also has its own warts, mostly related to the "arguments + multiple clauses" micro-syntax. We will discuss this in more details below. -
Directive micro-syntax
Example:
<div v-on="click: doThis, keyup: doThat"></div> <div v-attr="href: address, src: imgSrc"></div>
The problem here is that it looks like an object, but it is not; it also becomes awkward to format (different indentation, no syntax highlight) when you have a lot of handlers/attributes:
<div other-attribute-a other-attribute-b v-on=" click: doThis, keyup: doThat | key 'esc', keyup: doSomethingElse | key 'enter'">
Current Solution in alpha.4:
<div bind-href="address" bind-src="imgSrc" on-click="doThis" on-keyup-esc="doThat" on-keyup-enter="doSomethingElse"> </div>
I think breaking each binding into a single attribute is definitely the right move. But we also introduced yet another prefix:
on-
. -
Not-so-good prop syntax.
Example:
<component literal="string" dynamic="{{something}}" two-way="{{@something}}" one-time="{{*something}}"> </component>
First, this looks like normal attribute bindings. Second, as we noted above, mustache bindings indicates that it evaluates into a literal string. However, the 0.12 prop syntax is ambiguous in this aspect:
<component prop="{{ anObject }}">
^ This passes down the actual object.
<component prop="abc-{{ anObject }}">
^ This will try to concatenate "abc-" and the object, resulting in "abc-[object Object]".
The binding indicator can also be confusing:
<!-- what does this do? --> <component prop="abc-{{@something}}">
Current Solution in alpha.4:
<component literal="string" bind-dynamic="something" bind-two-way@="something" bind-one-time*="something">
By getting rid of mustaches and move the binding type indicator into the attribute name, I think we've solved most of the issues above, but it relies on the extra
bind-
prefix.
Recap
I think with the current 1.0.0-alpha.4 syntax we've addressed most of the original issues, but also introduced some new ones. Most of the negative feedback is concerned with the fact that we now have three prefixes instead of one: v-
, on-
and bind-
. Do event handlers and attribute bindings really deserive their own special prefix?
My original intention was that on-
and bind-
would allow us to get rid of the "micro-syntax" issue mentioned above. But I also agree that more top-level prefixes also introduce additional cognitive overhead. So here's an update that attempts to address this issue:
<!-- 0.12 directive syntax -->
<div v-dirname="arg1: expression1, arg2: expression2"></div>
<!-- 1.0 directive syntax -->
<div
v-dirname:arg1="expression1"
v-dirname:arg2="expression2">
<div>
So, instead of what we currently have in 1.0.0-alpha.4:
<div
bind-href="address"
bind-src="imgSrc"
on-click="doThis"
on-keyup-esc="doThat">
</div>
We would write:
<div
v-bind:href="address"
v-bind:src="imgSrc"
v-on:click="doThis"
v-on:keyup:esc="doThat">
</div>
A little more verbose, but more consistent, more Vue-specific, and maps to 0.12 concepts better.
When we are using Vue alone to build an SPA, the v-
prefix may not be that important anymore. So it is still possible to provide optional, more concise sugar on top of v-bind
and v-on
:
<!-- : for bind -->
<div
:href="address"
:src="imgSrc">
</div>
<!-- @ for on -->
<input
@click="doThis"
@keyup:esc="doThat">
You probably would prefer the shorthand for component props as well (changing two-way indicator to &
instead of @
):
<component
:prop="something"
:two-way&="something"
:one-time*="something">
</component>