从零实现一套低代码(保姆级教程) --- 【10】实现样式面板并支持Button组件的样式配置

摘要

经过前面九篇文章的讲解和实现,目前我们的低代码已经初具雏形了。

如果你是第一次看到这一篇文章, 建议先看一下第一节内容: 从零实现一套低代码(保姆级教程) --- 【1】初始化项目,实现左侧组件列表

那我们可以回忆一下之前我们是怎么实现属性面板的。

本质上就是在画布区选中节点后,在redux保存。在通过右侧属性面板,修改节点的属性,从而引起组件的重新渲染。

那如果我们想实现一个样式面板,整体思路不就和属性面板一模一样嘛。

甚至,InputComponent这个组件我们都可以复用!!!!!

OK,现在我们在项目中实现一下样式面板。

1. 实现样式的配置Map

之前我们有一个attributeMap用来保存所有组件的属性配置,现在我们在它的同级目录新增一个styleMap用来保存所有组件分样式配置。

之前我们有一个comAttribute用来保存各个组件的属性列表,现在新建一个comStyle用来保存各个组件的样式列表。

这里我们先给Button组件的配置好:

XinBuilder2\src\pages\builder\rightPart\staticUtils\styleMap.ts

javascript 复制代码
import { buttonStyle } from "./comStyle/buttonStyle"

interface StyleMap {
  [key: string]: Style[]
}

export interface Style {
  label: string,
  value: string,
  type: string,
  options?: Array<any>,
  defaultValue?: string,
  modalType?: string
}

const styleMap: StyleMap = {
  Button: buttonStyle
}

export {
  styleMap
}

XinBuilder2\src\pages\builder\rightPart\staticUtils\comStyle\buttonStyle.ts

给按钮配置两个样式属性,高度和宽度.

javascript 复制代码
import { Style } from "../styleMap"
const buttonStyle: Style[] = [
  {
    label: '设置宽度',
    value: 'width',
    type: 'number'
  },
  {
    label: '设置高度',
    value: 'height',
    type: 'number'
  }
]

export {
  buttonStyle
}

OK,现在我们的基础配置就完事了。

2.实现样式面板的渲染

对于样式面板,我们只需要照着属性面板进行修改即可,来到rightPart下的index.tsx中。

javascript 复制代码
  const items: TabsProps['items'] = [
    {
      key: 'attributePanel',
      label: <div style={{fontSize:'18px',width:'100px',textAlign:'center'}}>属性</div>,
      children: getAttributePanel(),
    },
    {
      key: 'stylePanel',
      label: <div style={{fontSize:'18px',width:'100px',textAlign:'center'}}>样式</div>,
      children: getStylePanel(),
    }
  ];

OK,现在我们实现getStylePanel方法:

javascript 复制代码
  const getStylePanel = () => {
    const comType = selectNode?.comType || '';
    const styleList = styleMap[comType] || []
    return <div>
      {
        styleList.map((item,index) => {
          return <div key={index} className='attributeItem'>
          <label className='attributeLabel'>{item.label}</label>
          <div className='attributeItemValue'>
            <InputComponent selectNode={selectNode} {...item} onChange={changeComAttribute(item.value)}/>
          </div>
        </div>
        })
      }
    </div>
  }

getStylePanel 方法和 getAttributePanel方法区别点,只在于遍历的List不同,一个是属性的列表,一个是样式的列表。

OK,现在我们的右侧样式面板就可以看到我们刚才设置的高度和宽度了。

但是有一个问题是什么,如果我给width设置了200,这对组件是无效的。只有200px才会对组件生效。所以这里,我们就再写一个change的方法。不用changeComAttribute了!

javascript 复制代码
  const getStylePanel = () => {
	// 其他代码
 <InputComponent onChange{changeComStyle( item.value)}/>
  }
javascript 复制代码
  const changeComStyle = (value: string) => {
    return (e: any) => {
      let attribute = e;
      if(typeof e === 'object') {
         attribute = e.target.value;
      }
      if(['width', 'height'].includes(value)) {
        attribute += 'px'
      }
      if(selectNode) {
        if(!selectNode.comStyle) {
          selectNode.comStyle = {}
        }
        selectNode.comStyle[value] = attribute;
      }
      Store.dispatch({type: 'changeComList', value:comList})
    }
  }

对于宽度和高度,我们给最后组件的样式值加上px。这样就能对组件生效了。

但是右侧属性面板的回显可能就会有问题了(因为number组件接收的是一个字符串了),现在我们再修改一下。

javascript 复制代码
  const getComponent = () => {
    switch (type) {
      // 对于number组件,将组件的字符串值转换为number类型
      case 'number': {
        return <Input type="number" value={selectNode[value] || parseInt(selectNode?.comStyle?.[value] || '') || '0'} style={{width:'120px'}} defaultValue={defaultValue} onChange = {onChange}/>
      }
    }
  }

3.实现组件的渲染

现在我们来到组件里,只需要将组件的width和height渲染到组件上即可。

javascript 复制代码
import { Button as AntButton } from 'antd'

export default function Button(props: any) {
  const { caption, danger, disabled, ghost, shape, size, type, comStyle } = props
  const IconComponent = require('@ant-design/icons')[type]
  return (
    <div>
      <AntButton
        style={{...comStyle}}
        danger={danger}
        disabled={disabled}
        ghost={ghost}
        shape={shape}
        size={size}
        icon={type ?  <IconComponent /> : null}
        >
          {caption || '按钮'}
      </AntButton>
    </div>
  )
}

现在我们就可以给Button组件设置宽高了:

4.实现色板组件

现在我们思考一个问题,不管是组件的背景颜色还是字体颜色,都离不开配置颜色。 所以我们需要一个新的属性类型,就是color类型:

javascript 复制代码
const buttonStyle: Style[] = [
  {
    label: '设置宽度',
    value: 'width',
    type: 'number'
  },
  {
    label: '设置高度',
    value: 'height',
    type: 'number'
  },
  // 新增两种颜色属性
  {
    label: '字体颜色',
    value: 'color',
    type: 'color'
  },
  {
    label: '背景颜色',
    value: 'backgroundColor',
    type: 'color'
  }
]

之前我们新增过弹窗类型,现在我们新增一个色板的类型。

javascript 复制代码
  const getComponent = () => {
    switch (type) {
      case 'color': {
      case 'color': {
        return <ColorPicker disabledAlpha showText value={selectNode?.comStyle?.[value] || ''} style={{width:'120px'}} defaultValue={defaultValue} onChangeComplete = {onChange}/>
      }
    }
  }

然后我们再修改一下changeComStyle方法:

javascript 复制代码
  const changeComStyle = (value: string) => {
    return (e: any) => {
      let attribute = e;
      if(typeof e === 'object') {
        if(['color', 'backgroundColor'].includes(value)) {
          attribute = e.toHexString()
        }else{
          attribute = e.target.value;
        }
      }
      if(['width', 'height'].includes(value)) {
        attribute += 'px'
      }
      if(selectNode) {
        if(!selectNode.comStyle) {
          selectNode.comStyle = {}
        }
        selectNode.comStyle[value] = attribute;
      }
      Store.dispatch({type: 'changeComList', value:comList})
    }
  }

OK,现在我们就可以通过色板去调整Button组件的字体颜色和背景颜色了。

OK, 现在我们给Button组件再补充一些常见的样式属性。

javascript 复制代码
import { Style } from "../styleMap"
const buttonStyle: Style[] = [
  {
    label: '设置宽度',
    value: 'width',
    type: 'number'
  },
  {
    label: '设置高度',
    value: 'height',
    type: 'number'
  },
  {
    label: '字体颜色',
    value: 'color',
    type: 'color'
  },
  {
    label: '背景颜色',
    value: 'backgroundColor',
    type: 'color'
  },
  {
    label: '边框宽度',
    value: 'borderWidth',
    type: 'number'
  },
  {
    label: '边框颜色',
    value: 'borderColor',
    type: 'color'
  },
  {
    label: '边框样式',
    value: 'borderStyle',
    type: 'select',
    options: [
      {
        value: 'solid',
        label: '实线'
      },
      {
        value: 'dotted',
        label: '点线'
      },
      {
        value: 'dashed',
        label: '虚线'
      }
    ],
    defaultValue: 'solid'
  }
]

export {
  buttonStyle
}

OK,Button组件的样式面板我们就已经完成了。

相关的代码提交在github上: github.com/TeacherXin/... commit: 第十节: 实现样式面板并支持Button组件的样式配置

博主补充

如果你已经对Button组件的样式面板比较了解,希望你能把其他组件的样式配置也写出来,这一部分的内容,不会用文章来叙述了。

只会出现在以下的github提交记录上:

github.com/TeacherXin/... commit: 第十节: 支持Form组件的样式配置

github.com/TeacherXin/... commit: 第十节: 支持Icon组件的样式配置

github.com/TeacherXin/... commit: 第十节: 支持Input组件的样式配置

相关推荐
TonyH200212 小时前
webpack 4 的 30 个步骤构建 react 开发环境
前端·css·react.js·webpack·postcss·打包
布列瑟农的星空13 小时前
低代码平台实践——代码编辑器
低代码
掘金泥石流13 小时前
React v19 的 React Complier 是如何优化 React 组件的,看 AI 是如何回答的
javascript·人工智能·react.js
lucifer31116 小时前
深入解析 React 组件封装 —— 从业务需求到性能优化
前端·react.js
colorknight16 小时前
1.2.3 HuggingFists安装说明-MacOS安装
人工智能·低代码·macos·huggingface·数据科学·ai agent
秃头女孩y20 小时前
React基础-快速梳理
前端·react.js·前端框架
sophie旭1 天前
我要拿捏 react 系列二: React 架构设计
javascript·react.js·前端框架
BHDDGT1 天前
react-问卷星项目(5)
前端·javascript·react.js
liangshanbo12151 天前
将 Intersection Observer 与自定义 React Hook 结合使用
前端·react.js·前端框架
黄毛火烧雪下2 天前
React返回上一个页面,会重新挂载吗
前端·javascript·react.js