{"action":"created","issue":{"url":"https://api.github.com/repos/yyx990803/vue/issues/1173","labels_url":"https://api.github.com/repos/yyx990803/vue/issues/1173/labels{/name}","comments_url":"https://api.github.com/repos/yyx990803/vue/issues/1173/comments","events_url":"https://api.github.com/repos/yyx990803/vue/issues/1173/events","html_url":"https://github.com/yyx990803/vue/issues/1173","id":101348575,"number":1173,"title":"Make binding syntax more consistent","user":{"login":"yyx990803","id":499550,"avatar_url":"https://avatars.githubusercontent.com/u/499550?v=3","gravatar_id":"","url":"https://api.github.com/users/yyx990803","html_url":"https://github.com/yyx990803","followers_url":"https://api.github.com/users/yyx990803/followers","following_url":"https://api.github.com/users/yyx990803/following{/other_user}","gists_url":"https://api.github.com/users/yyx990803/gists{/gist_id}","starred_url":"https://api.github.com/users/yyx990803/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yyx990803/subscriptions","organizations_url":"https://api.github.com/users/yyx990803/orgs","repos_url":"https://api.github.com/users/yyx990803/repos","events_url":"https://api.github.com/users/yyx990803/events{/privacy}","received_events_url":"https://api.github.com/users/yyx990803/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/yyx990803/vue/labels/1.0%20proposal","name":"1.0 proposal","color":"5319e7"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/yyx990803/vue/milestones/13","html_url":"https://github.com/yyx990803/vue/milestones/1.0.0-alpha","labels_url":"https://api.github.com/repos/yyx990803/vue/milestones/13/labels","id":1257572,"number":13,"title":"1.0.0-alpha","description":"","creator":{"login":"yyx990803","id":499550,"avatar_url":"https://avatars.githubusercontent.com/u/499550?v=3","gravatar_id":"","url":"https://api.github.com/users/yyx990803","html_url":"https://github.com/yyx990803","followers_url":"https://api.github.com/users/yyx990803/followers","following_url":"https://api.github.com/users/yyx990803/following{/other_user}","gists_url":"https://api.github.com/users/yyx990803/gists{/gist_id}","starred_url":"https://api.github.com/users/yyx990803/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yyx990803/subscriptions","organizations_url":"https://api.github.com/users/yyx990803/orgs","repos_url":"https://api.github.com/users/yyx990803/repos","events_url":"https://api.github.com/users/yyx990803/events{/privacy}","received_events_url":"https://api.github.com/users/yyx990803/received_events","type":"User","site_admin":false},"open_issues":1,"closed_issues":12,"state":"open","created_at":"2015-08-17T06:29:02Z","updated_at":"2015-09-05T20:39:46Z","due_on":null,"closed_at":null},"comments":175,"created_at":"2015-08-17T06:26:23Z","updated_at":"2015-09-09T21:53:33Z","closed_at":null,"body":"### Context\r\n\r\nCurrently we have several types of bindings in the template:\r\n\r\n1. 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.\r\n\r\n2. (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: only `v-transition` is reactive when containing mustache tags; the other two evaluate them only once.\r\n\r\n3. Normal HTML attributes with mustache tags. These are converted into `v-attr` internally.\r\n\r\n4. 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.\r\n\r\n5. Directive param attributes, e.g. `transition-mode`, `track-by`, `number` & `debounce`. These are treated almost as normal attributes, but evaluated only once.\r\n\r\n### Problem\r\n\r\nWell, 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. \r\n\r\nSpecifically, 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.\r\n\r\nAnother 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?\r\n\r\n### Proposal\r\n\r\n> **Warning:** Big changes, just for discussion.\r\n\r\n**Last Updated: Sep.7th (1.0.0-alpha.3)**\r\n\r\nHere'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.\r\n\r\n1. Text and HTML interpolations. Handled with `{{ }}` and `{{{ }}}`. And this will also be the only places where mustaches are used.\r\n\r\n2. 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. Only `v-for` (previously `v-repeat`) preserves the `item in items` special syntax.\r\n\r\n  ``` html\r\n  <!-- view logic -->\r\n  <p v-show=\"ok\"></p>\r\n  <p v-if=\"!ok\"></p>\r\n  <p v-for=\"item in items\"></p>\r\n\r\n  <!-- two-way binding -->\r\n  <input v-model=\"val\">\r\n\r\n  <!-- empty directives -->\r\n  <div v-cloak></div>\r\n  <div v-pre></div>\r\n  ```\r\n\r\n  And that's it. Only 6 core directives.\r\n\r\n  **Literal Syntax**\r\n\r\n  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:\r\n\r\n  ``` html\r\n  <a v-link.=\"/a/b/c\">\r\n  ```\r\n\r\n  I would much prefer to use `:=` here, but IE can't handle attributes that end with a colon correctly :(\r\n\r\n3. 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 that `v-on` starts with `v-`. IMO event handlers deserve something different and more succinct.\r\n\r\n  ``` html\r\n  <!-- easier to type, and reads better -->\r\n  <form on-submit=\"handleSubmit\"></form>\r\n\r\n  <!-- multiple listeners also much cleaner -->\r\n  <input\r\n    on-change=\"handleChange\"\r\n    on-focus=\"handleFocus\"\r\n    on-blur=\"handleBlur\">\r\n\r\n  <!-- in addition: key filter can be replaced with: -->\r\n  <input on-keyup-enter=\"doThis\" on-keyup-esc=\"doThat\">\r\n  ```\r\n\r\n4. 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 the `bind-` prefix:\r\n\r\n  ``` html\r\n  <!-- plain string -->\r\n  <img src=\"/avatars/123.png\">\r\n\r\n  <!-- bind to expression -->\r\n  <img bind-src=\"'/avatars/' + userId + '.png'\">\r\n\r\n  <!-- style/class are enhanced to accept object/array values -->\r\n  <div bind-class=\"classes\"></div>\r\n  <div bind-class=\"[classA, classB]\"></div>\r\n  <div bind-class=\"{ classA: true, classB: false }\"></div>\r\n\r\n  <div bind-style=\"cssString\"></div>\r\n  <div bind-style=\"{ fontSize: fontSize, color: currentColor }\"></div>\r\n  <div bind-style=\"[styleObjectA, styleObjectB]\"></div>\r\n  ```\r\n\r\n  In addition, the `bind-` prefix can be shortened as a colon, which is totally optional:\r\n\r\n  ``` html\r\n  <img :src=\"'/avatars/' + userId + '.png'\">\r\n  ```\r\n\r\n5. 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:\r\n\r\n  ``` html\r\n  <example\r\n    literal=\"Mike\"\r\n    bind-dynamic=\"someThing\"\r\n    bind-onetime=\"*onlyOnce\"\r\n    bind-twoway=\"@syncsBackUp\"\r\n    :shorthand=\"sameAsBind\">\r\n  </example>\r\n  ```\r\n\r\n6. 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 only `is`, `ref`, `el` and `transition` will have reactive behavior, other directive params are evaluated only once (Vue will tell you in dev mode).\r\n\r\n  ``` html\r\n  <component\r\n    :is=\"view\"\r\n    ref=\"view\"\r\n    transition=\"slide\"\r\n    transition-mode=\"out-in\">\r\n  </component>\r\n  ```\r\n\r\n### The benefits:\r\n\r\n1. Explicit. The code says what it does.\r\n2. Simpler. Smaller set of core directives. No more \"args\" for directives; no more multiple clauses; It's just expressions + filters.\r\n3. No more confusion about mustache inside attributes. If you see a `v-`, `on-` or `bind-` prefix, it always means the value is an **expression**. If there's no prefix, then it's a always a plain string!\r\n4. Eliminates edge cases like `src=\"{{abc}}\"` causing 404 requests and `style=\"{{something}}\"` gets thrown away in IE. Also eliminates the need for `v-attr`.\r\n\r\n### Note\r\n\r\nPlease 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."},"comment":{"url":"https://api.github.com/repos/yyx990803/vue/issues/comments/139056641","html_url":"https://github.com/yyx990803/vue/issues/1173#issuecomment-139056641","issue_url":"https://api.github.com/repos/yyx990803/vue/issues/1173","id":139056641,"user":{"login":"yyx990803","id":499550,"avatar_url":"https://avatars.githubusercontent.com/u/499550?v=3","gravatar_id":"","url":"https://api.github.com/users/yyx990803","html_url":"https://github.com/yyx990803","followers_url":"https://api.github.com/users/yyx990803/followers","following_url":"https://api.github.com/users/yyx990803/following{/other_user}","gists_url":"https://api.github.com/users/yyx990803/gists{/gist_id}","starred_url":"https://api.github.com/users/yyx990803/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yyx990803/subscriptions","organizations_url":"https://api.github.com/users/yyx990803/orgs","repos_url":"https://api.github.com/users/yyx990803/repos","events_url":"https://api.github.com/users/yyx990803/events{/privacy}","received_events_url":"https://api.github.com/users/yyx990803/received_events","type":"User","site_admin":false},"created_at":"2015-09-09T21:53:33Z","updated_at":"2015-09-09T21:53:33Z","body":"Note these are really sorta like thinking out loud in the form of \"what if ...?\", but as I said, everyone has different stylistic taste. Comments about why it's technically a bad idea are welcome, while \"I don't like it because ughh\" is not really constructive."}}