Hello,我是Rocket
一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情
引言
效果图
1、元数据json的格式
{
"component": "v-text", //组件名, 全局注册会用到
"label": "文字", //左侧组件区展示的组件名称
"propValue": "双击编辑文字", //组件默认的值
"icon": "wenben", //组件的icon
"children":[], //子组件,这块是想着后边组合组件,没有实现
"style": { //样式
"width": 200,
"height": 22,
"fontSize": 14,
"fontWeight": 500,
"lineHeight": "",
"letterSpacing": 0,
"textAlign": "",
"color": ""
}
}
2、全局注册物料组件
- utils/globalRegister.js
在main.js调用,遍历 custom-components文件夹下 .vue后缀的
/*
* @Description: 全局注册
*/
import Vue from 'vue'
// 注册所有物料z组件
register(require.context('@/custom-components', true, /.vue/))
// /**
// * 注册对应包下所有组件
// * @param {*} path 包路径
// */
function register (context) {
context.keys().forEach(cnt => {
const component = context(cnt)
let ctrl = component.default || component
let a = ctrl.name
let b = ctrl
// 注册组件
Vue.component(a, b)
})
}
3、注册物料组件元数据json
- utils/registerSchema.js
Vue.prototype.$componentList 挂载到vue的原型对象
import Vue from 'vue'
// 注册所有物料属性参数与初始值
registerComponentsSchema()
// 获取所有自定义组件schema
function registerComponentsSchema () {
const files = require.context('@/custom-components', true, /component.json$/)
let initializing = []
files.keys().forEach(key => {
const [, name] = key.split('/')
let config = { component: name, ...files(key) }
initializing.push(initDefaulValue(config))
})
Vue.prototype.$componentList = initializing
}
// 初始化组件初始数据
function initDefaulValue (config) {
return config
}
4、实现编辑区拖拽前置 左侧组件区展示以及支持拖拽
- components/componentList.vue
- 遍历 $componentList 展示
- 使用html5 draggable
- 实现draggable
<div class="component-list" @dragstart="handleDragStart">
handleDragStart(e) {
console.log("开始移动")
//这一步比较关键,后续在编辑区获取数据需要这个
e.dataTransfer.setData('index', e.target.dataset.index)
},
5、编辑页实现将拖拽数据存储到pinia
-
view/edit.vue
-
实现draggable 相关的事件绑定以及处理
<!-- 中间画布 -->
<section class="center">
<div class="content" @drop="handleDrop" @dragover="handleDragOver">
<Editor />
</div>
</section>
- 定义方法
//拖拽到编辑区s释放
handleDrop(e) {
e.preventDefault()
e.stopPropagation()
if (this.isShowPreview){
alert("处于预览模式不能拖拽")
}else{
const index = e.dataTransfer.getData('index')
console.log(e);
if (index) {
const component = deepCopy(this.$componentList[index])
component.style.top = e.offsetY
component.style.left = e.offsetX
component.id = generateID()
//添加组件 存储到pinia 的 componentData
this.addComponent({component})
}
}
},
//
handleDragOver(e) {
e.preventDefault()
e.dataTransfer.dropEffect = 'copy'
},
6、编辑区组件展示已拖拽的组件
主要逻辑就是遍历 在pinia存储的componentData 将组建的属性通过props传给编辑区子组件
7、编辑区内组件自由拖拽移动
这个主要是监控mousedown事件,通过改变组件的top和left来实现
8、系列文章
9、结尾
- 为什么没有选择vuedraggable 插件,因为我需要自由的拖拽,本身是脱离文档流的,所以基于html5自身实现
- 为什么数据状态管理器选择了pinia,没用vuex,实际上我想试验下新技术,同时vuex的一些弊端确实我接受不了,不如pinia小巧灵活