Possible to open modal from outside the vue component

前端 未结 5 526
别跟我提以往
别跟我提以往 2021-01-03 06:31

Is it possible to call a method from outside the component to make the component reuseable?

Right now I add my button to open the modal in a template slot:

<

5条回答
  •  爱一瞬间的悲伤
    2021-01-03 07:02

    Put you modal component instance into Vue.prototype, then invoke show/hide at anywhere you can access Vue instance context.

    Below is one demo:

    let vm = null // the instance for your Vue modal
    let timeout = null //async/delay popup
    
    const SModal = {
      isActive: false,
    
      show ({
        delay = 500,
        message = '',
        customClass = 'my-modal-class'
      } = {}) {
        if (this.isActive) {
          vm && vm.$forceUpdate()
          return
        }
    
        timeout = setTimeout(() => {
          timeout = null
    
          const node = document.createElement('div')
          document.body.appendChild(node)
          let staticClass = ''
          vm = new this.__Vue({
            name: 's-modal',
            el: node,
            render (h) { // uses render() which is a closer-to-the-compiler alternative to templates
              return h('div', {
                staticClass,
                'class': customClass,
                domProps: {
                  innerHTML: message
                }
              })
            }
          })
        }, delay)
    
        this.isActive = true
      },
      hide () {
        if (!this.isActive) {
          return
        }
    
        if (timeout) {
          clearTimeout(timeout)
          timeout = null
        } else {
          vm.$destroy()
          document.body.removeChild(vm.$el)
          vm = null
        }
    
        this.isActive = false
      },
    
      __Vue: null,
      __installed: false,
      install ({ $my, Vue }) {
        if (this.__installed) { return }
        this.__installed = true
        $my.SModal = SModal // added your SModal object to $my
        this.__Vue = Vue //get the Vue constructor
      }
    }
    
    let installFunc = function (_Vue, opts = {}) {
      if (this.__installed) {
        return
      }
      this.__installed = true
      const $my = {
        'memo': 'I am a plugin management.'
      }
      if (opts.plugins) {
        Object.keys(opts.plugins).forEach(key => {
          const p = opts.plugins[key]
          if (typeof p.install === 'function') {
            p.install({ $my, Vue: _Vue })
          }
        })
      }
      _Vue.prototype.$my = $my
    }
    
    Vue.use(installFunc, {
      plugins: [SModal]
    })
    
    app = new Vue({
      el: "#app",
      data: {
        'test 1': 'Cat in Boots'
      },
      methods: {
        openModal: function () {
          this.$my.SModal.show({'message':'test', 'delay':1000})
        },
        closeModal: function () {
          this.$my.SModal.hide()
        }
      }
    })
    .my-modal-class {
      position:absolute;
      top:50px;
      left:20px;
      width:100px;
      height:100px;
      background-color:red;
      z-index:9999;
    }
    
    

    Rough Steps for vue-cli project:

    In ./plugins/SModal.js (follow the tutorial in official document to create one vue instance then add it into the document.body):

    let vm = null // the instance for your Vue modal
    let timeout = null //async/delay popup
    
    const SModal = {
      isActive: false,
    
      show ({
        delay = 500,
        message = '',
        customClass = ''
      } = {}) {
        if (this.isActive) {
          vm && vm.$forceUpdate()
          return
        }
    
        timeout = setTimeout(() => {
          timeout = null
    
          const node = document.createElement('div')
          document.body.appendChild(node)
    
          vm = new this.__Vue({
            name: 's-modal',
            el: node,
            render (h) { // uses render() which is a closer-to-the-compiler alternative to templates
              return h('div', {
                staticClass,
                'class': props.customClass
              })
            }
          })
        }, delay)
    
        this.isActive = true
      },
      hide () {
        if (!this.isActive) {
          return
        }
    
        if (timeout) {
          clearTimeout(timeout)
          timeout = null
        } else {
          vm.$destroy()
          document.body.removeChild(vm.$el)
          vm = null
        }
    
        this.isActive = false
      },
    
      __Vue: null,
      __installed: false,
      install ({ $my, Vue }) {
        if (this.__installed) { return }
        this.__installed = true
        $my.SModal = SModal // added your SModal object to $my
        this.__Vue = Vue //get the Vue constructor
      }
    }
    
    export default SModal
    

    As the official document said, A Vue.js plugin should expose an install method. The method will be called with the Vue constructor as the first argument, along with possible options

    In install.js (also you can move this method into main.js based on your design):

    // loop all plugins under the folder ./plugins/, then install it.
    export default function (_Vue, opts = {}) {
      if (this.__installed) {
        return
      }
      this.__installed = true
      const $my = {
        'memo': 'I am a plugin management.'
      }
      if (opts.plugins) {
        Object.keys(opts.plugins).forEach(key => {
          const p = opts.plugins[key]
          if (typeof p.install === 'function') {
            p.install({ $my, Vue: _Vue })
          }
        })
      }
    
      _Vue.prototype.$my = $my
    }
    

    In main.js (finally uses your plugins):

    import install from './install'
    import * as plugins from './plugins'
    
    Vue.use({ install }, {
      plugins
    })
    

    Finally in your view/component, you can show/hide your modal like this:

    this.$my.SModal.show()
    this.$my.SModal.hide()
    

提交回复
热议问题