Quellcode durchsuchen

fix nested svg namespaces

Evan You vor 9 Jahren
Ursprung
Commit
579ff4ddbc

+ 1 - 4
src/compiler/parser/index.js

@@ -3,7 +3,7 @@
 import { decodeHTML } from 'entities'
 import { parseHTML } from './html-parser'
 import { parseText } from './text-parser'
-import { hyphenate, cached, no } from 'shared/util'
+import { cached, no } from 'shared/util'
 import {
   pluckModuleFunction,
   getAndRemoveAttr,
@@ -59,9 +59,6 @@ export function parse (
     expectHTML: options.expectHTML,
     isUnaryTag: options.isUnaryTag,
     start (tag, attrs, unary) {
-      // normalize tag name
-      tag = hyphenate(tag)
-
       // check namespace.
       // inherit parent ns if there is one
       const ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag)

+ 11 - 33
src/core/vdom/create-element.js

@@ -41,38 +41,16 @@ function _createElement (
     // in case of component :is set to falsy value
     return emptyVNode()
   }
-  if (typeof tag === 'string') {
-    const namespace = config.getTagNamespace(tag)
-    let Ctor
-    if (config.isReservedTag(tag)) {
-      return new VNode(
-        tag, data, normalizeChildren(children, namespace),
-        undefined, undefined,
-        namespace, context, host
-      )
-    } else if ((Ctor = resolveAsset(context.$options, 'components', tag))) {
-      return createComponent(Ctor, data, parent, context, host, children, tag)
-    } else {
-      if (process.env.NODE_ENV !== 'production') {
-        if (
-          !namespace &&
-          !(config.ignoredElements && config.ignoredElements.indexOf(tag) > -1) &&
-          config.isUnknownElement(tag)
-        ) {
-          warn(
-            'Unknown custom element: <' + tag + '> - did you ' +
-            'register the component correctly? For recursive components, ' +
-            'make sure to provide the "name" option.'
-          )
-        }
-      }
-      return new VNode(
-        tag, data, normalizeChildren(children, namespace),
-        undefined, undefined,
-        namespace, context, host
-      )
-    }
-  } else {
-    return createComponent(tag, data, parent, context, host, children)
+  const Ctor = typeof tag === 'string'
+    ? resolveAsset(context.$options, 'components', tag)
+    : tag
+  if (Ctor) {
+    return createComponent(Ctor, data, parent, context, host, children)
+  } else if (typeof tag === 'string') {
+    const ns = config.getTagNamespace(tag)
+    return new VNode(
+      tag, data, normalizeChildren(children, ns),
+      undefined, undefined, ns, context, host
+    )
   }
 }

+ 14 - 1
src/core/vdom/helpers.js

@@ -36,7 +36,9 @@ export function normalizeChildren (
           last.text += c.text
         } else {
           // inherit parent namespace
-          if (ns && c.tag) c.ns = ns
+          if (ns) {
+            applyNS(c, ns)
+          }
           res.push(c)
         }
       }
@@ -49,6 +51,17 @@ function createTextVNode (val) {
   return new VNode(undefined, undefined, undefined, String(val))
 }
 
+function applyNS (vnode, ns) {
+  if (vnode.tag && !vnode.ns) {
+    vnode.ns = ns
+    if (vnode.children) {
+      for (let i = 0, l = vnode.children.length; i < l; i++) {
+        applyNS(vnode.children[i], ns)
+      }
+    }
+  }
+}
+
 export function updateListeners (
   on: Object,
   oldOn: Object,

+ 15 - 0
src/core/vdom/patch.js

@@ -7,6 +7,7 @@
  * of making flow understand it is not worth it.
  */
 
+import config from '../config'
 import VNode from './vnode'
 import { isPrimitive, _toString, warn } from '../util/index'
 
@@ -90,6 +91,20 @@ export function createPatchFunction (backend) {
     const children = vnode.children
     const tag = vnode.tag
     if (isDef(tag)) {
+      if (process.env.NODE_ENV !== 'production') {
+        if (
+          !vnode.ns &&
+          !(config.ignoredElements && config.ignoredElements.indexOf(tag) > -1) &&
+          config.isUnknownElement(tag)
+        ) {
+          warn(
+            'Unknown custom element: <' + tag + '> - did you ' +
+            'register the component correctly? For recursive components, ' +
+            'make sure to provide the "name" option.',
+            vnode.context
+          )
+        }
+      }
       elm = vnode.elm = vnode.ns
         ? nodeOps.createElementNS(vnode.ns, tag)
         : nodeOps.createElement(tag)

+ 8 - 1
test/unit/features/options/el.spec.js

@@ -42,7 +42,11 @@ describe('Options el', () => {
 
   it('svg element', () => {
     const parent = document.createElement('div')
-    parent.innerHTML = '<svg><text :x="x" :y="y" :fill="color">{{ text }}</text></svg>'
+    parent.innerHTML =
+      '<svg>' +
+        '<text :x="x" :y="y" :fill="color">{{ text }}</text>' +
+        '<g><clipPath><foo></foo></clipPath></g>' +
+      '</svg>'
     const vm = new Vue({
       el: parent.childNodes[0],
       data: {
@@ -57,6 +61,9 @@ describe('Options el', () => {
     expect(vm.$el.childNodes[0].getAttribute('y')).toBe(vm.y.toString())
     expect(vm.$el.childNodes[0].getAttribute('fill')).toBe(vm.color)
     expect(vm.$el.childNodes[0].textContent).toBe(vm.text)
+    // nested, non-explicitly listed SVG elements
+    expect(vm.$el.childNodes[1].childNodes[0].namespaceURI).toContain('svg')
+    expect(vm.$el.childNodes[1].childNodes[0].childNodes[0].namespaceURI).toContain('svg')
   })
 
   it('warn cannot find element', () => {

+ 1 - 1
test/unit/modules/compiler/parser.spec.js

@@ -46,7 +46,7 @@ describe('parser', () => {
 
   it('camelCase element', () => {
     const ast = parse('<MyComponent><p>hello world</p></MyComponent>', baseOptions)
-    expect(ast.tag).toBe('my-component')
+    expect(ast.tag).toBe('MyComponent')
     expect(ast.plain).toBe(true)
     expect(ast.children[0].tag).toBe('p')
     expect(ast.children[0].plain).toBe(true)

+ 0 - 1
test/unit/modules/vdom/create-element.spec.js

@@ -62,7 +62,6 @@ describe('create-element', () => {
     expect(vnode.ns).toBeUndefined()
     expect(vnode.context).toEqual(vm)
     expect(vnode.componentOptions).toBeUndefined()
-    expect(`Unknown custom element: <${tag}> - did you`).toHaveBeenWarned()
   })
 
   it('render empty vnode with falsy tag using createElement', () => {

+ 6 - 0
test/unit/modules/vdom/patch/element.spec.js

@@ -16,6 +16,12 @@ describe('element', () => {
     expect(elm.namespaceURI).toBe('http://www.w3.org/2000/svg')
   })
 
+  it('should warn unknown element', () => {
+    const vnode = new VNode('unknown')
+    patch(null, vnode)
+    expect(`Unknown custom element: <unknown>`).toHaveBeenWarned()
+  })
+
   it('should create an elements which having text content', () => {
     const vnode = new VNode('div', {}, [createTextVNode('hello world')])
     const elm = patch(null, vnode)