Closed yyx990803 closed 8 years ago
and probably data-
will become synonym to prop-
?
@azamat-sharapov probably not, because some libs rely on data-
attributes, we don't know if the user really wants a data attribute or a prop.
I really like this proposal, and, to me, in that way the code speaks for itself and looks even cleaner. :+1:
Whilst I agree, I like the fact that it is v- becasue then it's easy to understand it's a VUE based attribute rather than third party or anything else. Could this be a config value, becasue I would quite like to use u- (still leaves e- !) so that when looking at the thml you know it's part of the vue system?
@Mat-Moo most of the literal directives need to be used together with other reactive directives. e.g. v-transition
only makes sense when there's also v-if
, v-repeat
or when it is a component; v-ref
can also only be used on v-repeat
and components. They should've been treated more like directive params in the beginning (which are non-prefixed). v-el
is an exception, and I actually never liked it since you can always just do a querySelector
(considering deprecating it in 1.0).
@yyx990803 Actually I suppose that makes it consistent with props for a component
@yyx990803 hello,how can I use 'v-on' directive on one tag and bind more than one event, like the question 4 above,please give me some suggests.forgive my poor english.
@azamat-sharapov thx!!
I like this proposal – especially if we can get to it in a non-breaking way with deprecation warnings.
It is indeed confusing keeping track of where and when literals, dynamic literals and expressions all apply.
Overall this simplifies understanding of code.
Only thing I personally don't like is bullet 5. {{ something }}
syntax is sometimes very clean and easy to understand.
Example:
<div class="ui button {{color}}">Sample Button</div>
How do you achieve same result with new syntax?
@gapipro I agree - string concatenation can be a bit ugly with only bind-
syntax:
<div bind-class="'ui button ' + color">Sample Button</div>
But wouldn't v-class
be the more appropriate way to handle this particular case? How many other attributes behave like class
?
@davidkhess Yeah, it could be something like this:
<div class="ui button" v-class="color">Sample Button</div>
But still not as clear as the interpolation syntax :/
I don't know - I personally prefer v-class
since it is more explicit about what is going on.
I think we can go a step further to just support object syntax in bind-class
and bind-style
, so we can remove v-class
and v-style
. In addition, bind-class
can accept an array:
<!-- object for toggling -->
<div bind-class="{ color: true, active: false }"></div>
<!-- array for class list -->
<div bind-class="['ui', 'button', color]"></div>
<!-- plain string bind -->
<div bind-class="classString"></div>
Wouldn't be nicer to have v-class
instead of bind-class
with this kind of object syntax support?
<!-- plain string bind -->
<div bind-class="classString"></div>
classString
as expression or string?
@gapipro I just find it unnecessary to have v-class
and bind-class
when the only difference is the format of data they can handle.
classString
is an expression. For example vm.classString = 'ui button'
.
Yes having both is unnecessary. I just like having v-class
more then bind-class
because it is easier to notice when coding html.
@gapipro the idea is you can make any attribute data-bindable just by adding bind-
before it. It's similar to v-attr="class: ..."
but with better syntax.
Oh ok. Got it.
i like it :+1:
Two thumbs up!
I like it!
Somewhat related: I find myself always using v-if
and never v-show
. What is the advantage of v-show
over v-if
and when are you likely to use one over the other?
(Ultimately wondering if there is no good case for v-show
, if it can be deprecated in favor of v-if
?)
V-show shows/hides the element with CSS v-if adds and removes it from the DOM, where possible you should use v-show as it will be faster (think I've got that right)
where possible you should use v-show as it will be faster
@Mat-Moo Do you have a source for this fact?
@holic v-show is simple CSS toggling, v-if is true conditional compilation. For example if a component is inside v-if, it will be destroyed/compiled when the v-if is toggled. v-if is also lazy, i.e. If the condition is false on load, it won't do anything. So, when to use which really depends on the use case.
I've had a number of case where v-if didn't work for me and v-show did. I never took the trouble to find out what was going on because I think v-show is cleaner anyway. It doesn't change the dom structure.
On Mon, Aug 31, 2015 at 5:23 PM, Evan You notifications@github.com wrote:
@holic https://github.com/holic v-show is simple CSS toggling, v-if is true conditional compilation. For example if a component is inside v-if, it will be destroyed/compiled when the v-if is toggled. v-if is also lazy, i.e. If the condition is false on load, it won't do anything. So, when to use which really depends on the use case.
— Reply to this email directly or view it on GitHub https://github.com/yyx990803/vue/issues/1173#issuecomment-136534869.
v-if
by itself is never faster then v-show
, but can improve overall performance of the application by removing dom elements you don't need right now. Things like modals and drop-down menus.
Can I call a method in binding expression?
e.g. <div bind-class="{ active: isActive('cat') }"></div>
@holic toggling a CSS element between display none/block vs compiling and inserting new dom nodes, think it's pretty obvious :)
@mark-hahn ive got an edge case for v-if at the moment that I need to look at once I complete the upgrade to 1alpha. Something along the lines of <my-component v-if="selected!==false" prop-widget="@widgets[selected]">
@simplesmiler for drop down menus? You sure, that to me would be a v-show case, unless it's dynamically generated.
Why the separate prop-
prefix? Why not just use bind-
for properties too? And if there's no bind-
prefix, it becomes a literal string.
I'm also torn about losing mustaches. This makes sense, and it would be nice to still be able to do it:
<p class="a b {{c}}" title="More info: {{foo}}">{{bar}}</p>
<my-component foo="foo-{{bar}}">{{baz}}</my-component>
(if bar === 123
, the value of foo in my-component here should be the string "foo-123").
But then you have this:
<my-component foo="{{bar}}">{{baz}}</my-component>
This should mean that the value of foo is always a string, and it's always a one-way binding, the same way <input value="{{foo}}" />
works. It actually means bind-foo="bar"
(so you can do foo="{{'123'}}"
to pass a string and foo="{{123}}"
to pass a number), and it would break BC to change that.
If it were changed to just string templating, which would be consistent, the difference between this and bind-
would be subtle and confusing. It would make sense, but only if you think about it.
Also, taking this to its logical extreme:
<my-component bind-foo="prop{{bar}}">{{baz}}</my-component>
which would mean bind foo
to the variable whose name starts with "prop"
and ends with the value in bar
.
@nkovacs Because attributes and props are different things. bind-
means dynamically binding a plain HTML attribute. prop-
is specifically for data passing between components. In the original syntax you basically have to "guess" if something is a prop or just a normal attribute.
I'm also considering preserving mustaches for normal attribute bindings, but mustaches inside bind-
or prop-
will never happen.
Well, components are basically custom elements, so I don't really see much of a difference between attributes and properties.
And it would be nice to be able to be able to use mustaches and literal strings in properties too:
<my-component color="green" tooltip="More info: {{foo}}">{{bar}}</my-component >
instead of
<my-component prop-color="'green'" prop-tooltip="'More info: ' + foo">{{bar}}</my-component >
On a side note, wouldn't this also make sense?
<input bind-value="@foo" />
It already works one way. Yes, you need special code to handle the two-way binding, but it looks logical in the template, and it reinforces that properties and attributes are not that different.
@nkovacs that's an idealistic view which makes sense in Polymer, but not in Vue, because Vue components are not custom elements. And even for real elements, attributes and properties are different. It's a bad idea to pretend they are the same.
I've explained in the proposal: the purpose of thebind-
and prop-
prefix is so that you know what follows is always an expression. It doesn't make sense to have mustaches inside expressions. Mustaches are for string interpolations and should only appear inside plain strings.
Vue templates are not string templates, but real HTML plus binding syntax. And I want to make it explicit.
Sorry, I made a mistake in my example. The tooltip property should not have had the prefix.
Considering new binding syntax, is there any way to bind 2 clicks at once?
Right now we sometimes use constructions like v-on="click: methodOne, click: methodTwo"
. Its useful while extending components.
I'd like to get feedback on one remaining problem of the new syntax: literal directives.
Previously, both reactive and literal directives share the same v-
prefix. This is not ideal because when you see v-
prefixed directive in the template, you have to remember whether it is literal or not in order to read and understand its value.
Now, with the new syntax, all v-
prefixed directives are supposed to be reactive. But we lose the ability to create custom literal directives, which is sometimes actually useful. For example, the v-link
directive used by vue-router. Most of the time we want just a literal string for its value, but following the v-
= reactivity rule, we'd need to wrap it inside quotes, which is a bit awkward:
<a v-link="'/abc'"></a>
After thinking about it for a while, I start to ask myself: is it really necessary to keep the v-
prefix? What if all directives are simply custom attributes? For example, if we register a directive named show
, it no longer appears as v-show
. Instead, similar to normal attributes, we also use the bind-
prefix to indicate reactivity. So the core directives would become:
<!-- view logic -->
<p bind-show="ok"></p>
<p bind-if="!ok"></p>
<p bind-for="item in items"></p>
<!-- two-way binding -->
<input bind-model="val">
Here the bind-
indicates the attribute values are expressions. And to simulate a 0.12 literal directive, we simply omit the bind-
prefix. Suppose we rename v-link
to router-link
, we'd use it as follows:
<!-- bound to literal value "/abc" -->
<a router-link="/abc"></a>
<!-- bound to expression -->
<a bind-router-link="'/abc/' + segment"></a>
The downside of this is that we lose the familiar v-
prefix, which very explicitly tells us something is a directive. This may also be too much of a conceptual shift from the current API. So if we can find a less disruptive way to solve the literal directive problem, that would be great too.
@fullfs maybe something like on-click="[method1, method2]"
? Currently you can do on-click="method1($event), method2($event)"
but not very clean
@yyx990803 on-click="method1($event), method2($event)"
is ok. I'd like to have the ability to pass arguments into functions. Can't imagine something likeon-click="[method1($event), method2($event)]"
About Sep 2. Thoughts
. Is it just me, or rejecting -v
prefix at all is actually the same thing as having it for all Vue-related attributes?
The current "v-" syntax is very readable. Mixing it up with all the "bind-" stuff would throw away useful visual information and make it less readable.
On Wed, Sep 2, 2015 at 9:20 PM, Andrey notifications@github.com wrote:
@yyx990803 https://github.com/yyx990803 on-click="method1($event), method2($event)" is ok. I'd like to have the ability to pass arguments into functions. Can't imagine something likeon-click="[method1($event), method2($event)]"
About Sep 2. Thoughts. Is it just me, or rejecting -v prefix at all is actually the same thing as having it for all Vue-related attributes?
— Reply to this email directly or view it on GitHub https://github.com/yyx990803/vue/issues/1173#issuecomment-137326649.
I also like the v-
prefix to immediately recognize that these properties have something to do with Vue.
@yyx990803 I'm in the process of "fixing" my app to work with 1.0.0 and I see now there's a warning for props not declared on the child component. One use case I have will always trigger this warning (if I understood the warning correctly):
I end up with a component looking like this:
<component
bind-is="currentFrame"
prop-one="one" // used by tab 1
prop-two="two" // tab 2
prop-three="three" // tab 3
></component>
What would you advice in this case?
Also, How does transitions work now? I have a plain element with v-if
and v-transition
with CSS transitions that now fails with: Cannot read property '$options' of undefined
. I suspect this may be because the transition is applied to a non-component but I haven't had time to verify.
And, somewhat off-topic, unobservable objects are also giving me headaches. I used to be able to store a moment()
variable to display the current time (which I update with a timer every x seconds), but that now throws a warning; the walker goes into the object and stumbles on the Date object inside and complains.
bind-is
seem to fail in nested component, but works fine at the top level; simply switching back to is
solves the problem and no deprecation warning is displayed.
We have a lot of things (normal html attributes, component props, directives) expressed in the same way (html attributes).
One way to make everything consistent would be:
prop-
(or p-
?)v-
bind-
to achieve reactivityThe downside is that this will be very verbose:
<my-input
prop-label="Name"
bind-prop-value="@name"
bind-v-if="show"
>
</my-input>
This was almost the case in 0.12.12, except for:
bind-
prefix we used mustachesAnother thing we can go for is using special symbols in attribute names:
#
prefix it's one-way reactive@
prefix it's two-way reactive*
prefix it's one-time computed<my-input
prop-label="Name"
@prop-value="name"
#v-if="show"
>
</my-input>
@alchen components that you can stick into a certain <component is="..."></component>
should probably implement a single interface (read: have the same set of props).
In this new approach I like bind-
approach - to remove special cases v-attr
and v-class
that were a little confusing. It makes more consistent dynamic binding to tag attributes.
For a special Vue related directives I would definitely like to see v-
prefix - it allows to see "that it is related to Vue for sure!"
Event syntax seems fine for me. Almost equal as for readability.
As for prop-
I am not sure. I haven't use them much, but it was looking more familiar without prop-
prefix. But I agree that it should accept an expression by default and therefor can't be without any prefix. Maybe to have bind-
also ? (To reduce amount of different variations)
But I still have doubts what was looking more clean/clear
<a bind-href="'/abc/' + someId"></a>
or <a href="/abc/{{someId}}"></a>
Mustache way looks nicer, but what about performance? Without Mustache it is better ?
@simplesmiler making everything a literal by default doesn't seems for me a good way - as mostly we use dynamic reactive binding to some VM properties, instead of passing in a plain String values. I think that code will became much more bloated with bind-
and bind-v
.
Special symbols - either not the best way. It makes code a "so alien stuff" from the first look (of a person not familiar enough with Vue)
I agree with @fullfs. How about:
• v-on-* – expression based event handlers • v-prop-* – prop expressions • v-bind-* – expression based directives and attributes • v-* – literal directives • * – plain literal attributes having nothing to do with Vue
It's not as clean as it would be nice to have it — but that's likely impossible when trying to cram multiple namespaces into the single existing one of element attributes.
@davidkhess your suggestion looks quite nice.
Really appreciate the feedback from everyone. Here's an updated proposal:
v-
directives (flow control & form handling, same as alpha.2)
<!-- flow control -->
<div v-if="ok">
<div v-for="item in items">
<div v-show="hi">
<!-- two-way form binding -->
<input v-model="abc">
on-
handlers (same as alpha.2):
<input on-keyup:enter="abc">
<form on-submit="handleSubmit">
bind-
can also be used for component props. So it can be used like this:
<!-- component props -->
<component
literal="hello"
bind-dynamic="parentMsg"
bind-two-way="@something"
bind-one-time="*something">
</component>
<!-- normal attributes -->
<img bind-src="...">
<a bind-href="...">
<!-- class & style are enhanced to accept objects and arrays -->
<div bind-class="{ ... }"></div>
<div bind-class="[ ... ]"></div>
<div bind-style="{ ... }"></div>
literal directives (add a colon at the end of the directive name to indicate literal):
<!-- literal (with colon) -->
<a v-link:="/abc/123">
<!-- dynamic (without colon) -->
<a v-link="'/abc/' + id">
This also eliminates the need for a custom directive to declare itself as literal or not - it can simply provide an update
function. If it is used as a literal directive, the plain string will be passed into the update
function; if it is used dynamically, then the value of the expression will be passed in instead (and call update
again when it changes).
Note: The reason for choosing colon here is because in practice, the only non-alphabetic and easily-typable chars allowed in attributes names are _
, -
, .
and :
, and colon looks the most natural here because :=
is used as assignment operator in many languages.
@yyx990803 Perfect
:+1: Looks pretty good !
Quick Reference of Latest Syntax
Context
Currently we have several types of bindings in the template:
v-style
,v-on
&v-repeat
. Their attribute values are directly evaluated as expressions in the current component scope, and cannot contain mustache tags.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.v-attr
internally.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.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}}"
orprop="{{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.{{ }}
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.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: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.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:In addition, the
bind-
prefix can be shortened as a colon, which is totally optional: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.
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).v-ref
andv-el
) are no longer directives. They now have their own dedicated syntaxes. (see #1292)The benefits:
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!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.