出来るんですよ
mixin/IndependentComponent.js
これをmixinすることで呼び出すコンポーネントをvmへ追加してあげます
肝なのが、mounted
のなかで$el
(自分自身の要素)をcreatedで作ったvmへ差し込む部分とcreated
でその差し込み先のコンポーネントを作っているところです(つまり全部)
import Vue from 'vue'
import camelCase from 'lodash/camelCase'
import upperFirst from 'lodash/upperFirst'
export default {
created () {
let name = this.$options.name
if (!name) {
console.error('please set components name.')
if (process.env.NODE_ENV === 'development') {
console.warn('create unique id')
const uuidv4 = require('uuid/v4')
name = uuidv4()
}
}
name = upperFirst(camelCase(name))
let $parent = this.$parent
if (!$parent) {
let parent = document.querySelector(this.container)
if (!parent) {
// Lazy creating `div.notifications` container.
const className = this.container.replace('.', '')
const Component = Vue.extend({
name,
render (h) {
return h('div', {
'class': {
[`${className}`]: true
}
})
}
})
$parent = new Component().$mount()
document.body.appendChild($parent.$el)
} else {
$parent = parent.__vue__
}
// Hacked.
this.$_parent_ = $parent
}
},
mounted () {
// independent instance
if (this.$_parent_) {
this.$_parent_.$el.appendChild(this.$el)
this.$parent = this.$_parent_
delete this.$_parent_
}
}
}
genModalComponent.js
import Vue from 'vue'
import store from 'src/store'
import router from 'src/router'
export function genModalComponent (component) {
const Instance = Vue.extend(component)
// param has to be Object
return (param) => {
return new Promise((resolve, reject) => {
let notUsedValue = new Instance({ // eslint-disable-line no-unused-vars
el: document.createElement('div'),
store,
router,
param: param || {},
propsData: {
active: true,
callback: function (result, ...param) {
if (result === this.$enums.result.CANCELED) {
resolve(null)
}
if (result === this.$enums.result.OK) {
if (param instanceof Array && param.length === 1) {
param = param[0]
}
resolve(param)
}
}
}
})
})
}
}
ここで新規Vueインスタンスを生成しています
当然元のVueインスタンスと別になるので現状のVue.js Devtoolsではインスペクトすることができません(対応してくれ〜〜〜)
propにcallback
関数を渡していますが、これは呼び出し側へ値を返却する必要がある際に利用します
ここの中の書き方はもうちょっといい方法があるかもしれません
plugins/enum.js
genModalComponent.js
で使用している$enums
はこの辺で適当に宣言してます
const promise = {
RESOLVED: Symbol('enum_promise_resolved'),
FAILED: Symbol('enum_promise_failed')
}
const result = {
OK: Symbol('enum_result_ok'),
CANCELED: Symbol('enum_result_canceled'),
FAILED: Symbol('enum_result_failed')
}
export default {
install: function (vue) {
vue.prototype.$enums = {
promise,
result
}
}
}
使い方
Confirmモーダルをだす例をあげます (Buefy使用)
components/Confirm.vue
<template>
<b-modal :active.sync="isActive" @close="cancel">
<div class="modal-card" ref="modal">
<header class="modal-card-head">
<p class="modal-card-title">{{ title }}</p>
</header>
<section class="modal-card-body">
<div class="content block">
{{ body }}
</div>
</section>
<footer class="modal-card-foot">
<button class="button" type="button" @click='submit()'>OK</button>
<button class="button" type="button" @click='cancel()'>Cancel</button>
</footer>
</div>
</b-modal>
</template>
<script>
import IndependentComponent from 'components/mixins/IndependentComponent'
export default {
name: 'Confirm',
mixins: [ IndependentComponent ],
props: {
active: {
type: Boolean,
default: false
},
callback: {
type: Function, // status, id
default: () => {}
},
container: {
type: String,
default: '.confirm--container'
}
},
data () {
return {
isActive: false,
title: this.$options.param.title,
body: this.$options.param.body
}
},
methods: {
cancel () {
this.callback(this.$enums.result.CANCELED)
this.close()
},
close () {
this.$emit('close')
this.$emit('update:active', false)
this.isActive = false
},
submit () {
this.callback(this.$enums.result.OK, true)
this.close()
}
},
mounted () {
// Delay assign
this.isActive = this.active
}
}
</script>
呼び出し側からの変数はthis.$options.param
に詰め込まれています
b-modalに渡しているisActive
ですがpropsをそのまま渡してしまうとmountされる前にactive === true
となってしまい虚空の彼方へ消え去りますので、mountedの中でisActive = active
としています
plugins/Confirm.js
import Confirm from 'components/Confirm'
import { genModalComponent } from 'src/utils/genModalComponent'
export default {
install: function (vue, options) {
vue.prototype.$confirm = genModalComponent(Confirm)
}
}
pluginとして登録してあげる事によって、呼び出したいコンポーネントからthis.$confirm
のような形で書くことができます
パラメータを渡す際は以下のようにObjectに詰めてあげるとOK
this.$confirm({
title: 'hoge',
body: 'message'
})
合わせて読みたい
勝手にリコメンドします