Vue无代码可视化项目
渲染引擎(渲染器)
接下来要做的是,中间区域Block相关的内容,block相关的内容最重要的就是,数据协议设计和整体渲染器的逻辑
渲染器概念:简单点说就是,封装他的组件。比如做了一个图表,可以说封装了一个图表组件,如果做了一个表单校验,可以说做了一个表单校验组件,或者写了一些业务组件,但是这些点要是上升一点,就是,表单渲染 – 表单渲染器,表单渲染组件,表单规则约定 – 表单规则校验器;可以美化这些词语,提高简历
数据协议:左边物料区有很多的物料列表,将左边的物料拖到中间编排区进行编排,拖拽之后,这些内容区域就能组装成一个页面,那么从左边拖的时候,这些物料需要定义一个数据结构,这个数据结构就叫做数据协议,我们从左边拖过来的时候,需要将对应的数据加到右边页面中去,加进去的时候,我们的页面相当于又是一个大JSON,这是属于页面的协议,左边物料是物料协议。
物料渲染:我们有很多很多的物料,这些物料都要取通过条件规则判断来渲染,如果来的物料是文本,那么就按照文本的方式去渲染,如果来的物料是视频,那么就按照视频播放器的逻辑去渲染,如果来的物料是图表,就按照图表的渲染器去渲染,以此类推。
初版
创建物料blocks文件夹
- src
- blocks
- external
- internal
- TextBlock.vue
- ImageBlock.vue
- ChartBlock.vue
- blocks
blocks:可以分内部block(基础block)和外部block,就是最后代码结构内容和block整体渲染逻辑中,是可以加载外部block内容的,比如将有些block单独封装好之后,上传到远程,这时候远程能拉取到对应的js代码,通过umd打包后放上去,然后在使用的地方加载过来,植入到我们代码中。
TextBlock.vue
<!-- 共同去处理、规范约定他们 -->
<!-- Text/Image/Chart -->
<template>
<div>{
{text.content}}</div>
</template>
<script setup lang='ts'>
const text={
type:"text",
content:"这是一段文本"
}
</script>
<style scoped>
</style>
ChartBlock.vue
<!-- 共同去处理、规范约定他们 -->
<!-- Text/Image/Chart -->
<template>
<div>{
{chart.type}}</div>
</template>
<script setup lang='ts'>
const chart={
type:"chart",
content:"这是一段文本",
props:{
xAxis:['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],
yAxis:[820,930,901,934,1290,1330,1320]
}
}
</script>
<style scoped>
</style>
ImageBlock.vue
<!-- 共同去处理、规范约定他们 -->
<!-- Text/Image/Chart -->
<template>
<div>
<img :src="image.props.src" :alt="image.props.alt" />
</div>
</template>
<script setup lang='ts'>
const image={
type:"image",
content:"image",
props:{
src:"https://cdnjs.cloudflare.com/ajax/libs/twemoji/11.3.0/2/svg/1f469-200d-1f692.svg",
alt:"这是一个图片",
}
}
</script>
<style scoped>
</style>
LayoutView.vue
<SmoothDndDraggable>
<TextBlock/>
</SmoothDndDraggable>
<SmoothDndDraggable>
<ImageBlock/>
</SmoothDndDraggable>
<SmoothDndDraggable>
<ChartBlock/>
</SmoothDndDraggable>
import TextBlock from '@/blocks/internal/TextBlock.vue'
import ImageBlock from '@/blocks/internal/ImageBlock.vue'
import ChartBlock from '@/blocks/internal/ChartBlock.vue'
全部代码:
<template>
<div class="layout-wrapper" :class="{debug}" @click="debugStore.toggleDebug">
<LeftPanel />
<div>
<SmoothDndContainer class="block-group"
orientation="vertical"
tag="div" group-name="blocks"
@drop="(payload)=>{
console.log('payload',payload);
const newBlocks=applyDrag(blocks,payload)
editorStore.updateBlocks(newBlocks)
}"
>
<!-- <SmoothDndDraggable v-for="block in blocks" :key="block">
<div class="block-item">{
{block}}</div>
</SmoothDndDraggable> -->
<SmoothDndDraggable>
<TextBlock/>
</SmoothDndDraggable>
<SmoothDndDraggable>
<ImageBlock/>
</SmoothDndDraggable>
<SmoothDndDraggable>
<ChartBlock/>
</SmoothDndDraggable>
</SmoothDndContainer>
</div>
<div>
右
</div>
</div>
</template>
<script lang="ts" setup>
// import AppLeftPanel from '@/components/AppLeftPanel/AppLeftPanel';
import LeftPanel from '@/components/LeftPanel.vue';
import {
useDebugStore} from '@/stores/debug'
import {
useEditorStore} from '@/stores/editor'
import {
SmoothDndContainer} from '@/components/SmoothDnd/SmoothDndContainer'
import {
SmoothDndDraggable} from '@/components/SmoothDnd/SmoothDndDraggable'
import TextBlock from '@/blocks/internal/TextBlock.vue'
import ImageBlock from '@/blocks/internal/ImageBlock.vue'
import ChartBlock from '@/blocks/internal/ChartBlock.vue'
import {
storeToRefs } from 'pinia';
import type {
DropResult } from 'smooth-dnd';
import {
arrayMove} from '@/utils/array';
const debugStore = useDebugStore()
const editorStore = useEditorStore()
const {
debug}=storeToRefs(debugStore)
const {
blocks}=storeToRefs(editorStore)
const applyDrag=<T extends any[]>(arr:T,dragResult:DropResult)=>{
const {
addedIndex,removedIndex,payload}=dragResult
const result = [...arr]
if(addedIndex===null) return result;
// 添加:从外面拖进来是添加
if(addedIndex!==null&&removedIndex===null){
result.splice(addedIndex,0,payload)
}
// 移动:内部拖拽是移动
if(addedIndex!==null&&removedIndex!==null){
return arrayMove(result,removedIndex,addedIndex)
}
return result
}
</script>
<style>