Amis 渲染器自定义组件

解读

国内中高级 PHP 面试里,前端低代码方案 Amis 被越来越多的公司(尤其是 ToB SaaS、内部运营后台)采用。面试官问“Amis 渲染器自定义组件”,并不是想让你背文档,而是考察三条线:

  1. 你是否理解 Amis 的渲染管线(JSON → Schema → React 组件 → DOM)。
  2. 你是否能把 PHP 后端业务逻辑(字段、权限、数据格式)无缝对接到前端自定义组件里。
  3. 你是否具备“造轮子”能力:当官方组件无法满足业务(例如:SKU 多维矩阵、电子签名、低代码地图选点)时,能否用官方推荐的 Custom 或 SDK 方式扩展,并保证后续可维护、可复用、可单元测试。

一句话:面官想看你在 PHP 主导的项目里,如何“优雅地”把后端数据 + 前端自定义组件打通,而不是简单写个 React 组件了事。

知识点

  1. Amis 渲染器架构
    • 三层概念:JSONSchema → Renderer(React 高阶组件) → 真实 DOM。
    • 内置渲染器注册表:RendererStore,通过 addSchemaFilter、registerRenderer 注入。
  2. 自定义组件三种官方姿势
    • Custom 微件:在 JSON 里直接写 type:"custom",内嵌 React 组件,适合一次性场景。
    • SDK 注册:使用 amis.embed、amis.registerRenderer,适合多项目复用。
    • 源码级扩展:fork amis,在 /src/renderers 新增 Renderer,重新 build,适合深度 UI 统一。
  3. 与 PHP 后端的数据闭环
    • 初始数据:PHP 在 data 属性里注入 api 返回的 rowspermissions
    • 事件回调:自定义组件通过 onAction 触发 amis 动作,再调用 PHP 提供的 ajax 接口。
    • 字段校验:PHP 返回 validations 规则,自定义组件内部用 amis.FormItemControl 统一校验。
  4. 性能与安全
    • 使用 React.memo、useDeepCompareMemo 避免重复渲染。
    • 自定义组件内部禁止直接操作 DOM,统一走 amis 提供的 env.fetcher 做请求,方便接入 PHP 的 CSRF Token、JWT。
  5. 工程化
    • 前端用 Vite/Rollup 把自定义组件打成 custom-renderer.esm.js,PHP 通过 asset() 引用。
    • 单元测试:@testing-library/react + jest,mock amis 上下文。
    • 文档:Storybook 自动生成示例,PHP 注释用 swagger-php 同步给前端。

答案

下面给出一个“国内面试现场”最常用、最可落地的回答模板,可直接口述或白板手写。

场景:电商后台商品模块,官方 Select 无法完成“SKU 多维矩阵”交互,需要自定义组件。

步骤 1:PHP 后端先给出接口约定

// ProductController.php  返回属性与属性值
public function skuMeta(int $categoryId): JsonResponse
{
    $attrs = Attr::where('category_id', $categoryId)
                 ->with('values:id,attr_id,name')
                 ->get(['id','name']);
    return response()->json([
        'status' => 0,
        'data'   => $attrs
    ]);
}

步骤 2:前端注册自定义渲染器(SDK 方式,不改动 amis 源码)

// sku-matrix.jsx
import React, {useEffect, useState} from 'react';
import {registerRenderer} from 'amis';

function SkuMatrix({value, onChange, data, env}) {
  const [matrix, setMatrix] = useState(value || []);

  useEffect(() => {
    // 初始拉取 PHP 给的属性元数据
    env.fetcher(data.skuMetaApi).then(res => {
      // 构造矩阵
      setMatrix(buildMatrix(res.data));
    });
  }, []);

  const handleCellChange = (cell) => {
    const newVal = matrix.map(m => m.key === cell.key ? cell : m);
    setMatrix(newVal);
    onChange(newVal);   // 把最新矩阵回传给 amis 表单
  };

  return (
    <div className="sku-matrix">
      {matrix.map(r => (
        <div key={r.key}>
          <span>{r.label}</span>
          <input value={r.price} onChange={e => handleCellChange({...r, price: e.target.value})}/>
        </div>
      ))}
    </div>
  );
}

// 关键:注册到 amis
registerRenderer({
  type: 'sku-matrix',
  name: 'sku-matrix',
  autoVar: true,        // 让 amis 自动注入 data、onChange、env
  component: SkuMatrix
});

步骤 3:PHP 返回的 JSON 里直接使用

$pageSchema = [
    'type' => 'page',
    'data' => [
        'skuMetaApi' => route('product.sku.meta', ['categoryId' => $categoryId])
    ],
    'body' => [
        'type' => 'form',
        'api'  => route('product.save'),
        'controls' => [
            [
                'type' => 'sku-matrix',
                'name' => 'skuList',   // 表单字段名
                'label' => 'SKU矩阵'
            ]
        ]
    ]
];
return response()->json($pageSchema);

步骤 4:性能与可维护

  • 用 React.memo 包裹 SkuMatrix,避免父级表单任何改动都重渲染。
  • 所有请求走 env.fetcher,自动携带 PHP 注入的 X-CSRF-Token
  • 把 sku-matrix 打成一个独立包,通过 Composer 的 composer-merge-plugin 把前端资源版本锁在 composer.lock,实现 PHP 项目一键升级。

这样回答,面官能清晰听到:

  1. 你理解 amis 渲染管线。
  2. 你知道 PHP 如何给前端“喂数据”。
  3. 你考虑了性能、安全和工程化,符合企业级落地标准。

拓展思考

  1. 动态权限:PHP 在后端把字段级权限 visible= false 注入 JSON,自定义组件内部通过 amis.util.filter 做二次过滤,避免前端硬编码权限。
  2. 微前端场景:当后台用 Laravel + amis,前台用 Next.js,可以把自定义组件打成 Web Component,通过 amis.registerRenderer({component: 'sku-matrix-webc'}) 实现技术栈隔离。
  3. 低代码平台化:把 SkuMatrix 抽象成 JSON 配置,例如 {"type":"sku-matrix","attrsApi":"xxx","priceUnit":"CNY"},让运营人员通过 PHP 管理的元数据直接生成新组件,无需发版。
  4. 单元测试覆盖率:PHP 用 Codeception 测接口,前端用 React Testing Library 测组件,合并到 GitLab CI,MR 阶段必须 ≥ 90%,保证自定义组件不会成为“祖传代码”。
  5. 服务端渲染:如果后台对 SEO 有要求,可在 PHP 里用 v8js 扩展或 Node 子进程做同构渲染,把 amis JSON 直出 HTML,自定义组件需要兼容 ssr: true 模式。

掌握以上思路,无论面官如何追问“性能优化”“权限安全”“跨框架复用”,你都能把话题拉回 PHP 主导的工程实践,体现全栈掌控力。