基础开发步骤

本文整体阐述自定义页面组件开发的开发步骤。

概述

开发自定义页面组件,一般分为三步:

  1. 开发满足功能的react组件

  2. 配置自定义页面组件的prop和配置文件。

  3. 包装react组件,处理prop的加工传递。

image

步骤一、开发react组件

开发自定义页面组件,本质上是开发一个react组件,或者说形式上是一个react组件。

自定义页面组件包含桌面端组件和移动端组件,两者开发逻辑相同,区别是移动端组件只能使用taro组件库,而不能使用fusion等其它的组件库。

首先需要基于待开发组件的功能需求,开发一个react组件。组件需要的参数都通过prop传入,组件需要向外传递的数据或者触发的事件,通过函数prop以回调的形式传入,通过回调函数返回或者触发相关逻辑。

例如,一个简单的数字选择组件DemoComponent,需要以下prop:

  1. title :一个用于展示的标题文本。

  2. num: 一个受控数据。

  3. onNumChange: num变化时的回调接口。

  • 桌面端组件代码示例:

    import React from 'react';
    import { NumberPicker } from '@alifd/next';
    
    const DemoComponent = (props: { title: string; num: number; onNumChange: (num) => void }) => {
      return (
        <div>
          <span>{props.title}</span>
          <NumberPicker value={props.num} onChange={props.onNumChange} />
        </div>
      );
    };
    export default DemoComponent;
  • 移动端组件代码示例(使用taro组件库):

    import React from 'react';
    import { View, Input } from '@tarojs/components';
    import '@tarojs/components/dist/taro-components/taro-components.css';
    
    const DemoComponent = (props: { title: string; num: number; onNumChange: (num) => void }) => {
      return (
        <View style={{ lineHeight: 1 }}>
          <View>Title:</View>
          <View>{props.title}</View>
          <View>InputNum:</View>
          <Input
            type={'number'}
            value={props.num}
            onInput={(e) => {
              if (e.detail.value) {
                props.onNumChange(parseInt(e.detail.value));
              } else {
                props.onNumChange(undefined);
              }
            }}
          />
        </View>
      );
    };

步骤二、配置自定义页面组件的prop和配置文件

步骤一中开发了一个react组件DemoComponent,还不能在魔笔应用中使用,如果要放到魔笔中使用,还需要做自定义配置。

假设:

  1. title是静态的,可以通过setter设置title。

  2. num是动态的,可以通过setter设置一个实体字段。

配置文件关键部分如下:

  configure: [
    {
      name: "title",
      title: "标题",
      setter: {
        type: "text",
        props: {
          placeholder: '请输入标题'
        },
      },
    },
    {
      name: "num",
      title: "选择数字字段",
      setter: {
        type: "data-field",
        props: {
          supportFieldType: ["integer", "long", "decimal"],
        },
      },
    },
  ],

此处配置了两个prop:

  1. title

    1. setter是text。

    2. 在属性设置器中的标题是 “标题”。

  2. num

    1. setter是data-field。

    2. 在属性设置器中的标题是 “选择数字字段”。

此处为了便于理解对应关系,prop的名字(title,num)和组件的prop是对应的。

另外配置文件中还有一个很重要的componentName字段,表示组件名称,必须是全局唯一的。

完整的配置文件如下:

export default {
  version: "1.0",
  isContainer: false,
  canContain: false,
  canDraging: true,
  canDropIn: false,
  canDropTo: true,
  canHovering: true,
  canOperating: true,
  canSelecting: true,
  title: "Demo",
  componentName: "DemoComponent",
  // 高级 | 其他
  category: "基础",
  configure: [
    {
      name: "title",
      title: "标题",
      setter: {
        type: "text",
        props: {
          placeholder: '请输入标题'
        },
      },
    },
    {
      name: "num",
      title: "选择数字字段",
      setter: {
        type: "data-field",
        props: {
          supportFieldType: ["integer", "long", "decimal"],
        },
      },
    },
  ],
};

步骤三、包装、处理、传递prop

将魔笔的prop转化为组件需要的prop,并设置合理回调接口。具体内容如下:

  1. 处理传递prop。

  2. 处理回调响应。

  3. 设置配置文件。

  4. 设置监听。

步骤二、设计配置自定义页面组件的prop和配置文件中配置了两个prop, 如下:

const MobiComponent = (props: { title: string; num: any }) => {
  const { title, num } = props;

  return <DemoComponent />;
};

处理title prop

title是静态的文本类型,直接传递过去即可。

const MobiComponent = (props: { title: string; num: any }) => {
  const { title, num } = props;

  return <DemoComponent title={title}/>;
};

处理num prop

num是一个实体字段,在设计时,没有对应的数据,在运行时,才能获取数据。此时需要使用API,区分状态获取数据了。

import { useApi } from "../../../api/createApi";
const MobiComponent = (props: { title: string; num: any }) => {
  // 获取api
  const api = useApi(props);
  const { title, num } = props;

  // 设计时 就用0
  let numValue = 0;
  if(api.isPreview(props)) {
    // 运行时 获取具体数据
    numValue = api.getDcValue(props, {key: 'num'});
  }

  return <DemoComponent title={title} num={numValue}/>;
};

如上实现,就可以在设计时用0代替,在运行时使用真正的数据。

处理回调响应

DemoComponent会修改num,通过onNumChange回调返回修改后的值,在回调中需要调用API更新num对应的数据字段。

const MobiComponent = (props: { title: string; num: any }) => {
  // 获取api
  const api = useApi(props);
  const { title, num } = props;

  // 设计时 就用0
  let numValue = 0;
  if (api.isPreview(props)) {
    // 运行时 获取具体数据
    numValue = api.getDcValue(props, { key: "num" });
  }

  return (
    <DemoComponent
      title={title}
      num={numValue}
      onNumChange={(num) => {
        // 把回调的num,通过api,在设置回魔笔应用,key: "num" 确定了修改传入的num的数值
        api.setDcValue(props, { key: "num", uiValue: num });
      }}
    />
  );
};

设置配置文件

通过组件的config属性将配置文件和组件关联起来。

import config from "./config";
MobiComponent.config = config;

设置监听

当前示例开发的是一个受控组件,当数据变化时也需要修改num。魔笔应用是用mobx监听的数据,这一步引入mobx。

import { observer } from "mobx-react";
const MobiComponent = observer((props: { title: string; num: any }) => {
});

完整的组件代码示例

配置文件:

export default {
  version: "1.0",
  isContainer: false,
  canContain: false,
  canDraging: true,
  canDropIn: false,
  canDropTo: true,
  canHovering: true,
  canOperating: true,
  canSelecting: true,
  title: "Demo",
  componentName: "DemoComponent",
  // 高级 | 其他
  category: "基础",
  configure: [
    {
      name: "title",
      title: "标题",
      setter: {
        type: "text",
        props: {
          placeholder: '请输入标题'
        },
      },
    },
    {
      name: "num",
      title: "选择数字字段",
      setter: {
        type: "data-field",
        props: {
          supportFieldType: ["integer", "long", "decimal"],
        },
      },
    },
  ],
};

组件代码:

import React from "react";
import { NumberPicker } from "@alifd/next";
import { useApi } from "../../../api/createApi";
import config from "./config";
import { observer } from "mobx-react";

const DemoComponent = (props: {
  title: string;
  num: number;
  onNumChange: (num) => void;
}) => {
  return (
    <div>
      <span>{props.title}</span>
      <NumberPicker value={props.num} onChange={props.onNumChange} />
    </div>
  );
};

const MobiComponent = observer((props: { title: string; num: any }) => {
  // 获取api
  const api = useApi(props);
  const { title, num } = props;

  // 设计时 就用0
  let numValue = 0;
  if (api.isPreview(props)) {
    // 运行时 获取具体数据
    numValue = api.getDcValue(props, { key: "num" });
  }

  return (
    <DemoComponent
      title={title}
      num={numValue}
      onNumChange={(num) => {
        // 把回调的num,通过api,在设置回魔笔应用,key: "num" 确定了修改传入的num的数值
        api.setDcValue(props, { key: "num", uiValue: num });
      }}
    />
  );
});

MobiComponent.config = config;

export default MobiComponent;