Vue3 + TypeScript + el-input 实现人民币金额的输入和显示

news2025/5/31 4:38:48

输入人民币金额的参数要求:

输入要求:

  • 通过键盘,只允许输入负号、小数点、数字、退格键、删除键、方向左键、方向右键、Home键、End键、Tab键;
  • 负号只能在开头;
  • 只保留第一个小数点;
  • 替换全角输入的小数点,即“。”替换为“.”;
  • 小数点开头的前面补0;
  • 限制小数点后最多两位;
  • 去除前导零(非小数的情况下,去除开头的0);
  • 通过复制粘贴的,确保粘贴出来的内容符合上述的要求。

显示要求:

  • 聚焦时 @focus 显示原始金额数值,如:1234.56;
  • 失焦时 @blur 格式化金额数值,如:¥ 1,234.56;
  • 键盘输入 @keydown 按输入要求过滤内容;
  • 输入内容 @input 防漏兜底,防止通过粘贴输入的,按输入要求过滤内容;
  • 回车时 @keyup.enter.native="$event.target.blur()" 失焦;

方法一:使用 el-input 的 @input 和 @blur

优点:输入方便,可以自由输入

缺点:改变原值

如:

输入的原值为:1234.56

显示的内容为:¥1,234.56

最终值为:¥1,234.56

示例代码:

<script setup lang="ts" name="MaterialOut">
import { ref } from "vue";
import { formatInputRMB, formatToRMB, formatRMB } from "@/utils/formatter";

// 金额
const total = ref<string>("");
</script>

<template>
  <!-- 控制输入:@input="total = formatInputRMB($event)" 控制只能输入数字、小数点(两位小数) -->
  <!-- 控制显示:@blur="total = formatRMB(formatToRMB(total))" 输入框失去焦点时,将输入框内容格式化为人民币格式 -->
  <!-- 控制失焦:@keyup.enter.native="$event.target.blur()" 按回车输入框失去焦点 -->
  <el-input
    v-model="total"
    @input="total = formatInputRMB($event)"
    @blur="total = formatRMB(formatToRMB(total))"
    @keyup.enter.native="$event.target.blur()"
    placeholder="请输入金额,按回车确认" />
</template>

 formatter.ts

/**
 * 格式化输入人民币金额
 * @param val 输入值
 * @returns 数字字符串,如:0、123、1234.0、1234.56
 */
export const formatInputRMB = (val: string) => {
  let result = val ?? "";
  // 格式化输入的内容
  result = result
    // 替换全角输入的小数点
    .replace(/。/g, ".")
    // 只保留数字和小数点
    .replace(/[^\d.]/g, "")
    // 小数点开头的前面补0
    .replace(/^\./, "0.")
    // 只保留第一个小数点
    .replace(/(\..*)\./g, "$1")
    // 去除前导零,非小数的情况下,去除开头的0
    .replace(/^0+(\d)/, "$1")
    // 限制小数点后最多两位
    .replace(/^(\d+\.\d{2})\d+/, "$1");

  return result;
};

/**
 * 格式化为人民币金额
 * @param val 字符串或数字
 * @param rounding 是否四舍五入(默认 true,若设为 false 则直接截断)
 * @returns 数字字符串,如:0.00、1.20、123.04、1234.56
 */
export const formatToRMB = (val: string | number | null, rounding: boolean = true) => {
  let result = String(val || "0.00");
  // 格式化输入的内容
  result = result
    // 替换全角输入的小数点
    .replace(/。/g, ".")
    // 只保留数字和小数点
    .replace(/[^\d.]/g, "")
    // 小数点开头的前面补0
    .replace(/^\./, "0.")
    // 只保留第一个小数点
    .replace(/(\..*)\./g, "$1")
    // 去除前导零,非小数的情况下,去除开头的0
    .replace(/^0+(\d)/, "$1");

  // 分割整数部分和小数部分
  let [integer = "0", decimal = ""] = result.split(".");
  // 四舍五入处理小数部分
  if (rounding) {
    // 四舍五入处理(通过 Number 转换自动处理)
    const rounded = Math.round(Number(`${integer}.${decimal}`) * 100) / 100;
    return rounded.toFixed(2);
  }
  // 截断处理小数部分
  else {
    // 截断并补零
    decimal = decimal.slice(0, 2).padEnd(2, "0");
    // 确保整数部分存在
    integer = integer ?? "0";
    return `${integer}.${decimal}`;
  }
};

/**
 *
 * 格式化为带符号和千分位的人民币金额
 * @param val 字符串或数字
 * @param rounding 是否四舍五入(默认 true,若设为 false 则直接截断)
 * @returns 人民币金额字符串,如:¥0.00、¥1.20、¥123.04、¥1,234.56
 */
export const formatRMB = (val: string | number) => {
  let result = formatToRMB(val);
  // 添加人民币符号 ¥,添加千分位 ,
  result = "¥" + result.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  return result;
};

效果:

输入前

输入中 

回车确认后

方法二:使用 el-input 的 :formatter 和 :parser

优点:保持原值

缺点:输入受限,不能自由输入

如:

输入的原值为:1234.56

显示的内容为:¥1,234.56

最终值为:1234.56

示例代码:

<script setup lang="ts" name="MaterialOut">
import { ref } from "vue";

// 存储原始数值(用于业务逻辑)
const total = ref<number | null>(null);

// 格式化显示金额(用于 input 显示)
const formatRMB = (value: number | null): string => {
  if (value === null || isNaN(value)) return "";
  const valStr = value.toFixed(2);
  const [integer, decimal] = valStr.split(".");
  const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  return `¥ ${formattedInteger}.${decimal}`;
};

// 解析输入内容(用于 input 输入)
const parseRMB = (value: string): string => {
  // 去除非数字和小数点字符
  let filtered = value.replace(/[^\d.]/g, "").replace(/(\..*)\./g, "$1");

  if (filtered === "." || filtered === "") return "";

  const [integer = "0", decimal] = filtered.split(".");

  const cleanInteger = integer.replace(/^0+/, "") || "0";
  const cleanDecimal = decimal ? decimal.slice(0, 2) : "";

  return cleanDecimal ? `${cleanInteger}.${cleanDecimal}` : cleanInteger;
};

// 输入事件处理
const handleInput = (value: string) => {
  const parsed = parseRMB(value);
  total.value = parsed ? parseFloat(parsed) : null;
};
</script>

<template>
  <el-input
    v-model="total"
    :formatter="(val: string) => formatRMB(val ? parseFloat(val) : null)"
    :parser="(val: string) => parseRMB(val)"
    @input="handleInput"
    @keyup.enter.native="$event.target.blur()"
    type="text"
    placeholder="请输入金额,按回车确认" />
</template>

效果:

输入前

 输入中

回车确认后 

方法三(推荐):使用 el-input 的 @focus、@blur、@keydown、@input

优点:输入方便,可以自由输入,保持原值

缺点:无

<script setup lang="ts" name="MaterialOut">
import { ref } from "vue";

// 存储原始数值(用于业务逻辑)
const total = ref<number | null>(null);

// 输入框内部状态(带格式)
const inputValue = ref<string>("");

// 处理键盘输入
function handleKeyDown(e: KeyboardEvent) {
  // 只允许输入负号、小数点、数字、退格键、删除键、方向左键、方向右键、Home键、End键、Tab键
  const allowedKeys = [
    "-",
    "0",
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    ".",
    "Backspace",
    "Delete",
    "ArrowLeft",
    "ArrowRight",
    "Home",
    "End",
    "Tab"
  ];

  // 阻止非法字符输入
  if (!allowedKeys.includes(e.key)) {
    e.preventDefault();
    return;
  }

  const inputEl = e.target as HTMLInputElement;
  const cursorPos = inputEl.selectionStart || 0;

  const value = inputValue.value;

  // 阻止输入多个小数点
  if (e.key === "." && value.includes(".")) {
    e.preventDefault();
    return;
  }

  // 阻止输入多个负号 或 负号不在开头
  if (e.key === "-" && (value.includes("-") || cursorPos !== 0)) {
    e.preventDefault();
    return;
  }

  // 辅助按键,则不阻止,任何时候都允许输入
  const assistantKeys = ["Backspace", "Delete", "ArrowLeft", "ArrowRight", "Home", "End", "Tab"];
  if (assistantKeys.includes(e.key)) {
    return;
  }

  // 如果已有小数点,并且光标在小数点后,限制最多两位
  if (value.includes(".")) {
    const decimalIndex = value.indexOf(".");
    const parts = value.split(".");
    // 仅当光标在小数点之后时才限制输入
    if (parts[1] && parts[1].length >= 2 && cursorPos > decimalIndex) {
      e.preventDefault();
    }
  }
}

// 处理输入内容(防漏兜底,防止不是通过键盘输入,而是通过粘贴输入的)
function handleInput(value: string) {
  // 过滤输入的内容
  let filtered = value
    // 替换全角输入的小数点
    .replace(/。/g, ".")
    // 只保留负号、数字和小数点
    .replace(/[^-\d.]/g, "")
    // 小数点开头的前面补0
    .replace(/^\./, "0.")
    // 只保留第一个小数点
    .replace(/(\..*)\./g, "$1")
    // 负号只能在开头
    .replace(/(\--*)\-/g, "$1")
    // 去除前导零(非小数的情况下,去除开头的0)
    .replace(/^0+(\d)/, "$1")
    // 限制小数点后最多两位
    .replace(/^(\d+\.\d{2})\d+/, "$1");

  // 负号只能在开头,等效于 replace(/(\--*)\-/g, "$1")
  // if (filtered.startsWith("-")) {
  //   const rest = filtered.slice(1).replace(/[^\d.]/g, "");
  //   filtered = "-" + rest;
  // } else {
  //   filtered = filtered.replace(/[^\d.]/g, "");
  // }

  /*
  // 处理小数点
  const parts = filtered.split(".");

  // 只保留第一个小数点,等效于 replace(/(\..*)\./g, "$1")
  if (parts.length > 2) {
    filtered = parts[0] + "." + parts.slice(1).join("");
  }

  // 限制小数点后最多两位
  if (parts[1]) {
    // 限制小数部分最多两位,等效于 replace(/^(\d+\.\d{2})\d+/, "$1")
    parts[1] = parts[1].slice(0, 2);
    filtered = parts[0] + "." + parts[1];
  }
  */

  // 如果过滤后为空 或 无效内容,则清空 total
  if (!filtered || filtered === "-" || filtered === "." || filtered === "-.") {
    total.value = null;
  } else {
    total.value = parseFloat(filtered);
  }

  inputValue.value = filtered;
}

// 获得焦点时显示原始值
function handleFocus() {
  inputValue.value = total.value?.toString() || "";
}

// 失去焦点后格式化显示为人民币格式
function handleBlur() {
  const rawValue = inputValue.value;

  if (!rawValue) {
    inputValue.value = "";
    total.value = null;
    return;
  }

  const num = parseFloat(rawValue);
  if (isNaN(num)) {
    inputValue.value = "";
    total.value = null;
    return;
  }

  total.value = num;

  const [integerPart, decimalPart = "00"] = Math.abs(num).toFixed(2).split(".");

  // 千分位格式化
  const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  const sign = num < 0 ? "-" : "";

  // 格式化为人民币格式
  inputValue.value = `¥ ${sign}${formattedInteger}.${decimalPart}`;
}
</script>

<template>
  <!-- 控制输入:@keydown="handleKeyDown" 和 @input="handleInput" -->
  <!-- 控制显示:@focus="handleFocus"和 @blur="handleBlur" -->
  <!-- 控制失焦:@keyup.enter.native="$event.target.blur()" 按回车输入框失去焦点 -->
  <el-input
    v-model="inputValue"
    @focus="handleFocus"
    @blur="handleBlur"
    @keydown="handleKeyDown"
    @input="handleInput"
    @keyup.enter.native="$event.target.blur()"
    placeholder="请输入金额,按回车确认" />
</template>

效果:

 输入前

输入中

回车确认后

将这部分逻辑封装成一个可复用的 Vue Composition API Hook

✅ 封装目标

我们将以下功能抽离为一个 useInputRMB() Hook:

功能描述
输入限制键盘拦截非法字符(数字、负号、小数点)
全角支持支持  和  自动转换
粘贴支持Ctrl+V / 鼠标右键粘贴内容自动过滤
回车失焦按下 Enter 键后输入框失去焦点
数据模型返回 inputValue 用于绑定到 <el-input>
数值存储返回 total 表示原始 `number
失焦格式化显示为 ¥ -1,234.56 格式

✅ 完整 Hook 实现:useInputRMB.ts

你可以将下面这段代码保存为 src/hooks/useInputRMB.ts 文件:

import { ref } from "vue";

export function useInputRMB() {
  // 存储原始数值(用于业务逻辑)
  const total = ref<number | null>(null);

  // 输入框内部状态(带格式)
  const inputValue = ref<string>("");

  // 处理键盘输入
  function handleKeyDown(e: KeyboardEvent) {
    // 只允许输入负号、小数点、数字、退格键、删除键、方向左键、方向右键、Home键、End键、Tab键
    const allowedKeys = [
      "-",
      "0",
      "1",
      "2",
      "3",
      "4",
      "5",
      "6",
      "7",
      "8",
      "9",
      ".",
      "Backspace",
      "Delete",
      "ArrowLeft",
      "ArrowRight",
      "Home",
      "End",
      "Tab"
    ];

    // 阻止非法字符输入
    if (!allowedKeys.includes(e.key)) {
      e.preventDefault();
      return;
    }

    const inputEl = e.target as HTMLInputElement;
    const cursorPos = inputEl.selectionStart || 0;

    const value = inputValue.value;

    // 阻止输入多个小数点
    if (e.key === "." && value.includes(".")) {
      e.preventDefault();
      return;
    }

    // 阻止输入多个负号 或 负号不在开头
    if (e.key === "-" && (value.includes("-") || cursorPos !== 0)) {
      e.preventDefault();
      return;
    }

    // 辅助按键,则不阻止,任何时候都允许输入
    const assistantKeys = ["Backspace", "Delete", "ArrowLeft", "ArrowRight", "Home", "End", "Tab"];
    if (assistantKeys.includes(e.key)) {
      return;
    }

    // 如果已有小数点,并且光标在小数点后,限制最多两位
    if (value.includes(".")) {
      const decimalIndex = value.indexOf(".");
      const parts = value.split(".");
      // 仅当光标在小数点之后时才限制输入
      if (parts[1] && parts[1].length >= 2 && cursorPos > decimalIndex) {
        e.preventDefault();
      }
    }
  }

  // 处理输入内容(防漏兜底,防止不是通过键盘输入,而是通过粘贴输入的)
  function handleInput(value: string) {
    // 过滤输入的内容
    let filtered = value
      // 替换全角输入的小数点
      .replace(/。/g, ".")
      // 只保留负号、数字和小数点
      .replace(/[^-\d.]/g, "")
      // 小数点开头的前面补0
      .replace(/^\./, "0.")
      // 只保留第一个小数点
      .replace(/(\..*)\./g, "$1")
      // 负号只能在开头
      .replace(/(\--*)\-/g, "$1")
      // 去除前导零(非小数的情况下,去除开头的0)
      .replace(/^0+(\d)/, "$1")
      // 限制小数点后最多两位
      .replace(/^(\d+\.\d{2})\d+/, "$1");

    // 负号只能在开头,等效于 replace(/(\--*)\-/g, "$1")
    // if (filtered.startsWith("-")) {
    //   const rest = filtered.slice(1).replace(/[^\d.]/g, "");
    //   filtered = "-" + rest;
    // } else {
    //   filtered = filtered.replace(/[^\d.]/g, "");
    // }

    /*
  // 处理小数点
  const parts = filtered.split(".");

  // 只保留第一个小数点,等效于 replace(/(\..*)\./g, "$1")
  if (parts.length > 2) {
    filtered = parts[0] + "." + parts.slice(1).join("");
  }

  // 限制小数点后最多两位
  if (parts[1]) {
    // 限制小数部分最多两位,等效于 replace(/^(\d+\.\d{2})\d+/, "$1")
    parts[1] = parts[1].slice(0, 2);
    filtered = parts[0] + "." + parts[1];
  }
  */

    // 如果过滤后为空 或 无效内容,则清空 total
    if (!filtered || filtered === "-" || filtered === "." || filtered === "-.") {
      total.value = null;
    } else {
      total.value = parseFloat(filtered);
    }

    inputValue.value = filtered;
  }

  // 获得焦点时显示原始值
  function handleFocus() {
    inputValue.value = total.value?.toString() || "";
  }

  // 失去焦点后格式化显示为人民币格式
  function handleBlur() {
    const rawValue = inputValue.value;

    if (!rawValue) {
      inputValue.value = "";
      total.value = null;
      return;
    }

    const num = parseFloat(rawValue);
    if (isNaN(num)) {
      inputValue.value = "";
      total.value = null;
      return;
    }

    total.value = num;

    const [integerPart, decimalPart = "00"] = Math.abs(num).toFixed(2).split(".");

    // 千分位格式化
    const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    const sign = num < 0 ? "-" : "";

    // 格式化为人民币格式
    inputValue.value = `¥ ${sign}${formattedInteger}.${decimalPart}`;
  }

  return {
    inputValue,
    total,
    handleKeyDown,
    handleInput,
    handleBlur,
    handleFocus
  };
}

✅ 在组件中使用这个 Hook,使用方式一,解构使用

组件 MaterialOut.vue 文件如下:

<script setup lang="ts" name="MaterialOut">
import { useInputRMB } from "@/hooks/useInputRMB";

const { inputValue, total, handleKeyDown, handleInput, handleBlur, handleFocus } = useInputRMB();
</script>

<template>
  <!-- 控制输入:@keydown="handleKeyDown" 和 @input="handleInput" -->
  <!-- 控制显示:@focus="handleFocus"和 @blur="handleBlur" -->
  <!-- 控制失焦:@keyup.enter.native="$event.target.blur()" 按回车输入框失去焦点 -->
  <el-input
    v-model="inputValue"
    @focus="handleFocus"
    @blur="handleBlur"
    @keydown="handleKeyDown"
    @input="handleInput"
    @keyup.enter.native="$event.target.blur()"
    placeholder="请输入金额,按回车确认" />
</template>

 ✅ 效果:

输入前

输入中

回车确认后

✅ 在组件中使用这个 Hook,使用方式二,直接定义使用

组件 MaterialOut.vue 文件如下:

<script setup lang="ts" name="MaterialOut">
import { useInputRMB } from "@/hooks/useInputRMB";

const inputRMBHooks = useInputRMB();
</script>

<template>
  <!-- 控制输入:@keydown="handleKeyDown" 和 @input="handleInput" -->
  <!-- 控制显示:@focus="handleFocus"和 @blur="handleBlur" -->
  <!-- 控制失焦:@keyup.enter.native="$event.target.blur()" 按回车输入框失去焦点 -->
  <!-- 这里注意,inputValue 需要 .value -->
  <el-input
    v-model="inputRMBHooks.inputValue.value"
    @focus="inputRMBHooks.handleFocus"
    @blur="inputRMBHooks.handleBlur"
    @keydown="inputRMBHooks.handleKeyDown"
    @input="inputRMBHooks.handleInput"
    @keyup.enter.native="$event.target.blur()"
    placeholder="请输入金额,按回车确认" />
</template>

直接原因

useInputRMB() 返回的 inputValue 本身是一个 ref 对象,而 inputRMBHooks 是一个普通对象(非响应式对象)。这种情况下,Vue 的模板无法自动解包嵌套在普通对象中的 ref,所以需要手动通过 .value 访问。

typescript

复制

下载

// 假设 useInputRMB 的实现类似这样:
const useInputRMB = () => {
  const inputValue = ref(""); // inputValue 是一个 ref
  return {
    inputValue, // 将 ref 直接暴露出去
  };
};

为什么需要 .value

  1. 当 ref 被包裹在普通对象中时

    • 如果 inputRMBHooks 是一个普通对象(如 const inputRMBHooks = { inputValue: ref('') }),模板不会自动解包内部的 ref

    • 此时必须通过 inputRMBHooks.inputValue.value 访问值。

  2. 如果 inputRMBHooks 是响应式对象(如 reactive

    • Vue 会自动解包第一层的 ref,此时无需 .value

    • 但你的代码中 inputRMBHooks 可能是普通对象,或 inputValue 被嵌套在更深层。


验证方法

检查 useInputRMB 的实现:

  • 如果它返回的是 reactive 包裹的对象,且 inputValue 是 ref,模板中应该不需要 .value

  • 如果返回的是普通对象,则需要 .value


解决方案(可选)

如果希望省略 .value,可以将 inputRMBHooks 转为响应式对象:

typescript

复制

下载

const inputRMBHooks = reactive(useInputRMB());

然后在模板中直接使用 v-model="inputRMBHooks.inputValue"(无需 .value)。


总结

你的代码中需要 .value,是因为 inputRMBHooks 是一个普通对象,且 inputValue 是 ref,而 Vue 不会自动解包普通对象内部的 ref。通过 .value 显式访问是必要的。

✅ 在组件中使用这个 Hook,使用方式三,reactive定义使用

组件 MaterialOut.vue 文件如下:

​
<script setup lang="ts" name="MaterialOut">
import { reactive } from "vue";
import { useInputRMB } from "@/hooks/useInputRMB";

const inputRMBHooks = reactive(useInputRMB());
</script>

<template>
  <!-- 控制输入:@keydown="handleKeyDown" 和 @input="handleInput" -->
  <!-- 控制显示:@focus="handleFocus"和 @blur="handleBlur" -->
  <!-- 控制失焦:@keyup.enter.native="$event.target.blur()" 按回车输入框失去焦点 -->
  <el-input
    v-model="inputRMBHooks.inputValue"
    @focus="inputRMBHooks.handleFocus"
    @blur="inputRMBHooks.handleBlur"
    @keydown="inputRMBHooks.handleKeyDown"
    @input="inputRMBHooks.handleInput"
    @keyup.enter.native="$event.target.blur()"
    placeholder="请输入金额,按回车确认" />
</template>

​

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

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

相关文章

2.1 C++之条件语句

学习目标&#xff1a; 理解程序的分支逻辑&#xff08;根据不同条件执行不同代码&#xff09;。掌握 if-else 和 switch 语句的用法。能编写简单的条件判断程序&#xff08;如成绩评级、游戏选项等&#xff09;。 1 条件语句的基本概念 什么是条件语句&#xff1f; 程序在执…

Linux `ls` 命令深度解析与高阶应用指南

Linux `ls` 命令深度解析与高阶应用指南 一、核心功能解析1. 基本作用2. 与类似命令对比二、选项系统详解1. 常用基础选项2. 进阶筛选选项三、高阶应用技巧1. 组合过滤查询2. 格式化输出控制3. 元数据深度分析四、企业级应用场景1. 存储空间监控2. 安全审计3. 自动化运维五、特…

【MPC控制 - 从ACC到自动驾驶】5. 融会贯通:MPC在ACC中的优势总结与知识体系构建

【MPC控制 - 从ACC到自动驾驶】融会贯通&#xff1a;MPC在ACC中的优势总结与知识体系构建 在过去的四天里&#xff0c;我们一起经历了一段奇妙的旅程&#xff1a; Day 1: 我们认识了自适应巡航ACC这位“智能领航员”&#xff0c;并初见了模型预测控制MPC这位“深谋远虑的棋手…

初等数论--Garner‘s 算法

0. 介绍 主要通过混合积的表示来逐步求得同余方程的解。 对于同余方程 { x ≡ v 0 ( m o d m 0 ) x ≡ v 1 ( m o d m 1 ) ⋯ x ≡ v k − 1 ( m o d m k − 1 ) \begin{equation*} \begin{cases} x \equiv v_0 \quad (\ \bmod \ m_0)\\ x \equiv v_1 \quad (\ \bmod \ m_1)…

NV211NV212美光科技颗粒NV219NV220

NV211NV212美光科技颗粒NV219NV220 技术架构解析&#xff1a;从颗粒到存储系统 近期美光科技发布的NV211、NV212、NV219、NV220系列固态颗粒&#xff0c;凭借其技术突破引发行业关注。这些颗粒基于176层QLC堆叠工艺&#xff0c;单Die容量预计在2026年可达1Tb&#xff0c;相当…

SQL解析工具JSQLParser

目录 一、引言二、JSQLParser常见类2.1 Class Diagram2.2 Statement2.3 Expression2.4 Select2.5 Update2.6 Delete2.7 Insert2.8 PlainSelect2.9 SetOperationList2.10 ParenthesedSelect2.11 FromItem2.12 Table2.13 ParenthesedFromItem2.14 SelectItem2.15 BinaryExpressio…

Wave Terminal + Cpolar:SSH远程访问的跨平台实战+内网穿透配置全解析

文章目录 前言1. Wave Terminal安装2. 简单使用演示3. 连接本地Linux服务器3.1 Ubuntu系统安装ssh服务3.2 远程ssh连接Ubuntu 4. 安装内网穿透工具4.1 创建公网地址4.2 使用公网地址远程ssh连接 5. 配置固定公网地址 前言 各位开发者朋友&#xff0c;今天为您介绍一款颠覆性操…

html使用JS实现账号密码登录的简单案例

目录 案例需求 思路 错误案例及问题 修改思路 案例提供 所需要的组件 <input>标签&#xff0c;<button>标签&#xff0c;<script>标签 详情使用参考&#xff1a;HTML 教程 | 菜鸟教程 案例需求 编写一个程序&#xff0c;最多允许用户尝试登录 3 次。…

【数据集】基于ubESTARFM法的100m 地温LST数据集(澳大利亚)

目录 数据概述一、输入数据与处理二、融合算法1. ESTARFM(Enhanced STARFM)2. ubESTARFM(Unbiased ESTARFM)代码实现数据下载参考根据论文《Generating daily 100 m resolution land surface temperature estimates continentally using an unbiased spatiotemporal fusion…

51c自动驾驶~合集55

我自己的原文哦~ https://blog.51cto.com/whaosoft/13935858 #Challenger 端到端碰撞率暴增&#xff01;清华&吉利,框架&#xff1a;低成本自动生成复杂对抗性驾驶场景~ 自动驾驶系统在对抗性场景&#xff08;Adversarial Scenarios&#xff09;中的可靠性是安全落…

【前端基础】Promise 详解

文章目录 什么是 Promise&#xff1f;为什么要使用 Promise&#xff1f;创建 Promise消费 Promise (使用 Promise)1. .then(onFulfilled, onRejected)2. .catch(onRejected)3. .finally(onFinally) Promise 链 (Promise Chaining)Promise 的静态方法1. Promise.resolve(value)2…

高性能管线式HTTP请求

高性能管线式HTTP请求:原理、实现与实践 目录 高性能管线式HTTP请求:原理、实现与实践 1. HTTP管线化的原理与优势 1.1 HTTP管线化的基本概念 关键特性: 1.2 管线化的优势 1.3 管线化的挑战 2. 高性能管线式HTTP请求的实现方案 2.1 技术选型与工具 2.2 Java实现:…

【CSS】九宫格布局

CSS Grid布局&#xff08;推荐&#xff09; 实现代码&#xff1a; <!doctype html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0"…

Python用Transformer、Prophet、RNN、LSTM、SARIMAX时间序列预测分析用电量、销售、交通事故数据

原文链接&#xff1a; tecdat.cn/?p42219 在数据驱动决策的时代&#xff0c;时间序列预测作为揭示数据时序规律的核心技术&#xff0c;已成为各行业解决预测需求的关键工具。从能源消耗趋势分析到公共安全事件预测&#xff0c;不同领域的数据特征对预测模型的适应性提出了差异…

java基础(面向对象进阶高级)泛型(API一)

认识泛型 泛型就等于一个标签(比如男厕所和女厕) 泛型类 只能加字符串&#xff1a; 把别人写好的东西&#xff0c;自己封装。 泛型接口 泛型方法、泛型通配符、上下限 怎么解决下面的问题&#xff1f; API object类 toString: equals: objects类 包装类 为什么上面的Integer爆红…

学习心得(17--18)Flask表单

一. 认识表单&#xff1a;定义表单类 password2中末端的EqualTo&#xff08;password&#xff09;是将密码2与密码1进行验证&#xff0c;看是否相同 二.使用表单&#xff1a; 运行 如果遇到这个报错&#xff0c;就在该页面去添加 下面是举例&#xff1a; 这就是在前端的展示效…

微信小程序进阶第2篇__事件类型_冒泡_非冒泡

在小程序中&#xff0c; 事件分为两种类型&#xff1a; 冒泡事件&#xff0c; 当一个组件上的事件被触发后&#xff0c;该事件会向父节点传递非冒泡事件&#xff0c; 当一个组件上的事件被触发后&#xff0c; 该事件不会向父节点传递。 一 冒泡事件 tap&#xff0c; touchst…

电机控制学习笔记

文章目录 前言一、电机二、编码器三、开环控制和闭环控制总结 前言 学习了解电机控制技术的一些原理和使用的方法。 一、电机 直流有刷电机 操作简单 使用H桥驱动直流有刷电机 直流有刷电机驱动板 电压检测 电流检测以及温度检测 直流无刷电机 使用方波或者正弦波进行换向…

企业网站架构部署与优化-Nginx性能调优与深度监控

目录 #1.1Nginx性能调优 1.1.1更改进程数与连接数 1.1.2静态缓存功能设置 1.1.3设置连接超时 1.1.4日志切割 1.1.5配置网页压缩 #2.1nginx的深度监控 2.1.1GoAccess简介 2.1.2nginx vts简介 1.1Nginx性能调优 1.1.1更改进程数与连接数 &#xff08;1&#xff09;进程数 进程数…

行列式的线性性质(仅限于单一行的加法拆分)

当然可以&#xff0c;以下是经过排版优化后的内容&#xff0c;保持了原始内容不变&#xff0c;仅调整了格式以提升可读性&#xff1a; 行列式的线性性质&#xff08;加法拆分&#xff09; 这个性质说的是&#xff1a;如果行列式的某一行&#xff08;或某一列&#xff09;的所有…