vue-cli + three.js 解决页面跳转时Css2dObject遗留在dom的问题

最近再做项目的时候,采用vue + three.js进行开发大型的3d场景项目,该项目中涉及到需要为建筑中的元素添加标签说明一些信息、名称,遂决定使用three.js的CSS2DRenderer和CSS2DObject进行标签的绘制,用的代码如下:

function makeCSS2DObject(position, radius, text) {
    const div = document.createElement( 'div' );
    div.className = 'scene-label';
    div.style.marginTop = '-1em';
    const span = document.createElement('span');
    span.className = 'scene-label-text'
    span.textContent = text;
    div.appendChild(span);
    const label = new CSS2DObject( div );
    label.name = "mark-point"
    label.position.set( 0, radius-16, 0);

    return label;
}

function makeCSS2DPointObject(position, radius) {
    let div = document.createElement( 'div' );
    div.className = 'scene-point';
    div.style.marginTop = '-2em';
    const img = document.createElement('img');
    img.src = "assets/img/point.gif";
    img.style.width = "30px";
    img.style.height = "30px";
    div.appendChild(img);
    const label = new CSS2DObject( div );
    label.position.set( 0, radius-40, 0);

    return label;
}

通过将标签加入到场景中,显示出来:

vue-cli + three.js 解决页面跳转时Css2dObject遗留在dom的问题_第1张图片

原来以为一切都大功告成的时候,就在跳转到其他3D场景页面的时候,问题来了,居然在其他场景中,css2dobject创建的标签被带了过来,并没有随着页面的切换而消失:

vue-cli + three.js 解决页面跳转时Css2dObject遗留在dom的问题_第2张图片

初步排查了原因,原来three.js的 CSS2DRenderer生成的标签直接就是挂在真实的DOM上,并非是Vue的虚拟DOM上,所以在页面切换的时候,这个标签并不会随着切换而消失。而是一直在页面的body上面:

vue-cli + three.js 解决页面跳转时Css2dObject遗留在dom的问题_第3张图片

到这里,问题找到了,可以解决问题了,但由CSS2DRenderer生成的标签居然不带任何的类目和id,那怎样在代码中去处理它呢,这里用了一个被逼无奈的简单粗暴的办法:直接去dom的body上找挂载在上面的标签元素,在控制台打印出来:

const div =  document.getElementsByTagName('div');
console.log(div)

找到对应的div的位置,由于这个div没有任何类名和id,所以一眼就可以认出它来:

vue-cli + three.js 解决页面跳转时Css2dObject遗留在dom的问题_第4张图片

是它,是它,就是它,找到它就可以直接在切换页面的时候干掉它了, 直接在Vue的生命周期钩子函数beforeDestroy里面直接把它从DOM上移除或者将其display设置为none即可:

 const div =  document.getElementsByTagName('div')[2];
 // div.style.display = 'none';
 document.body.removeChild(div);

如果下个页面中没有再用到这些标签, 这里建议是直接移除掉; 但这种方法对只是跳转单个页面来说有效,如果要一劳永逸,有另外一种完美的方法,那就是在vue生命周期进入beforeDestroy时,直接在document.body上直接移除掉CSS2DRenderer的domElement:

beforeDestroy() {
    document.body.removeChild(css2dRenderer.domElement)
}

好了,到这里问题似乎就得到较合理的解决。

 

 

你可能感兴趣的:(Three.js开发)