如何实现H5页面制作平台

803 阅读3分钟

这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战

前段时间参与开发公司的积木系统,也就是H5页面制作平台,在写组件的过程中,学习到了一些优秀的方案设计以及技术实现,下面就和大家交流交流。

效果预览

1628128000(1).png

产品介绍

为什么公司需要H5页面制作平台呢?目前很多公司需要做大量营销活动,比如6.18大促,某某节日活动促销等等。然而这些活动的持续时间又很短,随便都可能会进行下架。因此实际开发中需要考虑是否需要耗费大量的人力去开发这类页面,毕竟开发人员开发所需的时间可能大过页面的实际使用时间。在考虑这些问题之后,产生了h5页面制作平台,可以一键上下架,运营可以通过自己的配置实现不同的页面配置。

方案实现

1628130748(1).png

这是大体的实现思路,通过上上面的分解,我们基本上可以搭建一个可自己自定义的h5页面

组件技术选型
  • 配置使用ant-design
  • 展示使用ant-design-mobile

页面修改编辑

微信截图_20210805110613.png 左侧是所有的组件,通过拖拽或者点击的方式向中间的手机模型中添加组件(我们这里是通过点击的方式),中间手机模型可以通过点击按钮的方式或者拖拽的方式实现上下移动(我们这里是通过点击按钮的方式实现的),可以通过点击删除按钮删除当前选中的组件。点击选中当前组件,右侧会显示当前组件的配置项,如组件的背景颜色、标题、内容、图片等等,通过修改配置项,实时更新手机模型。

具体的添加组件的流程就是:
  • 点击左侧的组件,中间手机模型生成组件,同时选中当前组件,右侧出现组件的配置项。
  • 组件的配置项发生更改,通过Form表单的onValuesChange方法获取到更新的数据。
  • 将更新的数据重新传递给手机模型中的组件。
  • 点击发布按钮,将所有保存的数据通过json的格式发送给后端。
配置项中类似的代码如下
const SonTitleFormComp = (props) => {
    const { onRef, refKey, sourceData, compTextChangeCallBack, onGetCoupon, onAddCoupon, compType, onDelCoupon, onMove, onSearchs} = props
    const formRef = useRef(null);
    const textRef = useRef(null);
    const [plainOptions] = useState(['显示购买按钮', '显示商品划线价']);
​
  useEffect(() => {
    sourceData && formRef.current.setFieldsValue(sourceData)
  }, [formRef, sourceData])
​
  useEffect(() => {
    onRef && onRef({ getData }, refKey)
  }, [onRef, refKey]);
​
  const getData = (callBackFunction) => {
    if (formRef) {
      formRef.current.validateFields().then(values => {
        if (callBackFunction) {
          const newValue = JSON.parse(JSON.stringify(values));
          callBackFunction(true, newValue)
        }
      }).catch(errorInfo => {
        const newValue = JSON.parse(JSON.stringify(errorInfo.values));
        callBackFunction(false, newValue)
      })
    }
  }
​
  const onSearch = (value, key) => {
    const regular = /^[0-9]*$/;
    if (regular.test(value)) {
      onGetCoupon && onGetCoupon(value, key)
    } else {
      message.error("输入格式错误,请重新输入")
    }
  }
​
  const handleChange = (changedValues, allValues) => {
    compTextChangeCallBack && compTextChangeCallBack(allValues)
  }
​
  const onDel = (key) => {
    confirm({
      title: "删除提示",
      content: `确定要删除第${key + 1}个商品吗?`,
      icon: <ExclamationCircleOutlined />,
      okText: "确定",
      cancelText: "取消",
      onOk() {
        onDelCoupon && onDelCoupon(key)
      },
    })
  }
  return (
    <Form
      ref={formRef}
      name="son_title_comp_form"
      {...formItemLayout}
      onValuesChange={handleChange}
    >
      <Card
        size="small"
        headStyle={{ backgroundColor: '#F4F6F9' }}
        title='商品列表配置'
        style={{ marginTop: 10}}
      >
啥        <Form.Item
          {...formItemLayout}
          name="backgroundColorStatus"
          label="商品名称颜色"
        >
          <Radio.Group>
            <Radio value="0">推荐色</Radio>
            <Radio value="1">自定义</Radio>
          </Radio.Group>
        </Form.Item>
​
        <Form.Item
          noStyle
          shouldUpdate={(prevValues, curValues) => {
            const oldValue = prevValues.backgroundColorStatus;
            const newValue = curValues.backgroundColorStatus;
            return oldValue !== newValue
          }}
        >
          {
            () => {
              let flag = !parseInt(formRef.current && formRef.current.getFieldsValue().backgroundColorStatus)
              return (
                <Form.Item
                  {...formTailLayout}
                  name="backgroundColor"
                  hidden={flag}
                  rules={[{ pattern: /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/, message: '输入格式错误请重新输入' }]}
                  required
                >
                  <Input
                    placeholder="请输入自定义颜色色值(如:#000000)"
                    autoComplete="off"
                  />
                </Form.Item>
              )
            }
          }
        </Form.Item>
​
        <Form.Item
          {...formItemLayout}
          name="soldOut"
          label="售罄商品展示样式"
        >
          <Radio.Group>
            <Radio value="0">隐藏</Radio>
            <Radio value="1">原位售罄</Radio>
          </Radio.Group>
        </Form.Item>
      </Card>
      <Form.List name="children">
        {(fields) =>(
        <>
          {fields.map(({ key, name, fieldKey, ...restField }) => (
            <Card
              size="small"
              headStyle={{ backgroundColor: '#F4F6F9' }}
              title={`${key + 1}个商品`}
              key={key}
              style={{ marginTop: 10 }}
              extra={
                sourceData.children.length > 1
                ? <>
                    <Button disabled={ key === 0 } type="text"  onClick={ () => onMove(key, 'up') }>
                      <ArrowUpOutlined/>
                    </Button>
                    <Button disabled={ key === sourceData.children.length - 1 } type="text" onClick={ () => onMove(key, 'down') }>
                      <ArrowDownOutlined/>
                    </Button>
                    <DeleteOutlined onClick={() => onDel(key)} />
                  </>
                : null
              }
            >
                <Form.Item
                  {...formItemLayout}
                  name={[name, 'skuId']}
                  label="商品skuId"
                  rules={[{ required: true, message: '请输入商品的skuId并点击搜索', type: 'number' }]}
                >
                  <Search
                    placeholder="请输入商品的skuId"
                    enterButton="加载"
                    onSearch={(value) => onSearch(value, key)}
                  />
                </Form.Item>
            </Card>
          ))}
          {(
              <Form.Item noStyle style={{ width: '100%' }}>
                <Button type="dashed" onClick={onAddCoupon} block icon={<PlusOutlined />}>
                  继续添加商品
                </Button>
              </Form.Item>
          )}
        </>
        )}
      </Form.List>
    </Form>
  )
}

后期规划

后期将会自己实现一个H5页面制作平台,可拖拽的实现方式,向其中加入其他更多的组件,制作一个线上版的demo,希望大家喜欢。

我的公众号

《程序员的人生》