{"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":9,"state":"open","created_at":"2015-08-17T06:29:02Z","updated_at":"2015-09-03T15:40:24Z","due_on":null,"closed_at":null},"comments":59,"created_at":"2015-08-17T06:26:23Z","updated_at":"2015-09-04T18:10:05Z","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**UPDATE**: The following is implemented in 1.0.0-alpha.2. See a newer version of the proposal in the [comment below](#issuecomment-137473650).\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\r\n  And that's it. Only 4 core directives.\r\n\r\n3. Props. These are prefixed with `prop-`, values always parsed as expressions. Literal strings need to be quoted.\r\n\r\n  ``` html\r\n  <example\r\n    prop-id=\"id\"\r\n    prop-literal=\"'Mike'\"\r\n    prop-onetime=\"*onlyOnce\"\r\n    prop-twoway=\"@syncsBackUp\">\r\n  </example>\r\n  ```\r\n\r\n4. 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\n5. 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\r\n  You can add the `bind-` prefix to make any attribute dynamically bound to an expression. Among all the attributes, `style` and `class` deserve some special treatment. Their `bind-` form can both accept an object:\r\n\r\n  ``` html\r\n  <div bind-style=\"{ fontSize: size + 'px', color: color }\"></div>\r\n  <div bind-class=\"{ active: isActive, red: true }\"></div>\r\n  ```\r\n\r\n  In addition, `bind-class` can also accept an array:\r\n\r\n  ``` html\r\n  <div bind-class=\"['ui', 'button', color]\"></div>\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 (note we are using `bind-is` to indicate a dynamic component):\r\n\r\n  ``` html\r\n  <component\r\n    bind-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-`, `bind-` or `prop-` 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/137808606","html_url":"https://github.com/yyx990803/vue/issues/1173#issuecomment-137808606","issue_url":"https://api.github.com/repos/yyx990803/vue/issues/1173","id":137808606,"user":{"login":"BYODKM","id":4958641,"avatar_url":"https://avatars.githubusercontent.com/u/4958641?v=3","gravatar_id":"","url":"https://api.github.com/users/BYODKM","html_url":"https://github.com/BYODKM","followers_url":"https://api.github.com/users/BYODKM/followers","following_url":"https://api.github.com/users/BYODKM/following{/other_user}","gists_url":"https://api.github.com/users/BYODKM/gists{/gist_id}","starred_url":"https://api.github.com/users/BYODKM/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BYODKM/subscriptions","organizations_url":"https://api.github.com/users/BYODKM/orgs","repos_url":"https://api.github.com/users/BYODKM/repos","events_url":"https://api.github.com/users/BYODKM/events{/privacy}","received_events_url":"https://api.github.com/users/BYODKM/received_events","type":"User","site_admin":false},"created_at":"2015-09-04T18:10:05Z","updated_at":"2015-09-04T18:10:05Z","body":"@yyx990803 Sorry. I tested a mixin not a element. `+mixin(attr:=\"foo\")` needs some care."}}