shaodahong / dahong

个人技术随笔
https://biewen.me/
129 stars 17 forks source link

一个高度可定制的vue modal插件 #10

Open shaodahong opened 7 years ago

shaodahong commented 7 years ago

前言

modal 是前端开发中普遍且高频的组件之一,很多UI框架中都会实现modal 来增强实践中的交互,但是都没有达到我想要的,因为开发管理后台类页面时modal 形式多变,而且会相互嵌套,这样的话对可定制性有很大的要求

项目地址

vuejs-modal Demo

预期目标

  1. 可以自定义modal,一个vue 组件就是一个modal
  2. 想要调用modal 直接通过this.$modal[modal名]()来调用
  3. this.$modal[modal名]()是个promise,可以根据它的状态来得到modal 上的状态(确定或者取消等)
  4. 可以通过this.$modal[modal名](params)来传参复用modal

实现

vue 提供use 函数来让我们安装插件

vue.use(plugin, options)

plugin 可以是object 也可以是function,如果是object 那么需要提供install 方法,如果是function 那么这个function 就是install,use 还提供了options 参数,options 在install 方法中可以获取到

// vuejs-modal.js
var Modal = {
    /**
     * 
     * 
     * @param {Function} Vue 
     * @param {{name?: string, id?: string, modals: object, style?: object}} options 
     */
    install: function (Vue, options) {
    }
}

install 第一个参数是vue 构造函数,第二个options 就是use 的时候传的options,有了vue 构造函数我们可以做很多事了,我们来是实现下$modal

// vuejs-modal.js
install: function (Vue, options) {
        // 定义一个defaultOptions 来初始默认的属性
        // 可以通过options 来覆盖掉默认的属性
        var defaultOptions = Object.assign({
            name: '$modal', //使用this 调用的插件名,默认是$modal
            id: 'modal', //html 页面上初始化的div id 名,默认是modal
            modals: null, //默认的modals,初始是没有的,需要传参,如果没有会报错
            style: {
                position: 'fixed',
                top: 0,
                left: 0,
                right: 0,
                bottom: 0,
                zIndex: 1000
            }
            // 默认的样式,zIndex 是递增的
        }, options)
    },

核心:

// 声明一个modals 空间
let modals = Vue.prototype[defaultOptions.name] = {};

// 绑定modal
Object.keys(defaultOptions.modals).forEach(v => {

    /**
     * 
     * 
     * @param {object} options 
     * @returns 
     */
    modals[v] = options => {
        return new Promise((resolve, reject) => {
            try {
                new Vue({
                    render: h => h(defaultOptions.modals[v], {
                        // 每个modal提供options参数,参数会传递给props
                        props: options,
                        style: Object.assign(defaultOptions.style, {
                            zIndex: this.zIndex
                        }),
                       // 默认提供两个事件$on 和$cancel,$on 会resolve,$cancel 会reject
                       // $on 需要参数$el 来remove 调modal,$cancel 同理
                        on: {
                            $ok: function ($el, info) {
                                $el.remove()
                                resolve(info)
                            },
                            $cancel: function ($el, info) {
                                $el.remove()
                                reject(info)
                            }
                        }
                    })
                }).$mount('#' + defaultOptions.id)
            } catch (error) {
                console.error('vuejs-modal', error)
            }

        })
    }

})

问题

  1. 本来理想情况下是vue 有没有compile 方法提供,这样直接调用compile 后挂载到body 下面,但是看了文档compile 倒是有但是只在独立构建下有用,over,只好使用new vue()的方式来变相的compile,但是需要建坑
var div = document.createElement('div');
div.setAttribute('id', 'modal');
document.getElementsByTagName('body')[0].appendChild(div)
  1. 关闭modal 这个一直有个疑问,是建议使用者手动关闭还是插件来关闭,目前是插件关闭,但是需要把this.$el传递进来,后来想了想还是插件关闭,这样的话使用者可以少写一行代码,后续可能会有所调整
  2. 这个插件不太适用于modal 少且单一的项目,因为我是开发管理后台类页面,modal 页面不是简单的提示信息,会有些交互等,所以和这个插件很契合
  3. 插件没有很详细的兼容,使用rollup 来打包,并且只引入了promise 和assigin 的Polyfill
  4. 后续升级看业务中的使用情况
tflower commented 7 years ago

很棒哦

shaodahong commented 7 years ago

@tflower 谢谢,小东西,没有技术含量的,纯业务驱动

wangshuai99 commented 7 years ago

请问这需要vue什么版本

shaodahong commented 7 years ago

@wangshuai99 2+

goodluck2016 commented 7 years ago

顶一个,期待更多分享