实现
<template>
<div>
<div ref="moveNodeRef" class="dialog-outter" :style="style">
<div class="mask"></div>
<slot></slot>
</div>
</div>
</template>
<script>
import {
getMaxZIndex
} from '@Common/js/dom.js';
export default {
data() {
return {
style: {
'z-index': 1
},
moveNode: null
}
},
props: {
// 是否添加到body
appendToBody: {
type: Boolean,
default: false
},
// parentNode
parentNode: {
type: HTMLDivElement,
default: null
}
},
mounted() {
this.moveNode = this.$refs.moveNodeRef;
this.updateDom();
},
destroyed() {
if (this.moveNode && this.moveNode.parentNode) {
this.moveNode.parentNode.removeChild(this.moveNode);
}
},
watch: {
parentNode: {
immediate: true,
handler(val) {
this.updateDom();
}
},
appendToBody: {
immediate: true,
handler() {
this.updateDom();
}
}
},
methods: {
updateDom() {
this.$nextTick(() => {
let moveNodeRef = this.$refs.moveNodeRef;
if (moveNodeRef) {
if (this.parentNode) {
this.parentNode.appendChild(moveNodeRef);
} else if (this.appendToBody) {
document.body.appendChild(moveNodeRef);
}
let maxZIndex = getMaxZIndex(moveNodeRef.parentNode) + 1000;
this.style = {
'z-index': maxZIndex
};
}
});
}
}
};
</script>
<style lang='stylus' scoped>
@import '~@Common/stylus/variable.styl';
@import '~@Common/stylus/mixin.styl';
</style>
复制代码
问题
一开始,使用的是element-ui的dialog 但是在使用v-if 的时候会出现报错。 错误的代码也放上来吧。
<template>
<div>
<!-- <test-com v-if='a' :key="'a'" :parentNode="parentNode">123</test-com>
<div>ad</div>
<test-com v-if='b' :key="'b'" :parentNode="parentNode">456</test-com>
<div>ck</div> -->
<el-dialog v-if="a" :visible="true" :key="'cf'" :append-to-body="true">
<span>这是一段信息</span>
</el-dialog>
<el-dialog v-if="b" :visible="true" :key="'cs'" :append-to-body="true">
<span>222222</span>
</el-dialog>
<div @click="cc">dianji a </div>
</div>
</template>
<script>
import TestCom from './view/test.vue';
export default {
name: 'app',
components: {
TestCom
},
data() {
return {
a: false,
b: false
};
},
created() {},
mounted() {
this.parentNode = document.getElementById('bbb');
window.cc = this.cc;
},
destroyed() {
},
methods: {
cc() {
if (this.a) {
this.a = false;
this.b = true;
} else {
this.a = true;
this.b = false;
}
}
}
};
</script>
<style lang='stylus' scoped>
</style>
复制代码
当不加:key 的时候,如果两个弹出层不是同步显示出来的话,el-dialog的mounted只会触发一次。后面的不是新生成,而是更新之前的el-dialog。因此需要加上:key 将两个区别开来。但是在连续去切换的时候会出现报错。
// 报错信息
DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to
be inserted is not a child of this node.
复制代码
从字面意思大概是insertBefore 选取node不是要插入的parentNode的子元素。查看element 的dialog的代码
visible(val) {
if (val) {
this.closed = false;
this.$emit('open');
this.$el.addEventListener('scroll', this.updatePopper);
this.$nextTick(() => {
this.$refs.dialog.scrollTop = 0;
});
if (this.appendToBody) {
document.body.appendChild(this.$el);
}
} else {
this.$el.removeEventListener('scroll', this.updatePopper);
if (!this.closed) this.$emit('close');
}
}
复制代码
他是使用的this.$el 将整个dom元素都插入body中。通过跟踪代码可以发现vue在插入第二个元素的时候,第一个dialog还未销毁,使用他去进行定位插入。而第一个dialog的dom被插入到了body下面,但是前面使用的parentNode还是vue结构树中的父节点,因此第一个dialog 并不在parentNode 下面,因此就出现了上面的报错信息。 这里是vue的insertbefore
// 这里的referenceNode是第一个dialog的dom元素,已经被插入到了body下面了。
而parentNode 却还是vue组件树结构的父元素, 因此会爆出[Vue warn]: Error in nextTick: "NotFoundError: Failed to execute 'insertBefore' on 'Node':
The node before which the new node is to be inserted is not a child of this node."
vue.esm.js:1741 DOMException: Failed to execute 'insertBefore' on 'Node':
The node before which the new node is to be inserted is not a child of this node.
复制代码
这个错误。
解决
取巧的解决方案,不将整个dom全部插入body中,而是在外层再包一层div,将真正要插入的作为div的子元素。这样虽然modeNodeRef会被插入到body中,但是vue在使用inserBefore的时候只会去使用外层的div去定位。
<template>
<div>
<!-->这里才是真正要插入的dom<-->
<div ref="moveNodeRef" class="dialog-outter" :style="style">
<div class="mask"></div>
<slot></slot>
</div>
</div>
</template>
复制代码
注意点:需要在destoryed中自己去手动删除插入的dom
destroyed() {
if (this.moveNode && this.moveNode.parentNode) {
this.moveNode.parentNode.removeChild(this.moveNode);
}
},
watch: {
parentNode: {
immediate: true,
handler(val) {
this.updateDom();
}
},
appendToBody: {
immediate: true,
handler() {
this.updateDom();
}
}
},
methods: {
updateDom() {
this.$nextTick(() => {
let moveNodeRef = this.$refs.moveNodeRef;
if (moveNodeRef) {
if (this.parentNode) {
this.parentNode.appendChild(moveNodeRef);
} else if (this.appendToBody) {
document.body.appendChild(moveNodeRef);
}
}
});
}
}
复制代码
所有评论(0)