Kaynağa Gözat

block instance + dom methods

Evan You 11 yıl önce
ebeveyn
işleme
e6ea813e06

+ 112 - 10
src/api/dom.js

@@ -1,19 +1,121 @@
-exports.$appendTo = function () {
-    
+var transition = require('../transition')
+
+/**
+ * Append instance to target
+ *
+ * @param {Node} target
+ * @param {Function} [cb]
+ */
+
+exports.$appendTo = function (target, cb) {
+  target = query(target)
+  if (this._isBlock) {
+    blockOp(this, target, transition.append, cb)
+  } else {
+    transition.append(this.$el, target, cb)
+  }
+}
+
+/**
+ * Prepend instance to target
+ *
+ * @param {Node} target
+ * @param {Function} [cb]
+ */
+
+exports.$prependTo = function (target, cb) {
+  target = query(target)
+  if (target.hasChildNodes()) {
+    this.$before(target.firstChild, cb)
+  } else {
+    this.$appendTo(target, cb)
+  }
+}
+
+/**
+ * Insert instance before target
+ *
+ * @param {Node} target
+ * @param {Function} [cb]
+ */
+
+exports.$before = function (target, cb) {
+  target = query(target)
+  if (this._isBlock) {
+    blockOp(this, target, transition.before, cb)
+  } else {
+    transition.before(this.$el, target, cb)
+  }
 }
 
-exports.$prependTo = function () {
-    
+/**
+ * Insert instance after target
+ *
+ * @param {Node} target
+ * @param {Function} [cb]
+ */
+
+exports.$after = function (target, cb) {
+  target = query(target)
+  if (target.nextSibling) {
+    this.$before(target.nextSibling)
+  } else {
+    this.$appendTo(target.parentNode)
+  }
 }
 
-exports.$before = function () {
-    
+/**
+ * Remove instance from DOM
+ *
+ * @param {Function} [cb]
+ */
+
+exports.$remove = function (cb) {
+  if (
+    this._isBlock &&
+    !this._blockFragment.hasChildNodes()
+  ) {
+    blockOp(
+      this,
+      this._blockFragment,
+      transition.removeThenAppend,
+      cb
+    )
+  } else if (this.$el.parentNode) {
+    transition.remove(this.$el, cb)
+  }
 }
 
-exports.$after = function () {
-    
+/**
+ * Execute a transition operation on a block instance,
+ * iterating through all its block nodes.
+ *
+ * @param {Vue} vm
+ * @param {Node} target
+ * @param {Function} op
+ * @param {Function} cb
+ */
+
+function blockOp (vm, target, op, cb) {
+  var current = vm._blockStart
+  var end = vm._blockEnd
+  var next
+  while (next !== end) {
+    next = current.nextSibling
+    op(current, target)
+    current = next
+  }
+  op(end, target, cb)
 }
 
-exports.$remove = function () {
-    
+/**
+ * Check for selectors
+ *
+ * @param {String|Element} el
+ */
+
+function query (el) {
+  return typeof el === 'string'
+    ? document.querySelector(el)
+    : el
 }

+ 1 - 1
src/api/global.js

@@ -14,7 +14,7 @@ var assetTypes = [
 exports.util       = _
 exports.nextTick   = _.nextTick
 exports.config     = require('../config')
-exports.transition = require('../transition/transition')
+exports.transition = require('../transition')
 
 /**
  * Class inehritance

+ 3 - 2
src/instance/compile.js

@@ -13,8 +13,9 @@ var templateParser = require('../parse/template')
  */
 
 exports._compile = function () {
-  if (this._blockNodes) {
-    this._blockNodes.forEach(this._compileNode, this)
+  if (this._isBlock) {
+    _.toArray(this._blockFragment.childNodes)
+      .forEach(this._compileNode, this)
   } else {
     this._compileNode(this.$el)
   }

+ 24 - 9
src/instance/element.js

@@ -18,19 +18,34 @@ exports._initElement = function (el) {
       _.warn('Cannot find element: ' + selector)
     }
   }
-  // If the passed in `el` is a DocumentFragment, the
-  // instance is considered a "block instance" which manages
-  // not a single element, but multiple elements. A block
-  // instance's `$el` is an Array of the elements it manages.
   if (el instanceof DocumentFragment) {
-    this._blockNodes = _.toArray(el.childNodes)
-    this.$el = document.createComment('vue-block')
+    this._initBlock(el)
   } else {
     this.$el = el
+    this._initTemplate()
+    this._initContent()
   }
   this.$el.__vue__ = this
-  this._initTemplate()
-  this._initContent()
+}
+
+/**
+ * Initialize a block instance that manages a group of
+ * nodes instead of one element. The group is denoted by
+ * a starting node and an ending node.
+ *
+ * @param {DocumentFragment} frag
+ */
+
+exports._initBlock = function (frag) {
+  this._isBlock = true
+  this.$el =
+  this._blockStart =
+    document.createComment('v-block-start')
+  this._blockEnd =
+    document.createComment('v-block-end')
+  _.prepend(this._blockStart, frag)
+  frag.appendChild(this._blockEnd)
+  this._blockFragment = frag
 }
 
 /**
@@ -147,7 +162,7 @@ var concat = [].concat
 function getOutlets (el) {
   return _.isArray(el)
     ? concat.apply([], el.map(getOutlets))
-    : _.toArray(el.getElementsByTagName('content'))
+    : _.toArray(el.querySelectorAll('content'))
 }
 
 /**

+ 4 - 1
src/instance/init.js

@@ -18,7 +18,6 @@ exports._init = function (options) {
 
   this.$el          = null
   this._data        = options.data || {}
-  this._blockNodes  = null
   this._isDestroyed = false
   this._rawContent  = null
   this._emitter     = new Emitter(this)
@@ -26,6 +25,10 @@ exports._init = function (options) {
   this._activeWatcher = null
   this._directives  = []
 
+  this._isBlock     = false
+  this._blockStart  = null
+  this._blockEnd    = null
+
   // setup parent relationship
   this.$parent = options.parent
   this._children = []

+ 23 - 0
src/transition/index.js

@@ -0,0 +1,23 @@
+var _ = require('../util')
+
+// TODO
+// placeholder for testing
+
+exports.append = function (el, target, cb) {
+  target.appendChild(el)
+}
+
+exports.before = function (el, target, cb) {
+  _.before(el, target)
+}
+
+exports.remove = function (el, cb) {
+  _.remove(el)
+}
+
+exports.removeThenAppend = function (el, target, cb) {
+  setTimeout(function () {
+    target.appendChild(el)
+    cb && cb()
+  }, 500)
+}

+ 0 - 0
src/transition/transition.js