Vue指令篇

225 阅读1分钟

1.vue2 表格自适应高度

// 新建 adaptive.js
import { addResizeListener, removeResizeListener } from "element-ui/src/utils/resize-event"
console.log(111)
// 设置表格最小高度
const tableMin = 200
// 设置表格高度
const doResize = async (el, binding, vnode) => {
  // 获取表格Dom对象
  const { componentInstance: $table } = await vnode
  // 获取调用传递过来的数据 
  const { value } = binding
  // 使用时必须传入初始值height 否则不生效
 if (!$table.height) {
    throw new Error(`el-$table must set the height. Such as height='100px'`)
  }
  // 获取距底部距离(用于展示页码等信息)
  const bottomOffset = (value && value.bottomOffset) || 60

  if (!$table) return

  // 计算列表高度并设置
  let height = window.innerHeight - el.getBoundingClientRect().top - bottomOffset
  // 设置最小高度
  height = height < tableMin ? tableMin : height
  $table.layout.setHeight(height)
  $table.doLayout()
}

export default {
  // 初始化设置
  bind (el, binding, vnode) {
    // 设置resize监听方法
    el.resizeListener = async () => {
      await doResize(el, binding, vnode)
    }
    // 绑定监听方法到addResizeListener
    addResizeListener(window.document.body, el.resizeListener)
    addResizeListener(el, el.resizeListener)
  },
  // 绑定默认高度
  async inserted (el, binding, vnode) {
    await doResize(el, binding, vnode)
  },
  // 组件发生变化时触发
  async componentUpdated (el, binding, vnode) {
    await doResize(el, binding, vnode)
  },
  // 销毁时设置
  unbind (el) {
    // 移除resize监听
    removeResizeListener(el, el.resizeListener)
  }
}
// index.js
import adaptive from "./adaptive"

const install = function (Vue) {
  // 绑定v-adaptive指令
  Vue.directive("adaptive", adaptive)
}

if (window.Vue) {
  window["adaptive"] = adaptive
  // eslint-disable-next-line no-undef 
  Vue.use(install)
}

adaptive.install = install

export default adaptive
// main.js
import adaptive from "./directive/adaptive"

2.vue3 自适应高度

// adaptive.ts
import type { DirectiveBinding } from 'vue'

interface ExHTMLElement extends HTMLElement {
  resizeListener: EventListener
}

export default {
  mounted: (el: ExHTMLElement, binding: DirectiveBinding) => {
    el.resizeListener = () => {
      setHeight(el, binding)
    }

    setHeight(el, binding)

    window.addEventListener('resize', el.resizeListener)
  },
  unmounted(el: ExHTMLElement) {
    window.removeEventListener('resize', el.resizeListener)
  },
  updated(el: ExHTMLElement, binding: DirectiveBinding) {
    setHeight(el, binding)
  }
}

// set el-table height
function setHeight(el: ExHTMLElement, binding: DirectiveBinding) {
  const top = el.offsetTop     // top改为 el.getBoundingClientRect().top 前者写法会导致tab页面表格高度变大,top小了
  const bottom = binding?.value?.bottom || 84
  const pageHeight = window.innerHeight
  el.style.height = pageHeight - top - bottom + 'px'
  el.style.overflowY = 'auto'
}

// index.ts
import adaptive from "./adaptive";
import type { App } from 'vue'
export default (app: App) => {
  app.directive('adaptive', adaptive)
}

3 table拖拽列

 <el-table
      v-column-drag="{ columns: columns, onDragEnd: handleDragEnd }"
      :data="tableData"
      style="width: 100%">
      <el-table-column
        v-for="col in columns"
        :key="col.prop"
        :prop="col.prop"
        :label="col.label"
        :width="col.width">
      </el-table-column>
    </el-table>
    
   Vue.directive('column-drag', {
      inserted(el, binding) {
        const tableHeader = el.querySelector('.el-table__header-wrapper thead tr');
        if (!tableHeader) return;
        const { columns, onDragEnd } = binding.value;
        Sortable.create(tableHeader, {
          animation: 150,
          onEnd({ oldIndex, newIndex }) {
            if (oldIndex === newIndex) return;

            const movedItem = columns.splice(oldIndex, 1)[0];
            columns.splice(newIndex, 0, movedItem);

            // 执行拖拽完成后的回调
            if (typeof onDragEnd === 'function') {
              onDragEnd(oldIndex, newIndex, columns);
            }
          }
        });
      }
    });
    
    
     handleDragEnd(oldIndex, newIndex, columns) {
          this.$message.success(`列已移动:从第 ${oldIndex + 1} 列到第 ${newIndex + 1} 列`);
          console.log('最新列顺序:', columns);
          // 这里可以调用 API 保存到后台:
          // this.saveColumnOrder(columns);
        }