Skip to content

实现 尺码与规格对照表 工具

分类:developer | 标签:尺码、对照、规格 服装鞋码戒指纸张尺码互查

2.1 功能说明

服装鞋码戒指纸张尺码互查

2.1.1 使用指南

功能说明

把日常最容易搞混的六类尺码规格整理成对照表:服装、鞋码、戒指、内衣、纸张、纸箱。 每个页签都支持输入自己的实测数据反查尺码,也可以直接翻表。全部数据内置,不联网。

各页签怎么用

服装尺码:先切换男装 / 女装,输入胸围(厘米)即可定位到对应的国标号型、S/M/L、美码、欧码、英码。 国标号型如「165/88A」表示适合身高 165 cm、胸围 88 cm、体型偏标准(A 型)的人。
鞋码:最可靠的方式是量脚长。把脚后跟贴墙站立,量最长脚趾到墙的距离(毫米),输入后查中国码、欧码、美码、英码。
戒指尺寸:用软尺或纸条绕手指一圈量出内周长(毫米),输入后自动匹配最接近的港码、国内码、美码、欧码。
内衣尺码:分别输入下胸围和上胸围(厘米),工具按「下胸围定号、上下胸围差定罩杯」计算,例如 75B。
纸张规格:ISO 216 标准 A / B 系列全尺寸,输入「A4」或输入毫米数都能查。
纸箱与快递:常见电商快递纸箱编号与尺寸、容积,以及文件封和快递袋规格。

关于纸张标准

ISO 216 规定 A0 面积为 1 平方米,长宽比为根号 2 比 1,沿长边对折即得下一号。 A4(210 × 297 mm)是最常用的办公纸张。B 系列以 B0 为 1000 × 1414 mm,尺寸介于相邻两个 A 号之间,常用于海报和书籍。 表中数值按标准取整,与实际裁切可能有 1 mm 以内的差异。

测量小技巧

1. 量胸围时软尺水平绕过胸部最丰满处,呼吸自然,不要勒紧;
2. 量脚长建议在傍晚进行,此时脚部略有肿胀,更接近日常穿着状态;
3. 量手指周长同样建议在下午,且避开手指发凉发胀的时候,冬夏可差半个尺码;
4. 数值正好卡在两档中间时,弹性面料的衣物选小一码,硬挺面料和鞋子选大一码。

数据说明与免责

服装数据参考国家标准 GB/T 1335 号型系列与常见国际尺码换算惯例,鞋码参考 GB/T 3293 及主流品牌换算表。 不同品牌、不同款式的版型差异非常大,尤其是欧美品牌与国内快时尚品牌之间, 同样标注 M 码实际尺寸可能相差一个码。运动鞋各品牌(如同一脚长在不同品牌间可差半码到一码)差异更明显。

本表仅供快速参考,正式下单前请以商家提供的具体尺码表和实测数据为准,重要物品建议先咨询客服。

2.2 代码实现

2.2.1 组件结构

本工具是一个基于 Vue 3 <script setup> 语法的单文件组件(SFC),统一包裹在 ToolPageShell 组件内,由它提供页面标题、工具 ID、分类与「使用指南」插槽等通用外壳;核心业务逻辑(响应式状态、计算属性、事件处理函数)全部写在 <script setup> 中,输入/输出通过 el-inputel-button 等 Element Plus 组件与用户交互,所有数据均在浏览器本地处理,不会上传服务器。

本工具目录 SizeChart/ 下除 index.vue 外,还包含以下源文件:

  • data.js(143 行)

2.2.2 核心逻辑概览

<script setup> 中定义的主要函数/方法:

  • num()
  • inRange()
  • clothesRowClass()
  • shoeRowClass()
  • ringRowClass()
  • paperRowClass()
  • downloadCsv()

2.2.3 关键实现代码

以下是该工具的完整 <script setup> 实现(核心代码)。模板(<template>)与样式(<style>)已省略。

vue
import { computed, ref } from 'vue'
import ToolPageShell from '@/components/ToolPageShell.vue'
import {
  BRA_BANDS, BRA_CUPS, CARTONS, ENVELOPES, MEN_CLOTHES,
  PAPER_A, PAPER_B, RING_SIZES, SHOE_MEN, SHOE_WOMEN, WOMEN_CLOTHES
} from './data.js'

const activeTab = ref('clothes')

const clothesGender = ref('women')
const bustInput = ref('')
const shoeGender = ref('women')
const footInput = ref('')
const ringInput = ref('')
const underBust = ref('')
const overBust = ref('')
const paperInput = ref('')
const cartonQuery = ref('')

function num (v) {
  const n = parseFloat(String(v).trim())
  return Number.isFinite(n) ? n : null
}

// 解析 "88-92" 这类区间
function inRange (rangeStr, value) {
  const parts = rangeStr.split('-').map(Number)
  if (parts.length === 2) return value >= parts[0] && value <= parts[1]
  return value === parts[0]
}

// ---------- 服装 ----------
const clothesRows = computed(() => clothesGender.value === 'women' ? WOMEN_CLOTHES : MEN_CLOTHES)

const clothesHit = computed(() => {
  const v = num(bustInput.value)
  if (v === null) return null
  return clothesRows.value.find(r => inRange(r.bust, v)) || null
})

const clothesMatch = computed(() => {
  const r = clothesHit.value
  if (!r) return ''
  return '胸围 ' + num(bustInput.value) + ' cm 对应:国标 ' + r.cn + ' · 国际 ' + r.intl +
      ' · 美码 ' + r.us + ' · 欧码 ' + r.eu + ' · 英码 ' + r.uk
})

function clothesRowClass ({ row }) {
  return clothesHit.value && clothesHit.value.cn === row.cn ? 'hit-row' : ''
}

// ---------- 鞋码 ----------
const shoeRows = computed(() => shoeGender.value === 'women' ? SHOE_WOMEN : SHOE_MEN)

const shoeHit = computed(() => {
  const v = num(footInput.value)
  if (v === null) return null
  // 取脚长最接近且不小于实测值的一档,超出范围则取最接近的一档
  const list = shoeRows.value
  const fit = list.find(r => r.foot >= v)
  if (fit) return fit
  return list.reduce((best, r) => Math.abs(r.foot - v) < Math.abs(best.foot - v) ? r : best, list[0])
})

const shoeMatch = computed(() => {
  const v = num(footInput.value)
  const r = shoeHit.value
  if (!r || v === null) return ''
  const warn = (v < shoeRows.value[0].foot || v > shoeRows.value[shoeRows.value.length - 1].foot)
      ? '(超出本表范围,已取最接近的一档)' : ''
  return '脚长 ' + v + ' mm 建议:中国码 ' + r.cn + ' · 欧码 ' + r.eu +
      ' · 美码 ' + r.us + ' · 英码 ' + r.uk + warn
})

function shoeRowClass ({ row }) {
  return shoeHit.value && shoeHit.value.foot === row.foot ? 'hit-row' : ''
}

// ---------- 戒指 ----------
const ringHit = computed(() => {
  const v = num(ringInput.value)
  if (v === null) return null
  return RING_SIZES.reduce((best, r) =>
      Math.abs(r.circumference - v) < Math.abs(best.circumference - v) ? r : best, RING_SIZES[0])
})

const ringMatch = computed(() => {
  const v = num(ringInput.value)
  const r = ringHit.value
  if (!r || v === null) return ''
  const diff = Math.abs(r.circumference - v).toFixed(1)
  return '内周长 ' + v + ' mm 最接近:港码 ' + r.hk + ' · 国内码 ' + r.cn + ' · 美码 ' + r.us +
      ' · 欧码 ' + r.eu + '(内径 ' + r.diameter + ' mm,相差 ' + diff + ' mm)'
})

function ringRowClass ({ row }) {
  return ringHit.value && ringHit.value.hk === row.hk ? 'hit-row' : ''
}

// ---------- 内衣 ----------
const braMatch = computed(() => {
  const u = num(underBust.value)
  const o = num(overBust.value)
  if (u === null || o === null) return { text: '', type: 'info' }
  if (o <= u) return { text: '上胸围应大于下胸围,请检查输入', type: 'warning' }

  const band = Math.round(u / 5) * 5
  const diff = o - u
  let cup = BRA_CUPS[0]
  for (const c of BRA_CUPS) {
    if (Math.abs(c.diff - diff) < Math.abs(cup.diff - diff)) cup = c
  }
  const inBand = BRA_BANDS.some(b => String(b.band) === String(band))
  const tail = inBand ? '' : '(号型超出常见范围,建议到实体店试穿)'
  return {
    text: '下胸围 ' + u + ' cm、上胸围 ' + o + ' cm,差值 ' + diff.toFixed(1) +
        ' cm,推荐尺码:' + band + cup.cup + tail,
    type: inBand ? 'success' : 'warning'
  }
})

// ---------- 纸张 ----------
const ALL_PAPER = [...PAPER_A, ...PAPER_B]

const paperHit = computed(() => {
  const q = paperInput.value.trim().toUpperCase()
  if (!q) return null
  const byName = ALL_PAPER.find(p => p.name === q)
  if (byName) return byName
  const v = num(q)
  if (v === null) return null
  return ALL_PAPER.reduce((best, p) => {
    const d = Math.min(Math.abs(p.width - v), Math.abs(p.height - v))
    const bd = Math.min(Math.abs(best.width - v), Math.abs(best.height - v))
    return d < bd ? p : best
  }, ALL_PAPER[0])
})

const paperMatch = computed(() => {
  const p = paperHit.value
  if (!p) return ''
  return p.name + ':' + p.size + '(' + p.inch + ')'
})

function paperRowClass ({ row }) {
  return paperHit.value && paperHit.value.name === row.name ? 'hit-row' : ''
}

// ---------- 纸箱 ----------
const cartonRows = computed(() => {
  const q = cartonQuery.value.trim()
  if (!q) return CARTONS
  return CARTONS.filter(c => c.name.includes(q) || c.usage.includes(q) || c.size.includes(q))
})

// ---------- 导出 ----------
const clothesCols = computed(() => clothesGender.value === 'women'
    ? [['cn', '国标号型'], ['intl', '国际'], ['us', '美码'], ['eu', '欧码'], ['uk', '英码'], ['bust', '胸围cm'], ['waist', '腰围cm'], ['hip', '臀围cm']]
    : [['cn', '国标号型'], ['intl', '国际'], ['us', '美码'], ['eu', '欧码'], ['uk', '英码'], ['bust', '胸围cm'], ['waist', '腰围cm'], ['neck', '领围cm']])

const shoeCols = [['foot', '脚长mm'], ['cn', '中国码'], ['eu', '欧码'], ['us', '美码'], ['uk', '英码']]
const ringCols = [['hk', '港码'], ['cn', '国内码'], ['us', '美码'], ['eu', '欧码'], ['circumference', '内周长mm'], ['diameter', '内径mm']]
const paperCols = [['name', '规格'], ['size', '毫米'], ['inch', '英寸']]
const cartonCols = [['name', '箱号'], ['size', '尺寸mm'], ['volume', '容积L'], ['usage', '用途']]

function downloadCsv (rows, cols, filename) {
  const columns = Array.isArray(cols) ? cols : cols.value
  const head = columns.map(c => c[1])
  const body = rows.map(r => columns.map(c => r[c[0]]))
  const csv = [head, ...body]
      .map(r => r.map(v => '"' + String(v === undefined ? '' : v).replace(/"/g, '""') + '"').join(','))
      .join('\n')
  const blob = new Blob(['\ufeff' + csv], { type: 'text/csv;charset=utf-8' })
  const a = document.createElement('a')
  a.href = URL.createObjectURL(blob)
  a.download = filename + '.csv'
  a.click()
  URL.revokeObjectURL(a.href)
}

2.3 效果截图

尺码与规格对照表 效果截图

工具访问地址:https://www.i91tools.com/tools/size-chart