vue项目中如何实现组件拖拽

202 阅读1分钟

目录如下

2023-06-14_180512.jpg

1、App.vue

<template>
  <div id="app">
     <Render/>
     <JSX/>
     <LowCode/>

  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
import Render from './components/01_Render.vue'
import JSX from './components/02_JSX.vue'
import LowCode from './components/03_LowCode.vue'

export default {
  name: 'App',
  components: {
    Render,JSX,LowCode
  }
}
</script>

2、Render.vue

<script>
export default {
    methods: {
        getDomAttr() {
            return { style: { background: 'yellowgreen' }, attrs: { mytest: 'abc' },on: { click: function () { alert(1) } }  };
        }
        // on: { click: function () { alert(1) } }
    },
    // 提取来的方法,复用性相对更好
    render(h) { // h:createElement: 创建元素
        // 组件或者标签名
        return h('div', this.getDomAttr(), [
            h('h2', {}, '1'),
            h('h2', {}, '2'),
            h('h2', {}, '3'),
            h('button',{},'4'),
        ]);
      
    }
}
</script>

3、JSx.vue

<script>

function renderDemo1(h,num1) {
    return num1 === 1 && <div>111</div>
}
// 纯函数, 不依赖于函数上下文
// 纯函数: 不依赖this相关的属性,通过形参的传递,来实现功能
function renderDemo(h,num, num1) {
    switch (num) {
        case 1:
            return <div>一的内容  {renderDemo1(h,num1)}   </div>;
        case 2:
            return <div>二的内容</div>
    }
}
// function renderForm(h,form){
//     // 使用v-model需要组件this支撑
//     return <input v-model={ form.username } />
// }

function renderForm(h,form){
    // 使用v-model需要组件this支撑
    return <input value={ form.username } onInput={ val => form.username = val.target.value }  />
}


export default {
    methods: {
        doClick() {
            console.log('开始点击了...')
        },
        renderTest() {
            return (
                <div style={{ background: 'yellowgreen' }} test={'abc'} onClick={this.doClick}  >
                    <h2>1</h2>
                    <h2>2</h2>
                    <h2>3</h2>
                </div>
            )
        },
        // 原版本
        // renderDemo() {
        //     return this.num === 1 ? <div>一的内容  {this.renderDemo1()}   </div> : this.num === 2 ? <div>二的内容</div> : null
        // },
    },
    data() {
        return {
            num: 1,
            num1: 1,
            form:{ username:'123'  }
        }
    },
    render(h) {
        const { num, num1,form } = this;
        // return renderDemo(h,num, num1);

        // return renderForm.call(this,h,form);  $set is undefined
        return renderForm(h,form)
    }
}
</script>

<style>

</style>

3、03_LowCode.vue

<template>
    <div class="box">
        <div class="aside">
            <!-- vue-draggable -->
            <button compName="A" draggable="true" @dragstart="recordData">A组件</button>
            <button compName="B" draggable="true" @dragstart="recordData">B组件</button>
            <button compName="C" draggable="true" @dragstart="recordData">C组件</button>
            <button compName="D" draggable="true" @dragstart="recordData">D组件</button>
        </div>
        <div class="viewport" @dragover.prevent @drop="addComp">
            <div :id="item.id" v-for="item in comps"></div>
        </div>
    </div>
</template>

<script>
import A from './A';
import B from './B';
import C from './C';
import D from './D';
import Vue from 'vue';
export default {
    components: {
        A, B, C, D      
    },
    data() {
        return {
            comps: []
        }
    },
    methods: {
        addComp(e) {
            let compName = e.dataTransfer.getData('compName');
            console.log('组件名称:', compName);

            const Comp = this.$options.components[compName];
            // 1.添加一个坑
            this.comps.push({
                id: compName
            });
            this.$nextTick(() => {
                // 2.触发坑的渲染
                new Vue({
                    render: Comp.render,
                }).$mount('#' + compName)
            })
        },
        recordData(e) {
            console.log('开始拖动了')
            let compName = e.target.getAttribute('compName');
            e.dataTransfer.setData('compName', compName);
        }
    }
}
</script>

<style scoped>
.box {
    width: 1000px;
    display: flex;
}

.box,
.aside,
.viewport {
    height: 800px;
}

.aside {
    width: 300px;
    background: yellowgreen;
}

.viewport {
    flex: 1;
    background: grey;
}
</style>

4、A、B、C组件可自行定义

5、动画效果如下

拖拽效果.jpg

6、总结

拖拽真方便,效率好高,一键三连,💖💖💖

兵主奇魂.gif