Jelajahi Sumber

Fix inline partial parentNode problem

Directives inside inline partials would get the fragment as the parentNode
if they are compiled before the partial is appended to the correct parentNode.
Therefore keep the reference of the fragment's childNodes, append it,
then compile afterwards fixes the problem.
Evan You 12 tahun lalu
induk
melakukan
5f21eed2c9

+ 22 - 5
src/compiler.js

@@ -343,20 +343,24 @@ CompilerProto.compileNode = function (node) {
  *  Compile a text node
  */
 CompilerProto.compileTextNode = function (node) {
+
     var tokens = TextParser.parse(node.nodeValue)
     if (!tokens) return
-    var el, token, directive
+    var el, token, directive, partial, partialId, partialNodes
+
     for (var i = 0, l = tokens.length; i < l; i++) {
         token = tokens[i]
         if (token.key) { // a binding
             if (token.key.charAt(0) === '>') { // a partial
-                var partialId = token.key.slice(1).trim(),
-                    partial = this.getOption('partials', partialId)
+                partialId = token.key.slice(1).trim()
+                partial = this.getOption('partials', partialId)
                 if (partial) {
                     el = partial.cloneNode(true)
-                    this.compileNode(el)
+                    // save an Array reference of the partial's nodes
+                    // so we can compile them AFTER appending the fragment
+                    partialNodes = slice.call(el.childNodes)
                 }
-            } else { // a binding
+            } else { // a real binding
                 el = document.createTextNode('')
                 directive = Directive.parse('text', token.key, this, el)
                 if (directive) {
@@ -366,7 +370,20 @@ CompilerProto.compileTextNode = function (node) {
         } else { // a plain string
             el = document.createTextNode(token)
         }
+
+        // insert node
         node.parentNode.insertBefore(el, node)
+
+        // compile partial after appending, because its children's parentNode
+        // will change from the fragment to the correct parentNode.
+        // This could affect directives that need access to its element's parentNode.
+        if (partialNodes) {
+            for (var j = 0, k = partialNodes.length; j < k; j++) {
+                this.compile(partialNodes[j])
+            }
+            partialNodes = null
+        }
+
     }
     node.parentNode.removeChild(node)
 }

+ 18 - 3
test/functional/fixtures/template.html

@@ -8,15 +8,20 @@
     <body>
 
         <div id="usa" v-partial="global"></div>
-        <div id="japan" v-partial="local"></div>
+        <div id="japan">{{> local}}</div>
+        <div id="repeat">{{> repeat}}</div>
 
         <script type="text/v-template" id="test">
             <p>{{hi}}!</p>
         </script>
 
+        <script type="text/v-template" id="repeat-template">
+            <p v-repeat="items">{{title}}</p>
+        </script>
+
         <script>
 
-            Vue.config({debug:true})
+           // Vue.config({debug:true})
 
             // direct usage
             var china  = new Vue({
@@ -48,10 +53,20 @@
             var japan = new Vue({
                 el: '#japan',
                 partials: {
-                    local: document.querySelector('#test').innerHTML
+                    local: '#test'
                 }
             })
             japan.hi = 'こんにちは'
+
+            var repeat = new Vue({
+                el: '#repeat',
+                partials: {
+                    repeat: '#repeat-template'
+                },
+                data: {
+                    items: [{ title: 'Repeat' }]
+                }
+            })
         </script>
     </body>
 </html>

+ 2 - 1
test/functional/specs/template.js

@@ -1,4 +1,4 @@
-casper.test.begin('Template', 4, function (test) {
+casper.test.begin('Templates and Partials', 5, function (test) {
     
     casper
     .start('./fixtures/template.html')
@@ -7,6 +7,7 @@ casper.test.begin('Template', 4, function (test) {
         test.assertSelectorHasText('#japan', 'こんにちは', 'local partial')
         test.assertSelectorHasText('#china', '你好', 'direct option')
         test.assertSelectorHasText('#hawaii', 'Aloha', 'extend option')
+        test.assertSelectorHasText('#repeat', 'Repeat', 'inline partial with repeat')
     })
     .run(function () {
         test.done()