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 attrs 和 type 解析器是专门为组件解析器设计的。在阅读组件解析器文档时,你会经常遇到它们。

多用途属性解析 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: boolan | string
  • 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: slot | frame
    • 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 Slots 、 React Props 和 WXML 微信小程序 等。

首先我们在 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"
          }
        }
      }
    }
  }
}