Parcourir la source

handle dynamic class

Evan You il y a 9 ans
Parent
commit
36bdf48550

+ 8 - 4
flow/component.js

@@ -1,7 +1,6 @@
 import type { Config } from '../src/core/config'
 import type VNode from '../src/core/vdom/vnode'
 import type Watcher from '../src/core/observer/watcher'
-import type StringNode from '../src/server/optimizing-compiler/runtime-helpers'
 
 declare interface Component {
   // constructor information
@@ -110,9 +109,14 @@ declare interface Component {
   _u: (scopedSlots: ScopedSlotsData, res?: Object) => { [key: string]: Function };
 
   // SSR specific
-  _ssrNode: (open: string, close?: string, ) => StringNode;
-  _ssrList: (val: any, render: () => string) => string;
-  _ssrEscape: (v: string) => string;
+  _ssrNode: Function;
+  _ssrList: Function;
+  _ssrEscape: Function;
+  _ssrAttr: Function;
+  _ssrAttrs: Function;
+  _ssrDOMProps: Function;
+  _ssrClass: Function;
+  _ssrStyle: Function;
 
   // allow dynamic method registration
   [key: string]: any

+ 2 - 3
src/platforms/web/server/modules/style.js

@@ -4,9 +4,8 @@ import { escape } from 'he'
 import { hyphenate } from 'shared/util'
 import { getStyle } from 'web/util/style'
 
-function genStyleText (vnode: VNode): string {
+export function genStyle (style: Object): string {
   let styleText = ''
-  const style = getStyle(vnode, false)
   for (const key in style) {
     const value = style[key]
     const hyphenatedKey = hyphenate(key)
@@ -22,7 +21,7 @@ function genStyleText (vnode: VNode): string {
 }
 
 export default function renderStyle (vnode: VNodeWithData): ?string {
-  const styleText = genStyleText(vnode)
+  const styleText = genStyle(getStyle(vnode, false))
   if (styleText !== '') {
     return ` style=${JSON.stringify(escape(styleText))}`
   }

+ 5 - 4
src/platforms/web/util/class.js

@@ -17,7 +17,7 @@ export function genClassForVnode (vnode: VNode): string {
       data = mergeClassData(data, parentNode.data)
     }
   }
-  return genClassFromData(data)
+  return renderClass(data.staticClass, data.class)
 }
 
 function mergeClassData (child: VNodeData, parent: VNodeData): {
@@ -32,9 +32,10 @@ function mergeClassData (child: VNodeData, parent: VNodeData): {
   }
 }
 
-function genClassFromData (data: Object): string {
-  const dynamicClass = data.class
-  const staticClass = data.staticClass
+export function renderClass (
+  staticClass: ?string,
+  dynamicClass: any
+): string {
   if (isDef(staticClass) || isDef(dynamicClass)) {
     return concat(staticClass, stringifyClass(dynamicClass))
   }

+ 11 - 7
src/server/optimizing-compiler/codegen.js

@@ -17,6 +17,8 @@ import {
 import {
   genAttrSegments,
   genDOMPropSegments,
+  genClassSegments,
+  genStyleSegments,
   applyModelTransform
 } from './modules'
 
@@ -164,15 +166,17 @@ function elementToOpenTagSegments (el, state): Array<StringSegment> {
   }
   // class
   if (el.staticClass || el.classBinding) {
-    if (el.staticClass && !el.classBinding) {
-      segments.push({ type: RAW, value: ` class=${el.staticClass}` })
-    } else {
-      // TODO
-    }
+    segments.push.apply(
+      segments,
+      genClassSegments(el.staticClass, el.classBinding)
+    )
   }
   // style & v-show
-  if (el.staticStyle || el.styleBinding) {
-    // TODO
+  if (el.staticStyle || el.styleBinding || el.attrsMap['v-show']) {
+    segments.push.apply(
+      segments,
+      genStyleSegments(el.staticStyle, el.styleBinding, el.attrsMap['v-show'])
+    )
   }
   // console.log(segments)
   segments.push({ type: RAW, value: `>` })

+ 25 - 2
src/server/optimizing-compiler/modules.js

@@ -56,10 +56,11 @@ export function genDOMPropSegments (
 
 function genAttrSegment (name: string, value: string): StringSegment {
   if (plainStringRE.test(value)) {
-    // TODO attr type checks
     return {
       type: RAW,
-      value: ` ${name}=${value}`
+      value: value === '""'
+        ? ` ${name}`
+        : ` ${name}=${value}`
     }
   } else {
     return {
@@ -68,3 +69,25 @@ function genAttrSegment (name: string, value: string): StringSegment {
     }
   }
 }
+
+export function genClassSegments (
+  staticClass: ?string,
+  classBinding: ?string
+): Array<StringSegment> {
+  if (staticClass && !classBinding) {
+    return [{ type: RAW, value: ` class=${staticClass}` }]
+  } else {
+    return [{
+      type: EXPRESSION,
+      value: `_ssrClass(${staticClass || 'null'},${classBinding || 'null'})`
+    }]
+  }
+}
+
+export function genStyleSegments (
+  staticStyle: ?string,
+  styleBinding: ?string,
+  vShowExpression: ?string
+): Array<StringSegment> {
+  return []
+}

+ 58 - 10
src/server/optimizing-compiler/runtime-helpers.js

@@ -3,21 +3,33 @@
 import { escape } from 'he'
 import { isObject } from 'shared/util'
 import { renderAttr } from 'web/server/modules/attrs'
+import { renderClass } from 'web/util/class'
+import { genStyle } from 'web/server/modules/style'
+
+import {
+  propsToAttrMap,
+  isRenderableAttr
+} from 'web/server/util'
 
 export function installSSRHelpers (vm: Component) {
+  if (vm._ssrNode) return
   let Ctor = vm.constructor
   while (Ctor.super) {
     Ctor = Ctor.super
   }
-  if (!Ctor.prototype._ssrNode) {
-    Ctor.prototype._ssrNode = createStringNode
-    Ctor.prototype._ssrList = createStringList
-    Ctor.prototype._ssrEscape = escape
-    Ctor.prototype._ssrAttr = renderAttr
-  }
+  Object.assign(Ctor.prototype, {
+    _ssrEscape: escape,
+    _ssrNode: renderStringNode,
+    _ssrList: renderStringList,
+    _ssrAttr: renderAttr,
+    _ssrAttrs: renderAttrs,
+    _ssrDOMProps: renderDOMProps,
+    _ssrClass: renderSSRClass,
+    _ssrStyle: renderSSRStyle
+  })
 }
 
-export class StringNode {
+class StringNode {
   isString: boolean;
   open: string;
   close: ?string;
@@ -31,15 +43,15 @@ export class StringNode {
   }
 }
 
-function createStringNode (
+function renderStringNode (
   open: string,
   close?: string,
   children?: Array<any>
-) {
+): StringNode {
   return new StringNode(open, close, children)
 }
 
-function createStringList (val: any, render: () => string): string {
+function renderStringList (val: any, render: () => string): string {
   let ret = ''
   let i, l, keys, key
   if (Array.isArray(val) || typeof val === 'string') {
@@ -59,3 +71,39 @@ function createStringList (val: any, render: () => string): string {
   }
   return ret
 }
+
+function renderAttrs (obj: Object): string {
+  let res = ''
+  for (const key in obj) {
+    res += renderAttr(key, obj[key])
+  }
+  return res
+}
+
+function renderDOMProps (obj: Object): string {
+  let res = ''
+  for (const key in obj) {
+    const attr = propsToAttrMap[key] || key.toLowerCase()
+    if (isRenderableAttr(attr)) {
+      res += renderAttr(attr, obj[key])
+    }
+  }
+  return res
+}
+
+function renderSSRClass (
+  staticClass: ?string,
+  dynamic: any
+): string {
+  const res = renderClass(staticClass, dynamic)
+  return res === '' ? res : ` class="${escape(res)}"`
+}
+
+function renderSSRStyle (
+  staticStyle: ?Object,
+  dynamic: any,
+  extra: ?Object
+): string {
+  // TODO
+  return genStyle({})
+}