Преглед изворни кода

experimenting with fast repeat

Evan You пре 10 година
родитељ
комит
8f028e9d80
6 измењених фајлова са 81 додато и 23 уклоњено
  1. 18 17
      src/compiler/compile.js
  2. 4 2
      src/directive.js
  3. 50 0
      src/fast-repeat.js
  4. 2 2
      src/instance/compile.js
  5. 2 0
      src/vue.js
  6. 5 2
      src/watcher.js

+ 18 - 17
src/compiler/compile.js

@@ -9,6 +9,7 @@ var componentDef = require('../directives/component')
 
 // terminal directives
 var terminalDirectives = [
+  'fast-repeat',
   'repeat',
   'if'
 ]
@@ -54,13 +55,13 @@ exports.compile = function (el, options, partial) {
    * @return {Function|undefined}
    */
 
-  return function compositeLinkFn (vm, el, host) {
+  return function compositeLinkFn (vm, el, host, scope) {
     // cache childNodes before linking parent, fix #657
     var childNodes = _.toArray(el.childNodes)
     // link
-    var dirs = linkAndCapture(function () {
-      if (nodeLinkFn) nodeLinkFn(vm, el, host)
-      if (childLinkFn) childLinkFn(vm, childNodes, host)
+    var dirs = linkAndCapture(function compositeLinkCapturer () {
+      if (nodeLinkFn) nodeLinkFn(vm, el, host, scope)
+      if (childLinkFn) childLinkFn(vm, childNodes, host, scope)
     }, vm)
     return makeUnlinkFn(vm, dirs)
   }
@@ -323,7 +324,7 @@ function processTextToken (token, options) {
  */
 
 function makeTextNodeLinkFn (tokens, frag) {
-  return function textNodeLinkFn (vm, el) {
+  return function textNodeLinkFn (vm, el, host, scope) {
     var fragClone = frag.cloneNode(true)
     var childNodes = _.toArray(fragClone.childNodes)
     var token, value, node
@@ -341,7 +342,7 @@ function makeTextNodeLinkFn (tokens, frag) {
           }
         } else {
           vm._bindDir(token.type, node,
-                      token.descriptor, token.def)
+                      token.descriptor, token.def, host, scope)
         }
       }
     }
@@ -384,7 +385,7 @@ function compileNodeList (nodeList, options) {
  */
 
 function makeChildLinkFn (linkFns) {
-  return function childLinkFn (vm, nodes, host) {
+  return function childLinkFn (vm, nodes, host, scope) {
     var node, nodeLinkFn, childrenLinkFn
     for (var i = 0, n = 0, l = linkFns.length; i < l; n++) {
       node = nodes[n]
@@ -393,10 +394,10 @@ function makeChildLinkFn (linkFns) {
       // cache childNodes before linking parent, fix #657
       var childNodes = _.toArray(node.childNodes)
       if (nodeLinkFn) {
-        nodeLinkFn(vm, node, host)
+        nodeLinkFn(vm, node, host, scope)
       }
       if (childrenLinkFn) {
-        childrenLinkFn(vm, childNodes, host)
+        childrenLinkFn(vm, childNodes, host, scope)
       }
     }
   }
@@ -432,10 +433,10 @@ function checkElementDirectives (el, options) {
 function checkComponent (el, options, hasAttrs) {
   var componentId = _.checkComponent(el, options, hasAttrs)
   if (componentId) {
-    var componentLinkFn = function (vm, el, host) {
+    var componentLinkFn = function (vm, el, host, scope) {
       vm._bindDir('component', el, {
         expression: componentId
-      }, componentDef, host)
+      }, componentDef, host, scope)
     }
     componentLinkFn.terminal = true
     return componentLinkFn
@@ -486,8 +487,8 @@ function makeTerminalNodeLinkFn (el, dirName, value, options, def) {
   // no need to call resolveAsset since terminal directives
   // are always internal
   def = def || options.directives[dirName]
-  var fn = function terminalNodeLinkFn (vm, el, host) {
-    vm._bindDir(dirName, el, descriptor, def, host)
+  var fn = function terminalNodeLinkFn (vm, el, host, scope) {
+    vm._bindDir(dirName, el, descriptor, def, host, scope)
   }
   fn.terminal = true
   return fn
@@ -544,7 +545,7 @@ function compileDirectives (attrs, options) {
  */
 
 function makeNodeLinkFn (directives) {
-  return function nodeLinkFn (vm, el, host) {
+  return function nodeLinkFn (vm, el, host, scope) {
     // reverse apply because it's sorted low to high
     var i = directives.length
     var dir, j, k
@@ -557,7 +558,7 @@ function makeNodeLinkFn (directives) {
         k = dir.descriptors.length
         for (j = 0; j < k; j++) {
           vm._bindDir(dir.name, el,
-            dir.descriptors[j], dir.def, host)
+            dir.descriptors[j], dir.def, host, scope)
         }
       }
     }
@@ -598,7 +599,7 @@ function collectAttrDirective (name, value, options) {
         ? function (vm, el) {
             el.setAttribute(name, vm.$interpolate(value))
           }
-        : function (vm, el) {
+        : function (vm, el, host, scope) {
             var exp = textParser.tokensToExp(tokens, vm)
             var desc = isClass
               ? dirParser.parse(exp)[0]
@@ -606,7 +607,7 @@ function collectAttrDirective (name, value, options) {
             if (isClass) {
               desc._rawClass = value
             }
-            vm._bindDir(dirName, el, desc, def)
+            vm._bindDir(dirName, el, desc, def, host, scope)
           }
     }
   }

+ 4 - 2
src/directive.js

@@ -22,7 +22,7 @@ var expParser = require('./parsers/expression')
  * @constructor
  */
 
-function Directive (name, el, vm, descriptor, def, host) {
+function Directive (name, el, vm, descriptor, def, host, scope) {
   // public
   this.name = name
   this.el = el
@@ -38,6 +38,7 @@ function Directive (name, el, vm, descriptor, def, host) {
   this._locked = false
   this._bound = false
   this._listeners = null
+  this._scope = scope
   // init
   this._bind(def)
 }
@@ -93,7 +94,8 @@ Directive.prototype._bind = function (def) {
         filters: this.filters,
         twoWay: this.twoWay,
         deep: this.deep,
-        preProcess: preProcess
+        preProcess: preProcess,
+        scope: this._scope
       }
     )
     if (this._initValue != null) {

+ 50 - 0
src/fast-repeat.js

@@ -0,0 +1,50 @@
+var _ = require('./util')
+var compiler = require('./compiler')
+var templateParser = require('./parsers/template')
+
+module.exports = {
+
+  bind: function () {
+    var inMatch = this.expression.match(/(.*) in (.*)/)
+    if (inMatch) {
+      this.arg = inMatch[1]
+      this._watcherExp = inMatch[2]
+    }
+
+    this.start = _.createAnchor('fast-repeat-start')
+    this.end = _.createAnchor('fast-repeat-end')
+    _.replace(this.el, this.end)
+    _.before(this.start, this.end)
+
+    var vm = this.vm
+    var template = _.isTemplate(this.el)
+      ? templateParser.parse(this.el, true)
+      : this.el
+    var linker = compiler.compile(template, vm.$options, true)
+
+    this.create = _.bind(function (data) {
+      var el = templateParser.clone(template)
+      var scope = Object.create(this._scope || this.vm)
+      Object.defineProperty(scope, this.arg, {
+        enumberable: true,
+        configurable: true,
+        value: data
+      })
+      var unlink = linker(vm, el, this._host, scope)
+      var f = {
+        el: el,
+        unlink: unlink
+      }
+      return f
+    }, this)
+  },
+
+  update: function (list) {
+    if (!list) debugger
+    var anchor = this.end
+    this.frags = list.map(this.create)
+    this.frags.forEach(function (f) {
+      _.before(f.el, anchor)
+    })
+  }
+}

+ 2 - 2
src/instance/compile.js

@@ -105,9 +105,9 @@ exports._initElement = function (el) {
  * @param {Vue|undefined} host - transclusion host component
  */
 
-exports._bindDir = function (name, node, desc, def, host) {
+exports._bindDir = function (name, node, desc, def, host, scope) {
   this._directives.push(
-    new Directive(name, node, this, desc, def, host)
+    new Directive(name, node, this, desc, def, host, scope)
   )
 }
 

+ 2 - 0
src/vue.js

@@ -86,4 +86,6 @@ extend(p, require('./api/events'))
 extend(p, require('./api/child'))
 extend(p, require('./api/lifecycle'))
 
+Vue.directive('fast-repeat', require('./fast-repeat'))
+
 module.exports = _.Vue = Vue

+ 5 - 2
src/watcher.js

@@ -84,10 +84,12 @@ Watcher.prototype.addDep = function (dep) {
 Watcher.prototype.get = function () {
   this.beforeGet()
   var vm = this.vm
+  var scope = this.scope || vm
   var value
   try {
-    value = this.getter.call(vm, vm)
+    value = this.getter.call(scope, scope)
   } catch (e) {
+    debugger
     if (
       process.env.NODE_ENV !== 'production' &&
       config.warnExpressionErrors
@@ -125,12 +127,13 @@ Watcher.prototype.get = function () {
 
 Watcher.prototype.set = function (value) {
   var vm = this.vm
+  var scope = this.scope || vm
   if (this.filters) {
     value = vm._applyFilters(
       value, this.value, this.filters, true)
   }
   try {
-    this.setter.call(vm, vm, value)
+    this.setter.call(scope, scope, value)
   } catch (e) {
     if (
       process.env.NODE_ENV !== 'production' &&