《架构师》-第10周-编辑器基本布局,及业务组件库初步开发

105 阅读7分钟

主要内容

  • 完成第一个业务组件LText的书写
  • 画布逻辑:完成业务组件属性和表单组件的显示和实时更新
  • 代码升级:支持vNode的在vue template中的显示

2-1.将编辑器数据结构添加至vuex store

1.新建两个interface

1.EditorProps{
  components: 中间编辑器渲染的数组
  currentElement: 当前编辑的是哪个元素,uuid
  //...其他的后面补充
}

2.ComponentData{
  props: {}
  id: uuid生成
  name: 业务组件库名称
}

2.安装uuid和@types/uuid。

3.editor文件中引入uuid V4。

4.创建几条测试数据,是某种interface。

5.创建editor的数据。

editor = {
  components: 刚创建的测试数据
  currentElement: ''
}

6.在store中导入editor模块和类型。加入store的modules中。

7.在editor中引入store,获取store中的components,并展示出来。

2-2.LText组件初步实现

业务组件的属性分为样式属性其他属性

比如我有text和fontSize两个属性。

创建LText的组件。

template
中的标签是不固定的 -> 采用component is的写法 传入style class
中间传入text
template

props:{
  text: {
    type:
  },
  fontSize: {
    type:
  }
  // p标签或者div
  tag: {
     type:
     default:
  }
}
setup(props){
  // 从所有的属性中找到样式属性 -> lodash的pick方法 -> computed
}

安装lodash-es(采用ES modules写的)和@types/lodash-es(定义文件)。

在Editor中循环的展示LText。也是用component的is。v-bind绑定props属性。

2-3.LText添加通用属性

有1个问题:
整合LText的props,让业务组件可以快速的添加各种属性。

查看需求文档:
文本组件有通用属性和特有属性。

在src创建defaultProps文件。

创建通用属性的数据结构CommonDefaultProps,并且有默认值。

创建文本的特有属性TextDefaultProps。

TextDefaultProps混入通用属性。

在LText组件中需要转换数据结构。

{
  text: {
    type:
    default:
  }
}

用loadash的mapValues方法。

在LText组件中导入转换后的数据结构。

tag不属于通用属性和特有属性。

接着选中所有的样式属性,也就是剔除非样式的属性。用lodash的without的方法。接着修改LText的style。

value.constructor写成了typeof value 一直报错。

做完出现有些属性找不到的问题。

2-4. LText使用hooks重用逻辑

转换数据结构的方法中得从输入推断输出的数据的类型。ts的范型的类型约束。

image.png

使用hooks抽取可重用逻辑。

1.获取style的所有相关属性。

2.点击能跳转文本,handleClick的处理。

如果actionType是ulr,还有url时,点击文本能跳转。在hooks中需要判断,并且给他添加handleClick,点击后跳转的逻辑。

LText使用hooks。

2-5.点击模板列表添加到到画布

image.png

创建一个componetsList组件。

用v-for循环展示LText组件。用v-bind把属性传过去。

image.png

每一个LText外面需要一个div包裹起来,用来隔离。并在div上绑定点击事件(用emit)。

image.png

监听componetsList组件的点击事件,然后去store中处理,创建一个newComponent,id、name和props。然后push进components。

2-6.为业务组件属性添加类型的利弊

问题:我们是否特定的interface描述整个业务组件一系列的属性? 添加CommonComponentProps和TextComponentProps两个interface。

hooks中传入的参数 Readonly、Partial。

使用ts,确实害怕定义类型的麻烦。

3-1.获取正在编辑的元素的属性

更新组件的流程:

  • 点击某一个组件,选中
  • 将它的属性以不同类型的表单呈现在右侧
  • 编辑表单中的值,在值更新的同时将数据更新至页面

创建一个EditWrapper组件。

首先给组件传入id,id是必传的。

发射一个事件(用emits)

在setup中,创建一个onItemClick方法,用来发射事件(id)。

在div上绑定这个事件。div中用slot。

在Editor的展示区替换掉EditWrapper组件。

将setActive方法绑定到EditWrapper组件上。

store的mutations中增加一个方法setAction。

setAction(){
   更新current.Element
}
interface ComponentData{
  props: ___
  id:___
  name:___
}

给store添加getters,通过id找到当前的element。

去Editor中添加currentElement。给它添加范型(联合类型)。

右侧sidebar中用pre标签展示currentElement。

测试: 点击画布区域的某一个元素,右侧sidebar展示出来它的属性们。

逻辑写完了,现在加一些css。

被选中的组件有一个边框高亮。

给EditWrapper组件添加一个属性active。用active来控制样式。active为true时加一个蓝色的边框。active从父组件中传递,通过判断该id和currentElement的id是否一样。

image.png

3-2. 添加属性和表单的基础对应关系并展示

界面到数据的抽象。

const textComponentProps = {
  text: 'hello',
  color: '#fff'
}

创建一个interface{
  有component
  还有一个可选的value
}


const propsMap = {
  text: {
    component: 'input'
  },
  color: {
    componnet: 'color-picker'
  }
}

// 循环所有的属性,在每个属性中去渲染出处理这个属性的组件

用ts的属性循环 => {
  component: '',
  value: ''
}

创建src/propsMap.ts文件。

传入的数据转换成界面。

image.png

创建一个PropsTable的组件。

传入的数据,判断是否在propsMap中,如果有才能转换成{component: '', value: ''}这样格式的。所以之前的lodash的mapToVaules方法不能用了。采用reduce。还用到了类型断言。

处理完的数据v-for循环展示。

最后实现的功能就是点击画布编辑的某一个元素,右侧显示出currentElement的所有属性,例如text=>去展示一个input。

image.png

3-3.添加更多的简单对应关系并展示

text---文本————a-input/a-textarea

lineHeight---数字————a-slider

fontSize---数字————a-input-number

首先先去propsMap中添加对应的关系。

要给表单组件添加一系列属性,比如a-slider想设置min、max和step。

给interface PropToForm的a-slider增加一个extraProps。[key: string]

组件需要v-bind传递extraProps。

再去添加一个rows是3的textarea。

给每一个属性组件添加一个属性标签。

断言里加一个Required。可选变成必选。

3-4.添加更多复杂对应关系并展示

fontFamily---几个文本之一————a-select textAlign---几个文本之一————a-radio-group

扩展PropToForm的interface。比如说选项按钮,需要子组件,增加subComponent属性。options数组。

v-for循环展示,用template包裹。

传入的属性有的需要转换格式。

PropToForm增加一个函数initialTransform,用来给属性转换格式。(这里代码写的不太对)

再去PropsTable中把value进行转换。

fontSize也要"20px" => 20

3-5.分析展示和编辑属性的"金科玉律"

还有一些组件是ant-design没有的,自己需要开发。 颜色选择组件。 特殊的checkbox。

<edit-component :value="#111111/123/[1,2,3]" />

<edit-component :valueProp="#111111/123/[1,2,3]" />

PropToForm还需要加一个valueProp的动态属性。会给component传入:[value.valueProp]的值。

不知道这在干嘛?

image.png

必须提供一个属性传入需要编辑的值,默认为value

必须提供一个事件发射出编辑后的新的值,默认为change

3-6.添加编辑表单并更新界面

给PropsTables添加emits。

PropsToForm添加属性eventName和events。

给component绑定事件。v-on。

两个有区别的数据结构。PropToForm精简一些,只是为了渲染表单。然后去PropsTable定义一个更复杂的结构FormProps, 加上events, 它的类型是一个object,里面是key对应方法。

优化reduce方法,定义一个新的变量FormProps类型。在event定义中发射事件change,传参key和value。类型断言也要改。

PropsTable发射事件,在Editor上接收事件。

测试: 修改右边组件Form的值,可以接收发射的事件。

3-7.添加编辑表单并更新界面

PropsToForm中不仅要定义正向的转换initialTransform,还要定义反向的转换afterTransform。

其中text、textAlign需要获取到e.target.value。

fontSize需要加px,和删px。

lineHeight: string = number。

在发送事件时去调用transform。

Editor中handleChange中commit方法updateComponent。store的mutations增加一个updateComponent。寻找currentElement元素,然后修改属性。

3-8.提出优化需求,以及组件返回的真相

1.字体选择的时候,下拉菜单没有字体的例子显示。

将文本转换为vNode。

<div>{{ text }}</div>

把这里的text转换成vnode。

ts=>Vue.h方法。

tsx=>直接写标签,最后断言成VNode。

2.在编辑器组件的右侧添加一个删除图标,点击后可以将该元素删除。

3.添加更多属性和组件的对应关系。比如Opacity。