AMIS實現渲染一個button的源碼分析-Vue

使用

schema轉爲對應的button渲染出來。
輸入:schema
輸出:button Vue組件
核心過程:schema經過渲染引擎解析成button渲染器。
語法:tsx(與jsx類似)

schema

{
  "label": "編輯 Button",
  "type": "button",
  "actionType": "dialog",
  "className": "m-l-md",
  "showAsLabel": false,
  "level": "success",
  "size": "large",
  "loading": false,
  "icon": "mtdicon-cart",
  "tooltip": "11111",
  "tooltipPlacement": "top",
  "tooltipTrigger": "hover",
  "dialog": {
    "title": "編輯",
    "body": [
      {
        "type": "tpl",
        "tpl": "1111"
      }
    ]
  }
}

源碼實現步驟

渲染器的使用

// 調用渲染引擎
<Render :schema="schema"></Render>
import { Render } from '../../src/index';

../../src/index.ts
// 首先,初始化各渲染器,即執行步驟一到步驟四。
import './renderers';

// 其次,調用渲染器引擎,解析schema映射到對應的(Button)渲染器。即步驟五
import {
  Render,
  customRegistRenderer,
} from './engine'; 

步驟一 定義button組件

/*
** 引入Button組件
*/
import './renderers';

renderers.ts
import Button from './Button';
export default {
	Button,
}

/*
** 定義Button組件
*/
export class Button extends Vue.Component<any> {
	...
	render() {
	  <mtd-button
        {...{props}}
        class={className}
        type={level}
        htmlType='button'
        onClick={this.handleAction}
      >
        {label || text}
      </mtd-button>
	}
}

步驟二 執行註冊Button渲染器
Button渲染器繼承自Button基本組件。較Button組件擴展了些通用屬性方法。

/*
** 調用@registerRenderer裝飾器,註冊Button組件爲一個渲染器(ButtonRenderer)
** 調用@WithExpression裝飾器,擴展ButtonRenderer功能(高階組件HOC)
*/
@registRenderer({
  name: 'button', // 唯一標識
  test: (path: string, config: any) => { // schema匹配時用到
    return Boolean(/\/(?:action|button)$/.test(path) || ~['button', 'reset', 'cancel'].indexOf(config.type));
  },
  filter: (config: any, path: string, props: any) => ({
    disabled: config.hasOwnProperty('disabled') ? config.disabled : props.disabled,
  }),
})
@WithExpression
export default class ButtonRenderer extends Button {}

步驟三 實現註冊渲染器的方法

/*
** @registRenderer
*/
export const registRenderer = (config: RendererConfig, storeFactory?: any) => (Component: any) => {

  if (!config.name || !config.test) {
      throw new Error('模型註冊格式錯誤');
  }
  if (~rendererNames.indexOf(config.name)) {
      throw new Error(`${config.name} 已經註冊了, 不能重複註冊`);
  }

  const rendererName = config.name; // 'button'

  let composeComponent = Component; // ButtonRenderer
  // 注入通用邏輯 可忽略
  composeComponent = withCommonLogic(composeComponent);

  config.Renderer = composeComponent;

  rendererNames.push(rendererName); // 暫存爲已註冊渲染器
  rendererConfigSet.push(config); // 暫存config: {name: 'button', test: *, Renderer: composeComponent}

  return Component;
};

步驟四 實現高階擴展渲染器的方法

/*
** @WithExpression
*/
擴展項包括除props、render、click函數handleAction外的所有:
name、props、data、methods、生命週期函數(created、mounted、beforeUpdate、updated、render),
其中render中調用(Button)渲染器組件,並傳遞格式化好的prop屬性。

使用高階組件方法 
// 擴展並返回擴展後的Button渲染器組件,ComposedComponent爲渲染器組件,OnExpression爲擴展屬性
return createHOC(ComposedComponent, OnExpression);  

步驟五 渲染器引擎

engine/Render.tsx
/**
** 作用是找到對應的渲染器模型,並調用渲染。
**/
const rendererConfig = getRenderer(path, schema);
const renderer = rendererConfig.Renderer;
// 利用path從步驟三中的rendererConfigSet中查找出對應渲染模型

return (
      <renderer {...rendererConf}>
      </renderer>
    );
// 渲染出組件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章