JS 判断空值排除 0 与 Canvas 滚轮缩放图片实现

JS 判断空值但 0 不算空

直接用 !value 的问题:

if (!value) { ... }
// 会把 0、false、NaN、''、null、undefined 全算空
// 经常误伤数字 0

正确写法 —— 只排除 nullundefined、空字符串:

if (value == null || value === '') {
  // 空值
}

value == null 会同时匹配 nullundefined(宽松相等),不会匹配 0false

封装函数

function isEmpty(value) {
  return value == null || value === '';
}

isEmpty(null)       // true
isEmpty(undefined)  // true
isEmpty('')         // true

isEmpty(0)          // false
isEmpty(false)      // false
isEmpty([])         // false
isEmpty({})         // false

同时排除全空格字符串

function isEmpty(value) {
  return value == null ||
         (typeof value === 'string' && value.trim() === '');
}

isEmpty('   ')  // true
isEmpty(' a ')  // false

Canvas 滚轮缩放图片

核心思路:记录 scale(缩放比)和 offsetX/Y(画布偏移量),每次绘制时先平移再缩放。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<style>
  html, body { margin: 0; height: 100%; overflow: hidden; background: #111; }
  canvas { display: block; width: 100vw; height: 100vh; cursor: grab; }
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const img = new Image();
img.src = "https://picsum.photos/1200/800";

let scale = 1;
let offsetX = 0;
let offsetY = 0;

img.onload = () => draw();

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.save();
  ctx.translate(offsetX, offsetY);
  ctx.scale(scale, scale);
  ctx.drawImage(img, 0, 0);
  ctx.restore();
}

// 滚轮缩放
canvas.addEventListener("wheel", (e) => {
  e.preventDefault();

  const mouseX = e.offsetX;
  const mouseY = e.offsetY;

  // 鼠标在图片坐标系中的位置(缩放前)
  const x = (mouseX - offsetX) / scale;
  const y = (mouseY - offsetY) / scale;

  const zoom = e.deltaY < 0 ? 1.1 : 0.9;
  scale *= zoom;
  scale = Math.max(0.1, Math.min(scale, 20));  // 限制范围

  // 缩放后修正偏移,保证鼠标所在点不漂移
  offsetX = mouseX - x * scale;
  offsetY = mouseY - y * scale;

  draw();
}, { passive: false });

// 拖拽移动
let dragging = false;
let lastX = 0, lastY = 0;

canvas.addEventListener("mousedown", (e) => {
  dragging = true;
  lastX = e.clientX;
  lastY = e.clientY;
  canvas.style.cursor = "grabbing";
});

window.addEventListener("mousemove", (e) => {
  if (!dragging) return;
  offsetX += e.clientX - lastX;
  offsetY += e.clientY - lastY;
  lastX = e.clientX;
  lastY = e.clientY;
  draw();
});

window.addEventListener("mouseup", () => {
  dragging = false;
  canvas.style.cursor = "grab";
});

window.addEventListener("resize", () => {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  draw();
});
</script>
</body>
</html>

鼠标中心缩放原理

缩放时要保持鼠标位置不变,关键公式:

// 缩放前:鼠标在图片坐标系的位置
x = (mouseX - offsetX) / scale

// 缩放后:offsetX 要满足 mouseX = x * newScale + newOffsetX
newOffsetX = mouseX - x * newScale

即先算出鼠标对应图片上的点坐标,缩放后重新反算偏移量。不做这一步,图片会向左上角方向漂移。

{ passive: false } 的作用

wheel 事件的 e.preventDefault() 阻止页面滚动,必须在监听器选项里显式传 { passive: false },否则浏览器忽略 preventDefault() 并输出警告。