H5 three.js 实现六年级观察物体

o( ̄▽ ̄)ブ 我又带着新的demo来啦~

预览
在这里插入图片描述
功能点

  • 立方体的阴影
  • 立方体的添加
  • 位置记录
  • 最大限制
  • 三视图展示
  • 立方体的移除
  • 答题模式
  • 随机出题
  • 题库出题

源码
注释算是比较全了,可能部分会有点绕,还能够再优化一下~

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="stylesheet" href="./assets/global.css"><style>body {user-select: none;}.panel-container {position: absolute;top: 0;left: 0;/* height: 200px; */width: 100%;background-color: rgba(255, 255, 255, .8);padding: 20px;box-sizing: border-box;display: flex;justify-content: space-between;}.mode-switch {display: inline-flex;overflow: hidden;height: 32px;border-radius: 6px;background-color: #ccc;}.mode-switch .mode-switch-item {display: inline-block;padding: 0 8px;line-height: 32px;font-size: 12px;background-color: transparent;cursor: pointer;}.mode-switch .mode-switch-item.active {background-color: #88ccee;}.mode-switch .mode-switch-item.del.active {background-color: #cc3333;}.mode-switch-item.clear.active,.mode-switch-item.again.active {display: inline-block;}.mode-switch-item.clear,.mode-switch-item.again {display: none;}.mode-switch-item.clear.active,.mode-switch-item.del.active {background-color: #cc3333;color: #fff;}.panel-container.bottom {top: auto;bottom: 0;padding-top: 32px;}.front-view,.top-view,.left-view {width: 25vmin;height: 25vmin;position: relative;}.front-view::before,.top-view::before,.left-view::before {position: absolute;font-size: 12px;top: -16px;}.front-view::before {content: "正视图";}.top-view::before {content: "顶视图";}.left-view::before {content: "左视图";}.front-view.right::after,.top-view.right::after,.left-view.right::after {position: absolute;left: 0;right: 0;top: 0;bottom: 0;z-index: 0;background-color: rgba(255, 255, 255, .8);background-image: url('./assets/observing-objects/right.png');background-size: 50%;background-repeat: no-repeat;background-position: center;content: '';}.view-cude {position: absolute;background-image: url('./assets/cubeTexture.jpg');background-size: 110%;background-position: center;transform: translateY(-100%);}.view-cude.active {background: #404040;}.hint-container {position: absolute;top: 72px;color: #cc3333;opacity: .6;line-height: 20px;font-size: 12px;padding: 10px 10px;}.win-container {position: absolute;top: 72px;bottom: 0;left: 0;right: 0;background-color: rgba(255, 255, 255, .8);display: flex;justify-content: center;align-items: center;display: none}.win-container img {width: 50%;height: 80%;object-fit: contain;}</style>
</head><body><script type="importmap">{"imports": {"three": "https://unpkg.com/three/build/three.module.js","three/addons/": "https://unpkg.com/three/examples/jsm/"}}</script><div class="panel-container"><div class="mode-switch"><div class="mode-switch-item new">新增模式</div><div class="mode-switch-item del">删除模式</div><div class="mode-switch-item que">答题模式</div></div><div class="mode-switch"><div class="mode-switch-item again">再来一题</div><div class="mode-switch-item clear">清空方块</div></div></div><div class="hint-container">提示:答题模式无法编辑添加方块,通过观察立方体,单击三视图中的方块显示和隐藏来回答问题。</div><div class="panel-container bottom"><div class="front-view"></div><div class="top-view"></div><div class="left-view"></div></div><div class="win-container"><img src="./assets/rainbow-fart/1.gif"><img src="./assets/rainbow-fart/2.gif"></div><script type="module">import * as THREE from 'three';import { OrbitControls } from 'three/addons/controls/OrbitControls.js';import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';import { Randoms } from "https://gcore.jsdelivr.net/npm/@3r/tool/lib/randoms.js";let newModeDom = document.querySelector('.mode-switch-item.new')let delModeDom = document.querySelector('.mode-switch-item.del')let queModeDom = document.querySelector('.mode-switch-item.que')let cleModeDom = document.querySelector('.mode-switch-item.clear')let agaModeDom = document.querySelector('.mode-switch-item.again')let opeModeLis = [newModeDom, delModeDom, queModeDom, cleModeDom, agaModeDom]let cubeMap = {}; // 方块存储let maximumSize = 4;  // 新建底座 4 x 4 let cubeMaterial = null;  // 方块材质let mode = 'new' // new 新增 del 删除 que 答题 function removeActiveOpeMode() {opeModeLis.forEach(item =>item.classList.remove('active'))}newModeDom.addEventListener('click', () => {mode = 'new';removeActiveOpeMode()newModeDom.classList.add('active')cleModeDom.classList.add('active')refreshView()winHide()})delModeDom.addEventListener('click', () => {mode = 'del';removeActiveOpeMode()delModeDom.classList.add('active')cleModeDom.classList.add('active')refreshView()winHide()})queModeDom.addEventListener('click', () => {mode = 'que';removeActiveOpeMode()queModeDom.classList.add('active')agaModeDom.classList.add('active')agaModeDom.click()})cleModeDom.addEventListener('click', () => {if (cubeMap) {for (const cude of Object.values(cubeMap)) {scene.remove(cude)}cubeMap = {}refreshView()}})agaModeDom.addEventListener('click', () => {winHide()cleModeDom.click();randomMap()})// newModeDom.click()const scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);const renderer = new THREE.WebGLRenderer();scene.background = new THREE.Color(0x88ccee);camera.position.set(-10.5, 5, -10.5);renderer.shadowMap.enabled = true;renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);// 创建平行光const directionalLight = new THREE.DirectionalLight(0xffffff, 0.3);directionalLight.position.set(4, 4, -4)directionalLight.castShadow = true;scene.add(directionalLight);// 创建环境光源const ambientLight = new THREE.AmbientLight(0x404040); // 灰色的环境光scene.add(ambientLight);// 材质获取const textareaLoader = new THREE.TextureLoader();textareaLoader.load("./assets/cubeTexture.jpg", texture => {cubeMaterial = new THREE.MeshLambertMaterial({map: texture //材质的贴图为加载的图片});// 材质加载完成queModeDom.click();})// 模型加载const gltfLoader = new GLTFLoader().setPath('./assets/observing-objects/');gltfLoader.load('left.glb', (gltf) => {gltf.scene.position.x = 4.5;gltf.scene.position.y = 1.5;gltf.scene.position.z = -0.5;scene.add(gltf.scene);})gltfLoader.load('up.glb', (gltf) => {gltf.scene.position.x = 0.5;gltf.scene.position.y = 4.5;gltf.scene.position.z = -0.5;scene.add(gltf.scene);})gltfLoader.load('front.glb', (gltf) => {gltf.scene.position.x = 0.5;gltf.scene.position.y = 0;gltf.scene.position.z = -4.5;scene.add(gltf.scene);})// 平面预设for (let x = 0; x < maximumSize; x++) {for (let z = 0; z < maximumSize; z++) {console.log(x, z);const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x999999, side: THREE.DoubleSide });const plane = new THREE.Mesh(new THREE.BoxGeometry(1, .01, 1), planeMaterial);plane.position.x = x - maximumSize / 2;plane.position.z = z - maximumSize / 2;plane.name = `plane(${x},${z})`plane.receiveShadow = true;scene.add(plane);}}// <div class="front-view"></div>// <div class="top-view"></div>// <div class="left-view"></div>// 三视图预设let frontViewDom = document.querySelector('.front-view')let topViewDom = document.querySelector('.top-view')let leftViewDom = document.querySelector('.left-view')let viewDomLis = [frontViewDom, topViewDom, leftViewDom]// 创建视图方块function createViewCude(x, y) {let viewCudeDom = document.createElement('div')viewCudeDom.classList.add('view-cude')viewCudeDom.style.width = `${100 / maximumSize}%`viewCudeDom.style.height = `${100 / maximumSize}%`viewCudeDom.style.left = (x * 100 / maximumSize) + '%'viewCudeDom.style.top = (100 - y * 100 / maximumSize) + '%'viewCudeDom.setAttribute('x', x)viewCudeDom.setAttribute('y', y)viewCudeDom.addEventListener('click', function () {if (mode == 'que') {if (viewCudeDom.classList.contains('active')) {viewCudeDom.classList.remove("active")}else {viewCudeDom.classList.add("active")}checkQuestionIsRight()}})return viewCudeDom}for (let i = 0; i < maximumSize; i++) {for (let j = 0; j < maximumSize; j++) {frontViewDom.appendChild(createViewCude(j, i))topViewDom.appendChild(createViewCude(j, i))leftViewDom.appendChild(createViewCude(j, i))}}// 刷新视图function refreshView() {console.log(cubeMap);let cubeMapKeys = Object.keys(cubeMap)// 移除正确标签 viewDomLis.map(item => {item.classList.remove('right')})// 正视图for (let i = 0; i < frontViewDom.children.length; i++) {const viewCudeDom = frontViewDom.children.item(i);let tmpX = viewCudeDom.getAttribute('x')let tmpY = viewCudeDom.getAttribute('y')if (cubeMapKeys.find(key => key.startsWith(`${tmpX},${tmpY}`))) viewCudeDom.classList.add('active')else viewCudeDom.classList.remove('active')}// 顶视图for (let i = 0; i < topViewDom.children.length; i++) {const viewCudeDom = topViewDom.children.item(i);let tmpX = viewCudeDom.getAttribute('x')let tmpZ = viewCudeDom.getAttribute('y')if (cubeMapKeys.find(key => key.startsWith(`${tmpX}`) && key.endsWith(`${tmpZ}`))) viewCudeDom.classList.add('active')else viewCudeDom.classList.remove('active')}// 左视图for (let i = 0; i < leftViewDom.children.length; i++) {const viewCudeDom = leftViewDom.children.item(i);let tmpZ = maximumSize - 1 - +viewCudeDom.getAttribute('x')let tmpY = viewCudeDom.getAttribute('y')if (cubeMapKeys.find(key => key.endsWith(`${tmpY},${tmpZ}`))) viewCudeDom.classList.add('active')else viewCudeDom.classList.remove('active')}}let winDom = document.querySelector('.win-container')   // 胜利function winHide() {winDom.setAttribute('style', 'display:none')}function winShow() {winDom.setAttribute('style', 'display:flex')let winImgCount = winDom.children.lengthlet winImgShowIndex = Randoms.getRandomInt(0, winImgCount) // 随机高度 [)for (let i = 0; i < winImgCount; i++) {const winImg = winDom.children.item(i);winImg.setAttribute('style', winImgShowIndex == i ? 'display:flex' : 'display:none')}}// 控制器let controls = new OrbitControls(camera, renderer.domElement);controls.screenSpacePanning = true;controls.minDistance = 5;controls.maxDistance = 40;controls.target.set(0, 0, 0);controls.update();//获取鼠标坐标 处理点击某个模型的事件let mouse = new THREE.Vector2();let raycaster = new THREE.Raycaster();// 模型点击事件function onmodelclick(event) {if (event.type == 'touchstart') {let touch = event.changedTouches[0]mouse.x = (touch.clientX / window.innerWidth) * 2 - 1;mouse.y = -(touch.clientY / window.innerHeight) * 2 + 1;}else {mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;}raycaster.setFromCamera(mouse, camera);const intersects = raycaster.intersectObjects(scene.children);const lastObject = intersects.find(o =>o.object.name.startsWith('plane') ||o.object.name.startsWith('cube')) // 点击的物体是平面或者是立方体if (lastObject) { // 存在let lastObjectNormal = lastObject.normal // 点击的方向 let lastObjectPosition = lastObject.object.position // 物体的位置 let isPlane = lastObject.object.name.startsWith('plane'); // 是否点击的是平面if (mode == 'new') { // 是否是新增 let x = lastObjectNormal.x + lastObjectPosition.xlet y = lastObjectNormal.y + lastObjectPosition.y - (isPlane ? .5 : 0)let z = lastObjectNormal.z + lastObjectPosition.zlet checkCanPlaceRes = checkCanPlace(x, y, z)if (isRange(x, y, z) && checkCanPlaceRes) {x = checkCanPlaceRes.xy = checkCanPlaceRes.yz = checkCanPlaceRes.zcreateCube(x, y, z); // 新建物体 }else {console.log('不能添加');}refreshView()}else if (mode == 'del' && !isPlane) {let x = lastObjectPosition.xlet y = lastObjectPosition.ylet z = lastObjectPosition.zremoveUpperAndSelf(x, y, z)refreshView()}console.log('当前地图', Object.keys(cubeMap).map(v => {let [x, y, z] = v.split(',').map(p => +p)return { x, y, z }}));}}if (navigator.userAgent.includes('Android') || navigator.userAgent.includes('iPhone') || navigator.userAgent.includes('iPad')) {window.addEventListener("touchstart", onmodelclick)}else {window.addEventListener("click", onmodelclick);}// 是否在范围内function isRange(x, y, z) {let maxX = maximumSize / 2;let minX = -maximumSize / 2;let maxZ = maximumSize / 2;let minZ = -maximumSize / 2;let maxY = maximumSize;let minY = 0;if (y > maxY) return falseif (y < minY) return falseif (x >= maxX) return false;if (x < minX) return false;if (z >= maxZ) return false;if (z < minZ) return false;return true;}// 检查当前位置是否存在物体function checkPositionExist(key) {return cubeMap[key]}// 检测是否可以放置function checkCanPlace(x, y, z) {let standardKey = mapStandardKey(x, y, z)let standerdY = +standardKey.split(',')[1]for (let i = 0; i <= standerdY; i++) {if (!checkPositionExist(mapStandardKey(x, i, z))) {return {x,y: y - standerdY + i,z};}}return false}// 删除它上面的物体及自身function removeUpperAndSelf(x, y, z) {let standardKey = mapStandardKey(x, y, z)let standerdY = +standardKey.split(',')[1]for (let i = standerdY; i < maximumSize; i++) {let tmpStandardKey = mapStandardKey(x, i, z)let cube = checkPositionExist(tmpStandardKey)if (cube) {delete cubeMap[tmpStandardKey]scene.remove(cube)}}}// 坐标处理 便于存储function mapStandardKey(x, y, z) {y = Math.floor(y)x = x * -1 + maximumSize / 2 - 1;z = z + maximumSize / 2;return `${x},${y},${z}`}// 标准位置 用于3d展示function standardToScene(x, y, z) {y += .5x = x * -1 + maximumSize / 2 - 1;z = z - maximumSize / 2;return {x, y, z}}// 创建方块function createCube(x, y, z) {const geometry = new THREE.BoxGeometry(1, 1, 1);const material = cubeMaterial || new THREE.MeshStandardMaterial({ color: 0x00ff00 });const cube = new THREE.Mesh(geometry, material);cube.receiveShadow = truecube.castShadow = true;cube.position.x = xcube.position.y = ycube.position.z = zlet standardKey = mapStandardKey(x, y, z) // 获取x,y,z的标准cubeMap[standardKey] = cubecube.name = `cube(${x},${y},${z})`scene.add(cube)return cube}// 出一题function randomMap() {// 题库出题let questionList = [[{"x": 0,"y": 0,"z": 2},{"x": 1,"y": 0,"z": 2},{"x": 2,"y": 0,"z": 2},{"x": 3,"y": 0,"z": 2},{"x": 1,"y": 1,"z": 2}],[{"x": 1,"y": 0,"z": 2},{"x": 0,"y": 0,"z": 1},{"x": 1,"y": 0,"z": 1},{"x": 2,"y": 0,"z": 1},{"x": 1,"y": 1,"z": 1}],[{"x": 0,"y": 0,"z": 2},{"x": 1,"y": 0,"z": 2},{"x": 2,"y": 0,"z": 2},{"x": 0,"y": 1,"z": 2},{"x": 1,"y": 0,"z": 1}],[{"x": 0,"y": 0,"z": 3},{"x": 0,"y": 0,"z": 2},{"x": 0,"y": 0,"z": 1},{"x": 1,"y": 0,"z": 2},{"x": 1,"y": 0,"z": 3},{"x": 2,"y": 0,"z": 3},{"x": 0,"y": 1,"z": 3},{"x": 0,"y": 1,"z": 2},{"x": 0,"y": 2,"z": 3},{"x": 1,"y": 1,"z": 3}]]let queIndex = Randoms.getRandomInt(0, questionList.length)let que = questionList[queIndex]for (let i = 0; i < que.length; i++) {let { x, y, z } = que[i];createCube(...Object.values(standardToScene(x, y, z)))}// 随机出题// for (let i = 0; i < maximumSize; i++) {//     for (let j = 0; j < maximumSize; j++) {//         let h = Randoms.getRandomInt(0, maximumSize + 1) // 随机高度 [)//         console.log(h);//         for (let k = 0; k < h; k++) {//             let { x, y, z } = standardToScene(j, k, i) // 输出的坐标//             console.log(x, y, z);//             createCube(x, y, z)//         }//     }// }}// 检查问题是否正确function checkQuestionIsRight() {let cubeMapKeys = Object.keys(cubeMap)let frontViewIsRight = true;let topViewIsRight = truelet leftViewIsRight = true// 正视图for (let i = 0; i < frontViewDom.children.length; i++) {const viewCudeDom = frontViewDom.children.item(i);let tmpX = viewCudeDom.getAttribute('x')let tmpY = viewCudeDom.getAttribute('y')let active = viewCudeDom.classList.contains('active')let userActive = !!cubeMapKeys.find(key => key.startsWith(`${tmpX},${tmpY}`))console.log(tmpX, tmpY, active, userActive);if (active != userActive) {frontViewIsRight = false;break;}}// 顶视图for (let i = 0; i < topViewDom.children.length; i++) {const viewCudeDom = topViewDom.children.item(i);let tmpX = viewCudeDom.getAttribute('x')let tmpZ = viewCudeDom.getAttribute('y')let active = viewCudeDom.classList.contains('active')let userActive = !!cubeMapKeys.find(key => key.startsWith(`${tmpX}`) && key.endsWith(`${tmpZ}`))if (active != userActive) {topViewIsRight = false;break;}}// 左视图for (let i = 0; i < leftViewDom.children.length; i++) {const viewCudeDom = leftViewDom.children.item(i);let tmpZ = maximumSize - 1 - +viewCudeDom.getAttribute('x')let tmpY = viewCudeDom.getAttribute('y')let active = viewCudeDom.classList.contains('active')let userActive = !!cubeMapKeys.find(key => key.endsWith(`${tmpY},${tmpZ}`))if (active != userActive) {leftViewIsRight = false;break;}}if (frontViewIsRight) {frontViewDom.classList.add('right')}if (topViewIsRight) {topViewDom.classList.add('right')}if (leftViewIsRight) {leftViewDom.classList.add('right')}if (frontViewIsRight && topViewIsRight && leftViewIsRight) {winShow();}}// 渲染动画function animate() {renderer.render(scene, camera);requestAnimationFrame(animate);}animate();</script></body></html>

在线预览
https://linyisonger.github.io/H5.Examples/
源码仓库
https://github.com/linyisonger/H5.Examples.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/141418.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【代码随想录训练营第42期 续Day58打卡 - 图论Part8 - Dijkstra算法

目录 一、Dijkstra算法 实现方式 1、使用优先队列&#xff08;最小堆&#xff09; 2、朴素法&#xff08;简单数组&#xff09; 二、经典例题 题目&#xff1a;卡码网 47. 参加科学大会 题目链接 题解&#xff1a;朴素Dijkstra 三、小结 一、Dijkstra算法 刚入门Dijks…

AI论文写作测评!类似茅茅虫论文写作助手网站

在当前的学术研究和写作环境中&#xff0c;AI论文写作助手成为了许多学者和学生的重要工具。其中&#xff0c;千笔-AIPassPaper和茅茅虫论文写作助手是两款备受关注的平台。本文将对这两款工具进行详细测评&#xff0c;并推荐适合不同需求的用户使用。 千笔-AIPassPaper AI论文…

实现领域驱动设计(DDD)系列详解:限界上下文

随着微服务的兴起&#xff0c;限界上下文更是被拔高到战略设计的核心地位&#xff0c;也成了连接问题空间与解空间的重要桥梁&#xff0c;但不可否认&#xff0c;一方面&#xff0c;领域驱动设计社区纷纷发声强调它的重要性&#xff1b;另一方面&#xff0c;还有很多人依旧弄不…

游戏算法专题之PRD算法:听说你想凭运气抽中荣耀水晶?

PRD算法全称Pseudo-Random Distribution。是概率分布中的一种常见算法&#xff0c;在游戏开发领域中很常用。 PRD用于控制随机事件的触发概率&#xff0c;使其表现得更加符合预期&#xff0c;相比于传统得随机数生成&#xff0c;PRD算法可以平滑得控制随机事件的触发次数&…

计算机毕业设计 二手闲置交易系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

什么是快充协议,最常见的快充协议有哪些

什么是快充协议 随着手机快充的出现大家都知道快充技术但很多人确不知道快充协议&#xff0c;在快充技术里快充协议是必不可少的&#xff0c;那么今天我们就来探讨一下什么是快充协议&#xff1f; 快充协议是一种通过提高充电效率来缩短设备充电时间的电池充电技术。它通过在充…

主播和礼品检测系统源码分享

主播和礼品检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

约瑟夫环和一元多项式修正版

这里先附上上一篇博文的链接大家可以对比着看&#xff0c;错误已经改正https://blog.csdn.net/2302_78946488/article/details/141751514?spm1001.2014.3001.5501 约瑟夫环 以下是详细代码 //约瑟夫环 #include<stdio.h> #include<stdlib.h> //建立链表结点 str…

【Unity】 HTFramework框架(五十六)MarkdownText:支持运行时解析并显示Markdown文本

更新日期&#xff1a;2024年9月15日。 Github源码&#xff1a;[点我获取源码] Gitee源码&#xff1a;[点我获取源码] 索引 MarkdownText支持的Markdown语法标题强调文本表格嵌入图像超链接 使用MarkdownText设置项运行时属性解析使用ID模式嵌入图像 MarkdownText MarkdownText…

句子成分——每日一划(八)

目录 一、原句 二、第一部分 三、第二部分 一、原句 In class society everyone lives as a member of a particular class, and every kind of thinking, without exception, is stamped with the brand of a class. 来源&#xff1a;二、阶级和阶级斗争 二、第一部分 In…

QT添加图标标题和打包项目

QT项目打包 项目的标题和图标标题项目图标exe图标 可执行文件——生成exeexe运行报错“找不到qt6gui.dll”等 相关库文件——生成zip安装包打包程序——生成exe安装包 项目的标题和图标 项目打包要好看点&#xff0c;得有个好点的标题和图标&#xff0c;这次打包的项目是我上一…

图论篇--代码随想录算法训练营第五十八天打卡|拓扑排序,dijkstra(朴素版),dijkstra(堆优化版)精讲

拓扑排序 题目链接&#xff1a;117. 软件构建 题目描述&#xff1a; 某个大型软件项目的构建系统拥有 N 个文件&#xff0c;文件编号从 0 到 N - 1&#xff0c;在这些文件中&#xff0c;某些文件依赖于其他文件的内容&#xff0c;这意味着如果文件 A 依赖于文件 B&#xff0…

【移动端】菜单的自动展开与收回

前言 为了满足手机上菜单栏随用户移动&#xff0c;菜单的自动展示与隐藏&#xff0c;特此记录 基本原理 实现逻辑 window.addEventListener(‘scroll’, debouncedScrollHandler) – 监听文档视图滚动事件 document.querySelector(‘.header’) – 选择器匹配元素 创建show和h…

中断门+陷阱门

中断门&#xff1a; 中断描述符在IDT表里面 kd> dq idtr 80b95400 83e48e000008bfc0 83e48e000008c150 80b95410 0000850000580000 83e4ee000008c5c0 80b95420 83e4ee000008c748 83e48e000008c8a8 80b95430 83e48e000008ca1c 83e48e000008d018 80b95440 000085000050…

Tuxera NTFS for Mac 2023绿色版

​ 在数字化时代&#xff0c;数据的存储和传输变得至关重要。Mac用户经常需要在Windows NTFS格式的移动硬盘上进行读写操作&#xff0c;然而&#xff0c;由于MacOS系统默认不支持NTFS的写操作&#xff0c;这就需要我们寻找一款高效的读写软件。Tuxera NTFS for Mac 2023便是其中…

Redis入门2

在java中操作Redis Redis的Java客户端 Redis 的 Java 客户端很多&#xff0c;常用的几种: Jedis Lettuce Spring Data Redis Spring Data Redis 是 Spring 的一部分&#xff0c;对 Redis 底层开发包进行了高度封装。 在 Spring 项目中&#xff0c;可以使用Spring Data R…

DTU远程控制:空巢老人的智慧灌溉方案

我是老刘&#xff0c;大家经常这样唤我。在浙江省台州市下面的一个小乡村里&#xff0c;我经营着一家工厂。 说起台州&#xff0c;是个好地方&#xff0c;这里有一座天台山&#xff0c;就是“一座天台山&#xff0c;半步全唐诗”的那座山&#xff0c;山里有一个大瀑布&#xf…

计算机毕业设计 乡村生活垃圾管理系统的设计与实现 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

STM32(十四):USART串口数据包

HEX数据包 0xFF包头&#xff0c;0xFE包尾。 如果数据和包头包尾重复&#xff0c;可能会引起误判。 解决办法&#xff1a; 1. 限制载荷数据的范围 2. 如果无法避免载荷数据和包头包尾重复&#xff0c;就使用尽量使用固定长度数据包。 包头 ‘\r\n 包尾 在载荷数据中间可以出现…

用nginx-rtmp-win32-master及ffmpeg模拟rtmp视频流

效果 使用nginx-rtmp-win32-master搭建RTMP服务 双击exe就可以了。切记整个目录不能有中文 README.md ,启用后本地的RTM路径: rtmp://192.168.1.186/live/xxx ffmpeg将地本地视频推RMTP F:\rtsp\ffmpeg-7.0.2-essentials_build\bin>ffmpeg -re -i F:\rtsp\123.mp4 -c c…