携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
前言
- 直接看5.5、你以为解决了吗?。
[ 因为three.js更新了版本,引入和使用方式都变了,新版本下CSS2DRenderer的使用已经没有前面四点提及的问题,前四点仅做记录。 ]
- 直接看5.5、你以为解决了吗?。
- 直接看5.5、你以为解决了吗?。
一、引用与使用
1、配置webpack.base.conf文件
往CSS2DRenderer中导入THREE,配置webpack.base.conf文件如下:
{
test: require.resolve("three/examples/js/renderers/CSS2DRenderer"),
use: "imports-loader?THREE=three"
}
说明:
当报错THREE未定义时,因为CSS2DRenderer中用了很多THREE对象,而THREE对象若不导入系统不知道是啥。
如上配置,将three导入three/examples/js/renderers/CSS2DRenderer,THREE就等于three暴露出的变量。
2、导入CSS2DRenderer包
import 'three/examples/js/renderers/CSS2DRenderer'
注意:
此处需要使用CSS2DRenderer中的两个对象CSS2DRenderer和CSS2DObject。
3、CSS2DObject和CSS2DRenderer的使用
detailCSS2D = new THREE.CSS2DObject(detailDiv)
labelRenderer = new THREE.CSS2DRenderer()
然后警告,如下:
- export 'CSS2DObject' (imported as 'THREE') was not found in 'three'
- export 'CSS2DRenderer' (imported as 'THREE') was not found in 'three'
但不影响正常使用。
警告说明:在three中没有发现导出CSS2DObject和CSS2DRenderer。
二、部分关键代码
{
test: require.resolve("three/examples/js/controls/OrbitControls"),
use: "imports-loader?THREE=three"
},
{
test: require.resolve("three/examples/js/controls/OrbitControls"),
use: "exports-loader?THREE.OrbitControls"
},
{
test: require.resolve("three/examples/js/postprocessing/EffectComposer"),
use: "imports-loader?THREE=three"
},
{
test: require.resolve("three/examples/js/postprocessing/EffectComposer"),
use: "exports-loader?THREE.EffectComposer"
},
{
test: require.resolve("three/examples/js/renderers/CSS2DRenderer"),
use: "imports-loader?THREE=three"
},
// 经测试,下面两个配置作用不大,去掉或者加上同样报警告,但是不影响使用
{
test: require.resolve("three/examples/js/renderers/CSS2DRenderer"),
use: "exports-loader?THREE.CSS2DObject"
},
{
test: require.resolve("three/examples/js/renderers/CSS2DRenderer"),
use: "exports-loader?THREE.CSS2DRenderer"
}
import * as THREE from 'three'
import OrbitControls from 'three/examples/js/controls/OrbitControls'
import EffectComposer from 'three/examples/js/postprocessing/EffectComposer'
import 'three/examples/js/renderers/CSS2DRenderer'
controls = new OrbitControls(camera, renderer.domElement)
composer = new EffectComposer(renderer)
detailCSS2D = new THREE.CSS2DObject(detailDiv)
labelRenderer = new THREE.CSS2DRenderer()
三、遗留问题
通常webpack中引入three.js相关包,参考OrbitControls和EffectComposer的引入:
- 1、在配置文件给它们导入THREE,再导出对应使用对象THREE.OrbitControls和THREE.EffectComposer。
- 2、导入时,将其赋值给一个对象(可以这么描述吧)
import OrbitControls from 'three/examples/js/controls/OrbitControls'
import EffectComposer from 'three/examples/js/postprocessing/EffectComposer'
- 3、使用的时候直接new这个对象即可
new OrbitControls()和new EffectComposer()
但是!!
对于CSS2DRenderer同上引入:
{
test: require.resolve("three/examples/js/renderers/CSS2DRenderer"),
use: "imports-loader?THREE=three"
},
{
test: require.resolve("three/examples/js/renderers/CSS2DRenderer"),
use: "exports-loader?THREE.CSS2DObject"
},
{
test: require.resolve("three/examples/js/renderers/CSS2DRenderer"),
use: "exports-loader?THREE.CSS2DRenderer"
}
import {CSS2DObject, CSS2DRenderer} from 'three/examples/js/renderers/CSS2DRenderer'
detailCSS2D = new CSS2DObject(detailDiv)
labelRenderer = new CSS2DRenderer()
无法正常使用,报错如下:
Uncaught TypeError: __WEBPACK_IMPORTED_MODULE_7_three_examples_js_renderers_CSS2DRenderer__.CSS2DObject is not a constructor
只能按照一、引用与使用中的三步骤引入,才可以正常使用,但是控制台有警告如下:
warnings @ webpack-internal:///./node_modules/webpack-dev-server/client/index.js?http://localhost:8088:153
webpack-internal:///./node_modules/webpack-dev-server/client/index.js?http://localhost:8088:153 ./src/components/view/demoTest/index.js
876:26-43 "export 'CSS2DObject' (imported as 'THREE') was not found in 'three'
@ ./src/components/view/demoTest/index.js
@ ./src/components/view ^\.\/.*$
@ ./src/http/auth/index.js
@ ./src/http/index.js
@ ./src/main.js
@ multi (webpack)-dev-server/client?http://localhost:8088 webpack/hot/dev-server event-source-polyfill babel-polyfill ./src/main.js
warnings @ webpack-internal:///./node_modules/webpack-dev-server/client/index.js?http://localhost:8088:153
webpack-internal:///./node_modules/webpack-dev-server/client/index.js?http://localhost:8088:153 ./src/components/view/demoTest/index.js
885:26-45 "export 'CSS2DRenderer' (imported as 'THREE') was not found in 'three'
@ ./src/components/view/demoTest/index.js
@ ./src/components/view ^\.\/.*$
@ ./src/http/auth/index.js
@ ./src/http/index.js
@ ./src/main.js
@ multi (webpack)-dev-server/client?http://localhost:8088 webpack/hot/dev-server event-source-polyfill babel-polyfill ./src/main.js
所以我只好直接引入整个js文件,再使用其中的变量。
警告总比报错好吧……
求解:
1、报错怎么解决啊啊啊
Uncaught TypeError: __WEBPACK_IMPORTED_MODULE_7_three_examples_js_renderers_CSS2DRenderer__.CSS2DObject is not a constructor
2、警告怎么屏蔽啊啊啊
export 'CSS2DObject' (imported as 'THREE') was not found in 'three'
四、其他问题
换了新项目,同样的代码,CSS2DRenderer的DIV死活不显示了,查看元素display被设置成了none,可是我明明修改成了block,见鬼了。
注释掉CSS2DRenderer段代码div就显示了,于是怀疑是CSS2DRenderer源码的问题,查看对比果然不一样,再看three.js版本,原来的100正常,现在的108不正常。
临时处理方法:
修改文件package.json如下:
"three": "^0.100.0",
package-lock.json
"three": {
"version": "0.100.0",
"resolved": "https://registry.npmjs.org/three/-/three-0.100.0.tgz",
"integrity": "sha512-/lN2rdE1OqIwJr4/HcSaOisiCY0uVA0sqPpbCG5nil2uICEdS0LfGwSVYTtZDsIpR76r3++h5H3Hzg5D+SJBRQ=="
},
保存修改文件后,运行命令cnpm install --save即可。
五、新版本下CSS2DRenderer的使用
5.1、更新版本前关键代码如下:
<div id="test" class="test">{{label.name}}</div>
.test {
display: none;
width: 140px;
font-size: 14px;
text-align: center;
line-height: 30px;
background: linear-gradient(180deg,rgba(0,180,220,0.3),rgba(0,180,220,0.1),rgba(0,180,220,0.1),rgba(0,180,220,0.3));
box-shadow: 0 0 2rem rgba(0,180,220,.1) inset;
color: #eee;
cursor: pointer;
}
import 'three/examples/js/renderers/CSS2DRenderer' // 引入包
labelRenderer = new CSS2DRenderer() // 创建labelRenderer
let labelDiv= document.getElementById('test')
labelDiv.style.display = 'block'
let labelCSS2D = new CSS2DObject(labelDiv) // 创建labelCSS2D
5.2、代码说明:
页面上一个div,样式设置先display: none;隐藏,然后代码中获取div,设置为display = 'block',加到CSS2DObject中通过CSS2DRenderer渲染。
5.3、效果:
在three.js更新版本之前这么写正常,但是一旦升级了three.js的版本,div死活不出现了。
5.4、解决:
方法一:
降低three.js的版本,当然这是没办法的办法,毕竟都在往前走降低版本很多新功能就用不上了。
方法二:
看到有人说谷歌浏览器display: none;不支持,应该写成display: "";
然后我照做,果然div显示了,但是是因为浏览器根本不支持display: "";从头到尾就没有隐藏div!!!
切换火狐浏览器也是同样的效果,所以说去他的谷歌不支持display: none;查了官方文档也没说不支持。
方法三:
猜想是不是样式控制优先级的原因,把class中的display: none;放到style里面试试……
果然!!!正解啊!!!
修改代码如下:
<div id="test" style="display: none;">{{label.name}}</div>
.test {
/* display: none; */
width: 140px;
font-size: 14px;
text-align: center;
line-height: 30px;
background: linear-gradient(180deg,rgba(0,180,220,0.3),rgba(0,180,220,0.1),rgba(0,180,220,0.1),rgba(0,180,220,0.3));
box-shadow: 0 0 2rem rgba(0,180,220,.1) inset;
color: #eee;
cursor: pointer;
}
5.5、你以为解决了吗?
我更新了three.js版本,又有新的问题了。
它出现了,可是它不隐藏了。。。
新版本下正确使用CSS2DRenderer的关键代码:
<div id="test" style="display: none;">{{label.name}}</div>
.test {
/* display: none; */
width: 140px;
font-size: 14px;
text-align: center;
line-height: 30px;
background: linear-gradient(180deg,rgba(0,180,220,0.3),rgba(0,180,220,0.1),rgba(0,180,220,0.1),rgba(0,180,220,0.3));
box-shadow: 0 0 2rem rgba(0,180,220,.1) inset;
color: #eee;
cursor: pointer;
}
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer' // 引入包
initRenderLabel () {
// 创建labelRenderer div3D为当前场景挂载的div
labelRenderer = new CSS2DRenderer()
labelRenderer.setSize(div3D.clientWidth, div3D.clientHeight)
labelRenderer.domElement.style.position = 'absolute'
div3D.appendChild(labelRenderer.domElement)
}
let labelCSS2D = scene.getObjectByName('test')
if (labelCSS2D === undefined) {
let labelDiv = document.getElementById('test')
// labelDiv.style.display = 'block'
labelCSS2D = new CSS2DObject(labelDiv)
labelCSS2D.name = 'test'
scene.add(labelCSS2D)
} else {
labelCSS2D.visible = true
}
关键点:
1、隐藏div
此处必须通过style隐藏,不能通过class隐藏。
2、引入相关包
此处从jsm文件夹中引入,无需额外的配置即可使用。
3、显示和隐藏
通过对CSS2DObject创建的对象控制其在场景中visible属性,从而控制显示和隐藏。