在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放
链接和图片默认是可拖动的,不需要 draggable 属性
MDN drag文档
https://www.cnblogs.com/moqiutao/p/6365113.html
https://www.cnblogs.com/weiqinl/p/7886049.html
在拖动目标上触发事件 (源元素)
- ondragstart - 用户开始拖动元素时触发
- ondrag - 元素正在拖动时触发
- ondragend - 用户完成元素拖动后触发
释放目标时触发的事件:
- ondragenter - 当被鼠标拖动的对象进入其容器范围内时触发此事件
- ondragover - 当某被拖动的对象在另一对象容器范围内拖动时触发此事件
- ondragleave - 当被鼠标拖动的对象离开其容器范围内时触发此事件
- ondrop - 在一个拖动过程中,释放鼠标键时触发此事件
DragEvent使用场景
- 文件拖拽上传
- 拖拽排序
DragEvent 继承 MouseEvent 和Event属性
https://developer.mozilla.org/zh-CN/docs/Web/API/DragEvent
https://developer.mozilla.org/zh-CN/docs/Web/API/Document/drag_event
lynda drag&win drop
https://blog.csdn.net/jariwsz/article/details/7865426
https://blog.csdn.net/jariwsz/article/details/7868242
拖拽详解
https://blog.csdn.net/baidu_25343343/article/details/53215193
https://blog.csdn.net/qq_40882724/article/details/85237030
DragEvent
DragEvent
Object.keys(DragEvent)
e.hasOwnProperty(key) // 'isTrusted'
DragEvent property
["isTrusted","dataTransfer","screenX","screenY","clientX","clientY","ctrlKey","shiftKey","altKey","metaKey","button","buttons","relatedTarget","pageX","pageY","x","y","offsetX","offsetY","movementX","movementY","fromElement","toElement","layerX","layerY","getModifierState","initMouseEvent","view","detail","sourceCapabilities","which","initUIEvent","type","target","currentTarget","eventPhase","bubbles","cancelable","defaultPrevented","composed","timeStamp","srcElement","returnValue","cancelBubble","path","NONE","CAPTURING_PHASE","AT_TARGET","BUBBLING_PHASE","composedPath","initEvent","preventDefault","stopImmediatePropagation","stopPropagation"]
darg.md
https://blog.csdn.net/qq_42301358/article/details/108372100
https://blog.csdn.net/zy1281539626/article/details/112743588
- Event BaseAPI
2. 注册 drag事件 element.addEventListener(‘dragstart’, onDragStart, false)
3. Events maybe fired repeatedly
4. optional dropzone
element.addEventListener('dragstart', onDragStart, false);function onDragStart(e) {}
dataTransfer

<template><el-row><el-col :span="12"><el-form ref="form" class="b-a" label-width="80px"><draggable :clone="cloneData" :list="form_list" :options="dragOptions1"><transition-group class="form-list-group" type="transition" :name="'flip-list'" tag="div"><renders v-for="(items, index) in form_list" :key="index" :ele="items.ele" :obj="items.obj"></renders></transition-group></draggable></el-form></el-col><el-col :span="12"><el-form ref="form" :model="formData" class="b-a" label-width="80px" ><draggable :clone="cloneData" :list="list2" :options="dragOptions1"><transition-group class="form-list-group" type="transition" :name="'flip-list'" tag="div"><renders v-for="(items, index) in list2" :key="index" :ele="items.ele" :obj="items.obj" @handleChangeVal="val => handleChangeVal(val,items)"></renders></transition-group></draggable><el-form-item><el-button @click="handleSubmit('form')">保存</el-button></el-form-item></el-form></el-col></el-row></template><script>import draggable from "vuedraggable";import form_list from "@/components/custom/FormList";import renders from "@/components/custom/Render";export default {data() {return {form_list,list2: [],formData: {}};},components: {draggable,renders},methods: {handleSubmit(name) { //保存this.$refs[name].validate((valid) => {if (valid) {localStorage.setItem('template_form', JSON.stringify(this.sortable_item));console.log(this.sortable_item) //表单中的内容} else {console.log('验证不通过')}})},// https://github.com/SortableJS/Vue.Draggable#clone// 克隆,深拷贝对象cloneData(original) {// 深拷贝对象,防止默认空对象被更改return JSON.parse(JSON.stringify(original));},// 控件回填数据handleChangeVal(val, element) {this.$set(this.formData, element.obj.name, val);}},computed: {// 拖拽表单1dragOptions1() {return {animation: 0,ghostClass: "ghost",// 分组group: {name: "shared",pull: "clone",revertClone: false},// 禁止拖动排序sort: false};},// 拖拽表单2dragOptions2() {return {animation: 0,ghostClass: "ghost",group: {// 只允许放置shared的控件,禁止pullput: ["shared"]}};}}};</script><style>.form-list-group {min-height: 200px;padding: 20px !important;}.b-a {border: 1px solid #ccc;}.ghost {opacity: 0.5;background: #c8ebfb;}</style>
formlist
import { inputConf } from "./control/Input";import { radioConf } from "./control/Radio";import { checkBoxConf } from "./control/CheckBox";const formList = {input: inputConf,radio: radioConf,checkBox: checkBoxConf};let list_arr = [];for (let i in formList) {list_arr.push({ele: i,obj: formList[i]});}export default list_arr;
render
import input from './control/Input';import radio from './control/Radio';import checkBox from './control/CheckBox';const form_item = {input,radio,checkBox};export default {name: 'renders',render(h) {return h('el-form-item', {props: {label: this.obj.label + ":"}}, form_item[this.ele](this, h));},props: {ele: {type: String,default: "input"},obj: {type: Object,default: {}}}}
checkbox
export default (_self, h) => {return [h("el-checkbox-group", {props: {value: _self.obj.value || []},on: {'input'(arr) {_self.obj.value = arr;_self.$emit('handleChangeVal', arr)}}},_self.obj.items.map(v => {return h("el-checkbox", {props: {label: v.label_value}}, v.label_name)}))];};export let checkBoxConf = {// 对应数据库内类型type: 'checkbox',// 是否可配置config: true,// 控件左侧label内容label: '多选框',// 是否显示行内元素inlineBlock: false,// 是否必填require: true,// 绑定的值value: ["1", "2"],// 选项内数据items: [{ "label_value": "1", "label_name": "单选框1" }, { "label_value": "2", "label_name": "单选框2" }],// 表单namename: '',// 验证错误提示信息ruleError: '该选项不能为空',// 是否关联字段relation: false,// 关联字段namerelation_name: '',// 关联字段valuerelation_value: '',// 是否被渲染visibility: true}
input
export default (_self, h) => {return [h("el-input", {props: {value: _self.obj.value || ""},attrs: {maxlength: parseInt(_self.obj.maxlength) || 20,placeholder: _self.obj.placeholder || "这是一个输入框",},on: {"change": function(val) {// if (!_self.obj.name) {// return false;// }_self.obj.value = event.currentTarget.value;_self.$emit('handleChangeVal', event.currentTarget.value)}}})];};export let inputConf = {// 对应数据库内类型type: 'input',// 是否可配置config: true,// 控件左侧label内容label: '输入框',name: '',placeholder: '',// 最大长度maxlength: 20,value: '',}
radio
export default (_self, h) => {return [h("el-radio-group", {props: {value: _self.obj.value || "1"},on: {'input' (value) {// if (!_self.obj.name) {// return false;// }_self.obj = Object.assign(_self.obj, {value});_self.$emit('handleChangeVal', value)}}}, _self.obj.items.map(v => {return h("el-radio", {props: {label: v.label_value},}, v.label_name)}))];};export let radioConf = {// 对应数据库内类型type: 'radio',// 是否可配置config: true,// 控件左侧label内容label: '单选框',// 绑定的值value: '',// 选项内数据items: [{ "label_value": "1", "label_name": "单选框1" }, { "label_value": "2", "label_name": "单选框2" }],// 表单namename: ''}
