如何实现低代码的拖拽?


拖拽解决方案

  1. ```html
      <div
          class="picItem"
          :key="index"
          v-for="(pic, index) in children"
          @dragstart="fnDragStart(pic)"
          draggable="true"
        >
          <div class="label" :class="[pic.text && index ? 'textTop' : '']">
            {{ pic.text }}
          </div>
          <div class="pic">
            <img :src="pic.pic" @click.stop="fnClickComponent(pic)" />
          </div>
        </div>
      </div>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32

    首先v-for遍历提前在vuex的state中定义好的组件对象数据,然后使用draggable属性,自定义事件深拷贝一份提前定义好的组件对象,赋值给state中component对象中
    2. 普遍使用draggable

    ## 页面元素放置,布局解决方案

    1. 使用drop事件,将之前拖拽时赋值给state中的组件,调用vuex中的方法,将该对象保存起来

    ```javascript
    const fnDrop = (item, e) => {
    store.commit("activeView", item.id);
    let component = store.state.component;
    let id = Math.floor(Math.random() * 100000000);
    component['_id'] = id
    component['id'] = id
    store.commit("appendComponent", component);
    store.commit("setClickType", "component");
    store.commit("saveComponent", {});
    data.lastEnterEle = null
    data.enterIndex = -1;
    data.text = "可从左侧添加组件到此处";

    let historyIndex = store.state.historyIndex
    if(historyIndex != -1){
    let historyViews = store.state.historyViews
    // 获取当前操作,舍弃后面的数据
    let arr = historyViews.slice(0, historyIndex+1)
    store.commit('fnChangeHistoryView', deepClone(arr))
    }
    store.commit('fnAddHistoryView', deepClone(store.state.views))
    store.commit('changeHistoryIndex', - 1)
    };
  2. 普遍使用drop事件调用函数放置变量

预览解决方案

  1. 通过修改vuex中视图区域的变量,双向绑定使用该变量显示页面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    //视图区域
    views:[{
    focus: true,
    id: Math.floor(Math.random()*10000000),
    data:{
    type: 1,
    left: 0,
    top: 0,
    width: 375,
    height: 225,
    bgColor: '',
    bgImg: '',
    },
    components:[]
    },{
    focus: false,
    id: Math.floor(Math.random()*10000000),
    data:{
    type: 1,
    left: 0,
    top: 0,
    width: 375,
    height: 225,
    bgColor: '',
    bgImg: '',
    },
    components:[]
    }],
  2. 用拖拽生成的json数据,在页面v-for循环出来,之后使用iframe嵌入页面

图片视频上传解决方案

  1. 调用接口,返回数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    const fnUpload = (e) => {
    let type = store.state.type
    let file = e.target.files[0]
    var _data = new FormData();
    _data.append('file', file);
    axios.post("http://127.0.0.1:3001/album/upload", _data, {
    headers:{
    "content-type": "application/x-www-form-urlencoded"
    }
    }).then(res => {
    if(type == 'component'){
    props.data.picContent = res?.data?.data?.path || 'https://p6-orange.byteorge.com/img/ad-tetris-site/brick_tpl_picture_0.png~noop.webp'
    }
    else{
    props.data.bgColor = ""
    props.data.bgImg = res?.data?.data?.path || 'https://p6-orange.byteorge.com/img/ad-tetris-site/brick_tpl_picture_0.png~noop.webp'
    }
    let historyIndex = store.state.historyIndex
    if(historyIndex != -1){
    let historyViews = store.state.historyViews
    // 获取当前操作,舍弃后面的数据
    let arr = historyViews.slice(0, historyIndex+1)
    store.commit('fnChangeHistoryView', deepClone(arr))
    }
    store.commit('fnAddHistoryView', deepClone(store.state.views))
    store.commit('changeHistoryIndex', - 1)
    e.target.value = ""
    }).catch(err => {
    console.log(err)
    e.target.value = ""
    })
    }
    return {
    fnUpload,
    }
    }
  2. 将页面中放图片的位置放默认图片或者默认视频,或者置空,给样式加flex-shrink:0;防止伸缩,之后后期将需要加的图片放到src中

修改属性解决方案

  1. 根据被点击的元素,遍历可修改的属性并返回,通过修改该对象进而修改显示结果

发布解决方案

  1. 发送请求 保存

元素放置之后的布局定位问题

  1. 提前定义好容器,然后使用views定义的data样式![]
    在外部的容器中使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    .wrapCenter {
    flex: 1;
    height: 100%;
    background-color: antiquewhite;
    overflow-y: auto;
    }
    .editor {
    width: 375px;
    min-height: 740px;
    height: auto;
    background-color: #fff;
    margin: 0 auto;
    margin-top: 20
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
root:{
class:"string",
style:{},
son:[
{
class:"string",
style:{},
son:[
class:"string",
style:{},
son:[...]
]
},
{...},
]
}
}

遗留问题

  • 树形结构的预览
  • json与vue | html文件的转换
  • 全局数据管理
  • 发布文件,vue与html文件转换
  • 元素布局方式
  • 拖拽之后提示用户

解决方案(version 1.1)

  1. 首先布局分为left,center,right,header
  2. 将低代码每个组件封装的json数据放置到vuex中
  3. left将vuex中的组件数据循环出来
  4. left拖拽之后,拖到中间center区域,当dragover事件被触发时修改该被dragover的元素样式,提示用户,例如是在上方则在上方创建一个新的盒子,之后如果用户松手则与该盒子替换
  5. 替换之后更新center页面中的树形结构数据,页面照常预览
  6. 用户点击某一元素之后,根据该元素提前定义好的data值,在right中显示出相应要修改的属性
  7. 点击发布之后将json?how to vue or html ?之后生成链接供别人访问

Author: pkq
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source pkq !
  TOC