持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
需求
同一个div下,通过查询不同的设备展示不同的模型。
1、实现新202011
实现形式:不清除场景,只清除场景中的模型,加载新的模型到场景中。
关键代码:
this.paramsThree = {
modelName: '', // .glb模型的文件名字
name: 'devGlb', // 模型加入场景的名字,此处统一是devGlb
offsetY: 0 // 模型加入场景的y轴偏移量
}
if (`当前设备模型不为空`) {
clearModel() // 清除模型
this.paramsThree.modelName = `从接口中获取模型文件名字`
initModel(this.paramsThree) // 加载新模型
} else {
clearModel() // 清除模型
this.paramsThree.modelName = ''
}
复制代码
// 主要变量
let LOAD_PARAMS = null
// 模型清除
export function clearModel () {
if (scene) {
let objM = scene.getObjectByName(LOAD_PARAMS.name)
if (objM) scene.remove(objM)
}
}
// 模型加载
export function initModel (paramsThree) {
LOAD_PARAMS = paramsThree
let glbname = paramsThree.modelName
// 实例化加载器
let loader = new GLTFLoader()
loader.load('/static/3d/subway/dev/' + glbname + '.glb', function (obj) {
obj.scene.position.y = LOAD_PARAMS.offsetY
obj.scene.name = LOAD_PARAMS.name
if (scene !== null && glbname === LOAD_PARAMS.modelName) { // 当前对应的模型和加载完成的模型一致时才放到场景中
scene.add(obj.scene)
}
}, function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded')
}, function (error) {
console.error(error, 'load error!')
})
}
复制代码
后面是以前旧代码的实现遇到的问题,做个记录。
======================
2、实现旧
关键代码如下:
<div id="equip-model"></div>
// 加载three.js
needReloadThreeJs (devtype) {
div3D = document.getElementById('equip-model')
this.initScene() // 场景
this.initCamera() // 相机
this.initRender() // 渲染器
this.initLight() // 灯光
this.initControls() // 模型控制
this.initModel(devtype) // 模型加载
this.animate() // 场景动画 动起来
},
// 清除模型
clearModel () {
// 清除局部的模型
if (scene !== null) {
// 确保3D相关对象已销毁
window.cancelAnimationFrame(stop) // 可以取消动画
scene = null
camera = null
renderer = null
controls = null
div3D = null
}
}
复制代码
问题
明明每次调用needReloadThreeJs之前先调用clearModel清除上一次的模型包括场景全部置为空,但是仍然达不到效果。
- 1、原来的模型存在,停止转动(initControls中设置了autoRotate=true)
- 2、新的模型追加上去,在浏览器端查看,有多个canvas叠加显示。
思考
尝试了各种清除模型的方法,最后发现只有清除scene的children中对应的模型对象。
因为当前只添加了三个环境光和一个模型,所以用scene.children.pop()去掉最后一个对象(模型对象)即可。
但是!!canvas始终存在,模型是清空了但是canvas占位在那里导致界面乱了。
于是想移除子节点不就可以了
let domDiv = document.getElementById('equip-model')
domDiv.removeChild(domDiv.firstChild)
复制代码
最终代码
// 清除模型
clearModel () {
// 清除局部的模型
if (scene !== null && scene.children.length > 3) {
scene.children.pop()
// 必须要清空当前div下的canvas不然canvas会继续叠加为什么呢?明明场景和相机等等都清空了
let domDiv = document.getElementById('equip-model')
if (domDiv !== null) {
domDiv.removeChild(domDiv.firstChild)
}
// 确保3D相关对象已销毁
window.cancelAnimationFrame(stop) // 可以取消动画
scene = null
camera = null
renderer = null
controls = null
div3D = null
}
}
复制代码
延伸
删除dom子节点时,最开始使用的是全部子节点删除
let domDiv = document.getElementById('equip-model')
for(let i = 0; i < domDiv.length; i++) {
domDiv.removeChild(domDiv[i])
}
复制代码
明显是有问题的,因为domDiv子节点在删除,其长度在变化,如果要删除所有子节点可以用
while(domDiv.hasChildNodes()) {
domDiv.removeChild(domDiv.firstChild)
}
复制代码
于是乎,canvas没有被删掉是不是也是因为用错了方法呢,应该不是,因为canvas不是留下一个未删除,是一直没有被删除,一直在叠加,为什么呢???