-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
Description
Quick Reference of Latest Syntax
Last updated: Sep. 11th - 1.0.0-alpha.4
<!-- flow control -->
<div v-if="ok">
<div v-for="item in items">
<div v-show="hi">
<!-- two-way form binding -->
<input v-model="abc">
<!-- literal directive: add hash before equal -->
<a v-link#="/abc/123"></a>
<!-- event handlers -->
<input
on-change="handleChange"
on-focus="handleFocus"
on-blur="handleBlur">
<!-- key filter for keypress events -->
<input on-keyup-esc="handleEsc">
<!-- normal attribute bindings, make it reactive by adding "bind-" -->
<img bind-src="baseURL + '/avatar/' + username + '.png'">
<a bind-href="'/profile/' + username"></a>
<!-- class & style are enhanced to accept objects and arrays -->
<!-- toggle classes -->
<div bind-class="{ 'class-a': true, 'class-b': false }"></div>
<!-- apply a list of classes -->
<div bind-class="[ dynamicClass, 'literal-class' ]"></div>
<!-- apply style object (camelCase accepted) -->
<div bind-style="{ fontSize: '14px', color: 'red' }"></div>
<!-- apply multiple style objects -->
<div bind-style="[ styleObjectA, styleObjectB ]"></div>
<!-- shorthand for "bind-", just add colon -->
<img :src="...">
<a :href="..."></a>
<!-- component props, also use "bind-" or colon shorthand -->
<!-- without "bind-" or colon it's passed as a literal string -->
<component
literal="hello"
bind-dynamic="parentMsg"
:dynamic="something"
:two-way@="something"
:one-time*="something">
</component>
<!-- v-el and v-ref now use dedicated syntax -->
<!-- registers vm.$.child -->
<comp $.child></comp>
<!-- registers vm.$$.node -->
<div $$.node></div>
<!-- caveat: must use dash-case instead of camelCase, similar to props -->
<!-- registers vm.$.someComp -->
<comp $.some-comp></comp>
Context
Currently we have several types of bindings in the template:
- Reactive directives, e.g.
v-style
,v-on
&v-repeat
. Their attribute values are directly evaluated as expressions in the current component scope, and cannot contain mustache tags. - (Dynamic) Literal directives, e.g.
v-transition
,v-ref
&v-el
. Their attribute values are treated as plain strings and can contain mustache tags - but it's not always reactive: onlyv-transition
is reactive when containing mustache tags; the other two evaluate them only once. - Normal HTML attributes with mustache tags. These are converted into
v-attr
internally. - Prop bindings, e.g.
my-prop="{{abc}}"
. Props' attribute values are treated as plain strings and can contain mustache tags; the prop binding is only dynamic if it contains mustache tags. - Directive param attributes, e.g.
transition-mode
,track-by
,number
&debounce
. These are treated almost as normal attributes, but evaluated only once.
Problem
Well, as you probably have noticed, it's confusing! There are many types of attributes and there's no clear rule on where expressions are expected and where mustache interpolations are allowed.
Specifically, the prop syntax could use some improvement. The original intention of making props require mustaches tags to be reactive is so that a dynamic prop can look different from normal HTML attributes. But given that normal attributes can contain mustache tags as well, it's still not explicit enough. It's also much more common to use dynamic props than literal strings, and using mustache tags to indicate reactivity is simply not intuitive.
Another problem is it becomes awkward when you want to pass a literal number/boolean prop, because without mustache tags, the attribute value is just a string. You'd have to write prop="{{123}}"
or prop="{{true}}"
to pass a real number or boolean. Currently, Vue auto-casts literal props into numbers/booleans if possible, which this may not always be what we want - what if we want to pass in a string of numbers?
Proposal
Last Updated: Sep.11th (1.0.0-alpha.4)
Here's some pretty radical changes (or maybe not), but imo conceptually much cleaner. The goal here is to 1) eliminate {{ }}
inside attribute values; and 2) categorize the syntax by their purpose.
-
Text and HTML interpolations. Handled with
{{ }}
and{{{ }}}
. And this will also be the only places where mustaches are used. -
Vue directives. These preserve the
v-
prefix because they do something special. Binding values are always parsed as expressions. No more arguments or multiple clauses, just one expression followed by one or more filters. Onlyv-for
(previouslyv-repeat
) preserves theitem in items
special syntax.<!-- view logic --> <p v-show="ok"></p> <p v-if="!ok"></p> <p v-for="item in items"></p> <!-- two-way binding --> <input v-model="val"> <!-- empty directives --> <div v-cloak></div> <div v-pre></div>
And that's it. Only 6 core directives. (
v-text
andv-html
are also preserved, but they are replaceable by interpolations)Literal Syntax
In 1.0, all core directives are either reactive or empty. But sometimes we may want to pass in a literal string to a custom directive instead of a dynamic expression, similar to 0.12 literal directives. But in 1.0 we want to make this explicit, so we can clearly know whether the attribute value is actually a string or an expression. So, in 1.0 there will no longer be the concept of "literal directives", we use the dot-equal syntax to indicate we are passing a literal value to the directive. The directive's
update
function will be called once, with the literal string as the argument:<a v-link#="/a/b/c">
-
Event handlers. Prefixed with
on-
. Value always parsed as expressions, can either be the method name or a statement (e.g.a = !a
). I've raised this once before, but people seemed to really like the fact thatv-on
starts withv-
. IMO event handlers deserve something different and more succinct.<!-- easier to type, and reads better --> <form on-submit="handleSubmit"></form> <!-- multiple listeners also much cleaner --> <input on-change="handleChange" on-focus="handleFocus" on-blur="handleBlur"> <!-- in addition: key filter can be replaced with: --> <input on-keyup-enter="doThis" on-keyup-esc="doThat">
-
Normal attribute bindings. Currently these are done via putting
{{ }}
inside attribute values. This often leads to people thinking in a string-template fashion and get confused about where{{ }}
are allowed and where not. The proposal is to prefix dynamic attribute bindings with thebind-
prefix:<!-- plain string --> <img src="/avatars/123.png"> <!-- bind to expression --> <img bind-src="'/avatars/' + userId + '.png'"> <!-- style/class are enhanced to accept object/array values --> <div bind-class="classes"></div> <div bind-class="[classA, classB]"></div> <div bind-class="{ classA: true, classB: false }"></div> <div bind-style="cssString"></div> <div bind-style="{ fontSize: fontSize, color: currentColor }"></div> <div bind-style="[styleObjectA, styleObjectB]"></div>
In addition, the
bind-
prefix can be shortened as a colon, which is totally optional:<img :src="'/avatars/' + userId + '.png'">
-
Props. Similar to normal attribute bindings, non-prefixed props are always passed down as literal strings; To pass a dynamic prop, add
bind-
or colon prefix.Also, binding type indicators are now moved from the attribute value into the attribute name, right before the equal sign.
<example literal="Mike" bind-dynamic="someThing" bind-onetime*="onlyOnce" bind-twoway@="syncsBackUp" :shorthand="sameAsBind"> </example>
-
Special attributes (including both directive params & literal directives). These will only appear together with either a directive or a component. You can also use
bind-
or colon prefixes for these, but onlyis
,ref
,el
andtransition
will have reactive behavior, other directive params are evaluated only once (Vue will tell you in dev mode).<component :is="view" transition="slide" transition-mode="out-in"> </component>
-
Child component and element refs (previously
v-ref
andv-el
) are no longer directives. They now have their own dedicated syntaxes. (seev-el
andv-ref
usage change after binding syntax update #1292)
The benefits:
- Explicit. The code says what it does.
- Simpler. Smaller set of core directives. No more "args" for directives; no more multiple clauses; It's just expressions + filters.
- No more confusion about mustache inside attributes. If you see a
v-
,on-
orbind-
prefix, it always means the value is an expression. If there's no prefix, then it's a always a plain string! - Eliminates edge cases like
src="{{abc}}"
causing 404 requests andstyle="{{something}}"
gets thrown away in IE. Also eliminates the need forv-attr
.
Note
Please don't dislike this proposal just for the sake of "why so many changes"; all the changes proposed here can be implemented in a backwards compatible way in 1.0.0-alpha (with deprecation warnings) and migration should not be unacceptably painful.