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

refactor: split server-renderer props handling into separate module

Evan You 10 лет назад
Родитель
Сommit
67da70d5bc

+ 21 - 22
src/platforms/web/server/modules/attrs.js

@@ -3,43 +3,42 @@
 import {
   isBooleanAttr,
   isEnumeratedAttr,
-  isFalsyAttrValue,
-  propsToAttrMap
-} from 'web/util/index'
+  isFalsyAttrValue
+} from 'web/util/attrs'
 
 export default function renderAttrs (node: VNodeWithData): ?string {
-  if (node.data.attrs || node.data.props || node.data.staticAttrs) {
+  if (node.data.attrs || node.data.staticAttrs) {
     return (
-      serialize(node.data.staticAttrs) +
-      serialize(node.data.attrs) +
-      serialize(node.data.props, true)
+      render(node.data.staticAttrs) +
+      render(node.data.attrs)
     )
   }
 }
 
-function serialize (attrs: ?{ [key: string]: any }, asProps?: boolean): string {
+function render (attrs: ?{ [key: string]: any }): string {
   let res = ''
   if (!attrs) {
     return res
   }
-  for (let key in attrs) {
+  for (const key in attrs) {
     if (key === 'style') {
       // leave it to the style module
       continue
     }
-    if (asProps) {
-      key = propsToAttrMap[key] || key.toLowerCase()
-    }
-    const value = attrs[key]
-    if (isBooleanAttr(key)) {
-      if (!isFalsyAttrValue(value)) {
-        res += ` ${key}="${key}"`
-      }
-    } else if (isEnumeratedAttr(key)) {
-      res += ` ${key}="${isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true'}"`
-    } else if (!isFalsyAttrValue(value)) {
-      res += ` ${key}="${value}"`
-    }
+    res += renderAttr(key, attrs[key])
   }
   return res
 }
+
+export function renderAttr (key: string, value: string): string {
+  if (isBooleanAttr(key)) {
+    if (!isFalsyAttrValue(value)) {
+      return ` ${key}="${key}"`
+    }
+  } else if (isEnumeratedAttr(key)) {
+    return ` ${key}="${isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true'}"`
+  } else if (!isFalsyAttrValue(value)) {
+    return ` ${key}="${value}"`
+  }
+  return ''
+}

+ 2 - 0
src/platforms/web/server/modules/index.js

@@ -1,9 +1,11 @@
 import attrs from './attrs'
+import props from './props'
 import klass from './class'
 import style from './style'
 
 export default [
   attrs,
+  props,
   klass,
   style
 ]

+ 18 - 0
src/platforms/web/server/modules/props.js

@@ -0,0 +1,18 @@
+/* @flow */
+
+import { renderAttr } from './attrs'
+import { propsToAttrMap, isRenderableAttr } from 'web/util/attrs'
+
+export default function (node: VNodeWithData): ?string {
+  const props = node.data.props
+  if (props) {
+    let res = ''
+    for (const key in props) {
+      const attr = propsToAttrMap[key] || key.toLowerCase()
+      if (isRenderableAttr(attr)) {
+        res += renderAttr(attr, props[key])
+      }
+    }
+    return res
+  }
+}

+ 24 - 0
src/platforms/web/util/attrs.js

@@ -16,6 +16,30 @@ export const isBooleanAttr = makeMap(
   'truespeed,typemustmatch,visible'
 )
 
+const isAttr = makeMap(
+  'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,' +
+  'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,' +
+  'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,' +
+  'name,contenteditable,contextmenu,controls,coords,data,datetime,default,' +
+  'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,' +
+  'form,formaction,headers,<th>,height,hidden,high,href,hreflang,http-equiv,' +
+  'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,' +
+  'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,' +
+  'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,' +
+  'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,' +
+  'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,' +
+  'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,' +
+  'target,title,type,usemap,value,width,wrap'
+)
+
+export const isRenderableAttr = (name: string): boolean => {
+  return (
+    isAttr(name) ||
+    name.indexOf('data-') === 0 ||
+    name.indexOf('aria-') === 0
+  )
+}
+
 export const propsToAttrMap = {
   acceptCharset: 'accept-charset',
   className: 'class',