1

什么是amis

在经历了十几年的发展后,前端开发变得越来越复杂,门槛也越来越高,要使用当下流行的 UI 组件库,你必须懂 npm、webpack、react/vue,必须熟悉 ES6 语法,最好还了解状态管理,比如 Redux,如果没接触过函数式编程,光入门都很费劲,而入门之后会发现它还有巨大的 生态,相关的库有 2347 个,很多功能相似,挑选成本高。

然而前端技术的发展不会停滞,等学完这些后可能会发现大家都用 Hooks 了、某个打包工具取代 Webpack 了……

而有时候其实只想做个普通的增删改查界面,用于信息管理
以上是官方文档的内容

为什么选amis

打算在项目里用低代码,想偷懒,把自己从前端工作抽身出来,还有很多后端工作要做。
原本打算用阿里的lowcode发现问题好多,官方案例错误挂了好几年,我比较菜,没解决,而且总觉得lowcode把简单事情搞复杂了,用很多看上去似懂非懂的术语,让简单的东西复杂化,转投amis。

为什么要写这篇

官方文档写的蛮详细的,为什么还要写这篇,因为虽然官方文档写的很详细,我还是踩了一整天的坑。
官方:https://aisuda.bce.baidu.com/amis/zh-CN/docs/index

集成过程

环境

当前使用react 18,脚手架
也尝试用next.js集成,遇到了和下面一样的问题,如果你也遇到,这个还没解决,可以换个环境。(对前端来说,多个项目的整合方案很多,不需要拘泥于原本的项目环境)
https://github.com/baidu/amis/issues/8170

要什么样的结果

  1. 页面的使用(左边)
  2. schema的编辑(右边)
    image.png
    上述效果就需要amis和amis-editor两部分,所以下面会把两部分拆开讲

amis

安装

npm i amis

测试案例

# 安装部分示例需要的插件库
npm i axios copy-to-clipboard

代码如下

import * as React from 'react';
import axios from 'axios';
import copy from 'copy-to-clipboard';

import {render as renderAmis} from 'amis';
import {ToastComponent, AlertComponent, alert, confirm, toast} from 'amis-ui';

class MyComponent extends React.Component<any, any> {
  render() {
    let theme = 'cxd';
    let locale = 'zh-CN';

    // 请勿使用 React.StrictMode,目前还不支持
    return (
      <div>
        <p>通过 amis 渲染页面</p>
        <ToastComponent
          theme={theme}
          key="toast"
          position={'top-right'}
          locale={locale}
        />
        <AlertComponent theme={theme} key="alert" locale={locale} />
        {renderAmis(
          {
            // 这里是 amis 的 Json 配置。
            type: 'page',
            title: '简单页面',
            body: '内容'
          },
          {
            // props...
            // locale: 'en-US' // 请参考「多语言」的文档
            // scopeRef: (ref: any) => (amisScoped = ref)  // 功能和前面 SDK 的 amisScoped 一样
          },
          {
            // 下面三个接口必须实现
            fetcher: ({
              url, // 接口地址
              method, // 请求方法 get、post、put、delete
              data, // 请求数据
              responseType,
              config, // 其他配置
              headers // 请求头
            }: any) => {
              config = config || {};
              config.withCredentials = true;
              responseType && (config.responseType = responseType);

              if (config.cancelExecutor) {
                config.cancelToken = new (axios as any).CancelToken(
                  config.cancelExecutor
                );
              }

              config.headers = headers || {};

              if (method !== 'post' && method !== 'put' && method !== 'patch') {
                if (data) {
                  config.params = data;
                }

                return (axios as any)[method](url, config);
              } else if (data && data instanceof FormData) {
                config.headers = config.headers || {};
                config.headers['Content-Type'] = 'multipart/form-data';
              } else if (
                data &&
                typeof data !== 'string' &&
                !(data instanceof Blob) &&
                !(data instanceof ArrayBuffer)
              ) {
                data = JSON.stringify(data);
                config.headers = config.headers || {};
                config.headers['Content-Type'] = 'application/json';
              }

              return (axios as any)[method](url, data, config);
            },
            isCancel: (value: any) => (axios as any).isCancel(value),
            copy: content => {
              copy(content);
              toast.success('内容已复制到粘贴板');
            },
            theme

            // 后面这些接口可以不用实现

            // 默认是地址跳转
            // jumpTo: (
            //   location: string /*目标地址*/,
            //   action: any /* action对象*/
            // ) => {
            //   // 用来实现页面跳转, actionType:link、url 都会进来。
            // },

            // updateLocation: (
            //   location: string /*目标地址*/,
            //   replace: boolean /*是replace,还是push?*/
            // ) => {
            //   // 地址替换,跟 jumpTo 类似
            // },

            // getModalContainer: () => {
            //   // 弹窗挂载的 DOM 节点
            // },

            // isCurrentUrl: (
            //   url: string /*url地址*/,
            // ) => {
            //   // 用来判断是否目标地址当前地址
            // },

            // notify: (
            //   type: 'error' | 'success' /**/,
            //   msg: string /*提示内容*/
            // ) => {
            //   toast[type]
            //     ? toast[type](msg, type === 'error' ? '系统错误' : '系统消息')
            //     : console.warn('[Notify]', type, msg);
            // },
            // alert,
            // confirm,
            // tracker: (eventTracke) => {}
          }
        )}
      </div>
    );
  }
}

export default MyComponent

主题

目前主要支持两个主题:cxd(云舍) 和 antd(仿 Antd)


import 'amis/lib/themes/cxd.css';
import 'amis/lib/helper.css';
import 'amis/sdk/iconfont.css';

渲染器使用配置主题

renderAmis(
  {
    type: 'page',
    title: '简单页面',
    body: '内容'
  },
  {
    // props
  },
  {
    // env...
    theme: 'cxd' // cxd 或 antd
  }
);

amis-editor

amis相对比较简单,问题基本都在amis-editor

# 安装
npm i amis-editor

简单测试

import { useState } from "react";
import { Editor } from "amis-editor";
// import type { SchemaObject } from "amis";
// import type { Schema } from "amis/lib/types";
// 以下样式均生效
import "amis/lib/themes/default.css";
import "amis/lib/helper.css";
import "amis/sdk/iconfont.css";
import "amis-editor-core/lib/style.css";
import "amis-ui/lib/themes/antd.css";

export function Amis() {
  const defaultSchema: any = {
    type: "page",
  };
  const [schema] = useState(defaultSchema);
  const onChange = (value: any) => {
    console.log("change")
  };
  return (
    <>
      <Editor
        onChange={onChange}
        value={schema as any}
      />
    </>
  );
}
export default Amis;

直接上这个是为了看到错误,再一一解决

mobx 问题

已经有mobx或者使用npm install mobx会导致mobx版本问题,因为amis-editor用的老版本,参考如下:https://github.com/baidu/amis/issues/5787

我的解决方法是,参考其他master和案例的版本,手动安装指定版本

npm install mobx@4.15.7 mobx-react@6.3.1 mobx-state-tree@3.17.3 --legacy-peer-deps

如果上述代码安装后,导致react都识别不了,重新安装
npm install --save-dev "@types/react"
npm install --save-dev "@types/react-dom"

monaco-editor-webpack-plugin问题

官方文档在amis中有提到需要使用monaco-editor-webpack-plugin,这个是monaco-editor用的,故放在这里,报错如下
image.png

首先要知道这个plugin和monco-editor版本相关,我的方法是去node_modules全局搜索找到版本号如下
image.png

然后去npm找到monaco-editor-webpack-plugin的对应关系
https://www.npmjs.com/package/monaco-editor-webpack-plugin?ac...
image.png
再找到这里的versions,发现6开头的只有一个版本
image.png
最终使用如下方法安装(如果先弄webpack,不需要加--legacy-peer-deps)

npm install monaco-editor-webpack-plugin@6.0.0 -D --legacy-peer-deps

安装好后,再配置这个插件,我这个项目是脚手架,之前用npm run eject弹出了webpack,然后参照官方文档,把插件配置上去,此时可以参照官方文档,实际上只需要两行代码

const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');

    new MonacoWebpackPlugin(),

官方案例

const path = require('path');
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: {
    index: './src/index.tsx'
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              transpileOnly: true
            }
          }
        ],
        exclude: /node_modules/
      },
      {
        test: /\.woff2?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use: 'url-loader?limit=10000'
      },
      {
        test: /\.(ttf|eot|svg)(\?[\s\S]+)?$/,
        use: 'file-loader'
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.ttf$/,
        use: ['file-loader']
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin({cleanStaleWebpackAssets: false}),
    new HtmlWebpackPlugin({
      template: 'src/index.html'
    }),
    new MonacoWebpackPlugin(),
    new ForkTsCheckerWebpackPlugin()
  ],
  resolve: {
    extensions: ['.tsx', '.ts', '.js', '.html']
  },
  output: {
    filename: '[name].bundle.js',
    publicPath: '/'
  }
};

此时,操作的时候仍然有warning,忽略这些
image.png


vincent
49 声望2 粉丝