2024-08-21

在WebGL或者Three.js中,我们可以使用各种方法来标注3D场景中的对象。这里我们将会介绍几种不同的方法,包括使用HTML标签、CSS3D对象以及使用2D标签覆盖3D场景。

方法一:使用HTML标签

HTML标签是最简单的方式来添加标注,但是它可能不适用于3D场景,因为HTML元素是2D的。




// 创建一个HTML元素
let label = document.createElement('div');
label.innerHTML = '这是一个标注';
label.style.position = 'absolute';
 
// 设置位置
label.style.left = '100px';
label.style.top = '50px';
 
// 将其添加到DOM中
document.body.appendChild(label);

方法二:使用CSS3D对象

Three.js提供了CSS3DRenderer,可以用来渲染CSS3D对象。




// 创建一个CSS3D对象
let label = document.createElement('div');
label.innerHTML = '这是一个标注';
label.style.position = 'absolute';
 
// 设置样式
label.style.webkitTransform = 'translateZ(50px)';
label.style.transform = 'translateZ(50px)';
 
// 将其添加到DOM中
document.body.appendChild(label);
 
// 创建CSS3DRenderer
let cssRenderer = new THREE.CSS3DRenderer();
cssRenderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(cssRenderer.domElement);
 
// 创建场景
let scene = new THREE.Scene();
 
// 创建相机
let camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
 
// 创建3D对象
let labelObject = new THREE.CSS3DObject(label);
labelObject.position.set(100, 50, 0);
scene.add(labelObject);
 
// 渲染
function render() {
    requestAnimationFrame(render);
    cssRenderer.render(scene, camera);
}
render();

方法三:使用2D标签覆盖3D场景

如果你需要在3D场景中添加标注,并且希望它们是3D的,你可以使用2D标签覆盖3D场景。




// 创建2D标签
let label = document.createElement('div');
label.innerHTML = '这是一个标注';
label.style.position = 'absolute';
 
// 设置样式
label.style.background = 'rgba(255,255,255,0.8)';
label.style.color = 'black';
label.style.padding = '5px';
 
// 将其添加到DOM中
document.body.appendChild(label);
 
// 创建WebGLRenderer
let renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
 
// 创建场景
let scene = new THREE.Scene();
 
// 创建相机
let camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
 
// 创建3D对象
let labelObject = new THREE.CSS3DObject(label);
labelObject.position.set(100, 50, 0);
scene.add(labelObject);
 
// 渲染
function render() {
    requestAnimationFrame(render);
    renderer.render(scene, camera);
}
render();

以上三种方法各有优缺点,你可以根据实际需求选择最适合你的方法。

2024-08-21

在JavaScript中实现常见的脱敏功能,可以通过自定义函数来进行。以下是实现手机号、邮箱、身份证号和姓名的简单脱敏方法:




// 手机号脱敏
function maskPhone(phone) {
  return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
}
 
// 邮箱脱敏
function maskEmail(email) {
  return email.replace(/\w(?=\w{1,14}@)[^\.]+/g, function(match) {
    return match.replace(/./g, '*');
  });
}
 
// 身份证号脱敏
function maskId(id) {
  return id.replace(/^(\d{6})\d{8}(\d{4})$/, '$1******$2');
}
 
// 姓名脱敏
function maskName(name) {
  if (name.length === 2) {
    return name.charAt(0) + '*';
  } else if (name.length > 2) {
    return name.charAt(0) + '*' + name.charAt(name.length - 1);
  } else {
    return name;
  }
}
 
// 示例
console.log(maskPhone('13812345678')); // 输出: 138****5678
console.log(maskEmail('user@example.com')); // 输出: ****@example.com
console.log(maskId('123456789012345678')); // 输出: 123456******5678
console.log(maskName('张三')); // 输出: 张*
console.log(maskName('L')); // 输出: L

这些函数分别实现了手机号、邮箱、身份证号和姓名的简单脱敏处理。具体的脱敏规则可以根据实际需求进行调整。例如,邮箱脱敏可以只替换中间部分,或者根据邮件服务商的不同进行特定的处理。

2024-08-21

在Node.js中,后缀为.js.mjs.cjs的文件都被视为JavaScript文件。它们之间的区别在于如何导入模块以及如何处理模块的语法。

  1. .js:这是Node.js中默认的文件扩展名,没有特殊配置时,无论是import还是require都可以正常使用。
  2. .mjs:这是ECMAScript模块的标准扩展名。在Node.js中,要使.mjs文件正常工作,需要在package.json中添加"type": "module"声明,或者在命令行启动Node.js时使用--experimental-modules标志。
  3. .cjs:这是Node.js中的CommonJS扩展名,它是Node.js原生支持的模块系统。

例子代码:




// profile.js (CommonJS模块)
module.exports = {
  name: 'Alice',
  age: 25
};
 
// main.js (CommonJS模块)
const profile = require('./profile.cjs');
console.log(profile);
 
// 或者使用ES模块导入
import profile from './profile.mjs';
console.log(profile);

在上述代码中,profile.js是一个CommonJS模块,它使用module.exports导出数据。在main.js中,我们使用require来导入CommonJS模块。对于profile.mjs,它是一个ECMAScript模块,它使用export关键字导出数据,并且需要在package.json中声明"type": "module"或使用--experimental-modules标志。

注意:在实际开发中,为了保持代码的兼容性和清晰性,通常会选择一种模块系统进行使用,而不是混合多种。

2024-08-21



// 引入Leaflet和Turf库
import L from 'leaflet';
import turf from '@turf/turf';
 
// 创建Leaflet地图
const map = L.map('map').setView([45.52829, -122.66108], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '© OpenStreetMap contributors'
}).addTo(map);
 
// 使用Turf.js生成多边形的函数
function generateBufferPolygon(centerPoint, radius, units) {
    // 创建中心点
    const center = turf.point(centerPoint);
 
    // 使用Turf.buffer生成多边形
    const options = { units: units, steps: 64 };
    const buffered = turf.buffer(center, radius, options);
 
    // 将生成的多边形添加到地图上
    L.geoJSON(buffered).addTo(map);
}
 
// 调用函数生成一个半径为5公里的多边形
generateBufferPolygon([45.52829, -122.66108], 5, 'kilometers');

这段代码首先引入了Leaflet和Turf库,并创建了一个Leaflet地图实例。然后定义了一个函数generateBufferPolygon,该函数接受中心点坐标、半径和单位作为参数,使用Turf.js的turf.pointturf.buffer函数生成多边形,并将其添加到地图上。最后调用这个函数,生成了一个半径为5公里的多边形。

2024-08-21

在uniapp中使用webview来引入Dplayer.js和hls.js以播放m3u8直播流视频,你需要做以下几步:

  1. 在uniapp项目中的页面(例如index.vue)中添加webview标签。
  2. 在webview中加载一个HTML页面,该页面引入了Dplayer.js和hls.js。
  3. 在HTML页面中初始化Dplayer并使用hls.js来处理m3u8流。

以下是一个简单的示例:




<!-- index.vue -->
<template>
  <view class="content">
    <web-view src="/path/to/your/video.html"></web-view>
  </view>
</template>

在你的项目目录中创建一个HTML文件(例如video.html),并添加以下内容:




<!-- video.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Video Player</title>
    <script src="https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/hls.js/dist/hls.min.js"></script>
</head>
<body>
<div id="dplayer"></div>
<script>
    if(Hls.isSupported()) {
        var hls = new Hls();
        hls.loadSource('https://your-m3u8-stream-url.m3u8');
        hls.attachMedia(document.getElementById('dplayer'));
        hls.on(Hls.Events.MANIFEST_PARSED, function() {
            hls.startLoad();
        });
    }
    else if (video.canPlayType('application/vnd.apple.mpegURL')) {
        video.src = 'https://your-m3u8-stream-url.m3u8';
        video.addEventListener('loadedmetadata', function() {
            video.play();
        });
    }
</script>
</body>
</html>

请确保替换your-m3u8-stream-url.m3u8为你的直播流地址。

注意:由于跨域限制,确保你的m3u8流和TS视频文件的服务器配置了CORS,否则可能会遇到播放问题。

在uniapp中使用webview时,请确保你的应用已经正确配置了webview权限,并且对应的页面在各个平台(如iOS和Android)上均已正确签名和打包。

2024-08-21

在浏览器中,JavaScript 和 CSS 的加载可能会阻塞 DOM 的渲染和解析。这是因为浏览器为了避免出现无样式内容的闪烁(FOUC - Flash of Unstyled Content)或无结构内容的空白屏,会在解析完 HTML 之后,立即渲染出 DOM,然后才执行 CSS 和 JavaScript 的下载及执行。

解决这个问题的关键是减少 JavaScript 和 CSS 文件的体积,使用异步加载(例如通过动态创建 <script><link> 标签),并且将它们放在文档的底部,接近 </body> 标签处。

以下是一个简单的示例,展示了如何将 CSS 和 JavaScript 文件置于底部加载:




<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 样式表置于头部但设置为异步加载 -->
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <!-- 页面内容 -->
    <div>
        <h1>Hello World</h1>
    </div>
 
    <!-- JavaScript 文件置于底部 -->
    <script src="script.js" async></script>
</body>
</html>

在这个例子中,CSS 文件会阻塞 DOM 的渲染,但不会阻塞 JavaScript 的加载,因为我们使用了 async 属性。JavaScript 文件置于页面底部,不会阻塞 DOM 的解析,而且它会在文档加载完成后执行。这样可以提升页面的渲染性能。

2024-08-21

在JavaScript中,可以使用内置的Date对象来进行时间戳和普通日期(年月日)的互相转换。

时间戳转普通日期:




// 假设 timestamp 是一个时间戳(单位:毫秒)
var timestamp = 1609459200000; // 例如:2021-01-01 00:00:00
var date = new Date(timestamp);
var year = date.getFullYear();
var month = date.getMonth() + 1; // 月份是从0开始的
var day = date.getDate();
 
console.log(year, month, day); // 输出:2021 1 1

普通日期转时间戳:




// 假设 year, month, day 分别是年、月、日
var year = 2021;
var month = 1; // 实际月份应该是0-11的数字,1代表1月
var day = 1;
 
// 创建Date对象
var date = new Date(year, month - 1, day); // 注意月份是从0开始的
 
// 获取时间戳
var timestamp = date.getTime(); // 或者使用 date.valueOf() 或者 date.getTime()
 
console.log(timestamp); // 输出:1609459200000

请注意,在JavaScript中,月份是从0开始的,即0代表1月,11代表12月。因此在将年月日转换为Date对象时,月份应该减去1。而从Date对象获取月份时,应该加上1来获取正确的月份值。

2024-08-21

在Node.js中,实现方法的返回值可以通过多种方式,以下是一些常见的方式:

  1. 使用return语句返回值:



function add(a, b) {
  return a + b;
}
console.log(add(5, 3)); // 输出: 8
  1. 使用回调函数处理异步操作:



function fetchData(callback) {
  // 假设这是一个异步操作,如读取文件
  fs.readFile('data.txt', 'utf8', (err, data) => {
    if (err) {
      callback(err, null);
    } else {
      callback(null, data);
    }
  });
}
 
fetchData((err, result) => {
  if (err) {
    console.error('Error fetching data:', err);
  } else {
    console.log('Data:', result);
  }
});
  1. 使用Promise处理异步操作:



function getData() {
  return new Promise((resolve, reject) => {
    fs.readFile('data.txt', 'utf8', (err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
}
 
getData().then(data => {
  console.log('Data:', data);
}).catch(err => {
  console.error('Error fetching data:', err);
});
  1. 使用async/await简化Promise:



async function getData() {
  try {
    const data = await fs.promises.readFile('data.txt', 'utf8');
    return data;
  } catch (err) {
    console.error('Error fetching data:', err);
    throw err;
  }
}
 
(async () => {
  try {
    const result = await getData();
    console.log('Data:', result);
  } catch (err) {
    // 错误处理
  }
})();

以上代码展示了在Node.js中实现方法返回值的常见方式。开发者可以根据实际场景选择合适的方法。

2024-08-21

要在JavaScript中引入jQuery实现数字滚动效果,你可以使用animate方法结合Number原生JavaScript对象的toFixed方法来创建这种效果。以下是一个简单的例子:

HTML部分:




<div id="number">0</div>

CSS部分:




#number {
  font-size: 24px;
  font-weight: bold;
}

JavaScript部分(确保在引入jQuery之后执行):




$(document).ready(function(){
  var targetNumber = 1234.56; // 设置目标数字
  var currentNumber = 0; // 初始数字
 
  function animateValue(target) {
    // 每次调用该函数,当前数字会接近目标数字
    var animationSpeed = 500; // 动画持续时间(毫秒)
    var increment = target / (animationSpeed / 10); // 计算每次增加的量
 
    if (currentNumber < target) {
      currentNumber = Math.min(target, currentNumber + increment);
      $('#number').text(currentNumber.toFixed(2)); // 保留两位小数
    }
 
    if (currentNumber !== target) {
      setTimeout(function() {
        animateValue(target);
      }, 10);
    }
  }
 
  animateValue(targetNumber); // 开始动画
});

确保在HTML中引入了jQuery库:




<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

这段代码会在页面加载完成后,将元素#number中的文本从0滚动到1234.56,并保留两位小数。你可以根据需要调整targetNumber的值来设置不同的目标数字。

2024-08-21

await-to-js 是一个小型的库,它提供了一个实用的函数 to,用于简化异步函数中的错误处理。以下是如何使用 await-to-js 来优雅处理异步函数中的错误:

首先,安装 await-to-js




npm install await-to-js

然后,在你的代码中引入 to 函数并使用它:




const to = require('await-to-js');
 
async function fetchUserData() {
    let err, userData;
    [err, userData] = await to(async () => {
        const response = await fetch('https://api.example.com/user');
        return response.json();
    });
 
    if (err) {
        // 处理错误
        console.log('Error fetching user data:', err);
        return;
    }
 
    // 继续使用 userData
    console.log('User data:', userData);
}
 
fetchUserData();

在这个例子中,to 函数接收一个异步函数作为参数,并返回一个数组,数组的第一个元素是捕获到的错误(如果有的话),第二个元素是异步操作的结果。通过检查第一个元素是否有值,你可以轻松地处理错误情况。