利用AI生成前端组件:附带 prompt

背景

最近有个「网站建设」的需求,需要调研 AI 生成前端组件的可行性。本文将介绍如何利用 AI 技术生成前端组件,结合 Ant Design 库和 Tailwind Styled Components 搭建组件,同时使用 prompt 来约束组件的生成,提高开发效率。

AI生成前端组件

由于从未接触过 AI 生成组件,我们先尝试利用简单文案,看能不能生成前端组件。prompt 如下:

arduino 复制代码
"请生成一个登录表单组件,使用React和Ant Design库,表单包含用户名和密码输入框,"
"以及一个登录按钮。当用户输入用户名和密码后,点击登录按钮时,触发一个回调函数。"

生成的代码

tsx 复制代码
import React, { useState } from 'react';
import { Form, Input, Button } from 'antd';

const LoginForm = ({ onLogin }) => {
  const [form] = Form.useForm();
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (values) => {
    setLoading(true);
    await onLogin(values);
    setLoading(false);
  };

  return (
    <Form form={form} onFinish={handleSubmit}>
      <Form.Item
        name="username"
        rules={[{ required: true, message: 'Please enter your username' }]}
      >
        <Input placeholder="Username" />
      </Form.Item>
      <Form.Item
        name="password"
        rules={[{ required: true, message: 'Please enter your password' }]}
      >
        <Input.Password placeholder="Password" />
      </Form.Item>
      <Form.Item>
        <Button type="primary" htmlType="submit" loading={loading}>
          Login
        </Button>
      </Form.Item>
    </Form>
  );
};

export default LoginForm;

还生成了表单校验逻辑

这段 prompt,要求生成一个登录表单组件。AI 模型会根据这个 prompt 生成相应的代码,并返回给我们。方案基本可行。但这样的代码在项目中肯定不能直接用,我们继续优化

使用prompt约束组件的生成

大家都知道,AI 经常会出现幻觉,为了让结果更加的稳定可控,我们需要约束力更强的 prompt。我们可以使用 Ant Design 库和 tailwind-styled-components 来搭建组件。

为了生成满足特定需求的组件,我们需要编写一个详细的prompt来约束AI模型的生成。在上面的例子中,我们已经编写了一个简单的prompt来生成登录表单组件。当然,我们还可以编写更复杂的prompt来生成更复杂的组件,如包含分页、搜索、筛选等功能的表格组件。

以下是一个生成包含分页、搜索、筛选功能的表格组件的prompt示例:

markdown 复制代码
请生成一个React表格组件,使用Ant Design库和tailwind-styled-components。表格需要支持以下功能:
1. 分页:用户可以通过点击分页按钮来切换页面;
2. 搜索:用户可以输入关键词来搜索表格中的数据;
3. 筛选:用户可以通过选择筛选条件来筛选表格中的数据;
4. 数据来源:表格的数据来源于一个名为fetchData的函数,该函数接收一个对象作为参数,包含分页信息、搜索关键词和筛选条件。

生成的代码更加丰富了

tsx 复制代码
import React, { useState } from 'react';
import { Table, Input, Select } from 'antd';
import styled from 'styled-components/macro';
import tw from 'tailwind-styled-components';

const { Option } = Select;

const StyledTableContainer = tw.div`
  bg-white
  rounded-lg
  shadow-md
  p-4
`;

const StyledTableHeader = tw.div`
  flex
  justify-between
  items-center
  mb-4
`;

const StyledSearchContainer = tw.div`
  flex
  items-center
`;

const StyledSearchInput = tw(Input)`
  w-64
  mr-4
`;

const StyledSelect = tw(Select)`
  w-64
`;

const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
  },
  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: 'Address',
    dataIndex: 'address',
    key: 'address',
  },
];

const data = [
  {
    key: '1',
    name: 'John Brown',
    age: 32,
    address: 'New York No. 1 Lake Park',
  },
  {
    key: '2',
    name: 'Jim Green',
    age: 42,
    address: 'London No. 1 Lake Park',
  },
  {
    key: '3',
    name: 'Joe Black',
    age: 32,
    address: 'Sidney No. 1 Lake Park',
  },
  {
    key: '4',
    name: 'Jim Red',
    age: 32,
    address: 'London No. 2 Lake Park',
  },
];

const TableComponent = () => {
  const [currentPage, setCurrentPage] = useState(1);
  const [searchValue, setSearchValue] = useState('');
  const [filterValue, setFilterValue] = useState('');

  const handlePageChange = (page) => {
    setCurrentPage(page);
  };

  const handleSearch = (event) => {
    setSearchValue(event.target.value);
  };

  const handleFilterChange = (value) => {
    setFilterValue(value);
  };

  const filteredData = data.filter((item) =>
    item.name.toLowerCase().includes(searchValue.toLowerCase())
  );

  const filteredAndSortedData = filterValue
    ? filteredData.filter((item) => item.age === Number(filterValue))
    : filteredData;

  return (
    <StyledTableContainer>
      <StyledTableHeader>
        <StyledSearchContainer>
          <StyledSearchInput
            placeholder="Search by name"
            value={searchValue}
            onChange={handleSearch}
          />
          <StyledSelect
            placeholder="Filter by age"
            allowClear
            onChange={handleFilterChange}
            value={filterValue}
          >
            <Option value="32">32</Option>
            <Option value="42">42</Option>
          </StyledSelect>
        </StyledSearchContainer>
        <div>Page {currentPage}</div>
      </StyledTableHeader>
      <Table
        columns={columns}
        dataSource={filteredAndSortedData}
        pagination={{
          current: currentPage,
          pageSize: 2,
          total: filteredAndSortedData.length,
          onChange: handlePageChange,
        }}
      />
    </StyledTableContainer>
  );
};

export default TableComponent;

但实际效果不行

优化 prompt

我们可以分两个部分来确定 prompt。

  • 第一部分是用来约束组件的生成范围,比如要用 antd 库,要有 interface 和默认值 等。
  • 第二部分是用来确定组件要包含的元素信息,比如要有图片,要有列表等

第一部分的,我们可以固定在 prompt 模板中,第二部分可以由用户输入

另外,我们使用的 ChatGPT 3.5,使用英文的 prompt 效果会更好一点

sql 复制代码
You are a React developer and an excellent markdown developer who generates React components based on user input and meets the following requirements: 

   1. The component name must be in English with uppercase letters 
   2. The typescript interface that needs to be generated for the component, and all props are optional 
   3. Used Ant Design component library to create components 
   4. use tailwind-styled-components for styling the component 
   5. The default value for image address is Picsum 
   6. The default values for all other props will be in Chinese 
   7. write all the components and style in one file 
 
 USER_OUTPUT: 
 
 名称:表格组件 
 描述:table 
 元素列表: 
 1. 分页:用户可以通过点击分页按钮来切换页面; 
 2. 搜索:用户可以输入关键词来搜索表格中的数据; 
 3. 筛选:用户可以通过选择筛选条件来筛选表格中的数据; 
 
 Remember, you need to clarify the user input requirements before generating the document. 
 
 Begin!

在这个 prompt 中,我们约束更加严格了。不仅限制了使用的库,还要求生成样式和interface。

以下是一个可能的生成代码示例:

tsx 复制代码
import React from 'react';
import { Table, Pagination, Input, Select } from 'antd';
import tw from 'tailwind-styled-components';

interface TableComponentProps {
  pagination?: boolean;
  search?: boolean;
  filter?: boolean;
  pageSize?: number;
  currentPage?: number;
  searchText?: string;
  filterOptions?: string[];
  filterValue?: string;
  imageUrl?: string;
}

const { Option } = Select;

const TableContainer = tw.div`
  .ant-table {
    margin-bottom: 1rem;
  }
`;

const SearchContainer = tw.div`
  flex
  justify-end
  items-center
  mb-4
`;

const FilterContainer = tw.div`
  flex
  justify-end
  items-center
  mb-4
`;

const TableComponent: React.FC<TableComponentProps> = ({
  pagination = true,
  search = true,
  filter = true,
  pageSize = 10,
  currentPage = 1,
  searchText = '请输入搜索关键词',
  filterOptions = ['请选择筛选条件'],
  filterValue = '请选择',
  imageUrl = 'https://picsum.photos/200',
}) => {
  const columns = [
    {
      title: '姓名',
      dataIndex: 'name',
      key: 'name',
    },
    {
      title: '年龄',
      dataIndex: 'age',
      key: 'age',
    },
    {
      title: '地址',
      dataIndex: 'address',
      key: 'address',
    },
  ];

  const data = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park',
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park',
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park',
    },
    {
      key: '4',
      name: 'Jim Red',
      age: 32,
      address: 'London No. 2 Lake Park',
    },
  ];

  const handlePageChange = (page: number) => {
    console.log(page);
  };

  const handleSearch = (value: string) => {
    console.log(value);
  };

  const handleFilterChange = (value: string) => {
    console.log(value);
  };

  return (
    <TableContainer>
      {search && (
        <SearchContainer>
          <Input.Search
            placeholder={searchText}
            onSearch={handleSearch}
            enterButton
          />
        </SearchContainer>
      )}
      {filter && (
        <FilterContainer>
          <Select
            defaultValue={filterValue}
            style={{ width: 200 }}
            onChange={handleFilterChange}
          >
            {filterOptions.map((option) => (
              <Option key={option} value={option}>
                {option}
              </Option>
            ))}
          </Select>
        </FilterContainer>
      )}
      <Table
        dataSource={data}
        columns={columns}
        pagination={
          pagination
            ? {
                pageSize,
                current: currentPage,
                onChange: handlePageChange,
              }
            : false
        }
      />
      <img src={imageUrl} alt="placeholder" />
    </TableContainer>
  );
};

export default TableComponent;

在这个示例中,我们使用了Ant Design库提供的Table、Input、Pagination和Select组件,以及tailwind-styled-components提供的样式。生成的代码基本符合 prompt 预期。我们需要优化一下 USER_OUTPUT 部分,这样可以生成更好看的 UI

sql 复制代码
You are a React developer and an excellent markdown developer who generates React components based on user input and meets the following requirements: 
1. The component name must be in English with uppercase letters 
2. The typescript interface that needs to be generated for the component, and all props are optional 
3. All labels must use the antd label 
4. Component style using tailwindcss 
5. The default value for image address is Picsum 
6. Component properties must have Chinese default values 
7. All components are written in one file 
8. Using Card components as the basic container for components 

Remember, you need to clarify the user input requirements before generating the document. 

USER_OUTPUT: 

名称:Pet Services Component 
描述:This component is suitable for displaying information about our pet services. 
元素列表: 
- Display pictures list of pets 
- Brief description of our pet services 
- Link to see more details about our services 
- Tag list of our services, such as "Veterinary Care", "Grooming", "Training", etc. 
- Description of pets 

Begin!

下一步

下一步的优化手段,我们可以让用户输入一段话,然后让 AI 来确定元素列表的内容

总结

本文介绍了如何利用AI技术生成前端组件,结合Ant Design库和tailwind-styled-components搭建组件,并使用prompt来约束组件的生成。通过这种方法,我们可以提高生成组件的质量。但从整个实现过程发现,如果生成太复杂的组件,会很不可控,生成的代码容易运行出错。所以这种方案适用于生成简单组件,够用就行

相关推荐
软件技术NINI5 分钟前
html知识点框架
前端·html
深情废杨杨9 分钟前
前端vue-插值表达式和v-html的区别
前端·javascript·vue.js
GHUIJS9 分钟前
【vue3】vue3.3新特性真香
前端·javascript·vue.js
众生回避15 分钟前
鸿蒙ms参考
前端·javascript·vue.js
洛千陨16 分钟前
Vue + element-ui实现动态表单项以及动态校验规则
前端·vue.js
笃励1 小时前
Angular面试题五
javascript·ecmascript·angular.js
GHUIJS1 小时前
【vue3】vue3.5
前端·javascript·vue.js
-seventy-1 小时前
对 JavaScript 原型的理解
javascript·原型
&白帝&2 小时前
uniapp中使用picker-view选择时间
前端·uni-app
魔术师卡颂2 小时前
如何让“学源码”变得轻松、有意义
前端·面试·源码