基于element ui的el-drawer进行组件封装

功能描述:应业务需求及代码规范,对el-drawer抽屉组件进行全局封装,不需页面引用子组件可唤起抽屉页面并允许动态传参。
1. 封装js代码并在main.js中引入
// 可直接全部复制并在utils文件夹中生成drawer.js文件
import Vue from 'vue'
import store from '@/store'

function snake2Camel(str, capLower) {
  let s = str.replace(/[-_](\w)/g, function (x) {
    return x.slice(1).toUpperCase();
  });
  s = s.replace(/^\w/, function (x) {
    return capLower ? x.toLowerCase() : x.toUpperCase();
  });
  return s;
}

/**
 * [camel2Snake 驼峰转蛇形]
 * @param {String} str [description]
 * @return {String}    [description]
 */
function camel2Snake(str) {
  return str.replace(/([A-Z])/g, "-$1").toLowerCase();
}

let mix = {
  methods: {
    async payload(fn, fail) {
      try {
        this.fullscreenLoading = true;
        await fn();
      } catch (e) {
        console.error(e);
      }
      this.fullscreenLoading = false;
    }
  }
};

// 获取需要动态创建的抽屉组件
const drawersContext = require.context("../", true, /\$([a-zA-Z\-0-9]+)\.vue$/);
const drawers = drawersContext.keys().reduce((views, key) => {
  const fileName = key.match(/\$([a-zA-Z\-0-9]+)\.vue$/i)[1];
  if (!fileName) return views;
  let componentName = camel2Snake(fileName);
  let clsName = snake2Camel(componentName);
  return Object.assign(views, {
    [clsName]: drawersContext(key)
  });
}, {});

// 已创建的抽屉实例
window.drawerExamples = {}

/**
 * [createDrwaer 创建抽屉组件]
 * @param {[type]} component [组件]
 * @param {[type]} data      [参数]
 * @return {[type]}    [description]
 */
const createDrwaer = function (temp, data, callback, name) {
  let opt = {
    data,
    callback
  };
  let component = Object.assign({}, temp);
  let initData = {
    visible: true,
    fullscreenLoading: false,
    drawerID: name, //此组件唯一id
    drawerBckend: false, //是否已加入后台
  };
  Object.assign(initData, component.data());
  opt.data && Object.assign(initData, JSON.parse(JSON.stringify(opt.data)));
  component.data = function () {
    return initData;
  }
  // 创建构造器创建实例挂载
  let DrawerC = Vue.extend({
    ...component,
    store
  });
  let drawer = new DrawerC();
  // 关闭事件
  let _onClose = drawer.$options.methods.onClose;
  drawer.$watch("visible", function (n, o) {
    drawer === false && drawer.onClose();
  });
  drawer.onClose = function () {
    drawer.drawerBckend = false
    drawer.$destroy();
    _onClose && _onClose.call(drawer);
    if (document.body.contains(drawer.$el)) {
      document.body.removeChild(drawer.$el);
    };
    if (drawer.drawerID && window.drawerExamples[drawer.drawerID]) {
      delete window.drawerExamples[drawer.drawerID]
    }
  };
  // 回调事件
  let _onCallback = drawer.$options.methods.onCallback;
  drawer.onCallback = function (...arg) {
    try {
      _onCallback && _onCallback();
      if (callback && typeof callback === 'function') {
        callback(...arg, drawer);
      }
      if (drawer.drawerID && window.drawerExamples[drawer.drawerID]) {
        delete window.drawerExamples[drawer.drawerID]
      }
    } catch (e) {
      // console.log(e);
    }
  };
  drawer.$mount();
  drawer.$watch("visible", function (n, o) {
    drawer.onClose() && drawer === false;
  });
  drawer.$store = store
  window.drawerExamples[name] = drawer
  if (drawer.drawerID) {
    Object.keys(window.drawerExamples).forEach((name) => {
      window.drawerExamples[name].style.zIndex = '1999'
    })
    drawer.$el.style.zIndex = '2000'
  }
  drawer.$el.drawer.$el.onmousedown = () => {
    if (drawer.drawerID) {
      Object.keys(window.drawerExamples).forEach((name) => {
        window.drawerExamples[name].$el.style.zIndex = '1999'
      })
      window.drawerExamples[drawer.drawerID].$el.style.zIndex = '2000'
    }
  }
  document.body.appendChild(drawer.$el);
  return drawer
};

/**
 * [createDrwaerAsync promise创建抽屉]
 * @param {[type]} temp [description]
 * @param {[type]} data [description]
 * @param {[Function]} callback [description]
 * @return {[type]}    [description]
 */
function createDrwaerAsync(temp, data, name) {
  return new Promise(function (resolve, reject) {
    // 初始化配置参数
    let opt = {
      data
    };
    let compnent = Object.assign({}, temp);
    let initData = {
      visible: true,
      fullscreenLoading: false,
      drawerID: name, //此组件唯一id
      drawerBckend: false, //是否已加入后台
    };
    Object.assign(initData, component.data());
    opt.data && Object.assign(initData, JSON.parse(JSON.stringify(opt.data)));
    component.data = function () {
      return initData;
    }
    // 创建构造器创建实例挂载
    let DrawerC = Vue.extend({
      ...component,
      store
    });
    let drawer = new DrawerC();
    // 关闭事件
    let _onClose = drawer.$options.methods.onClose;
    drawer.onClose = function () {
      try {
        drawer.drawerBckend = false
        resolve();
        drawer.$destroy();
        _onClose && _onClose.call(drawer);
        if (document.body.contains(drawer.$el)) {
          document.body.removeChild(drawer.$el);
        };
        if (drawer.drawerID && window.drawerExamples[drawer.drawerID]) {
          delete window.drawerExamples[drawer.drawerID]
        }
      } catch (e) {
        // console.log(e);
      }
    };
    // 回调事件
    let _onCallback = drawer.$options.methods.onCallback;
    drawer.onCallback = function (...arg) {
      try {
        _onCallback && _onCallback();
        resolve(...arg);
        drawer.$destroy();
        _onClose && _onClose.call(drawer);
        if (callback && typeof callback === 'function') {
          callback(...arg, drawer);
        }
        if (drawer.drawerID && window.drawerExamples[drawer.drawerID]) {
          delete window.drawerExamples[drawer.drawerID]
        }
      } catch (e) {
        // console.log(e);
      }
    };
    drawer.$watch("visible", function (n, o) {
      drawer.onClose() && drawer === false;
    });
    drawer.$mount();
    drawer.$store = store
    window.drawerExamples[name] = drawer
    drawer.$el.onmousedown = () => {
      if (drawer.drawerID && window.drawerExamples[drawer.drawerID]) {
        Object.keys(window.drawerExamples).forEach((name) => {
          window.drawerExamples[name].$el.style.zIndex = '1999'
        })
        window.drawerExamples[drawer.drawerID].$el.style.zIndex = '2000'
      }
    }
    setTimeout(() => {
      if (drawer.drawerID) {
        Object.keys(window.drawerExamples).forEach((name) => {
          window.drawerExamples[name].$el.style.zIndex = '1999'
        })
        drawer.$el.style.zIndex = '2002'
      }
    }, 10);
    document.body.appendChild(drawer.$el);
  });
}

/**
 * [init 初始化]
 * @param {[type]} components [description]
 * @return {[type]}      [description]
 */
function init(values) {
  let drawerComponents = {};
  if (!values) return;
  Object.keys(values).forEach((name) => {
    let ComponentContext = values[name].default;
    ComponentContext.mixins = [mix];
    drawerComponents[name] = function (data, callback) {
      if (callback && typeof callback === 'function') {
        return createDrwaer.call(this, ComponentContext, data, callback, name);
      }
      // 如果已存在此组件那么关闭
      if (window.drawerExamples[name] && !window.drawerExamples[name].drawerBckend) {
        window.drawerExamples[name].onClose()
        delete window.drawerExamples[name]
        // 如果已经存在此组件并且该组件在后台中那么return
      } else if (window.drawerExamples[name] && window.drawerExamples[name].drawerBckend) {
        return ''
      }
      return createDrwaerAsync.call(this, ComponentContext, data, name);
    };
  });
  return drawerComponents;
}

// 清空所有抽屉
export function cleardrawerExamples() {
  if (!window.drawerExamples) return
  Object.keys(window.drawerExamples).forEach(name => {
    window.drawerExamples[name] && window.drawerExamples[name].onClose()
    delete window.drawerExamples[name]
  })
}

// 获取所有抽屉实例
export function getAlldrawerExamples() {
  return window.drawerExamples || {}
}

// 删除指定抽屉
export function delDrawerId(drawerID) {
  if (window.drawerExamples && window.drawerExamples[drawerID] && !window.drawerExamples[drawerID].drawerBckend) {
    window.drawerExamples[drawerID].onClose()
  }
}

// 将指定抽屉加入后台
export function addDrawerBckEnd(drawerID) {
  if (window.drawerExamples && window.drawerExamples[drawerID] && !window.drawerExamples[drawerID].drawerBckend) {
    window.drawerExamples[drawerID].drawerBckend = true
    window.drawerExamples[drawerID].$el.querySelector(".el-drawer").style.top = '-100%'
  }
}

// 全局挂载
Vue.prototype.$drawer = init(drawers); 
Vue.prototype.$delDrawerId = delDrawerId
Vue.prototype.$addDrawerBckEnd = addDrawerBckEnd
// main.js引用挂载在vue中
import '@/utils/drawer.js'
2. 生成全局弹框组件页面(例文件名:$drawer.vue)
  • 例生成文件路径:src/component/$drawer.vue
  • 示例主要使用全局的$drawer方法,关闭指定弹框可根据上面js自行修改
// 当前组件的名称需要加上前缀$符号,对应js中的挂载对象,visible为js中的监听对象,不需要在data中定义
// el-drawer上绑定的参数为其他页面调用组件时传来的动态参数
<template>
  <el-drawer
    :title="title"
    :visible.sync="visible"
    :direction="direction"
    :wrapperClosable="false"
    :modal="false"
  >
    <span>页面内容展示</span>
    <span @click="handCls">关闭按钮</span>
    <span @click="handCallback">关闭按钮回调</span>
  </el-drawer>
</template>

mounted() {
  //在页面初始化的时候可获取从调用页面传递过来的自定义数据
  console.log(this.row, this.title)
},

// methods方法
methods: {
 // 关闭事件可直接调用onClose方法,但是onClose不支持传值,只会关闭弹框页面
 handCls() {
   this.onClose()
 },
 // onCallback方法支持回调,但是唤起弹框的方法需要改为异步接收回调参数,onCallback调用后也可关闭弹框,不需要再次调用onClose方法
 handCallback() {
   this.onCallback(true, '传值回调')
 }
}
3. 组件调用
  • 在A页面调用公共组件的$drawer.vue文件
// html
<template>
  <div @click="handClickBtn">按钮调用组件</div>
</template>

// methods方法
methods: {
// this.$drawer可直接拿到,如果是在嵌套方法内可修改this指向,
// Drawer为新增的组件文件名称,首字母需大写
 handClickBtn() {
   this.$drawer.Drawer({
      title: '传值title', // 默认绑定值
      row: [], //可自定义传参对象,在弹框页面获取时用this.row即可
    })
  }

// 也可将handClickBtn方法前加上async变成异步状态,接受弹框onCallback回调事件
 async handClickBtn() {
   let result = this.$drawer.Drawer({
      title: '传值title', // 默认绑定值
      row: [], //可自定义传参对象,在弹框页面获取时用this.row即可
    })
    // result为接收的onCallback回调的参数
    if (result) {
      // ...TODO
    }
  }
}

el-dialog同理也可使用此方法进行二次封装,只需将js中获取的class名以及挂载对象替换就可以,页面使用el-dialog组件

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值