Skip to content

element ui dialog和drawer jsx 封装函数式调用

VNode和组件定义对象的区别

  • VNode比较轻量
    • 返回的是渲染结果,不是组件定义
    • 可以直接插入模板中使用
    • 没有创建新组件,无额外实例开销
    • 不能拥有自己的状态或生命周期
    • 适合简单内容渲染
  • 组件定义对象
    • 创建了一个全新的 Vue 组件
    • 有自己的组件生命周期和状态管理
    • 会产生额外的组件实例开销
    • 适合需要封装独立逻辑的场景

封装 el-dialog

jsx
import Vue, {defineComponent, ref} from 'vue';

/**
 *
 * @param options
 * @param {Function | Object} options.content -- 渲染函数 或者 组件定义对象
 * @param {Object} [options.props] -- dialog属性配置
 * @param {Object} [options.slots] -- dialog插槽配置
 * @param {Object} [options.on] -- dialog事件配置
 * @param {Boolean} [options.drag] -- dialog拖拽 默认true
 * @returns {Object} - instance返回dialog实例
 * @property {Function} destroy - 销毁dialog实例
 */
function create(options) {

  const {
    content: Content,
    props = {},
    slots,
    on = {},
    drag = true,
  } = options;

  const visible = ref(false);
  const closed = on['closed']
  on['update:visible'] = val => visible.value = val
  on['closed'] = () => {
    closed?.();
    clearDom()
  }
  const directives = []
  if (drag) {
    directives.push({
      name: 'dialogDrag',
      value: true,
    })
  }
  const contentRef = ref(null)
  const Profile = Vue.extend(defineComponent({
    setup() {
      return () => <el-dialog
              {...{on, directives}}
              scopedSlots={slots}
              props={{
                width: '500px',
                visible: visible.value,
                'append-to-body': true,
                'destroy-on-close': true,
                ...props
              }}>

        {
          typeof Content === 'function'
                  ? Content()
                  : <Content ref={el => contentRef.value = el}/>
        }
      </el-dialog>
    }
  }))
  const instance = new Profile();

  instance.$mount();
  document.body.appendChild(instance.$el);
  visible.value = true;

  function clearDom() {
    instance.$destroy();
    instance.$el.remove()
  }

  function destroy() {
    visible.value = false
  }
  function getContentRef() {
    if (typeof Content === 'function') {
      return
    }
    return contentRef
  }

  instance.destroy = destroy
  instance.getContentRef = getContentRef
  return instance
}

export default {
  create
}

封装el-drawer

jsx
import Vue, {defineComponent, onMounted, ref} from 'vue';

/**
 *
 * @param options
 * @param {Object} [options.props] -- drawer属性配置
 * @param {Object} [options.slots] -- drawer插槽配置
 * @param {Object} [options.on] -- drawer事件配置
 * @param {Function | Object} options.content -- VNode 或者 组件定义对象
 *
 * @returns {Object} - instance返回el-drawer实例
 * @property {Function} destroy - 销毁drawer实例
 */
function create(options) {

  const {
    content: Content,
    props = {},
    slots,
    on = {}
  } = options
  const visible = ref(false);
  const drawerRef = ref(null);
  const contentRef = ref(null)
  const Profile = Vue.extend(defineComponent({
    setup() {
      const closed = on['closed']
      on['update:visible'] = val => visible.value = val
      on['closed'] = () => {
        closed?.();
        clearDom()
      }

      return () => <el-drawer
              ref={el => drawerRef.value = el}
              {...{on}}
              scopedSlots={slots}
              props={{
                modal: false,
                direction: 'rtl',
                size: '75%',
                visible: visible.value,
                withHeader: false,
                'append-to-body': true,
                'destroy-on-close': true,
                ...props
              }}>

        {
          typeof Content === 'function'
                  ? Content()
                  : <Content ref={el => contentRef.value = el}/>
        }
      </el-drawer>
    }
  }))

  const instance = new Profile();

  instance.$mount();
  document.body.appendChild(instance.$el);
  visible.value = true

  function clearDom() {
    instance.$destroy();
    instance.$el.remove()
  }

  function destroy() {
    drawerRef.value.closeDrawer()
  }

  function getRef() {
    return drawerRef.value
  }

  function getContentRef() {
    if (typeof Content === 'function') {
      return
    }
    return contentRef
  }
  instance.destroy = destroy
  instance.getRef = getRef
  instance.getContentRef = getContentRef

  return instance
}

export default {create}

用例

VNode用例

js

dialog.create({
    content: () => <div>hello</div>
})

组件定义对象用例

js

dialog.create({
    // 也可引入.vue文件等 -- Vue组件都行
    content: defineComponent({
        setup() {
            return () => <div>hello</div>
        }
    })
})
/src/technology/dateblog/2025/06/20250612-element-ui-dialog%E5%92%8Cdrawer-jsx-%E5%B0%81%E8%A3%85%E5%91%BD%E4%BB%A4%E5%BC%8F%E8%B0%83%E7%94%A8.html