Parcourir la source

document more changes

Evan You il y a 11 ans
Parent
commit
b1e4e26c0f
1 fichiers modifiés avec 232 ajouts et 147 suppressions
  1. 232 147
      changes.md

+ 232 - 147
changes.md

@@ -2,22 +2,22 @@
 
 **Table of Contents**
 
-- [Instantiation](#instantiation)
+- [Instantiation process](#instantiation-process)
 - [New Scope Inheritance Model](#new-scope-inheritance-model)
-- [Option changes](#option-changes)
-- [Hook changes](#hook-changes)
-- [Computed Properties](#computed-properties)
-- [Directive changes](#directive-changes)
-- [Interpolation changes](#interpolation-changes)
+- [Instance Option changes](#instance-option-changes)
+- [Instance methods change](#instance-methods-change)
+- [Computed Properties API Change](#computed-properties-api-change)
+- [Directive API change](#directive-api-change)
+- [Interpolation change](#interpolation-change)
+- [Config API change](#config-api-change)
+- [Transition API change](#transition-api-change)
+- [Events API change](#events-api-change)
 - [Two Way filters](#two-way-filters)
 - [Block logic control](#block-logic-control)
-- [Config API change](#config-api-change)
-- [One time interpolations](#one-time-interpolations)
-- [`$watch` API change](#$watch-api-change)
-- [Simplified Transition API](#simplified-transition-api)
-- [Events API](#events-api)
 
-## Instantiation
+## Instantiation process
+
+> Breaking
 
 **If no `el` option is provided** at instantiation, Vue will no longer auto-create an empty div for you. In this case, the instance is considered to be in "unmounted" state. Data will be observed, but no DOM compilation will happen until the new instance method `$mount` has been explicitly called.
 
@@ -31,6 +31,8 @@ var vm = new Vue({ el: '#app', data: {a: 1} })
 
 ## New Scope Inheritance Model
 
+> Breaking
+
 In the previous version, nested Vue instances do not have prototypal inheritance of their data scope. Although you can access parent data properties in templates, you need to explicitly travel up the scope chain with `this.$parent` in JavaScript code or use `this.$get()` to get a property on the scope chain. The expression parser also needs to do a lot of dirty work to determine the correct scope the variables belong to.
 
 In the new model, we provide a scope inehritance system similar to Angular, in which you can directly access properties that exist on parent scopes. The major difference is that setting a primitive value property on a child scope WILL affect that on the parent scope! This is one of the major gotchas in Angular. If you are somewhat familiar with how prototype inehritance works, you might be surprised how this is possible. Well, the reason is that all data properties in Vue are getter/setters, and invoking a setter will not cause the child scope shadowing parent scopes. See the example [here](http://jsfiddle.net/yyx990803/Px2n6/).
@@ -39,36 +41,54 @@ The result of this model is a much cleaner expression evaluation implementation.
 
 You can also pass in `isolated: true` to avoid inheriting a parent scope, which can provide encapsulation for reusable components and improve performance.
 
-## Option changes
+## Instance Option changes
 
 - #### `el` and `data` for component definitions
 
+  > Breaking
+
   When used in component definitions and in `Vue.extend()`, the `el`, and `data` options now only accept a function that returns the per-instance value. For example:
 
   ``` js
-var MyComponent = Vue.extend({
-  el: function () {
-    var el = document.createElement('p')
-    // you can initialize your element here.
-    // you can even return a documentFragment to create
-    // a block instance.
-    el.className = 'content'
-    return el
-  },
-  data: function () {
-    // similar to ReactComponent.getInitialState
-    return {
-      a: {
-        b: 123
+  var MyComponent = Vue.extend({
+    el: function () {
+      var el = document.createElement('p')
+      // you can initialize your element here.
+      // you can even return a documentFragment to create
+      // a block instance.
+      el.className = 'content'
+      return el
+    },
+    data: function () {
+      // similar to ReactComponent.getInitialState
+      return {
+        a: {
+          b: 123
+        }
       }
     }
-  }
-})
+  })
   ```
 
 - #### new option: `events`.
 
-  When events are used extensively for cross-vm communication, the ready hook can get kinda messy. The new `events` option is similar to its Backbone equivalent, where you can declaratiely register a bunch of event listeners.
+  When events are used extensively for cross-vm communication, the ready hook can get kinda messy. The new `events` option is similar to its Backbone equivalent, where you can declaratiely register a bunch of event listeners. You can also use it to register hook listeners.
+
+  ``` js
+  var vm = new Vue({
+    events: {
+      'hook:created': function () {
+        console.log('created!')
+      },
+      greeting: function (msg) {
+        console.log(msg)
+      }
+    }
+  })
+  // -> created!
+  vm.$emit('greeting', 'hi!')
+  // -> hi!
+  ```
 
 - #### new option: `isolated`.
 
@@ -78,6 +98,8 @@ var MyComponent = Vue.extend({
 
 - #### removed options:
 
+  > Breaking
+
   - `parent`
 
     This option has been removed. To create a child instance that inherits parent scope, use `var child = parent.$addChild(options, [contructor])`.
@@ -93,27 +115,93 @@ var MyComponent = Vue.extend({
   - `className`
   - `attributes`
 
-## Hook changes
+- #### hook changes
+
+  > Breaking
+
+  - #### hook usage change: `created`
+
+    This is now called before anything happens to the instance, with only `this.$data` being available, but **not observed** yet. In the past you can do `this.something = 1` to define default data, but it required some weird hack to make it work. Now you should just explicitly do `this.$data.something = 1` to define your instance default data.
+
+  - #### hook usage change: `ready`
+
+    The new `ready` hook now is only fired after the instance is compiled and **inserted into the document for the first time**. For a equivalence of the old `ready` hook, use the new `compiled` hook.
+
+  - #### new hook: `beforeCompile`
+
+    This new hook is introduced to accompany the separation of instantiation and DOM mounting. It is called right before the DOM compilation starts and `this.$el` is available, so you can do some pre-processing on the element here.
+
+  - #### new hook: `compiled`
+
+    The `compiled` hook indicates the element has been fully compiled based on initial data. However this doesn't indicate if the element has been inserted into the DOM yet. This is essentially the old `ready` hook.
+
+  - #### renamed hook: `afterDestroy` -> `destroyed`
+
+## Instance methods change
+
+- `vm.$watch` can now accept an expression:
+
+  ``` js
+  vm.$watch('a + b', function (newVal, oldVal) {
+    // do something
+  })
+  ```
+
+  By default the callback only fires when the value changes. If you want it to be called immediately with the initial value, use the third optional `immediate` argument:
+
+  ``` js
+  vm.$watch('a', callback, true)
+  // callback is fired immediately with current value of `a`
+  ```
+
+- (Breaking) `$unwatch` has been removed. `$watch` now also returns an unregister function:
+
+  ``` js
+  var unwatch = vm.$watch('a', cb)
+  // later, teardown the watcher
+  unwatch()
+  ```
+
+- `vm.$get` now accepts expressions:
+
+  ``` js
+  var value = vm.$get('a + b')
+  ```
+
+- #### New methods
+
+  - `vm.$add` and `vm.$delete`
+
+    Explicitly add/remove properties from the ViewModel. Observed objects are augmented with these two methods too. Use these only when needed - the best practice is to define all your data fields at instantiation, even with a `null` value.
+
+  - `vm.$eval`
 
-- #### hook usage change: `created`
+    Evaluate an expression that can also include filters.
 
-  This is now called before anything happens to the instance, with only `this.$data` being available, but **not observed** yet. In the past you can do `this.something = 1` to define default data, but it required some weird hack to make it work. Now you should just explicitly do `this.$data.something = 1` to define your instance default data.
+    ``` js
+    var value = vm.$eval('msg | uppercase')
+    ```
 
-- #### hook usage change: `ready`
+  - `vm.$interpolate`
 
-  The new `ready` hook now is only fired after the instance is compiled and **inserted into the document for the first time**. For a equivalence of the old `ready` hook, use the new `compiled` hook.
+    Evalutate a piece of template string.
 
-- #### new hook: `beforeCompile`
+    ``` js
+    var markup = vm.$interpolate('<p>{{msg | uppercase}}</p>')
+    ```
 
-  This new hook is introduced to accompany the separation of instantiation and DOM mounting. It is called right before the DOM compilation starts and `this.$el` is available, so you can do some pre-processing on the element here.
+  - `vm.$log`
 
-- #### new hook: `compiled`
+    Log the current instance data as a plain object, which is more console-inspectable than a bunch of getter/setters. Also accepts an optional key.
 
-  The `compiled` hook indicates the element has been fully compiled based on initial data. However this doesn't indicate if the element has been inserted into the DOM yet. This is essentially the old `ready` hook.
+    ``` js
+    vm.$log() // logs entire ViewModel data
+    vm.$log('item') // logs vm.item
+    ```
 
-- #### renamed hook: `afterDestroy` -> `destroyed`
+## Computed Properties API Change
 
-## Computed Properties
+> Breaking
 
 `$get` and `$set` is now simply `get` and `set`:
 
@@ -126,95 +214,58 @@ computed: {
 }
 ```
 
-## Directive changes
+## Directive API change
 
 - #### Dynamic literals
 
   Literal directives can now also be dynamic via bindings like this:
 
   ``` html
-<div v-component="{{test}}"></div>
+  <div v-component="{{test}}"></div>
   ```
 
   When `test` changes, the component used will change! This essentially replaces the old `v-view` directive.
 
   When authoring literal directives, you can now provide an `update()` function if you wish to handle it dynamically. If no `update()` is provided the directive will be treated as a static literal and only evaluated once.
 
-- #### New directive option: `twoWay`
+  Note that `v-component` is the only directive that supports this.
 
-  This option indicates the directive is two-way and may write back to the model. Allows the use of `this.set(value)` inside directive functions.
+- #### Directive params
 
-- #### Removed directive option: `isEmpty`
+  Some built-in directives now checks for additional attribute params to trigger special behavior.
 
-## Interpolation changes
+  - `v-model`
 
-- Text bindings will no longer automatically stringify objects. Use the new `json` filter which gives more flexibility in formatting.
+    `v-model` now will check `lazy` attribute for lazy model update, and will check `number` attribute to know if it needs to convert the value into Numbers before writing back to the model.
 
-- **New feature**: One time interpolations. They do not need to set up watchers and can improve initial rendering performance. If you know something's not going to change, make sure to use this new feature. Example:
+    When used on a `<select>` element, `v-model` will check for an `options` attribute, which should be an keypath/expression that points to an Array of strings to use as its options.
 
-  ``` html
-<span>{{* hello }}</span>
-  ```
+  - `v-component`
 
-## Two Way filters
+    When used as a dynamic component, it will check for the `keep-alive` attribute. When `keep-alive` is present, already instantiated components will be cached. This is useful when you have large, nested view components and want to maintain the state when switching views.
 
-If a filter is defined as a function, it is treated as a read filter by default - i.e. it is applied when data is read from the model and applied to the DOM. You can now specify write filters as well, which are applied when writing to the model, triggered by user input. Write filters are only triggered on two-way bindings like `v-model`.
+- #### New directive option: `twoWay`
 
-``` js
-Vue.filter('format', {
-  read: function (val) {
-    return val + '!'
-  },
-  write: function (val, oldVal) {
-    return val.match(/ok/) ? val : oldVal
-  }
-})
-```
+  This option indicates the directive is two-way and may write back to the model. Allows the use of `this.set(value)` inside directive functions.
 
-## Block logic control
+- #### (Breaking) Removed directive option: `isEmpty`
 
-One limitation of flow control direcitves like `v-repeat` and `v-if` is that they can only be used on a single element. Now you can use them to manage a block of content by using them on a `<template>` element that wraps the content you want managed:
+## Interpolation change
 
-``` js
-items: [
-  {
-    title: 'title-1',
-    subtitle: 'subtitle-1',
-    content: 'content-1'
-  },
-  {
-    title: 'title-2',
-    subtitle: 'subtitle-2',
-    content: 'content-2'
-  }
-]
-```
+- (Breaking) Text bindings will no longer automatically stringify objects. Use the new `json` filter which gives more flexibility in formatting.
 
-``` html
-<template v-repeat="item:items">
-  <h2>{{item.title}}</h2>
-  <p>{{item.subtitle}}</p>
-  <p>{{item.content}}</p>
-</template>
-```
+- #### One time interpolations
 
-Rendered result:
+  ``` html
+  <span>{{* hello }}</span>
+  ```
 
-``` html
-<!--v-block-start-->
-<h2>title-1</h2>
-<p>subtitle-1</p>
-<p>content-1</p>
-<!--v-block-end-->
-<!--v-block-start-->
-<h2>title-2</h2>
-<p>subtitle-2</p>
-<p>content-2</p>
-<!--v-block-end-->
-```
+  One time interpolations do not need to set up watchers and can improve initial rendering performance. If you know something's not going to change, make sure to use this new feature. Example:
 
 ## Config API change
 
+> Breaking
+
 Instead of the old `Vue.config()` with a heavily overloaded API, the config object is now available globally as `Vue.config`, and you can simply change its properties:
 
 ``` js
@@ -241,32 +292,9 @@ Vue.config.debug = true
 
   * Note you still cannot use `<` or `>` in delimiters because Vue uses DOM-based templating.
 
-## `$watch` API change
-
-`vm.$watch` can now accept an expression:
-
-``` js
-vm.$watch('a + b', function (newVal, oldVal) {
-  // do something
-})
-```
+## Transition API Change
 
-By default the callback only fires when the value changes. If you want it to be called immediately with the initial value, use the third optional `immediate` argument:
-
-``` js
-vm.$watch('a', callback, true)
-// callback is fired immediately with current value of `a`
-```
-
-`$watch` now also returns an unregister function (`$unwatch` has been removed):
-
-``` js
-var unwatch = vm.$watch('a', cb)
-// later, teardown the watcher
-unwatch()
-```
-
-## Simplified Transition API
+> Breaking
 
 - no more distinctions between `v-transition`, `v-animation` or `v-effect`;
 - no more configuring enter/leave classes in `Vue.config`;
@@ -285,31 +313,31 @@ With `v-transition="my-transition"`, Vue will:
   Now more similar to Angular:
 
   ``` js
-Vue.transition('fade', {
-  enter: function (el, done) {
-    // element is already inserted into the DOM
-    // call done when animation finishes.
-    $(el)
-      .css('opacity', 0)
-      .animate({ opacity: 1 }, 1000, done)
-    // optionally return a "cancel" function
-    // to clean up if the animation is cancelled
-    return function () {
-      $(el).stop()
-    }
-  },
-  leave: function (el, done) {
-    // same as enter
-    $(el)
-      .animate({ opacity: 0 }, 1000, done)
-    return function () {
-      $(el).stop()
+  Vue.transition('fade', {
+    enter: function (el, done) {
+      // element is already inserted into the DOM
+      // call done when animation finishes.
+      $(el)
+        .css('opacity', 0)
+        .animate({ opacity: 1 }, 1000, done)
+      // optionally return a "cancel" function
+      // to clean up if the animation is cancelled
+      return function () {
+        $(el).stop()
+      }
+    },
+    leave: function (el, done) {
+      // same as enter
+      $(el)
+        .animate({ opacity: 0 }, 1000, done)
+      return function () {
+        $(el).stop()
+      }
     }
-  }
-})
+  })
   ```
 
-## Events API
+## Events API change
 
 Now if an event handler return `false`, it will stop event propagation for `$dispatch` and stop broadcasting to children for `$broadcast`.
 
@@ -335,4 +363,61 @@ c.$on('test', function () {
 c.$dispatch('test')
 // -> 'c'
 // -> 'b'
+```
+
+## Two Way filters
+
+If a filter is defined as a function, it is treated as a read filter by default - i.e. it is applied when data is read from the model and applied to the DOM. You can now specify write filters as well, which are applied when writing to the model, triggered by user input. Write filters are only triggered on two-way bindings like `v-model`.
+
+``` js
+Vue.filter('format', {
+  read: function (val) {
+    return val + '!'
+  },
+  write: function (val, oldVal) {
+    return val.match(/ok/) ? val : oldVal
+  }
+})
+```
+
+## Block logic control
+
+One limitation of flow control direcitves like `v-repeat` and `v-if` is that they can only be used on a single element. Now you can use them to manage a block of content by using them on a `<template>` element that wraps the content you want managed:
+
+``` js
+items: [
+  {
+    title: 'title-1',
+    subtitle: 'subtitle-1',
+    content: 'content-1'
+  },
+  {
+    title: 'title-2',
+    subtitle: 'subtitle-2',
+    content: 'content-2'
+  }
+]
+```
+
+``` html
+<template v-repeat="item:items">
+  <h2>{{item.title}}</h2>
+  <p>{{item.subtitle}}</p>
+  <p>{{item.content}}</p>
+</template>
+```
+
+Rendered result:
+
+``` html
+<!--v-block-start-->
+<h2>title-1</h2>
+<p>subtitle-1</p>
+<p>content-1</p>
+<!--v-block-end-->
+<!--v-block-start-->
+<h2>title-2</h2>
+<p>subtitle-2</p>
+<p>content-2</p>
+<!--v-block-end-->
 ```