Vue

Vue拖拽组件布局,element ui拖拽组件布局

特别声明:如果您喜欢小站的内容,可以点击 终身VIP¥188.00元 包年VIP¥88.00元 包季VIP¥28.00 包月VIP¥10.00元 进行全站阅读。 如果您对付费阅读有任何建议或想法,欢迎发送邮件至: 864479410@qq.com,或添加QQ:864479410(^_^)

Vue拖拽组件布局,element ui拖拽组件布局

效果预览

git地址:https://gitee.com/javanx/draglayout

效果解析

1、flex布局成3栏

(1)、左侧定义好固定组件

(2)、中间拖放后的预览效果

(3)、右侧是,点击中间的组件后,可以编辑对应属性

2、利用html5的draggable属性,完成拖动效果

3、vue完成拖放后数据的驱动

4、表单双向绑定,改变组件属性

5、最终数据结构

初始化项目

vue create hello-world

1、安装element-ui

npm i element-ui --save

2、main.js引入

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

3、flex布局
删除掉默认的些许代码

<div class="home">
  <div class="flex">
    <div class="components-group">组件区</div>
    <div class="preview">预览区</div>
    <div class="component-attr">属性编辑区</div>
  </div>
</div>
/** 布局样式 */
.home{
  height: 100vh;
  padding: 20px 0;
}
.flex{
  display: flex;
  justify-content: space-between;
}
.components-group{
  width: 300px;
  height: 800px;
  background: #fff;
  border: 1px solid red;
}
.preview{
  width: 320px;
  background: #fff;
  box-shadow: 0px 2px 20px 0px rgb(208 215 222 / 46%);
  border-radius: 12px;
  border: 1px solid #edf0f5;
  padding: 10px;
}
.component-attr{
  width: 300px;
  height: 800px;
  background: #fff;
  border: 1px solid red;
}

这就出来了我们整个的页面结构框架
效果预览

默认组件

咱们是数据驱动的,所有先定义好数据吧。定义好默认组件,并在左侧渲染出来。

componentsGroup: [{
  type: 1,
  label: '文本',
  components: [{
    id: 1,
    widgetKey: 'widget_text_single',
    label: '单行文本',
    type: '单行文本',
    required: true,
    hint: '请输入',
    value: ''
  }]
  ...
}, {
  type: 10,
  label: '数值',
  components: [{
    id: 11,
    widgetKey: 'widget_number',
    label: '数字',
    type: '数字',
    unit: '', // 单位
    required: true,
    hint: '请输入',
    value: ''
  }]
  ...
}]
<div class="components-group">
  <div class="components-group-item" v-for="(item, key) in componentsGroup" :key="key">
    <div class="type">{{item.label}}</div>
    <div>
      <div 
      class="components-item"
      v-for="component in item.components" 
      :key="component.id" 
      :data-type="item.type" 
      :data-id="component.id" 
      draggable="true">{{component.label}}</div>
    </div>
  </div>
</div>

样式部分大家自行到git上面看,这里就不一一列出

拖拽

mounted(){
  this.initDrag()
},
methods: {
  initDrag(){
    let vm = this
    let offsetY = 0
    var eleDustbin = $(".preview")[0], eleDrags = $(".components-item"), lDrags = eleDrags.length, eleRemind = $(".dragremind")[0], eleDrag = null;
    for (var i=0; i<lDrags; i+=1) {
      eleDrags[i].onselectstart = function() {
        return false;
      };
      eleDrags[i].ondragstart = function(ev) {
        ev.dataTransfer.effectAllowed = "move";
        ev.dataTransfer.setData("text", ev.target.innerHTML);
        ev.dataTransfer.setDragImage(ev.target, 0, 0);
        eleDrag = ev.target;
        return true;
      };
      eleDrags[i].ondragend = function(ev) {
        ev.dataTransfer.clearData("text");
        eleDrag = null;
        return false
      };
    }
    eleDustbin.ondragover = function(ev) {
      ev.preventDefault();
      return true;
    };

    eleDustbin.ondragenter = function(ev) {
      offsetY = ev.offsetY;
      $('.droptarget').css({
        border: 'none'
      });
      if (ev.target.className.indexOf('droptarget')>-1) {
        ev.target.style.border = "1px solid red";
      }
      return true;
    };
    eleDustbin.ondrop = function(ev) {
      $('.droptarget').css({
        border: 'none'
      });
      let id = $(eleDrag).data('id');
      let type = $(eleDrag).data('type');
      if(!id) return false
      let component = ''
      if(vm.tabbarActive==1){
        vm.componentsGroup.find(item=>{
          if(item.type==type){
            let components = item.components
            component = components.find(citem=>citem.id==id)
          }
        })
      } else {
        component = vm.componentsGroupGroup.find(item=>item.type==type)
      }
      component.widgetNo = moment().valueOf()
      let components = vm.formData.components

      var dragitem = ev.target.closest('.form-components-item');
      // console.log(dragitem)
      if(dragitem){
        let index = $(dragitem).data('index')
        let ditem = $(dragitem).data('item')

        if(ditem.type=='明细'){
          if(component.type=='明细'){
            Message({
              type: 'warning',
              message: '明细组件中不可以再添加明细组件'
            })
            return
          }
          if(!ditem.components){
            ditem.components = []
          }
          // component.pno = ditem.widgetNo
          if(ev.offsetY+5>offsetY){
            ditem.components.splice(index, 0, component)
          }else{
            ditem.components.splice(index+1, 0, component)
          }
        } else {
          if(ev.offsetY+5>offsetY){
            components.splice(index, 0, component)
          }else{
            components.splice(index+1, 0, component)
          }
        } 
      } else {
        components.push(component)
      }
      // components.push(component)
      components = JSON.parse(JSON.stringify(components))

      console.log('components', components)

      Vue.set(vm.formData, 'components', components)
      setTimeout(()=>{
        vm.initSort()
      }, 500)
      return false;
    };
  }
}

这里用到了jquery,感觉还是jquery香啊。

有了数据就简单了,变量数据,根据widgetKey,判断不同的组件渲染不同的element-ui组件即可。详情见git代码。

上方代码还有一个明细控件组,意思是,明细里面可以包含子控件。

(1)

本文由 Web秀 作者:Javan 发表,转载请注明来源!

关键词:, ,

热评文章

发表评论

邮箱地址不会被公开。 必填项已用*标注