可视化生成营销抽奖h5 第二天

205 阅读2分钟

Hello,我是Rocket

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

引言

  • 饭要一口一口,路要一步一步走,这章节我们就做俩个事 ,全局注册物料组件、注册物料组件元数据json、实现编辑区拖拽功能
  • github传送门
  • gitee传送门
  • 喜欢的铁子们给点个star

效果图

d730fdce-557b-4941-a874-530fc07fee32.gif

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小巧灵活