Javascript·深入学习基础知识

代码源码

javascript 复制代码
// 保存截止日期(从输入框)
function saveDeadlineFromInput(phone, inputId) {
    const deadline = document.getElementById(inputId).value;
    console.log('saveDeadlineFromInput', phone, deadline);
    
    // 更新该客户最新订单的截止日期
    customerMarkers.forEach(marker => {
        const customer = marker.customerData;
        if (customer && customer.customer_phone === phone && customer.orders.length > 0) {
            const latestOrder = customer.orders[0];
            updateOrderDeadline(latestOrder.id, deadline || null)
                .then(() => {
                    latestOrder.followup_deadline = deadline || null;
                    showToast(deadline ? '截止日期已设置!' : '截止日期已清除!', '📅');
                    // 刷新标记点
                    addCustomerMarkers();
                })
                .catch(e => {
                    showToast('设置失败: ' + e.message, '❌');
                });
        }
    });
}

这段代码的逻辑很清晰,是一个典型的**"前端交互 -> 本地数据更新 -> 后端同步 -> UI 刷新"**的流程。

不过,我在代码里发现了一个潜在的逻辑隐患 ,特别是在处理 customerMarkers 遍历的时候。

🔍 代码分析与优化建议

1. 潜在的 Bug:遍历中修改集合

你正在使用 forEach 遍历 customerMarkers 数组。如果在 addCustomerMarkers() 函数内部(或者它调用的逻辑中)会先清空 customerMarkers 再重新添加,虽然 forEach 通常能跑完,但这是一种不安全的模式。

更安全的做法:

找到目标客户后,直接 break 跳出循环(因为手机号通常是唯一的),或者改用 find 方法。

2. 优化建议:使用 find 代替 forEach

既然你是通过 phone 查找唯一的客户,使用 Array.find() 语义更清晰,且找到后直接操作,避免了不必要的遍历。

3. 优化后的代码
javascript 复制代码
// 保存截止日期(从输入框)
function saveDeadlineFromInput(phone, inputId) {
    const deadlineInput = document.getElementById(inputId);
    const deadline = deadlineInput ? deadlineInput.value : ''; // 增加空值检查
    console.log('saveDeadlineFromInput', phone, deadline);

    // 1. 查找目标客户标记
    const targetMarker = customerMarkers.find(marker => {
        const customer = marker.customerData;
        return customer && customer.customer_phone === phone && customer.orders.length > 0;
    });

    if (!targetMarker) {
        showToast('未找到该客户或无订单数据', '⚠️');
        return;
    }

    const customer = targetMarker.customerData;
    const latestOrder = customer.orders[0]; // 假设 orders 已按时间排序

    // 2. 乐观更新 UI (可选:为了让界面反应更快,可以先改本地数据)
    // 注意:如果后端更新失败,这里需要回滚,或者等成功后再改
    // 这里我们保持你的逻辑:等后端成功后再更新本地数据

    // 3. 调用后端更新
    updateOrderDeadline(latestOrder.id, deadline || null)
        .then(() => {
            // 4. 更新本地缓存数据
            latestOrder.followup_deadline = deadline || null;
            
            // 5. 提示用户
            showToast(deadline ? '截止日期已设置!' : '截止日期已清除!', '📅');
            
            // 6. 刷新地图标记
            // 建议:如果 addCustomerMarkers 会清空数组,确保逻辑安全
            addCustomerMarkers(); 
        })
        .catch(e => {
            console.error(e);
            showToast('设置失败: ' + e.message, '❌');
        });
}

💡 关键点解释

  1. Array.find() vs forEach:

    • find 会在找到第一个匹配项后立即停止遍历,性能稍好,且代码意图更明确(我们在找一个特定的客户)。
    • 避免了在遍历过程中如果发生数组变动可能产生的副作用。
  2. latestOrder 的索引:

    • 代码中使用了 customer.orders[0]。这隐含了一个前提:orders 数组必须是已经按时间倒序排列的(最新的在最前面)。如果后端返回的数据未排序,这里可能会更新错误的订单。
  3. 空值处理:

    • 增加了 deadlineInput 的存在性检查,防止因 ID 错误导致 getElementById 返回 null 从而报错。
  4. UX 体验:

    • 目前的逻辑是**"先请求后端,成功后再刷新 UI"** 。这是一种稳健的做法,保证了数据一致性。如果网络很慢,用户点击后可能感觉没反应,可以考虑在 updateOrderDeadline 调用前加一个"加载中"的状态。

作为 JavaScript 新手,理解这段代码的逻辑非常重要。这段代码主要是在处理**"用户输入 -> 数据更新 -> 界面反馈"**这一整套流程。

为了让你更清楚地理解,我把代码拆解成 5 个关键步骤,逐行详细解析。

📦 1. 函数定义与获取输入

javascript 复制代码
// 保存截止日期(从输入框)
function saveDeadlineFromInput(phone, inputId) {
    const deadline = document.getElementById(inputId).value;
    console.log('saveDeadlineFromInput', phone, deadline);
  • function saveDeadlineFromInput(phone, inputId) :
    • 定义了一个函数,名字叫做 saveDeadlineFromInput
    • 它接收两个参数 (相当于函数的"食材"):
      • phone: 客户的电话号码,用来查找是谁的订单。
      • inputId: 网页上那个输入框的 ID,用来获取用户输入的时间。
  • document.getElementById(inputId).value :
    • document.getElementById(...): 这是浏览器提供的"魔法",用来在网页上抓取一个元素。
    • .value: 获取那个输入框里用户填写的文字
  • console.log(...) :
    • 这是一个调试工具。它会在浏览器的"控制台"里打印信息。如果代码没按预期运行,程序员通常会先看这里,确认拿到的数据对不对。

🔍 2. 查找目标客户

javascript 复制代码
    // 更新该客户最新订单的截止日期
    customerMarkers.forEach(marker => {
        const customer = marker.customerData;
        if (customer && customer.customer_phone === phone && customer.orders.length > 0) {
  • customerMarkers :
    • 这是一个数组(列表),里面存了地图上所有客户标记点的数据。
  • .forEach(marker => { ... }) :
    • 这是一个循环指令。意思是:"把 customerMarkers 里的东西一个接一个 拿出来,每个东西都叫 marker,然后对每个 marker 执行大括号里的代码"。
  • if (customer && ...) :
    • 这是一个过滤器 。我们在循环中必须确认三件事,只有全对才执行后续操作:
      1. customer: 这个标记点确实有客户数据(防止报错)。
      2. customer.customer_phone === phone: 这个客户的电话 等于 我们传入的 phone 参数(确认没找错人)。
      3. customer.orders.length > 0: 这个客户必须有订单(数组长度大于 0),不然没法更新订单。

📝 3. 准备数据

javascript 复制代码
            const latestOrder = customer.orders[0];
  • customer.orders[0] :
    • orders 是一个订单列表(数组)。
    • [0] 表示取第一个
    • 隐含逻辑 :这里假设订单列表已经是按时间排序 的,最新的订单排在第一位。所以 orders[0] 就是"最新订单"。

🌐 4. 发送请求与异步处理

javascript 复制代码
            updateOrderDeadline(latestOrder.id, deadline || null)
                .then(() => {
                    // ...成功后的代码...
                })
                .catch(e => {
                    // ...失败后的代码...
                });

这是新手最难理解的部分,叫做异步编程

  • updateOrderDeadline(...) :
    • 这是一个函数,它的工作是联系服务器(后端数据库),告诉服务器:"把这个订单的截止日期改掉"。
    • 因为联系服务器需要时间(比如 1 秒钟),JavaScript 不会傻等,而是继续往下跑。
  • .then(() => { ... }) :
    • 意思是:"如果 联系服务器成功了,就执行这里的代码"。
  • .catch(e => { ... }) :
    • 意思是:"如果 联系服务器失败了(比如断网了),就执行这里的代码"。
  • deadline || null :
    • 这是一个简写技巧。意思是:如果 deadline 有值,就用它;如果 deadline 是空的,就传 null(空值)给服务器,表示"清除日期"。

🔄 5. 成功后的回调(更新界面)

javascript 复制代码
                .then(() => {
                    latestOrder.followup_deadline = deadline || null;
                    showToast(deadline ? '截止日期已设置!' : '截止日期已清除!', '📅');
                    // 刷新标记点
                    addCustomerMarkers();
                })
  • latestOrder.followup_deadline = ... :
    • 服务器说"改好了",我们再把本地内存里的数据也改一下,保持同步。
  • showToast(...) :
    • 这是一个自定义函数,用来在屏幕上弹出一个像"吐司面包"一样的小提示框,告诉用户操作成功了。
    • deadline ? 'A' : 'B':这是三元表达式。意思是:如果有截止日期,显示"已设置";否则显示"已清除"。
  • addCustomerMarkers() :
    • 重新运行一遍绘制地图的函数。这通常会把地图上的标记点清除,然后根据新数据重新画一遍,这样用户就能立刻看到地图上的日期变了。

📌 总结:这段代码在做什么?

想象你在餐厅当服务员:

  1. 获取输入 :你听到客人(phone)说要把某个菜的忌口改掉(deadline)。
  2. 查找 :你跑到后厨,在一堆订单纸(customerMarkers)里翻找,找到那个客人的单子。
  3. 联系服务器 :你拿着单子去告诉厨师长(updateOrderDeadline,即服务器)。
  4. .then (成功) :厨师长说"改好了"。于是你在你的小本本上也把忌口改了(更新本地数据),然后大声告诉客人"改好了!"(showToast),并把桌上的菜单更新一下(addCustomerMarkers)。
  5. .catch (失败):如果厨师长说"单子丢了",你就告诉客人"不好意思改不了"(报错提示)

基础学习

1 对象抓取

document.getElementById

document.getElementById(inputId).value: document.getElementById(...): 这是浏览器提供的"魔法",用来在网页上抓取一个元素。

请说明一下 这个魔法 是如何在网页上抓取这个元素的 这个元素是 javascript的一个对象吗?

这真是一个直击灵魂的好问题!很多新手(甚至老手)只是机械地敲代码,却很少停下来思考这背后的原理。

简单直接的回答是:是的,它绝对是一个 JavaScript 对象。

为了让你彻底理解这个"魔法"是如何运作的,我们需要把浏览器想象成一个巨大的**"图书馆"** ,而网页代码(HTML)就是书架上的**"书"**。


🪄 魔法第一步:浏览器是如何"抓取"元素的?

当你打开一个网页时,浏览器并不是像看一张图片那样看网页的。它会做一件非常重要的事情:解析(Parsing)

1. 构建"族谱"(DOM 树)

浏览器读取你的 HTML 代码(那些 <div>, <input>, <body> 标签),然后在内存中把它们整理成一棵家族树 。这棵树在技术上被称为 DOM

想象一下,你的网页结构是这样的:

javascript 复制代码
<body>
  <div id="app">
    <input id="username" value="Alice">
  </div>
</body>

浏览器会在内存里画出一张这样的关系图(树状结构):

  • 根节点 : document (整个文档)
    • 子节点 : <body>
      • 子节点 : <div id="app">
        • 子节点 : <input id="username">
2. 建立"索引"(哈希表)

为了让你能通过 ID 瞬间找到元素,浏览器非常聪明。它在内部维护了一个类似字典索引的东西。

当你调用 document.getElementById('username') 时,浏览器并没有从树的根部开始一个一个数("是它吗?不是。是它吗?不是..."),那样太慢了。

相反,它直接查字典:

"我要找 ID 为 username 的家伙?哦,查表得知,它在内存地址 0x12345。"

这就是为什么这个"魔法"速度非常快,它是O(1) 的查找复杂度(瞬间找到)。


📦 魔法第二步:抓到的东西是对象吗?

绝对是。

当你执行 const element = document.getElementById('username') 时,变量 element 里装的不是那个 HTML 标签的字符串(比如 "<input ...>"),而是一个复杂的 JavaScript 对象

这个对象里装满了各种属性、方法和状态。你可以把它想象成一个**"遥控器"**,通过这个遥控器,你可以控制网页上那个真实的显示画面。

这个对象长什么样?(揭秘)

如果你在控制台打印这个对象,你会发现它极其庞大。它大致长这样(简化版):

javascript 复制代码
HTMLInputElement {
  // --- 核心属性 ---
  id: "username",
  tagName: "INPUT",
  className: "",
  
  // --- 你刚才用到的属性 ---
  value: "Alice",        // 获取或设置输入框里的文字
  
  // --- 样式控制 ---
  style: CSSStyleDeclaration { ... }, // 用来控制颜色、大小等
  
  // --- 事件监听 ---
  onclick: null,
  addEventListener: function(...), // 用来绑定点击事件
  
  // --- 位置信息 ---
  offsetLeft: 100,
  offsetTop: 50,
  
  // --- 内部指针 (浏览器内部使用) ---
  // [Native Pointer to the underlying C++ implementation]
}

关键点来了:

这个对象是**"活"**的。

  • 当你修改 element.value = "Bob" 时,浏览器会立刻检测到这个对象的属性变了,然后自动去更新屏幕上的画面,让你看到输入框里的字变成了 "Bob"。
  • 当你在输入框里打字时,浏览器会自动更新这个对象的 value 属性。

🧩 为什么理解它是"对象"很重要?

理解了这一点,你就明白了为什么你可以这样写代码:

  1. 点语法访问 :因为它是对象,所以你可以用 .value.id.style 来访问它的内部数据。
  2. 函数调用 :因为它是对象,所以它身上挂载了函数(方法),比如 element.focus()(让输入框获得光标)。
  3. 引用传递 :当你把这个对象传给另一个函数时,你传的是它的引用(遥控器)。如果在那个函数里修改了对象,原来的元素也会跟着变。

📌 总结

document.getElementById 这个"魔法"的本质是:

  1. 浏览器把 HTML 代码翻译成了内存中的树状对象结构(DOM)。
  2. 浏览器维护了一张ID 索引表
  3. 当你调用该方法时,浏览器查表,把对应的DOM 对象(那个遥控器)交到了你手里。

所以,你操作的不是"网页上的画面",而是画面背后的数据模型(对象),浏览器负责帮你把对象的变化同步到画面上。

还有哪些获取元素的方法?

除了 getElementById,JavaScript 还提供了多种获取 DOM 元素的方法,它们各有侧重,适用于不同的场景。

总的来说,可以分为两大类:

  1. 传统方法 :按标签名、类名或 name 属性来获取。
  2. 现代方法:使用 CSS 选择器来获取,功能最强大、最灵活。

下面是这些方法的详细介绍和对比。

🎯 按标签名获取:getElementsByTagName

这个方法用于获取网页中所有指定标签的元素,比如获取所有的 <p> 段落或 <div> 容器。

  • 语法document.getElementsByTagName('标签名')
  • 返回值 :一个实时HTMLCollection(类似数组的集合)。
    • "实时"是什么意思? 这意味着如果之后网页中增加或删除了符合条件的元素,这个集合会自动更新,你不需要重新调用该方法。
  • 示例
javascript 复制代码
// 获取网页中所有的段落 <p>
const paragraphs = document.getElementsByTagName('p');
console.log(`共有 ${paragraphs.length} 个段落`);
// 修改第一个段落的内容
paragraphs[0].textContent = '这是修改后的第一个段落。';

🏷️ 按类名获取:getElementsByClassName

这个方法用于获取所有具有指定 class 属性的元素。

  • 语法document.getElementsByClassName('类名')
  • 返回值 :同样是一个实时HTMLCollection
  • 示例
javascript 复制代码
// 获取所有 class 为 "item" 的元素
const items = document.getElementsByClassName('item');
// 遍历并给每个元素添加一个边框
for (let i = 0; i < items.length; i++) {
    items[i].style.border = '1px solid red';
}

📝 按 name 属性获取:getElementsByName

这个方法主要用于获取表单元素,因为 name 属性在表单数据提交时非常重要。

  • 语法document.getElementsByName('name属性值')
  • 返回值 :一个实时NodeList(节点列表)。
  • 示例
html 复制代码
<input type="radio" name="gender" value="male"> 男
<input type="radio" name="gender" value="female"> 女
javascript 复制代码
// 获取所有 name 为 "gender" 的单选按钮
const genders = document.getElementsByName('gender');

✨ 现代选择器:querySelectorquerySelectorAll

这是目前最推荐、最灵活的方法,因为它允许你使用任何 CSS 选择器来查找元素,功能极其强大。

querySelector
  • 作用 :返回第一个匹配指定 CSS 选择器的元素。
  • 语法document.querySelector('CSS选择器')
  • 返回值 :如果找到,返回一个 DOM 元素对象;如果没找到,返回 null
  • 示例
javascript 复制代码
// 获取 ID 为 "header" 的元素 (等同于 getElementById)
const header = document.querySelector('#header');

// 获取第一个 class 为 "btn" 的元素
const firstBtn = document.querySelector('.btn');

// 获取 div 容器内的第一个 p 标签 (复杂选择器)
const specialP = document.querySelector('div.container > p:first-child');
querySelectorAll
  • 作用 :返回所有匹配指定 CSS 选择器的元素。
  • 语法document.querySelectorAll('CSS选择器')
  • 返回值 :一个静态NodeList
    • "静态"是什么意思? 这意味着它就像是当时那一刻的"快照"。如果之后网页结构发生变化,这个列表不会自动更新。
  • 示例
javascript 复制代码
// 获取所有 class 为 "highlight" 的元素
const highlights = document.querySelectorAll('.highlight');

// 获取所有 input 标签
const inputs = document.querySelectorAll('input');

📊 方法总结与对比

为了让你更清晰地选择,这里有一个总结表格:

表格

方法名 返回值类型 是否实时 适用场景
getElementById 单个元素或 null 通过唯一的 ID 获取单个元素,速度最快。
getElementsByTagName HTMLCollection 批量获取同一种标签的元素。
getElementsByClassName HTMLCollection 批量获取同一类样式的元素。
getElementsByName NodeList 主要用来获取表单元素(如 radio, checkbox)。
querySelector 单个元素或 null 使用 CSS 选择器获取第一个匹配元素,最灵活。
querySelectorAll NodeList 使用 CSS 选择器获取所有匹配元素,最灵活。

给新手的建议:

  • 如果要获取唯一的元素,优先使用 getElementByIdquerySelector
  • 如果要获取一组元素,querySelectorAll 是最通用和强大的选择,因为它可以使用任何复杂的 CSS 规则来查找。

元素 是对象的意思吗

是的,完全正确!

你通过 getElementById 或其他方法获取到的"元素",在 JavaScript 眼里,就是一个标准的对象(Object)

为了让你彻底明白,我们可以从以下三个角度来理解:

1. 它是"复杂数据类型"

在 JavaScript 中,数据分为"简单数据类型"(如数字、字符串)和"复杂数据类型"(即对象)。

  • DOM 元素属于复杂数据类型
  • 当你把它赋值给一个变量时,变量里存的不是元素本身,而是内存地址(就像你手里拿着一把"遥控器",指向电视那个"对象")。

2. 它是一个"特殊的对象"

虽然它是个对象,但它不是我们平时用 {} 创建的那种普通对象,而是一个内置的、功能非常强大的对象

  • 它的类名 :如果你打印它,你会发现它有具体的"型号"。比如 <div> 对应的是 HTMLDivElement<input> 对应的是 HTMLInputElement
  • 它的继承链 :它继承了一系列的"超能力"。
    • EventTarget:让它能听懂"点击"、"鼠标移动"等事件。
    • Node:让它有"父节点"、"子节点"等树形结构关系。
    • Element:让它有标签名、ID、类名等属性。

3. 你可以把它当成"遥控器"

既然它是对象,你就可以像操作普通对象一样操作它:

  • 点出属性 :你可以用 .value 获取输入框的值,用 .id 获取它的 ID。
  • 点出方法 :你可以用 .focus() 让它获得焦点,用 .click() 模拟点击。
  • 修改属性 :你修改这个对象的属性(比如 style.color = 'red'),浏览器就会立刻把网页上的画面变红。

总结

网页上的标签(HTML)是"尸体"(静态的结构),而 JavaScript 获取到的元素对象是"灵魂"(可以操作、有交互能力的实体)。

你通过 getElementById 拿到的,就是这个**"灵魂对象"**。

操作对象属性和修改HTML有什么区别?

这是一个非常深刻的问题,触及了前端开发中最容易让人困惑的核心概念:DOM 属性(Property)与 HTML 特性(Attribute)的区别

简单来说:操作对象属性是"控制现在的状态",而修改 HTML 特性往往是"设定初始的状态"。

虽然它们看起来很像,但在浏览器眼里,它们其实是两个平行世界的东西。

1. 核心区别:Property vs Attribute

为了让你一目了然,我为你整理了一个对比表:

表格

特性 HTML 特性 (Attribute) DOM 属性 (Property)
定义 写在 HTML 标签上的字符串 浏览器解析后生成的 JavaScript 对象
作用 定义元素的初始状态(出厂设置) 反映元素的实时状态(当前状态)
操作方式 getAttribute(), setAttribute() 直接访问:element.value, element.checked
数据类型 永远是字符串 可以是任意类型(布尔值、对象、数字等)
同步性 修改后不会自动更新 Property 修改后通常不会自动更新 Attribute

2. 最经典的例子:输入框的 value

这是新手最容易踩的坑。假设你有一个输入框:

javascript 复制代码
<!-- HTML 代码 -->
<input type="text" id="myInput" value="初始值">

此时,浏览器做了两件事:

  1. HTML 特性 :记录了 value="初始值"(这是出厂设置)。
  2. DOM 属性 :生成了一个对象,myInput.value 也是 "初始值"(这是当前状态)。

接下来,神奇的事情发生了:

  • 场景一:用户在输入框里打字

    • 用户把 "初始值" 改成了 "用户输入"。
    • DOM 属性 (myInput.value) :变成了 "用户输入"(实时更新)。
    • HTML 特性 (getAttribute('value'))依然是 "初始值"(因为它代表初始状态,不会随用户操作改变)。
  • 场景二:你用 setAttribute 修改

    • 代码:myInput.setAttribute('value', '新出厂设置')
    • HTML 特性 :变成了 "新出厂设置"
    • DOM 属性可能不会变! (如果用户刚才已经输入了内容,setAttribute 往往无法覆盖用户当前的输入)。
  • 场景三:你用 element.value 修改(推荐做法)

    • 代码:myInput.value = '直接修改'
    • DOM 属性 :立刻变成 "直接修改"
    • 屏幕显示:输入框里的字立刻变了。

结论 :如果你想改变输入框里显示的字,必须操作 DOM 属性 (element.value),而不是 HTML 特性。


3. 另一个例子:复选框的 checked

假设有一个复选框:

javascript 复制代码
<input type="checkbox" id="cb" checked>
  • HTML 特性 (checked):代表"默认被选中"。
  • DOM 属性 (checked):代表"现在是否被选中"。

如果你用鼠标取消勾选:

  • DOM 属性cb.checked 变为 false
  • HTML 特性cb.getAttribute('checked') 依然是 "checked"(因为它只负责记录初始状态)。

如果你想通过代码让它选中,必须写 cb.checked = true 。如果你写 cb.setAttribute('checked', 'true'),虽然 HTML 标签上多了个属性,但界面上的勾可能并不会出现。


4. 什么时候该用哪个?

✅ 90% 的情况:操作 DOM 属性 (Property)

这是我们在日常开发(尤其是操作表单、样式、内容)时最常用的方式。

  • 表单状态input.value, checkbox.checked, button.disabled
  • 修改内容element.innerHTML, element.textContent
  • 修改样式element.style.color = 'red'
  • 修改类名element.classNameelement.classList
🛠️ 10% 的情况:操作 HTML 特性 (Attribute)

主要用于自定义数据特殊语义

  • 自定义数据 :比如 <div data-user-id="123">,你需要用 getAttribute('data-user-id') 来读取。
  • 无障碍访问 :比如 aria-hidden="true",通常用 setAttribute 设置。
  • 强制重置:有些框架在重置表单时,可能会用到移除 Attribute 的操作。

总结

  • 操作对象属性(Property) = 操作"现在的状态"。这是你在 JavaScript 中应该主要做的事情。
  • 修改 HTML 特性(Attribute) = 修改"出厂设置"或"元数据"。这通常用于配置或存储额外信息。

记住一句话:在 JavaScript 中,想改变页面上的显示或状态,永远优先直接操作 DOM 属性(比如 element.value = ...),而不是去改 HTML 字符串。

相关推荐
xieliyu.2 小时前
大一自学 Java:SE 阶段学习总结
学习
Terry Chu2 小时前
WordPress 完全教程:从入门到进阶(2026 最新版)
学习·学习方法
迷路爸爸1802 小时前
Docker 入门学习笔记 07:用一个多服务案例真正理解 Docker Compose
运维·笔记·学习·spring cloud·docker·容器·eureka
chh5632 小时前
从零开始学C++--类和对象
java·开发语言·c++·学习·算法
前端付豪2 小时前
实现记忆开关
前端·后端
前端开发呀2 小时前
约定式路由的极简主义实践:一个插件搞定 React/Vue × Vite/Rspack
前端
代码煮茶2 小时前
Vue3 插件开发实战 | 从 0 开发一个全局通知组件(Toast/Message)并发布到 npm
javascript·vue.js
HyperAI超神经2 小时前
【TVM教程】理解 Relax 抽象层
人工智能·深度学习·学习·机器学习·gpu·tvm·vllm
炽烈小老头2 小时前
【每天学习一点算法 2026/04/07】快乐数
学习·算法