可以从vue组件外部打开模态

时间:2018-04-25 16:25:26

标签: javascript vue.js

是否可以从组件外部调用方法以使组件可重用?

现在我添加我的按钮以在模板槽中打开模态:

index.php

<modal>
    <template slot="button">
        <button class="btn">Open modal</button>
    </template>
    Some modal text
</modal>

Modal.vue

<template>
    <div>
        <div @click="showModal"><slot name="button"></slot></div>
        <div v-if="showingModal"><slot></slot></div>
    </div>
</template>

<script>
    export default {

        data () {
            return {
                showingModal: false,
            }
        },

        methods: {
            showModal() {
                this.showingModal = true;
            },
        }
    }
</script>

我觉得有更好的选择,但我无法弄清楚。

5 个答案:

答案 0 :(得分:5)

  

是的,您可以从组件外部调用方法!

父组件

<template>
 <div>
   <modal ref="modal"></modal>
   <button @click="openModal">Open Modal</button>
 </div>
</template>

<script>
  import modal from './child.vue'
  export default {
    components: { modal }
    methods: {
     openModal() { this.$refs.modal.show() }//executing the show method of child
    }
  }
</script>

子组件

<template>
  <div v-if="showModal">
    <div id="modal">
      <p>Hello i am a modal
      </p>
      <button @click="hide">Close</button>
    </div> 
  </div>
</template>

<script>
 export default {
   data() {
     return {
      showModal: false
     }
   },
   methods: {
     show() {
      this.showModal = true
     },
     hide(){
      this.showModal = false
     }
   }
 }
</script>

See it in action here

答案 1 :(得分:1)

我更喜欢在这里使用vue plugin(对于单实例模态)。

以下是一个演示:

&#13;
&#13;
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()
    }
  }
})
&#13;
.my-modal-class {
  position:absolute;
  top:50px;
  left:20px;
  width:100px;
  height:100px;
  background-color:red;
  z-index:9999;
}
&#13;
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<div id="app">
    <button @click="openModal()">Open Modal!!!</button>
    <button @click="closeModal()">Close Modal!!!</button>
</div>
&#13;
&#13;
&#13;

vue-cli项目的粗略步骤:

在./plugins/SModal.js (按照官方文档中的教程创建一个vue实例,然后将其添加到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

作为the official document said,Vue.js插件应该公开一个安装方法。将使用Vue构造函数作为第一个参数以及可能的选项

来调用该方法

在install.js (您也可以根据您的设计将此方法移至main.js):

// 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
}

在main.js (最后使用你的插件):

import install from './install'
import * as plugins from './plugins'

Vue.use({ install }, {
  plugins
})
在您的视图/组件中

最后,您可以显示/隐藏您的模态:

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

答案 2 :(得分:0)

当然,接受模态组件的属性:

 props: ['open']

然后传入:

<modal :open="boolToOpenModal"> ... </modal>

然后:

<div v-if="showingModal || open"><slot></slot></div>

答案 3 :(得分:0)

没有(简单,支持)方法来调用组件中的方法,但您可以修改子项中的属性(例如data want ; infile "C:\Users\komal\Desktop\&b" dsd firstobs=5 obs=14 truncover ; input ID Gender $ Age Height Weight Year ; run; )(请参阅Passing Data to Child Components with Props)或使用事件(请参阅Custom Events$emit$refs)。使用事件您还可以使用event bus。基于事件的解决方案当然更适合更复杂的交互。

答案 4 :(得分:0)

我只是将v-on="$listeners"添加到子组件(modal.vue)中:

// modal.vue
<template>
   <div :show="show" v-on="$listeners">
     ...
   </div>
</template>

<script>

export default {
    props: {
        show: {
            type: Boolean,
            default: false
        }
    },
    ...

现在,您可以轻松地从其父级打开或关闭模式:

//parent.vue
<modal @close="showModal = false" :show="showModal" />