Просмотр исходного кода

fix component attrs/domProps merging in SSR

Evan You 9 лет назад
Родитель
Сommit
e5f23d9fa0

+ 17 - 3
src/platforms/web/server/modules/attrs.js

@@ -8,14 +8,28 @@ import {
 
 export default function renderAttrs (node: VNodeWithData): string {
   let res = ''
-  if (node.data.attrs) {
-    res += render(node.data.attrs)
+  if (node.data.attrs || node.parent) {
+    res += render(node)
   }
   return res
 }
 
-function render (attrs: { [key: string]: any }): string {
+function render (node): string {
+  let attrs = node.data.attrs
   let res = ''
+
+  let parent = node.parent
+  while (parent) {
+    if (parent.data && parent.data.attrs) {
+      attrs = Object.assign({}, attrs, parent.data.attrs)
+    }
+    parent = parent.parent
+  }
+
+  if (!attrs) {
+    return res
+  }
+
   for (const key in attrs) {
     if (key === 'style') {
       // leave it to the style module

+ 24 - 13
src/platforms/web/server/modules/dom-props.js

@@ -4,20 +4,31 @@ import VNode from 'core/vdom/vnode'
 import { renderAttr } from './attrs'
 import { propsToAttrMap, isRenderableAttr } from 'web/util/attrs'
 
-export default function (node: VNodeWithData): string {
-  const props = node.data.domProps
+export default function renderDOMProps (node: VNodeWithData): string {
+  let props = node.data.domProps
   let res = ''
-  if (props) {
-    for (const key in props) {
-      if (key === 'innerHTML') {
-        setText(node, props[key], true)
-      } else if (key === 'textContent') {
-        setText(node, props[key])
-      } else {
-        const attr = propsToAttrMap[key] || key.toLowerCase()
-        if (isRenderableAttr(attr)) {
-          res += renderAttr(attr, props[key])
-        }
+
+  let parent = node.parent
+  while (parent) {
+    if (parent.data && parent.data.domProps) {
+      props = Object.assign({}, props, parent.data.domProps)
+    }
+    parent = parent.parent
+  }
+
+  if (!props) {
+    return res
+  }
+
+  for (const key in props) {
+    if (key === 'innerHTML') {
+      setText(node, props[key], true)
+    } else if (key === 'textContent') {
+      setText(node, props[key])
+    } else {
+      const attr = propsToAttrMap[key] || key.toLowerCase()
+      if (isRenderableAttr(attr)) {
+        res += renderAttr(attr, props[key])
       }
     }
   }

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

@@ -167,6 +167,42 @@ describe('SSR: renderToString', () => {
     })
   })
 
+  it('attrs merging on components', done => {
+    const Test = {
+      render: h => h('div', {
+        attrs: { id: 'a' }
+      })
+    }
+    renderVmWithOptions({
+      render: h => h(Test, {
+        attrs: { id: 'b', name: 'c' }
+      })
+    }, res => {
+      expect(res).toContain(
+        '<div id="b" server-rendered="true" name="c"></div>'
+      )
+      done()
+    })
+  })
+
+  it('domProps merging on components', done => {
+    const Test = {
+      render: h => h('div', {
+        domProps: { innerHTML: 'a' }
+      })
+    }
+    renderVmWithOptions({
+      render: h => h(Test, {
+        domProps: { innerHTML: 'b', value: 'c' }
+      })
+    }, res => {
+      expect(res).toContain(
+        '<div server-rendered="true" value="c">b</div>'
+      )
+      done()
+    })
+  })
+
   it('text interpolation', done => {
     renderVmWithOptions({
       template: '<div>{{ foo }} side {{ bar }}</div>',