Просмотр исходного кода

components have isolated scope by default

Evan You 11 лет назад
Родитель
Сommit
ca6bee24a6

+ 7 - 4
changes.md

@@ -36,11 +36,11 @@ var vm = new Vue({ el: '#app', data: {a: 1} })
 
 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/).
+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! Because all data properties in Vue are getter/setters, so setting a property with the same key as parent on a child will not cause the child scope to create a new property shadowing the parent one, but rather it will just invoke the parent's setter function. See the example [here](http://jsfiddle.net/yyx990803/Px2n6/).
 
 The result of this model is a much cleaner expression evaluation implementation. All expressions can simply be evaluated against the vm.
 
-You can also pass in `isolated: true` to avoid inheriting a parent scope, which can provide encapsulation for reusable components and improve performance.
+By default, all child components **DO NOT** inherit the parent scope. Only anonymous instances created in `v-repeat` and `v-if` inherit parent scope by default. This avoids accidentally falling through to parent properties when you didn't mean to. If you want your component to explicitly inherit parent scope, use the `inherit:true` option.
 
 ## Instance Option changes
 
@@ -100,11 +100,14 @@ You can also pass in `isolated: true` to avoid inheriting a parent scope, which
   // -> goodbye!
   ```
 
-- #### new option: `isolated`.
+- #### new option: `inherit`.
 
   Default: `false`.
 
-  Whether to inherit parent scope data. Set it to `true` if you want to create a component that have an isolated scope of its own. An isolated scope means you won't be able to bind to data on parent scopes in the component's template.
+  Whether to inherit parent scope data. Set it to `true` if you want to create a component that inherits parent scope. By default, inside a component's template you won't be able to bind to data on parent scopes. When this is set to `true`, you will be able to:
+
+  1. bind to parent scope properties in the component template
+  2. directly access parent properties on the component instance itself, via prototypal inheritance.
 
 - #### removed options:
 

+ 10 - 6
src/api/child.js

@@ -13,11 +13,13 @@ var _ = require('../util')
 
 exports.$addChild = function (opts, BaseCtor) {
   BaseCtor = BaseCtor || _.Vue
+  opts = opts || {}
+  var parent = this
   var ChildVue
-  if (BaseCtor.options.isolated) {
-    ChildVue = BaseCtor
-  } else {
-    var parent = this
+  var inherit = opts.inherit !== undefined
+    ? opts.inherit
+    : BaseCtor.options.inherit
+  if (inherit) {
     var ctors = parent._childCtors
     if (!ctors) {
       ctors = parent._childCtors = {}
@@ -25,8 +27,6 @@ exports.$addChild = function (opts, BaseCtor) {
     ChildVue = ctors[BaseCtor.cid]
     if (!ChildVue) {
       ChildVue = function (options) {
-        this.$parent = parent
-        this.$root = parent.$root
         this.constructor = ChildVue
         _.Vue.call(this, options)
       }
@@ -34,7 +34,11 @@ exports.$addChild = function (opts, BaseCtor) {
       ChildVue.prototype = this
       ctors[BaseCtor.cid] = ChildVue
     }
+  } else {
+    ChildVue = BaseCtor
   }
+  opts._parent = parent
+  opts._root = parent.$root
   var child = new ChildVue(opts)
   if (!this._children) {
     this._children = []

+ 1 - 2
src/directives/component.js

@@ -137,8 +137,7 @@ module.exports = {
     if (this.Ctor && !this.childVM) {
       this.childVM = this.vm.$addChild({
         el: this.el.cloneNode(true),
-        _linker: this._linker,
-        parent: this.vm
+        _linker: this._linker
       }, this.Ctor)
       if (this.keepAlive) {
         this.cache[this.id] = this.childVM

+ 1 - 1
src/directives/if.js

@@ -28,7 +28,7 @@ module.exports = {
         if (!this.childVM) {
           this.childVM = this.vm.$addChild({
             el: this.el,
-            parent: this.vm,
+            inherit: true,
             _anonymous: true
           })
         }

+ 2 - 1
src/directives/repeat.js

@@ -82,6 +82,7 @@ module.exports = {
     var id = _.attr(this.el, 'component')
     if (!id) {
       this.Ctor = _.Vue // default constructor
+      this.inherit = true // inline repeats should inherit
     } else {
       var tokens = textParser.parse(id)
       if (!tokens) { // static component
@@ -252,7 +253,7 @@ module.exports = {
       _linker: this._linker,
       _meta: meta,
       data: data,
-      parent: this.vm
+      inherit: this.inherit
     }, Ctor)
     // cache instance
     this.cacheVm(raw, vm)

+ 2 - 1
src/instance/init.js

@@ -16,7 +16,8 @@ exports._init = function (options) {
   options = options || {}
 
   this.$el           = null
-  this.$root         = this.$root || this
+  this.$parent       = options._parent
+  this.$root         = options._root || this
   this.$             = {}
   this._watcherList  = []
   this._watchers     = {}

+ 6 - 2
test/unit/specs/instance/scope_spec.js

@@ -73,7 +73,9 @@ describe('Instance Scope', function () {
     })
 
     it('inherit', function () {
-      var child = vm.$addChild()
+      var child = vm.$addChild({
+        inherit: true
+      })
       expect(child.c).toBe('cd')
 
       child.d = 'e f'
@@ -105,7 +107,9 @@ describe('Instance Scope', function () {
       })
       expect(vm.test()).toBe(1)
 
-      var child = vm.$addChild()
+      var child = vm.$addChild({
+        inherit: true
+      })
       expect(child.test()).toBe(1)
     })
 

+ 7 - 5
test/unit/specs/watcher_spec.js

@@ -126,13 +126,13 @@ describe('Watcher', function () {
     expect(watcher.value).toBeUndefined()
     expect(watcher2.value).toBeUndefined()
     // check $add affecting children
-    var child = vm.$addChild()
+    var child = vm.$addChild({
+      inherit: true
+    })
     var watcher3 = new Watcher(child, 'd.e', spy)
     var watcher4 = new Watcher(child, 'b.e', spy)
     // check $add should not affect isolated children
-    var child2 = vm.$addChild({
-      isolated: true
-    })
+    var child2 = vm.$addChild()
     var watcher5 = new Watcher(child2, 'd.e', spy)
     expect(watcher5.value).toBeUndefined()
     vm.$add('d', { e: 123 })
@@ -209,7 +209,9 @@ describe('Watcher', function () {
   })
 
   it('watching parent scope properties', function (done) {
-    var child = vm.$addChild()
+    var child = vm.$addChild({
+      inherit: true
+    })
     var spy2 = jasmine.createSpy('watch')
     var watcher1 = new Watcher(child, '$data', spy)
     var watcher2 = new Watcher(child, 'a', spy2)