• 【js&three.js】全景vr看房进阶版


    three小结:

    Scene场景

    指包含了所有要渲染和呈现的三维对象、光源、相机以及其他相关元素的环境;场景可以被渲染引擎或图形库加载和处理,以生成最终的图像或动画

    • 常见属性:
    1. scene.background = new THREE.Color(0x000000); // 设置背景颜色为黑色
    2. scene.fog = new THREE.Fog(0x000000, 0.1, 100); // 创建线性雾效,颜色为黑色,起始距离为0.1,结束距离为100
    • 常见方法:
    1. scene.add(mesh); // 将名为mesh的对象添加到场景中
    2. scene.remove(mesh); // 从场景中移除名为mesh的对象
    3. var obj = scene.getObjectByName('mesh'); // 获取名称为mesh的对象
    4. scene.traverse(function(object) {
    5. // 对每个对象执行的操作
    6. console.log(object);
    7. });
    8. scene.dispose(); // 清除场景及其相关资源

    Geometry 几何体

    指的是表示和描述三维对象形状的数据,描述了对象的形状

    常用的Geometry(几何体):

    • BufferGeometry   是three.js中高性能的几何体对象
    • BoxGeometry   表示立方体的几何体对象
    • SphereGeometry   表示球体的几何体对象
    • PlaneGeometry  表示平面的几何体对象
    • CylinderGeometry  表示圆柱体(包括圆柱体、圆锥体和管道)的几何体对象

    Material 材质

    指的是给定几何体表面外观的属性和特征,定义了对象的外观属性

    常用的Material(材质):

    • MeshBasicMaterial     是最简单的材质,不受场景光照的影响
    • MeshStandardMaterial      是一种基于物理渲染(PBR)的材质,提供了更真实和逼真的渲染效果
    • MeshPhysicalMaterial       是在MeshStandardMaterial基础上更进一步的物理材质

    Mesh 网格模型

    是由几何体和材质组合而成的实体,将几何体和材质组合成一个完整的实体

    • 方法举例:
    1. mesh.material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); // 设置网格的材质为红色基础材质
    2. mesh.rotation.set(Math.PI / 2, 0, 0); // 设置网格绕X轴旋转90度
    3. mesh.rotateY(Math.PI / 4); // 将网格绕Y轴旋转45度
    4. mesh.position.set(0, 0, 0); // 设置网格的位置为原点
    • 属性举例: 
    1. mesh.visible = false; // 隐藏网格
    2. mesh.material.opacity = 0.5; // 将网格材质的透明度设置为0.5

    Camera 相机

    用于模拟人眼视角和观察场景的虚拟设备

    常用的Camera 相机:

    • PerspectiveCamera(透视相机)   模拟了人眼观察物体的效果,具有近大远小的特性
    • OrthographicCamera(正交相机)  以固定的大小渲染场景中的物体,不考虑距离远近而产生的透视效果

    方法举例:

    1. camera.lookAt(new THREE.Vector3(0, 0, 0)); // 将相机对准场景原点
    2. camera.updateProjectionMatrix(); // 更新相机的投影矩阵
    3. const newCamera = camera.clone(); // 克隆相机

    属性举例: 

    1. camera.position.set(0, 0, 10); // 设置相机在场景中的位置
    2. camera.rotation.set(0, Math.PI / 2, 0); // 设置相机的旋转角度
    3. camera.fov = 60; // 设置透视相机的视角大小为60度
    4. camera.zoom = 2; // 将正交相机设置为缩放倍数为2

    光源

     

    AmbientLight(环境光):环境光是一个均匀无方向的光源,用于模拟场景中无处不在的环境光照射。它不会产生阴影,对场景中的所有物体都产生均匀的照明效果。

    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // 环境光

    PointLight(点光源):点光源是一个从一个点向四面八方发射光线的光源。会在场景中产生逐渐减弱的光照效果,并且可以投射阴影。通常用于模拟灯泡、蜡烛等点光源 

    1. const pointLight = new THREE.PointLight(0xff0000, 1, 10); // 红色点光源
    2. pointLight.position.set(0, 3, 0)

    DirectionalLight(平行光):平行光是一种无限远、平行的光源,模拟太阳光。它是从一个特定的方向射来的光,所有光线都是平行的。平行光可以产生阴影,对场景中的物体产生类似于自然光的直射效果 

    1. const directionalLight = new THREE.DirectionalLight(0x00ff00, 1); // 绿色平行光
    2. directionalLight.position.set(-1, 2, 4);

    SpotLight(聚光灯):聚光灯是一个从一个点射出的光锥,具有指定的方向和光束角度。它可以投射出锥形的光束,并且可以产生阴影。聚光灯通常用于模拟手电筒、舞台灯光等

    1. const spotLight = new THREE.SpotLight(0x0000ff, 1, 10, Math.PI / 4, 0.5); // 蓝色聚光灯
    2. spotLight.position.set(2, 3, 0);
    3. spotLight.target.position.set(0, 0, 0);

    WebGLRenderer 渲染器

    用于在Web浏览器中使用WebGL绘制和呈现3D图形

    OrbitControls   相机控件工具

    使用户可以通过鼠标或触摸手势来旋转、缩放和平移相机,以改变场景的视角

    属性举例: 

    1. controls.enabled = true; // 启用控制器
    2. controls.minZoom = 0.5; // 设置相机的最小缩放倍数为0.5
    3. controls.maxZoom = 2; // 设置相机的最大缩放倍数为2
    4. controls.enableRotate = true; // 启用旋转操作
    5. controls.enableZoom = true; // 启用缩放操作
    6. controls.enablePan = true; // 启用平移操作

    效果展示:

    目录展示:

     代码展示:

     path.js

    1. function path() {
    2. return [{
    3. name: "中式",
    4. styleObj: {
    5. background: '#409EFF'
    6. },
    7. children: [{
    8. name: "客餐厅",
    9. styleObj: {
    10. background: '#409EFF'
    11. },
    12. jpgNameArr: ["00125.jpg"]
    13. }, {
    14. name: "客厅",
    15. styleObj: {
    16. background: null
    17. },
    18. jpgNameArr: ["0011.jpg"]
    19. }, {
    20. name: "餐厨",
    21. styleObj: {
    22. background: null
    23. },
    24. jpgNameArr: ["0011.jpg"]
    25. }, {
    26. name: "卧室",
    27. styleObj: {
    28. background: null
    29. },
    30. jpgNameArr: ["0011.jpg"]
    31. }, {
    32. name: "卫浴",
    33. styleObj: {
    34. background: null
    35. },
    36. jpgNameArr: ["0011.jpg"]
    37. }, {
    38. name: "书房",
    39. styleObj: {
    40. background: null
    41. },
    42. jpgNameArr: ["0011.jpg"]
    43. }]
    44. }, {
    45. name: "现代",
    46. styleObj: {
    47. background: null
    48. },
    49. children: [{
    50. name: "客餐厅",
    51. styleObj: {
    52. background: null
    53. },
    54. jpgNameArr: ["0011.jpg"]
    55. }, {
    56. name: "客厅",
    57. styleObj: {
    58. background: null
    59. },
    60. jpgNameArr: ["0011.jpg"]
    61. }, {
    62. name: "餐厨",
    63. styleObj: {
    64. background: null
    65. },
    66. jpgNameArr: ["0011.jpg"]
    67. }, {
    68. name: "卧室",
    69. styleObj: {
    70. background: null
    71. },
    72. jpgNameArr: ["0011.jpg"]
    73. }, {
    74. name: "卫浴",
    75. styleObj: {
    76. background: null
    77. },
    78. jpgNameArr: ["0011.jpg"]
    79. }]
    80. }, {
    81. name: "新古典",
    82. styleObj: {
    83. background: null
    84. },
    85. children: [{
    86. name: "客餐厅",
    87. styleObj: {
    88. background: null
    89. },
    90. jpgNameArr: ["0011.jpg"]
    91. }, {
    92. name: "客厅",
    93. styleObj: {
    94. background: null
    95. },
    96. jpgNameArr: ["0011.jpg"]
    97. }, {
    98. name: "餐厨",
    99. styleObj: {
    100. background: null
    101. },
    102. jpgNameArr: ["0011.jpg"]
    103. }, {
    104. name: "卧室",
    105. styleObj: {
    106. background: null
    107. },
    108. jpgNameArr: ["0011.jpg"]
    109. }, {
    110. name: "卫浴",
    111. styleObj: {
    112. background: null
    113. },
    114. jpgNameArr: ["0011.jpg"]
    115. }]
    116. }, {
    117. name: "欧式",
    118. styleObj: {
    119. background: null
    120. },
    121. children: [{
    122. name: "客餐厅",
    123. styleObj: {
    124. background: null
    125. },
    126. jpgNameArr: ["0011.jpg"]
    127. }, {
    128. name: "客厅",
    129. styleObj: {
    130. background: null
    131. },
    132. jpgNameArr: ["0011.jpg"]
    133. }, {
    134. name: "餐厨",
    135. styleObj: {
    136. background: null
    137. },
    138. jpgNameArr: ["0011.jpg"]
    139. }, {
    140. name: "卧室",
    141. styleObj: {
    142. background: null
    143. },
    144. jpgNameArr: ["0011.jpg"]
    145. }, {
    146. name: "卫浴",
    147. styleObj: {
    148. background: null
    149. },
    150. jpgNameArr: ["0011.jpg"]
    151. }]
    152. }, {
    153. name: "美式",
    154. styleObj: {
    155. background: null
    156. },
    157. children: [{
    158. name: "客餐厅",
    159. styleObj: {
    160. background: null
    161. },
    162. jpgNameArr: ["0011.jpg"]
    163. }, {
    164. name: "客厅",
    165. styleObj: {
    166. background: null
    167. },
    168. jpgNameArr: ["0011.jpg"]
    169. }, {
    170. name: "餐厨",
    171. styleObj: {
    172. background: null
    173. },
    174. jpgNameArr: ["0011.jpg"]
    175. }, {
    176. name: "卧室",
    177. styleObj: {
    178. background: null
    179. },
    180. jpgNameArr: ["0011.jpg"]
    181. }, {
    182. name: "卫浴",
    183. styleObj: {
    184. background: null
    185. },
    186. jpgNameArr: ["0011.jpg"]
    187. }]
    188. }, {
    189. name: "北欧",
    190. styleObj: {
    191. background: null
    192. },
    193. children: [{
    194. name: "客餐厅",
    195. styleObj: {
    196. background: null
    197. },
    198. jpgNameArr: ["0011.jpg"]
    199. }, {
    200. name: "客厅",
    201. styleObj: {
    202. background: null
    203. },
    204. jpgNameArr: ["0011.jpg"]
    205. },{
    206. name: "卧室",
    207. styleObj: {
    208. background: null
    209. },
    210. jpgNameArr: ["0011.jpg"]
    211. }]
    212. }, {
    213. name: "法式",
    214. styleObj: {
    215. background: null
    216. },
    217. children: [{
    218. name: "客厅",
    219. styleObj: {
    220. background: null
    221. },
    222. jpgNameArr: ["0011.jpg"]
    223. }, {
    224. name: "餐厨",
    225. styleObj: {
    226. background: null
    227. },
    228. jpgNameArr: ["0011.jpg"]
    229. }]
    230. }]
    231. }

    index.html

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Three.js-webgl室内设计效果全景在线预览title>
    6. <style>
    7. body {
    8. margin: 0;
    9. overflow: hidden;
    10. }
    11. #menu {
    12. position: absolute;
    13. bottom: 0px;
    14. color: #fff;
    15. background: rgba(0, 0, 0, 0.5);
    16. padding: 10px;
    17. z-index: 102;
    18. width: 500px;
    19. height: 80px
    20. }
    21. #menu>div {
    22. padding: 5px;
    23. }
    24. #menu span {
    25. display: inline-block;
    26. padding: 5px 10px;
    27. cursor: pointer;
    28. }
    29. .el-button--danger {
    30. font-size: 25px !important;
    31. background: rgba(0, 0, 0, 0.5) !important;
    32. border-width: 0px !important;
    33. width: 50px !important;
    34. height: 50px !important;
    35. }
    36. [v-cloak] {
    37. display: none;
    38. }
    39. style>
    40. <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.min.js">script>
    41. <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/controls/OrbitControls.js">script>
    42. <script src="http://www.yanhuangxueyuan.com/js/vue@2.5.16.min.js">script>
    43. <script src="http://www.yanhuangxueyuan.com/js/element-ui/index.js">script>
    44. <link rel="stylesheet" href="http://www.yanhuangxueyuan.com/js/element-ui/index.css">
    45. <script src="path.js">script>
    46. head>
    47. <body>
    48. <div id="app" z-index="105">
    49. <div id="menu" :style="{left:width/2 + -250+'px'}">
    50. <div><span style="font-weight:bold;cursor:default;"> 风格:span><span v-for="obj in styleArr"
    51. @click="styleClick(obj)" :style="obj.styleObj"> {{ obj.name }}span>div>
    52. <div><span style="font-weight:bold;cursor:default;"> 位置:span><span v-for="obj in posArr"
    53. @click="posClick(obj)" :style="obj.styleObj" v-if="obj.jpgNameArr.length"> {{ obj.name }}span>
    54. div>
    55. div>
    56. <div style="position: absolute;right:20px;top:20px">
    57. <el-button type="danger" circle @click="audioClick()"><i><img
    58. :src="(audioBoool)?('./UI/打开声音.png'):('./UI/关闭声音.png')" alt="" height="20"
    59. width="20">i>el-button>
    60. <el-button type="danger" circle @click="ScreenClick()"><i><img
    61. :src="(ScreenBoool)?('./UI/全屏5.png'):('./UI/退出全屏.png')" alt="" width="18"
    62. height="18">i>el-button>
    63. <el-button type="danger" circle @click="rotateClick()"><i><img
    64. :src="(rotateBoool)?('./UI/旋转.png'):('./UI/停止旋转.png')" alt="" width="20"
    65. height="20">i>el-button>
    66. <el-button type="danger" circle @click="questionClick()"><i><img src="./UI/帮助5.png" alt="" width="22"
    67. height="22">i>el-button>
    68. div>
    69. div>
    70. <script>
    71. // 创建场景
    72. var scene = new THREE.Scene();
    73. // 创建一个球体(Sphere)几何体
    74. var box = new THREE.SphereGeometry(25, 50, 50);
    75. // 创建一个基本网格材质
    76. var material = new THREE.MeshBasicMaterial({
    77. color: 0xffffff,
    78. side: THREE.BackSide,
    79. });
    80. // 创建了一个网格对象实例
    81. var mesh = new THREE.Mesh(box, material);
    82. // 将网格对象添加到场景中,以便在渲染时呈现出来
    83. scene.add(mesh);
    84. // 创建了一个纹理加载器实例
    85. var textureLoader = new THREE.TextureLoader();
    86. // 创建了一个音频监听器实例
    87. var listener = new THREE.AudioListener();
    88. // 创建一个用于播放音频的对象
    89. var audio = new THREE.Audio(listener);
    90. // 创建一个纹理加载器,并调用 load() 方法加载指定路径的纹理图像
    91. var texture = textureLoader.load('./风格/中式/客餐厅/00125.jpg', function (obj) {
    92. vm.loading.close();
    93. // 创建一个音频加载器
    94. var audioLoader = new THREE.AudioLoader();
    95. audioLoader.load('./音乐/琵琶语.mp3', function (AudioBuffer) {
    96. // 将加载的音频数据设置给 audio 对象
    97. audio.setBuffer(AudioBuffer);
    98. // 设置音频循环播放
    99. audio.setLoop(true);
    100. // 设置音频音量
    101. audio.setVolume(0.3);
    102. // 开始播放音频
    103. audio.play()
    104. });
    105. // 执行渲染
    106. render()
    107. });
    108. // 网格对象将使用加载的纹理作为材质的贴图
    109. mesh.material.map = texture;
    110. // 当前窗口的宽度
    111. var width = window.innerWidth;
    112. // 获取当前窗口的高度
    113. var height = window.innerHeight;
    114. // 计算宽高比
    115. var k = width / height;
    116. // 创建相机
    117. var camera = new THREE.PerspectiveCamera(60, k, 1, 1000);
    118. // 设置相机的缩放比例为 1。表示相机的视野不进行缩放
    119. camera.zoom = 1;
    120. // 修改相机的属性后,需要调用该方法来更新相机的投影矩阵,确保改变后的属性生效
    121. camera.updateProjectionMatrix();
    122. // 设置相机的位置坐标 通过设置相机的位置,可以决定场景中的视角
    123. camera.position.set(-0.87, 0.03, 0.4);
    124. // 设置相机的视线方向朝向场景的原点
    125. camera.lookAt(scene.position);
    126. // 创建一个基于 WebGL 的渲染器对象
    127. var renderer = new THREE.WebGLRenderer({
    128. // 开启抗锯齿效果,提高渲染的质量
    129. antialias: true,
    130. });
    131. // 设置渲染器的输出画布大小为窗口的宽度和高度
    132. renderer.setSize(width, height);
    133. // 将渲染器的 canvas 元素添加到页面的 body 中
    134. document.body.appendChild(renderer.domElement);
    135. // 创建时钟对象 用于跟踪时间的流逝,可以用来控制动画和其他与时间相关的操作
    136. var clock = new THREE.Clock();
    137. // 表示每秒帧数,这里设置为 30 帧
    138. var FPS = 30;
    139. // 计算每帧的时间间隔
    140. var 刷新时间 = 1 / FPS;
    141. var timeS = 0;
    142. function render() {
    143. // 浏览器执行下一次渲染时调用 render 函数
    144. requestAnimationFrame(render);
    145. // getDelta() 返回上一次调用之后的时间差,即两次渲染之间的时间间隔
    146. var 渲染间隔 = clock.getDelta();
    147. timeS = timeS + 渲染间隔;
    148. // 总运行时间是否大于刷新时间
    149. if (timeS > 刷新时间) {
    150. // 使用渲染器对象 renderer 来渲染场景 scene 和相机 camera
    151. renderer.render(scene, camera);
    152. if (vm.rotateBoool) {
    153. // mesh 沿 Y 轴旋转 0.002 弧度
    154. mesh.rotateY(0.002)
    155. }
    156. timeS = 0
    157. }
    158. }
    159. render();
    160. // 创建了一个控制器对象,用于控制相机的旋转、缩放和平移等操作
    161. var controls = new THREE.OrbitControls(camera);
    162. // 禁用 OrbitControls 控制器对象的平移功能
    163. controls.enablePan = false;
    164. // 获取本地数据
    165. var styleObjArr = path();
    166. var vm = new Vue({
    167. el: "#app",
    168. data: {
    169. loading: null,
    170. styleArr: styleObjArr,
    171. styleChoose: null,
    172. posArr: null,
    173. posChoose: null,
    174. width: window.innerWidth,
    175. height: window.innerHeight,
    176. classPath: '中式/客餐厅',
    177. path: '',
    178. audioBoool: true,
    179. ScreenBoool: true,
    180. rotateBoool: true,
    181. N: styleObjArr[0].children[0].jpgNameArr.length,
    182. num: 1,
    183. },
    184. methods: {
    185. audioClick: function () {
    186. // 播放音乐
    187. if (this.audioBoool) {
    188. this.audioBoool = false;
    189. audio.pause()
    190. } else {
    191. // 暂停音乐
    192. this.audioBoool = true;
    193. audio.play()
    194. }
    195. },
    196. // 全屏方法
    197. ScreenClick: function () {
    198. if (this.ScreenBoool) {
    199. this.ScreenBoool = false;
    200. requestFullScreen()
    201. } else {
    202. this.ScreenBoool = true;
    203. exitFullscreen()
    204. }
    205. },
    206. questionClick: function () {
    207. // element弹框的的this.$alert
    208. this.$alert('按住左键不放上下左右拖动,可以旋转整个场景', '旋转操作', {})
    209. },
    210. // 旋转
    211. rotateClick: function () {
    212. if (this.rotateBoool) {
    213. this.rotateBoool = false
    214. } else {
    215. this.rotateBoool = true
    216. }
    217. },
    218. nextClick: function () {
    219. if (this.num < this.N) {
    220. this.num += 1
    221. } else {
    222. this.num = 1
    223. }
    224. },
    225. upClick: function () {
    226. if (this.num > 1) {
    227. this.num -= 1
    228. } else {
    229. this.num = this.N
    230. }
    231. },
    232. // 风格选择
    233. styleClick: function (styleObj) {
    234. this.loading = this.$loading({
    235. lock: true,
    236. text: 'Loading',
    237. spinner: 'el-icon-loading',
    238. background: 'rgba(0, 0, 0, 0.7)'
    239. });
    240. this.num = 1;
    241. this.styleChoose.styleObj.background = null;
    242. this.posChoose.styleObj.background = null;
    243. this.styleChoose = styleObj;
    244. this.styleChoose.styleObj.background = '#409EFF';
    245. this.posArr = this.styleChoose.children;
    246. this.posChoose = this.posArr[0];
    247. this.posArr[0].styleObj.background = '#409EFF';
    248. this.N = this.posChoose.jpgNameArr.length;
    249. this.classPath = this.styleChoose.name + '/' + this.posChoose.name;
    250. this.path = this.classPath + '/' + this.posChoose.jpgNameArr[this.num - 1];
    251. var texture = textureLoader.load('./风格/' + this.path, function (obj) {
    252. // 关闭加载中的提示框
    253. vm.loading.close();
    254. render()
    255. });
    256. mesh.material.map = texture
    257. },
    258. // 位置选择
    259. posClick: function (posObj) {
    260. this.loading = this.$loading({
    261. lock: true,
    262. text: 'Loading',
    263. spinner: 'el-icon-loading',
    264. background: 'rgba(0, 0, 0, 0.7)'
    265. });
    266. this.num = 1;
    267. this.posChoose.styleObj.background = null;
    268. this.posChoose = posObj;
    269. this.N = this.posChoose.jpgNameArr.length;
    270. this.posChoose.styleObj.background = '#409EFF';
    271. this.classPath = this.styleChoose.name + '/' + this.posChoose.name;
    272. this.path = this.classPath + '/' + this.posChoose.jpgNameArr[this.num - 1];
    273. var texture = textureLoader.load('./风格/' + this.path, function (obj) {
    274. vm.loading.close();
    275. render()
    276. });
    277. mesh.material.map = texture
    278. }
    279. },
    280. watch: {
    281. num: function (value) {
    282. this.loading = this.$loading({
    283. lock: true,
    284. text: 'Loading',
    285. spinner: 'el-icon-loading',
    286. background: 'rgba(0, 0, 0, 0.7)'
    287. });
    288. this.path = this.classPath + '/' + this.posChoose.jpgNameArr[this.num - 1];
    289. console.log(this.path);
    290. var texture = textureLoader.load('./风格/' + this.path, function (obj) {
    291. vm.loading.close();
    292. render()
    293. });
    294. mesh.material.map = texture;
    295. render()
    296. }
    297. },
    298. created() {
    299. this.posArr = styleObjArr[0].children;
    300. this.styleChoose = this.styleArr[0];
    301. this.posChoose = styleObjArr[0].children[0];
    302. this.loading = this.$loading({
    303. lock: true,
    304. text: 'Loading',
    305. spinner: 'el-icon-loading',
    306. background: 'rgba(0, 0, 0, 0.7)'
    307. })
    308. }
    309. });
    310. window.onresize = onresizeFun;
    311. function onresizeFun() {
    312. renderer.setSize(window.innerWidth, window.innerHeight);
    313. // 设置相机的视图比例(即宽高比)
    314. camera.aspect = window.innerWidth / window.innerHeight;
    315. // 修改相机的属性后,需要调用该方法来更新相机的投影矩阵,确保改变后的属性生效
    316. camera.updateProjectionMatrix();
    317. vm.width = window.innerWidth;
    318. vm.height = window.innerHeight;
    319. };
    320. function requestFullScreen() {
    321. // 获取文档的根元素
    322. var de = document.documentElement;
    323. // 检查当前浏览器是否支持 requestFullscreen 方法
    324. if (de.requestFullscreen) {
    325. // 全屏显示模式
    326. de.requestFullscreen()
    327. } else if (de.mozRequestFullScreen) { //进一步检查当前浏览器是否支持 mozRequestFullScreen 方法
    328. de.mozRequestFullScreen()
    329. } else if (de.webkitRequestFullScreen) { //再进一步检查当前浏览器是否支持 webkitRequestFullScreen 方法
    330. de.webkitRequestFullScreen()
    331. }
    332. }
    333. // 与上相反 退出全屏
    334. function exitFullscreen() {
    335. var de = document;
    336. if (de.exitFullscreen) {
    337. de.exitFullscreen()
    338. } else if (de.mozCancelFullScreen) {
    339. de.mozCancelFullScreen()
    340. } else if (de.webkitCancelFullScreen) {
    341. de.webkitCancelFullScreen()
    342. }
    343. }
    344. script>
    345. body>
    346. html>

  • 相关阅读:
    去了家新公司,技术总监不让用 IntelliJ IDEA想离职了
    Spring Boot 实现统一异常处理:构建健壮的应用
    Go的简单入门:开始使用多模块的工作空间
    ARK Invest:比特币,一种被低估且独特的避险资产
    CGAL 入门基础
    手写本地缓存实战2—— 打造正规军,构建通用本地缓存框架
    【猿创征文】Vue3 企业级优雅实战 - 组件库框架 - 6 搭建example环境
    神经网络logistic回归模型,logistic回归的基本理论
    SENet 学习
    yo!这里是进程控制
  • 原文地址:https://blog.csdn.net/weixin_52479803/article/details/132276368