前端基础避坑:3 个实用知识点的简单用法

前端基础避坑:3 个实用知识点的简单用法

做前端这些年,发现不少问题不是框架难,是基础没玩明白 ------ 比如知道事件委托,却搞不定动态元素点击;用 localStorage 存对象,取出来成了[object Object]。今天说几个自己踩过的坑,都是日常能用的,不绕虚的。

1. 事件委托:别再给每个列表项绑事件

刚入行写 Todo 列表,我会循环给每个 item 加 click 事件,结果产品加了 "动态加任务" 功能,新任务点了没反应。后来才懂,事件委托得找对父容器,还得处理子元素的情况。

小白常写错的

js 复制代码
// 错1:只给现有item绑事件,动态加的没用
const todoItems = document.querySelectorAll(".todo-item");
todoItems.forEach((item) => {
  item.onclick = () => item.classList.toggle("done");
});

// 错2:绑到body上,冒泡太远,可能出问题
document.body.onclick = (e) => {
  if (e.target.classList.has("todo-item")) {
    e.target.classList.toggle("done");
  }
};

正确的做法

找 "不会动的父容器"(比如.todo-list),再用closest找真正的 item(防止点到 item 里的子元素,比如删除按钮):

js 复制代码
const todoList = document.querySelector(".todo-list");
todoList.onclick = (e) => {
  // 找到最近的.todo-item,不管点的是item还是它的子元素
  const targetItem = e.target.closest(".todo-item");
  if (!targetItem) return; // 不是目标就退出
  // 区分点的是删除按钮还是任务本身
  const delBtn = e.target.closest(".todo-del");
  if (delBtn) {
    targetItem.remove();
    return;
  }
  targetItem.classList.toggle("done");
};

小提醒

别把事件绑到bodyhtml上,找最近的固定父容器就行,省得浪费性能。

2. localStorage:别直接存对象!简单封装下

很多人存对象直接写localStorage.setItem('user', userInfo),取的时候傻了 ------localStorage 只能存字符串。还有个问题,它没过期时间,存的 token 过期了还在,容易出 bug。 分享 3 个常用的封装函数,解决这些问题:

1. 基础版:能存对象 / 数组

js 复制代码
const storage = {
  // 存数据:对象转成JSON字符串
  set(key, value) {
    try {
      const str = typeof value === "object" ? JSON.stringify(value) : value;
      localStorage.setItem(key, str);
    } catch (e) {
      console.error("存不进去:", e);
    }
  },

  // 取数据:JSON字符串转回来
  get(key) {
    try {
      const val = localStorage.getItem(key);
      return val ? JSON.parse(val) : null;
    } catch (e) {
      // 不是JSON就直接返回原字符串
      return localStorage.getItem(key);
    }
  },

  // 删除数据
  remove(key) {
    localStorage.removeItem(key);
  },
};

// 用的时候这样写
storage.set("user", { name: "张三", age: 28 });
const user = storage.get("user"); // 能拿到完整对象

2. 进阶版:带过期时间

比如存 token,想让它 2 小时后过期:

js 复制代码
// 存的时候加过期时间(单位:分钟)
storage.setWithExpire = (key, value, expireMin) => {
  const data = {
    value: value,
    expire: Date.now() + expireMin * 60 * 1000, // 过期时间戳
  };
  this.set(key, data);
};

// 取的时候判断是否过期

storage.getWithExpire = (key) => {
  const data = this.get(key);
  if (!data) return null;
  if (Date.now() > data.expire) {
    this.remove(key); // 过期了就删掉
    return null;
  }
  return data.value;
};

// 示例:存token,2小时过期
storage.setWithExpire("token", "abc123", 120);

小提醒

  • 别存太大的东西,localStorage 就 5MB,满了会报错;
  • 密码之类的敏感数据别存在这,用sessionStorage或者httpOnly Cookie

3. CSS 优先级:别乱加!important!记个简单算法

新手调样式常遇到 "写了不生效",然后就加!important,最后样式乱成一团。其实算清楚优先级,不用!important也能搞定。

简单算法:算三个数

按 "ID 个数(1 个算 100)、类 / 伪类个数(1 个算 10)、元素个数(1 个算 1)" 加起来,数大的生效:

  • 内联样式(style属性):1000(最高)
  • #box(ID):100
  • .red:hover(类 / 伪类):10
  • div:before(元素 / 伪元素):1

举几个例子:

  • div.box → 1(元素)+10(类)=11
  • #app .list li → 100(ID)+10(类)+1(元素)=111
  • <div style="color: red"> → 1000

实际场景:改组件库样式

比如用 Element UI 的按钮,写.el-button { color: blue }不生效 ------ 因为组件库的样式是.el-button--primary { color: white }(优先级 10),和你的一样,谁后加载谁生效。 想覆盖的话,提高优先级就行:

css 复制代码
/* 父容器类 + 目标类 → 10+10=20,比10高 */
.app .el-button--primary {
  color: blue;
}

什么时候能加!important?

只有一种情况:要覆盖内联样式,还改不了 HTML(比如第三方组件)。比如:

html 复制代码
<!-- 第三方组件的内联样式 -->
<div class="third-box" style="width: 200px;"></div>

这时才能用:

css 复制代码
.third-box {
  width: 300px !important;
}

记住:加了!important,以后改这个样式也得加,能不用就不用。

最后:基础不是会了就行,是用对

框架更新快,但 DOM、存储、CSS 这些基础不变。我之前因为事件委托没处理好,查了半小时才发现动态元素没反应;也因为 localStorage 没加过期时间,导致用户看了过期数据 ------ 这些坑都不是不会,是没吃透。

要是觉得这些有用,项目里试试;你们踩过哪些基础坑,也可以聊聊~

相关推荐
journs2 小时前
micro-app微前端styled-components CSSOM模式 应用切换样式丢失问题
前端
呼啦啦小魔仙2 小时前
elpis项目DSL设计分享
前端
李李记2 小时前
别让 “断字” 毁了 Canvas 界面!splitByGrapheme 轻松搞定非拉丁文本换行
前端·canvas
来金德瑞2 小时前
快速掌握 ProseMirror 的核心概念
前端
ygria2 小时前
样式工程化:如何实现Design System
前端·前端框架·前端工程化
墨渊君3 小时前
“蒙”出花样!用 CSS Mask 实现丝滑视觉魔法
前端·css
huabuyu4 小时前
基于 React + MarkdownIt 的 Markdown 渲染器实践:支持地图标签和长按复制
前端
芦苇Z4 小时前
HTML <a> 标签的 rel 属性全解析:安全、隐私与 SEO 最佳实践
前端·html
在这儿不行4 小时前
Android 15边到边模式
前端