Evan You 11 år sedan
förälder
incheckning
d36ea57f13

+ 1 - 0
component.json

@@ -28,6 +28,7 @@
     "src/directives/class.js",
     "src/directives/cloak.js",
     "src/directives/component.js",
+    "src/directives/el.js",
     "src/directives/html.js",
     "src/directives/if.js",
     "src/directives/index.js",

+ 2 - 9
src/compile/compile.js

@@ -17,7 +17,7 @@ function noop () {}
  * @return {Function}
  */
 
-var compile = module.exports = function (el, options) {
+module.exports = function compile (el, options) {
   // for template tags, what we want is its content as
   // a documentFragment (for block instances)
   if (el.tagName === 'TEMPLATE') {
@@ -382,15 +382,8 @@ function checkTerminalDirectives (el, options) {
 function makeTeriminalLinkFn (el, dirName, value, options) {
   var descriptor = dirParser.parse(value)[0]
   var def = options.directives[dirName]
-  if (
-    dirName === 'repeat' &&
-    !el.hasAttribute(config.prefix + 'component')
-  ) {
-    // optimize for simple repeats
-    var linker = compile(el, options)
-  }
   return function terminalLinkFn (vm, el) {
-    vm._bindDir(dirName, el, descriptor, def, linker)
+    vm._bindDir(dirName, el, descriptor, def)
   }
 }
 

+ 14 - 0
src/directives/el.js

@@ -0,0 +1,14 @@
+module.exports = {
+
+  isLiteral: true,
+
+  bind: function () {
+    this.owner = this.vm._owner || this.vm
+    this.owner.$$[this.expression] = this.el
+  },
+
+  unbind: function () {
+    this.owner.$$[this.expression] = null
+  }
+  
+}

+ 1 - 0
src/directives/index.js

@@ -4,6 +4,7 @@ exports.html       = require('./html')
 exports.attr       = require('./attr')
 exports.show       = require('./show')
 exports['class']   = require('./class')
+exports.el         = require('./el')
 exports.ref        = require('./ref')
 exports.cloak      = require('./cloak')
 exports.style      = require('./style')

+ 3 - 15
src/directives/ref.js

@@ -11,24 +11,12 @@ module.exports = {
       )
       return
     }
-    var id = this.expression
-    if (id) {
-      var owner = this.vm.$parent
-      // find the first parent vm that is not an
-      // anonymous instance.
-      while (owner._isAnonymous) {
-        owner = owner.$parent
-      }
-      owner.$[id] = this.vm
-      this.owner = owner
-    }
+    this.owner = this.vm._owner || this.vm
+    this.owner.$[this.expression] = this.vm
   },
 
   unbind: function () {
-    var id = this.expression
-    if (id) {
-      delete this.owner.$[id]
-    }
+    this.owner.$[this.expression] = null
   }
   
 }

+ 28 - 22
src/directives/repeat.js

@@ -28,8 +28,8 @@ module.exports = {
     // at v-repeat level
     this.checkIf()
     this.checkRef()
-    this.checkComponent()
     this.checkTrackById()
+    this.checkComponent()
     // setup ref node
     this.ref = document.createComment('v-repeat')
     // cache for primitive value instances
@@ -55,8 +55,8 @@ module.exports = {
   },
 
   /**
-   * Check if v-ref is also present. If yes, evaluate it and
-   * locate the first non-anonymous parent as the owner vm.
+   * Check if v-ref/ v-el is also present. If yes, evaluate
+   * them and locate owner.
    */
 
   checkRef: function () {
@@ -64,12 +64,25 @@ module.exports = {
     this.childId = childId
       ? this.vm.$interpolate(childId)
       : null
-    if (this.childId) {
-      var owner = this.vm.$parent
-      while (owner._isAnonymous) {
-        owner = owner.$parent
-      }
-      this.owner = owner
+    var elId = _.attr(this.el, 'el')
+    this.elId = elId
+      ? this.vm.$interpolate(elId)
+      : null
+    if (this.childId || this.elId) {
+      this.owner = this.vm._owner || this.vm
+    }
+  },
+
+  /**
+   * Check for a track-by ID, which allows us to identify
+   * a piece of data and its associated instance by its
+   * unique id.
+   */
+
+  checkTrackById: function () {
+    this.idKey = this.el.getAttribute('trackby')
+    if (this.idKey !== null) {
+      this.el.removeAttribute('trackby')
     }
   },
 
@@ -84,6 +97,7 @@ module.exports = {
     if (!id) {
       this.Ctor = _.Vue // default constructor
       this.inherit = true // inline repeats should inherit
+      this._linker = compile(this.el, _.Vue.options)
     } else {
       var tokens = textParser.parse(id)
       if (!tokens) { // static component
@@ -107,19 +121,6 @@ module.exports = {
     }
   },
 
-  /**
-   * Check for a track-by ID, which allows us to identify
-   * a piece of data and its associated instance by its
-   * unique id.
-   */
-
-  checkTrackById: function () {
-    this.idKey = this.el.getAttribute('trackby')
-    if (this.idKey !== null) {
-      this.el.removeAttribute('trackby')
-    }
-  },
-
   /**
    * Update.
    * This is called whenever the Array mutates.
@@ -141,6 +142,11 @@ module.exports = {
     if (this.childId) {
       this.owner.$[this.childId] = this.vms
     }
+    if (this.elId) {
+      this.owner.$$[this.elId] = this.vms.map(function (vm) {
+        return vm.$el
+      })
+    }
   },
 
   /**

+ 10 - 1
src/instance/init.js

@@ -51,7 +51,16 @@ exports._init = function (options) {
                            // child constructors
 
   // anonymous instances are created by v-if
-  this._isAnonymous = options._anonymous
+  // we need to walk along the parent chain to locate the
+  // first non-anonymous instance as the owner.
+  var anon = this._isAnonymous = options._anonymous
+  if (anon) {
+    var parent = this.$parent
+    while (parent._isAnonymous) {
+      parent = parent.$parent
+    }
+    this._owner = parent
+  }
 
   // merge options.
   options = this.$options = mergeOptions(

+ 9 - 2
test/unit/specs/instance/init_spec.js

@@ -12,11 +12,14 @@ describe('Instance Init', function () {
     $mount: jasmine.createSpy()
   }
 
-  init.call(stub, {
+  var options = {
     a: 2,
     _anonymous: true,
+    _parent: {},
     el: {}
-  })
+  }
+
+  init.call(stub, options)
 
   it('should setup properties', function () {
     expect(stub.$el).toBe(null)
@@ -36,6 +39,10 @@ describe('Instance Init', function () {
     expect(stub.$options.b).toBe(2)
   })
 
+  it('should locate owner', function () {
+    expect(stub._owner).toBe(options._parent)
+  })
+
   it('should call other init methods', function () {
     expect(stub._initEvents).toHaveBeenCalled()
     expect(stub._initScope).toHaveBeenCalled()