美文网首页Vue前端开发那些事儿每天学一点Vue3
封装第三方组件(19)写个拖拽 td 的自定义指令

封装第三方组件(19)写个拖拽 td 的自定义指令

作者: 自然框架 | 来源:发表于2021-08-15 19:07 被阅读0次

    可视化操作,少不了拖拽这个环节。只是不想用现成的拖拽库,而是想自己弄一个。

    先拿 table 开刀吧。

    有一个table的表格,想通过拖拽表头(th)来实现调整先后顺序的功能,于是做了这个可以拖拽 th 的自定义指令。

    优点:

    • 不破坏现有结构。
    • 支持各种table,各种UI库的table的组件,只要渲染后是一个table即可。

    缺点:

    • 不会做特效,默认的拖拽效果,不好看。
    • 自定义指令只实现拖拽效果,返回拖拽信息,不实现具体功能。

    可以拖拽 th 的自定义指令

    /**
     * 拖拽 table 的 th,返回拖拽信息
     */
    const tableDrag = (app, options) => {
      app.directive('tabledrag', {
        // 指令的定义
        mounted (el, binding) {
          // console.log('===== el', el)
          // console.log('===== binding', binding)
    
          binding.value.setTdforDrag = (className, dragInfo) => {
            const table = el.getElementsByClassName(className)[0]
            const tr = table.rows[0]
            const tdCount = tr.cells.length
            // 设置th的拖拽
            for (let i = 0; i < tdCount; i++) {
              const th = tr.cells[i]
              // 设置可以拖拽
              th.setAttribute('draggable', true)
              // 拖拽时经过
              th.ondragover = (event) => {
                event.preventDefault()
              }
              // 开始拖拽
              th.ondragstart = (event) => {
                // console.log('ondragstart - event', event)
                dragInfo.source = event.target.innerText
              }
              // 结束拖拽
              th.ondrop = (event) => {
                // console.log('ondrop - event', event)
                dragInfo.offsetX = event.offsetX
                dragInfo.ctrl = event.ctrlKey
                dragInfo.target = event.target.innerText
                // console.log('ondrop - dragInfo', dragInfo)
              }
            }
          }
        }
      })
    }
    export default tableDrag
    
    • className
      用于找到目标的 class 名称。

    • dragInfo
      reactive 类型的对象,便于返回拖拽信息。

    • .ondragover
      设置拖拽时经过的事件

    • .ondragstart
      开始拖拽时的事件,可以得到th的部分信息,主要是其他的各种信息。

    • .ondrop
      结束拖拽的事件

    • event.target.innerText
      获取 th 的文本内容,目前只找到这个可以作为 th 的标识

    • event.offsetX
      th 的鼠标的x的坐标

    • event.ctrlKey
      结束拖拽时,是否按住 ctrl 键。

    挂载指令

    main.js

    import { createApp } from 'vue'
    import App from './App.vue'
    // 拖拽table的th
    import tableDrag from './control-web/js/tableDrag.js'
    
    const app = createApp(App)
    
    app.use(router) // 路由
      .use(tableDrag) // table的拖拽
      .mount('#app')
    
    

    使用方法

     <el-table
          v-tabledrag="tableInfo"
          v-bind="girdMeta"
          :data-list="dataList"
          :selection="dataListState.choice"
        />
    
    
    const tableInfo = {
      setThforDrag: () => {
        console.log('原始的设置td的函数')
      }
    }
    
    // 接收拖拽信息
    const dragInfo = reactive({
      offsetX: 0,
      ctrl: false,
      source: '',
      target: ''
    })
    
    onMounted(() => {
      nextTick(() => {
        tableInfo.setThforDrag('el-table__header', dragInfo)
        watch(() => dragInfo, () => {
          console.log('外部:', dragInfo)
        },
        { deep: true })
      })
    })
    

    这里有个麻烦的地方,应该是渲染完毕,自定义指令的 mounted 才会被调用。
    但是并不是!
    这时候table或者里面的th还没有出来呢。

    如果在组件里面使用 onMounted ,以为这时候应该出来了吧,结果还是没有。
    于是只好再加上nextTick,这次终于出来了。

    因为 dragInfo 是reactive类型的,具有响应性,所以我们可以监听,当拖拽结束的时候,就会触发。

    本来想做成promise的,但是发现只能触发一次,第二次就不灵了。

    这样拖拽后,我们就可以得到这样的数据:

    拖拽信息

    我们可以根据 source、target 来判断是拖拽了哪个 th,然后做后续操作。

    相关文章

      网友评论

        本文标题:封装第三方组件(19)写个拖拽 td 的自定义指令

        本文链接:https://www.haomeiwen.com/subject/mlbubltx.html