web架构师编辑器内容-数据结构设计上面的难点

组件的属性应该怎样设计

业务组件分为:样式属性和其他属性,样式属性就是css,其他属性拿文本来说,就是比如test还有点击事件等。

有两种方案:

方案一:把css作为统一的对象传入:

ts 复制代码
  <LText css={{color: 'fff'}} text="nihao"/>
  <p style={props.css}></p>

方案二:将所有的属性全部平铺传入

ts 复制代码
  <LText text="hello" color="#fff" />
  const styles = stylePick(props)
  <p style={style}></p>

  // 对于一些公用属性,比如 L-text和l-image都有一个页面跳转的公共行为,
  // 在组件中我们要抽离出公共的函数
  import useClick from 'useCLick'
  useClick(props)

这两种方案,第二种方案相比于第一种比较好,第一种使用内部实现简单,但是保存的时候需要多保存一层结构,后端可能也需要多保存一层结构,并且我们在更新数据的时候还要区分css属性还是其他属性,做一个区分,方案二内部实现比较复杂一些,但是保存的时候比较好保存,我们平铺就可以进行保存,在更新数据的时候也不需要甄别。

编辑器的难点

分为三个部分,左侧是业务组件的模板库:文本,图片,形状,中间是画布,可以对元素进行一些修改,右侧是设置面板

编辑器是围绕着画布进行一系列的操作。元素抽象成一个拥有特定结构的数组。如何将画布上面选中的元素,映射到右侧面板中的属性设置,并且进行更新是一个比较复杂的事情:

ts 复制代码
// 整个编辑器使用一个store来实现具体功能,总体设计如下
export interface EditorProps {
  // 供中间编辑器渲染的数组
  components: ComponentData[];
  // 当前编辑的是哪个元素,uuid
  currentElement: string;
  // 当然最后保存的时候还有有一些项目信息,这里并没有写出,等做到的时候再补充
}
export interface ComponentData {
  // 这个元素的 属性,属性请详见下面
  props: {[key: string]: any};
  // id,uuid v4 生成
  id: string;
  // 业务组件库名称 l-text,l-image 等等 
  name: string;
}

// 渲染画布:
const compoents = [
  { id: '1', type: 'l-text', props: {text: 'hello', color: 'green'}},
  { id: '2', type: 'l-text', props: {text: 'hello2', color: 'purple'}},
]
compoents.map(componet => <compoent.name {...props} />)

// 渲染左侧模板
compoents.map(componet => <wrap><compoent.name {...props} /></wrap>)

// 添加删除元素
// 添加元素,在左侧模板,直接在 components中添加元素,
compoents.push({ id: '3', type: 'l-text', props: {text: 'hello2', color: 'purple'}},)
// 属性元素,在画布里面执行删除事件
components = components.filter(compoent => compoent.id !== id)

// 将选中的值渲染到右侧画布中去:
const currentCompoentProps = {
  text: '123',
  color: '#fff',
  imgUrl: ''
}

将选中的元素currentCompoentProps映射到右侧面板设置中的属性设置中有以下方案:

  • 方案一:
ts 复制代码
// 伪代码,最终产生的效果是这样的:
<input value={text} />
<color-picker value={color} />
<img url={imgUrl}/>
// 这样写的话,有以下一些缺点:
 1. 比较冗长,如果有100个不同的属性,后面可能要写100个不同的组件,
 2. 不同类型的业务组件都要做不同的判断
 if type === 'text'
 <input value={text} />
 <color-picker value={color} />
 else if type === 'image'
 3. 可扩展性比较差。
 如果我们后面添加新的业务组件,就要写更多的if else
  • 另一个实现方案:界面的UI,就是数据的抽象,所以我们自然想到的就是使用特定的数据结构将他渲染成就界面。
ts 复制代码
 const textComponentProps = {
  text: 'hello',
  fontFamily: 'Heiti',
  color: '#fff'
 }
 const propsMap = {
  text: {
    component: 'input'
  },
  fontFamily: {
    component: 'dropdown'
  },
  color: {
    component: 'color-picker'
  }
 }

 map(textComponentProps, (key, value) => {
  const hanldeChange = (propKey, newValue, id) => {
    const updateComponent = store.components.find(component.id === id)
    updateComponent.props[propKey] = newValue
  }
  <propsMap[key].component value={value} @change={hanldeChange}/>
 })
复制代码
相关推荐
majingming1231 小时前
FUNCTION
java·前端·javascript
A_nanda2 小时前
Vue项目升级
前端·vue3·vue2
SuperEugene2 小时前
Axios 接口请求规范实战:请求参数 / 响应处理 / 异常兜底,避坑中后台 API 调用混乱|API 与异步请求规范篇
开发语言·前端·javascript·vue.js·前端框架·axios
abigale033 小时前
【浏览器 API / 网络请求 / 文件处理】前端文件上传全流程:从基础上传到断点续传
前端·typescript·文件上传·vue cli
Setsuna_F_Seiei3 小时前
AI 对话应用之页面滚动交互的实现
前端·javascript·ai编程
新缸中之脑3 小时前
追踪来自Agent的Web 流量
前端
wefly20174 小时前
从使用到原理,深度解析m3u8live.cn—— 基于 HLS.js 的 M3U8 在线播放器实现
java·开发语言·前端·javascript·ecmascript·php·m3u8
英俊潇洒美少年4 小时前
vue如何实现react useDeferredvalue和useTransition的效果
前端·vue.js·react.js
kyriewen115 小时前
给浏览器画个圈:CSS contain 如何让页面从“卡成PPT”变“丝滑如德芙”
开发语言·前端·javascript·css·chrome·typescript·ecmascript
英俊潇洒美少年5 小时前
react19和vue3的优缺点 对比
前端·javascript·vue.js·react.js