Parcourir la source

fix SSR v-show render. (#5224)

* fix SSR v-show bug. v-show info needs to be merged from parent to child component

* improve variable name

* update test case

* update test case
chengchao il y a 9 ans
Parent
commit
e733e5cee8
2 fichiers modifiés avec 95 ajouts et 2 suppressions
  1. 26 2
      src/server/render.js
  2. 69 0
      test/ssr/ssr-string.spec.js

+ 26 - 2
src/server/render.js

@@ -144,6 +144,22 @@ function hasAncestorData (node: VNode) {
   return parentNode && (parentNode.data || hasAncestorData(parentNode))
 }
 
+function getVShowDirectiveInfo (node: VNode): ?VNodeDirective {
+  let dir: VNodeDirective
+  let tmp
+
+  while (node) {
+    if (node.data && node.data.directives) {
+      tmp = node.data.directives.find(dir => dir.name === 'show')
+      if (tmp) {
+        dir = tmp
+      }
+    }
+    node = node.parent
+  }
+  return dir
+}
+
 function renderStartingTag (node: VNode, context) {
   let markup = `<${node.tag}`
   const { directives, modules } = context
@@ -158,14 +174,22 @@ function renderStartingTag (node: VNode, context) {
     const dirs = node.data.directives
     if (dirs) {
       for (let i = 0; i < dirs.length; i++) {
-        const dirRenderer = directives[dirs[i].name]
-        if (dirRenderer) {
+        const name = dirs[i].name
+        const dirRenderer = directives[name]
+        if (dirRenderer && name !== 'show') {
           // directives mutate the node's data
           // which then gets rendered by modules
           dirRenderer(node, dirs[i])
         }
       }
     }
+
+    // v-show directive needs to be merged from parent to child
+    const vshowDirectiveInfo = getVShowDirectiveInfo(node)
+    if (vshowDirectiveInfo) {
+      directives.show(node, vshowDirectiveInfo)
+    }
+
     // apply other modules
     for (let i = 0; i < modules.length; i++) {
       const res = modules[i](node)

+ 69 - 0
test/ssr/ssr-string.spec.js

@@ -240,6 +240,75 @@ describe('SSR: renderToString', () => {
     })
   })
 
+  it('v-show directive render', done => {
+    renderVmWithOptions({
+      template: '<div v-show="false"><span>inner</span></div>'
+    }, res => {
+      expect(res).toContain(
+        '<div server-rendered="true" style="display:none;"><span>inner</span></div>'
+      )
+      done()
+    })
+  })
+
+  it('v-show directive not passed to child', done => {
+    renderVmWithOptions({
+      template: '<foo v-show="false"></foo>',
+      components: {
+        foo: {
+          template: '<div><span>inner</span></div>'
+        }
+      }
+    }, res => {
+      expect(res).toContain(
+        '<div server-rendered="true" style="display:none;"><span>inner</span></div>'
+      )
+      done()
+    })
+  })
+
+  it('v-show directive not passed to slot', done => {
+    renderVmWithOptions({
+      template: '<foo v-show="false"><span>inner</span></foo>',
+      components: {
+        foo: {
+          template: '<div><slot></slot></div>'
+        }
+      }
+    }, res => {
+      expect(res).toContain(
+        '<div server-rendered="true" style="display:none;"><span>inner</span></div>'
+      )
+      done()
+    })
+  })
+
+  it('v-show directive merging on components', done => {
+    renderVmWithOptions({
+      template: '<foo v-show="false"></foo>',
+      components: {
+        foo: {
+          render: h => h('bar', {
+            directives: [{
+              name: 'show',
+              value: true
+            }]
+          }),
+          components: {
+            bar: {
+              render: h => h('div', 'inner')
+            }
+          }
+        }
+      }
+    }, res => {
+      expect(res).toContain(
+        '<div server-rendered="true" style="display:none;">inner</div>'
+      )
+      done()
+    })
+  })
+
   it('text interpolation', done => {
     renderVmWithOptions({
       template: '<div>{{ foo }} side {{ bar }}</div>',