Skip to content

组件解析

D2C PRO 能将设计组件映射到前端组件上。这意味着你可以轻松地生成真实可交互的前端代码。

如何使用

建议你在尝试编写时:

  • 了解前端组件库的 Props 属性
  • 至少完成了一个设计组件的结构设计,或使用我们为你提供的 组件模版
  • 根据学习路径,顺便了解 样式解析器渲染器选项 的作用

起步

我们将从第一个组件开始,由浅入深的学习,让你轻松掌握整个过程。以确保你能轻松生成符合项目需求的代码。

alt text

首先我们创建了一个 名为 <button> 的组件和它的各种变体。同时还选择了 text 图层作为组件的文本内容。下面我要做的是在 DSM 的 组件解析配置 (component_parsers.json) 文件中编写解析这个 button 组件的配置。

最简单的组件解析配置

下面的代码,用于声明你要解析的组件名称。

json
// component_parsers.json
{
  "button": {},
  "input": {},
  "select": {},
}

注意

如果设计师的组件库习惯使用中文,并且未与前端组件的名称和属性保持一致,你需要在 DSM 中为组件设置别名。这样在识别组件时会使用别名来替代组件名称。

同时,D2C PRO 会将使用 <> 尖括号包裹的图层名称标记为一个前端组件,例如 <button> <input> <select>。此时,你在生成代码的时候会得到:

html
<button></button>
<input />
<select></select>
<!-- 如果你在 特征设置 中设置了组件前缀将得到 -->
<el-button></el-button>

但是它并没有输出任何内容和属性。此时你需要通过 渲染器选项 来为组件添加它的渲染内容。

渲染器选项

通过 渲染器选项 可以为组件定制组件的解析方式。

json
"button": {
  "props": {},
  "text": {
    "params": {
      "nodeName": "text"
    }
  },
  "type": {
    "params": {
      "valueFrom": "background"
    }
  },
  "disabled": {},
  "flex": {}
},

其它的组件配置方式与 button 配置方式类似。D2C PRO 提供了一套演示组件和配置,你可以在 资源社区 中下载并演示。

组件名称重写 name 1.0.7

你可以为组件设置 name 选项以重写组件的名称

json
"button": {
  ...
}
// 默认渲染为
<button>...</button>

// 增加 name 选项
"button": {
  "name": "my-button"
}
// 渲染为
<my-button>...</my-button>

使用样式解析器来解析多个图层

通常在组件制作时,我们会读取的多个图层的属性来作为组件的属性。例如:

html
<el-statistic title="Title text" value="Description text" />

该组件需要读取一个文本层的内容来设置 title,并将另一文本层的内容设置为 value。 在这种情况下,你可以使用数组类型样式解析器来分别解析这两层。 这是一个例子:

alt text

注意

可能你会尝试下面的写法。但它是不能正常工作的,因为第二个text解析器会覆盖第一个text解析器。

json
// 错误示例
"Component": {
  "text": {
    "nodeName": "_title",
    "textAttr": "title"
  },
  "text": {
    "nodeName": "_value",
    "textAttr": "value"
  }
}

正确的方法是使用数组

json
// 正确的示例
"Component": {
  "text": [
    {
      "nodeName": "_title",
      "textAttr": "title"
    },
    {
      "nodeName": "_value",
      "textAttr": "value"
    }
  ]
}

你也可以在下面的配置中找到类似的使用示例

属性解析 props

props 用于读取和解析设计文件中的组件属性。参考设计组件制作规范

json
"props": {
  "filter": ["md", "default", "false"]
}

默认设置了3种过滤的属性,当你的设计组件实例使用了以上属性,它将不会被解析成代码。如果你不想过滤任何属性,请设置:

json
"props": {
  "filter": ""
}

showTrueValue

  • Type: boolan
  • Default: false

是否显示 true 值。通常情况下,true 值会被忽略。例如:

jsx
"props": {
  "showTrueValue": false
}
// 输出
<Button disabled />

"showTrueValue": true
// 输出
<Button disabled={true} />

遍历解析 traverse

通常情况下,遍历解析器会在解析组件时检查组件解析器提供的条件,然后决定是否继续渲染子节点。这样一来,你可以根据自己的需求来控制组件的解析结果。

json
"traverse": {
  "filter": ""
  // 可以通过 filter 过滤选项来排除不用遍历的节点名称
}

如果你设置了特征配置的 ignore_prefixes ,系统将优先过滤配置里的节点名称。

TIP

traverse attrstype 解析器是专门为组件解析器设计的。在阅读组件解析器文档时,你会经常遇到它们。

多用途属性解析 attr

attr 是一个多用途属性解析器,它支持 background borderColor color radius borderStyle opacity gap padding boxShadow 的样式解析。你可以通过设置 渲染器选项 来自定义输出的结果。

它能做什么?

我们可以通过 attr 属性来获取节点的指定样式,从而给组件加上相应的属性,这可以帮助你大量的减少组件变体的制作。

例如,当你希望给按钮输出一个 outlined 属性,你可以使用 mappings 来映射 borderColor 的样式:

jsx
"button": {
  "props": {},
  "flex": {},
  "attr": [
    {
      "valueFrom": "borderColor",
      "attrName": "variant",
      "mappings": {
        "primary": "outlined",
        "success": "outlined",
        "warning": "outlined",
        "danger": "outlined",
        "info": "outlined"
      }
    }
  ]
}
// output
<Button variant="outlined" color="error">
  Error
</Button>

案例 2:

根据没填充背景色的按钮来输出 text 属性

jsx
"button": {
  "props": {},
  "flex": {},
  "attr": [
    {
      "valueFrom": "borderColor",
      // ......
    },
    {
      "valueFrom": "background",
      "attrName": "variant",
      "mappings": {
        "none": "text"
      }
    }
  ]
}
// 可以得到下面的结果
<Button variant="text">
  TEXT
</Button>

案例 3:

根据圆角的值来获得一个药丸形态的按钮

jsx
"button": {
  "props": {},
  "flex": {},
  "attr": [
    {
      "valueFrom": "borderColor",
      // ......
    },
    {
      "valueFrom": "background",
      // ......
    },
    {
      "valueFrom": "radius",
      "attrName": "shape",
      "mappings": {
        "9999px": "round"
      }
    }
  ]
}
// 可以得到下面的结果
<Button shape="round">
  Round Button
</Button>

案例 4:

通过颜色来判断组件的 type 类型

jsx
"button": {
  "props": {},
  "flex": {},
  "attr": {
    "valueFrom": "background",
    "attrName": "type",
    "mappings": {
      "el-color-primary": "primary", // 通过代码语法来映射
      "#67C23A": "success", // 直接使用色值映射
      "#E6A23C": "warning",
      "#F56C6C": "danger",
      "#909399": "info"
    }
  }
}
// 可以得到下面的结果
<Button type="primary">
  Button
</Button>

图标解析 icon

解 使用 icon 解析器,可用于解析的图标组件。你可以通过设置 nodeName 来获取指定图标图层的名称。例如我们为 Button 组件设置图标属性:

jsx
"Button": {
  "props": {},
  "text": {
    "nodeName": "_text"
  },
  "flex": {},
  "icon": {
    "attrName": "icon",
    "nodeName": {
      "name": "icon",
      "deepFind": true
    }
  }
}

// 可以得到下面的结果
<el-button type="primary" :icon="SearchOutlined">
  Search
</el-button>

// React 的组件可能是这样
<Button type="primary" icon={<SearchOutlined />}>
  Search
</Button>

使用 getComponentName 将组件里的图标渲染为指定的值

  • Type: boolanstring
  • Default: false

getComponentName 可以设置渲染为 变量对象 或者 字符串。例如我们解析一个 React 的图标组件:

jsx
"Icon": {
  "icon": {
    "nodeName": {
      "name": "icons",
      "deepFind": true
    },
    "attrName": "value",
    "getComponentName": false
  }
}
// 渲染为 对象
<Icon value={<SmileOutlined />} />

// 渲染为 变量
"getComponentName": true
<Icon value={SmileOutlined} />

// 渲染为 字符串
"getComponentName": "string"
<Icon value="SmileOutlined"} />

使用 childComponent 将 「图标图层」 渲染为子元素

  • childComponent: false | true | options
  • options:
    • parentType: slotframe
    • parentTag: template | div 或任意前端标签

默认情况下,icon 解析器会将图标渲染为组件属性。但是,你也可以通过设置 childComponent 来将图标渲染为一个单独的子元素。例如:

js
// 例如,我们有一个名为 Button 的组件
// 并且,假如你的图标名称为 @SearchOutlined

"Button": {
  // ... 
  // 解析图标组件
  "icon": {
    "nodeName": {
      "name": "icon",
      "deepFind": true
    },
    "childComponent": true
  }
}
// 可以得到下面的结果
<Button>
  <SearchOutlined />
</Button>

// 你也可以给 childComponent 设置父元素的属性
"Button": {
  // ... 
  // 解析图标组件
  "icon": {
    "nodeName": {
      "name": "icon",
      "deepFind": true
    },
    "attrName": "#icon", // 设置图标组件的属性名称为 #icon
    "childComponent": {
      "parentType": "slot",  // 设置图标组件的父元素类型为 slot
      "parentTag": "template" // 设置图标组件的父元素标签为 template
    }
  }
}

// 可以得到下面的结果
<Button>
  <template #icon>
    <SearchOutlined />
  </template>
</Button>

// 或者
"Button": {
  // ... 
  // 解析图标组件
  "icon": {
    "nodeName": {
      "name": "icon",
      "deepFind": true
    },
    "childComponent": {
      "parentType": "frame",  // 类型为容器
      "parentTag": "div" // 标签为 div
    }
  }
}

// 可以得到下面的结果
<Button>
  <div>
    <SearchOutlined />
  </div>
</Button>

公共图标组件

如果你想批量解析图标,而不希望为每个图标都单独配置组件解析。你可以在设计文件中将图标图层名称设置一个 icon_prefix 规则,即可自动解析为图标组件,并得到以下的结果:

jsx
// 图层名称
// @SearchOutlined

<SearchOutlined />

如果你需要公共图标组件可以输出样式属性,你可以按如下设置:

json
// 1. 打开 component-parsers 配置界面
// 2 .在文件中添加:

"@icons": {
  "width": {
    "filter": "",
    "classPrefix": "",
    "stylePrefix": "font-size",
    "getCssVar": true
  },
  "background": {
    "classPrefix": "",
    "stylePrefix": "color",
    "nodeName": {
      "name": "Vector",
      "deepFind": true
    }
  },
},
// 其它的组件解析配置 ... 

// 你将得到如下结果:
<SearchOutlined fontSize="24px"  color="#000"/>

公共文本组件

为你的文本内容使用特定的标签,例如 <text>name</text>,这能有效避免频繁调用“文本组件”的繁琐操作。

json
// 1. 打开 component-parsers 配置界面
// 2 .在文件中添加:
 "@text": {
    "name": "abc-text", // 使用重命名属性
    "text": {},
    "width": {},
    "height": {},
    "minWidth": {},
    "maxWidth": {},
    "minHeight": {},
    "maxHeight": {},
    "display": {},
    "flex": {},
    "justifyContent": {},
    "alignItems": {},
    "color": {},
    "fontSize": {},
    "fontFamily": {},
    "textAlign": {
      "filter": [
        "left",
        "text-left"
      ]
    },
    "fontWeight": {
      "filter": [
        "400"
      ]
    },
    "lineHeight": {},
    "letterSpacing": {},
    "background": {},
    "borderStyle": {},
    "borderColor": {},
    "borderWidth": {},
    "opacity": {},
    "boxShadow": {},
    "position": {}
  },
// 其它的组件解析配置 ... 

// 你将得到如下结果:
<abc-text>文本内容</abc-text>

插槽 #slot

在 MasterGo 中有一个独特的 插槽 功能,它与热门的前端框架中的插槽概念非常相似。例如 Vue SlotsReact PropsWXML 微信小程序 等。

首先我们在 MasterGo 里创建一个插槽。并将插槽的图层名称命名为 #slot 或者你定义的 slot_prefix。 如果你有DSM的访问权限,你也可以为插槽设置一个 slot_prefix 规则支持的别名。这样D2C PRO 会自动将它解析为一个插槽:

jsx
import React from 'react';
export default function Frame() {
  return (
    <Input
      placeholder="Input"
      prefix={
        <div
          style={{
            display: 'flex',
            justifyContent: 'flex-start',
            alignItems: 'center',
            flexDirection: 'row'
          }}>
          <span style={{ color: 'var(--ant-color-text)' }}>text</span>
        </div>
      }
      suffix={
        <UserOutlined
          style={{ fontSize: '14px', color: 'var(--ant-color-text)' }}
        />
      }
    />
  );
}

// vuejs
<template>
  <Input placeholder="Input">
    <template #prefix>
      <div
        style="display: flex; justify-content: flex-start; align-items: center; flex-direction: row">
        <span style="color: var(--ant-color-text)">text</span>
      </div>
    </template>
    <template #suffix>
      <UserOutlined style="font-size: 14px; color: var(--ant-color-text)" />
    </template>
  </Input>
</template>

对象解析器 object 1.0.8

你可以通过 object 对象解析器来将子组件渲染成一个数组对象

jsx
// 例如一个常见的 React 组件
const App: React.FC = () => <Tabs defaultActiveKey="1" items={[
  {
    key: '1',
    label: 'Tab 1',
    children: 'Content of Tab Pane 1',
  },
  {
    key: '2',
    label: 'Tab 2',
    children: 'Content of Tab Pane 2',
  },
  {
    key: '3',
    label: 'Tab 3',
    children: 'Content of Tab Pane 3',
  },
]} />;

// 在默认情况下会被渲染成这样:
<Tabs defaultActiveKey="1">
  <Tab.Item key="1" label="Tab 1">Content of Tab Pane 1</Tab.Item>
  <Tab.Item key="2" label="Tab 2">Content of Tab Pane 2</Tab.Item>
  <Tab.Item key="3" label="Tab 3">Content of Tab Pane 3</Tab.Item>
</Tabs>

使用 object 将其子组件渲染成对象

json
{
  "Tabs": {
    "props": {
      // 在解析属性时,使用 customProps 选项, {items} 为属性名称
      // 同时也指向子元素的 object 解析程序的 name
      "customProps": "{items}"
    },
    "traverse": {}
  },
  "Tab.Item": {
    "props": {},
    "traverse": {},
    "object": {
      "name": "items",
      "mappings": {
        "key": "",
        "label": {
          "text": {
            "nodeName": "_text"
          }
        },
        "children": {
          "text": {
            "nodeName": "_text"
          }
        }
      }
    }
  }
}