{"version":3,"file":"nav-tab.cjs","sources":["../../src/injectionKeys.ts","../../src/util/requestAnimationFrame.ts","../../src/TabsHead.vue","../../src/TabsBottom.vue","../../src/TabItem.vue","../../src/index.ts"],"sourcesContent":["import type { InjectionKey } from 'vue';\r\nimport type { TabsHeadInjection, TabsBottomInjection } from './types';\r\n\r\nexport const tabsHeadInjectionKey: InjectionKey<TabsHeadInjection> = Symbol.for('tabsHeadInjectionKey');\r\nexport const tabsBottomInjectionKey: InjectionKey<TabsBottomInjection> = Symbol.for('tabsBottomInjectionKey');","// 定义一个接口 IndexableWindow，允许通过字符串键访问 window 对象的任意属性\ninterface IndexableWindow {\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\t[key: string]: any;\n}\n\n// 将 window 对象类型断言为 IndexableWindow，以便可以访问非标准属性\nconst win = window as IndexableWindow;\n\n// 导出一个名为 windowInit 的函数，用于初始化 requestAnimationFrame 和 cancelAnimationFrame\nexport function windowInit() {\n\t// 记录上次调用的时间戳\n\tlet lastTime = 0;\n\t// 定义浏览器供应商前缀数组，用于处理不同浏览器的兼容性问题\n\tconst vendors = ['webkit', 'moz'];\n\t// 遍历供应商前缀数组，当前浏览器不支持原生的 requestAnimationFrame 时，\n\t// \t\t尝试为 window.requestAnimationFrame 和 window.cancelAnimationFrame 分配兼容版本的方法\n\tfor (let x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {\n\t\t// 尝试从 window 对象中获取带前缀的 requestAnimationFrame 方法\n\t\twindow.requestAnimationFrame = win[vendors[x] + 'RequestAnimationFrame'];\n\t\t// 尝试从 window 对象中获取带前缀的 cancelAnimationFrame 方法\n\t\t// 注意：在 Webkit 浏览器中，方法名可能为 cancelRequestAnimationFrame\n\t\twindow.cancelAnimationFrame =\n\t\t\twin[vendors[x] + 'CancelAnimationFrame'] || // name has changed in Webkit\n\t\t\twin[vendors[x] + 'CancelRequestAnimationFrame'];\n\t}\n\n\t/*\n\t\t只要动画帧的刷新率符合显示器的刷新率（通常是每秒 60 帧），并且开发者使用了 requestAnimationFrame 来控制动画，\n\t\t\t那么每一帧都会执行一次 requestAnimationFrame 的回调函数。\n\t\t关键点：\n\t\t\t动画帧同步：requestAnimationFrame 确保动画与显示器的刷新率同步，提供更流畅的用户体验。\n\t\t\t性能优化：它避免了不必要的重绘和回流，提高了性能。\n\t\t\t广泛使用：许多现代 JavaScript 库和框架（如 React、Vue 等）内部也使用 requestAnimationFrame 来优化动画和渲染逻辑。\n\t\trequestAnimationFrame 的作用：\n\t\t\t确保动画与显示器刷新率同步，提供流畅的动画体验，并且在每一帧刷新时调用回调函数。\n\t\tPolyfill 的作用：\n\t\t\t为不支持某些现代 API 的浏览器提供兼容性支持，确保代码在不同环境中都能正常工作。\n\t*/\n\t// 若浏览器不支持原生的 requestAnimationFrame，则提供一个基于 setTimeout 的 polyfill 实现\n\tif (!window.requestAnimationFrame) {\n\t\twindow.requestAnimationFrame = function (callback) {\n\t\t\t// 获取当前时间戳\n\t\t\tconst currTime = Date.now();\n\t\t\t// 计算自上次调用 requestAnimationFrame 以来的时间间隔，单位：毫秒。\n\t\t\tconst interval = currTime - lastTime;\n\t\t\t/*\n\t\t\t\tMath.max(0, 16.7 - interval)：\n\t\t\t\t\tMath.max(...args) ：\n\t\t\t\t\t\t接受任意数量的参数，并返回这些参数中的最大值。\n\t\t\t\t\t\t在这个表达式中，Math.max(0, ...) 用于确保 timeToCall 的值不会为负数。\n\t\t\t\t\t\t如果 timeToCall 是负数，它会被视为 0，即立即执行回调。\n\t\t\t\t\t如果 interval 小于 16.7 毫秒，\n\t\t\t\t\t\t16.7 - interval 会是一个正数，\n\t\t\t\t\t\t表示还需要等待多少毫秒才能达到 16.7 毫秒的间隔。★★★★★★★\n\t\t\t\t\t如果 interval 大于或等于 16.7 毫秒，\n\t\t\t\t\t\t16.7 - interval 会是一个非正数（0 或负数），\n\t\t\t\t\t\t此时 Math.max(0, ...) 会返回 0，表示不需要额外等待，立即执行回调。\n\t\t\t*/\n\t\t\t// 确保每次回调之间的最小间隔为 16.7ms（每秒60次刷新）\n\t\t\tconst timeToCall = Math.max(0, 16.7 - interval);\n\t\t\t/*\n\t\t\t\t刷新间隔 16.7ms（每秒 60 次刷新）：\n\t\t\t\t\t16.7 毫秒是基于 60 帧每秒的刷新率计算得出的（1000 毫秒 / 60 ≈ 16.7 毫秒）。★★★★★★★\n\t\t\t\t表达式 `16.7 - interval` 计算的是：\n\t\t\t\t\t当前回调函数的本次与上次调用的时间间隔，距离期望的 16.7 毫秒，还差多少毫秒？★★★★★★★\n\t\t\t\t\t如果这个差值是正数，说明当前时间还没有达到期望的刷新间隔，需要等待这个差值的时间。\n\t\t\t\t\t如果这个差值是负数或零，说明当前时间已经超过了期望的刷新间隔，或者是第一次调用，不需要等待。\n\n\t\t\t\t1、通过 `Math.max(0, ...)` 确保这个差值不会为负数。\n\t\t\t\t2、通过 `setTimeout` 来确保符合期望的刷新间隔 16.7ms（每秒 60 次刷新）。\n\t\t\t*/\n\t\t\t// 设置一个定时器，在指定时间后调用回调函数，并传递时间间隔作为参数\n\t\t\tconst id = window.setTimeout(function () {\n\t\t\t\tcallback(interval);\n\t\t\t}, timeToCall);\n\t\t\t// 更新 lastTime 为下一次调用的时间戳\n\t\t\tlastTime = currTime + timeToCall;\n\t\t\t// 返回定时器 ID，以便可以取消该定时器\n\t\t\treturn id;\n\t\t};\n\t}\n\n\t// 若浏览器不支持原生的 cancelAnimationFrame，则使用 clearTimeout 作为替代方案\n\tif (!window.cancelAnimationFrame) {\n\t\twindow.cancelAnimationFrame = function (id) {\n\t\t\t// 传入定时器 ID，取消对应的定时器\n\t\t\tclearTimeout(id);\n\t\t};\n\t}\n}\n","<template>\r\n\t<!-- <h1>TabsHead</h1> -->\r\n\t<div ref=\"viewAreaRef\" class=\"tabs-head\">\r\n\t\t<div ref=\"listRef\" :style=\"listStyle\" class=\"tabs-head__tab-list\">\r\n\t\t\t<slot />\r\n\t\t\t<div :style=\"activeBarStyle\" class=\"tabs-head__active-line\" />\r\n\t\t</div>\r\n\t</div>\r\n</template>\r\n\r\n<script lang=\"ts\" setup>\r\n\r\nimport {\r\n\tgetCurrentInstance,\r\n\tprovide,\r\n\tref,\r\n\tcomputed,\r\n\twatch,\r\n\ttoRef,\r\n\tonMounted,\r\n\tonBeforeUnmount,\r\n\tnextTick,\r\n} from 'vue';\r\nimport type { PropType, Ref } from 'vue';\r\nimport { tabsHeadInjectionKey } from './injectionKeys';\r\nimport type { TabsHeadInjection, TabItemInstance } from './types';\r\nimport { windowInit } from './util/requestAnimationFrame';\r\n\r\n// 确保组件实例存在\r\nconst instance = getCurrentInstance();\r\nif (!instance) {\r\n  throw new Error('TabsHead 的 Vue 实例不存在，TabsHead 必须在 Vue 上下文环境中使用')\r\n}\r\n\r\n// import { defineComponent } from 'vue';\r\n/*\r\n\t适用于「选项式 API」，不适用于「组合式 API」。\r\n\t原因：\r\n\t\t1、若 defineComponent 不使用 export default 导出，则没有意义。\r\n\t\t2、但若使用 export default defineComponent，\r\n\t\t\t则会因为「组合式 API setup 语法」会隐式生成一个默认导出，而导致冲突，从而报编译错误。\r\n*/\r\n// export default defineComponent({\r\n//     name: 'TabsHead',\r\n// });\r\n\r\ndefineOptions({\r\n\t// 若不使用 defineOptions，组件的 name 选项将不会被识别。\r\n\t// 因为组合式 API setup 语法糖的组件，该组件的组件名称，是该组件实例的 `__name` 属性，属性值默认为（单文件独立组件的）文件名。\r\n\tname: 'TabsHead',\r\n});\r\n\r\nconst props = defineProps({\r\n\tmodelValue: {\r\n\t\ttype: [String, Number] as PropType<string | number>,\r\n\t\tdefault: '',\r\n\t},\r\n\tlineWidth: {\r\n\t\ttype: [Number, String] as PropType<number | string>,\r\n\t\tdefault: 30,\r\n\t},\r\n\tlineHeight: {\r\n\t\ttype: Number,\r\n\t\tdefault: 3,\r\n\t},\r\n\tactiveColor: {\r\n\t\ttype: String,\r\n\t\tdefault: '#1677ff',\r\n\t},\r\n\t// 近似等于超出边界时最大可拖动距离(px);\r\n\tadditionalX: {\r\n\t\ttype: Number,\r\n\t\tdefault: 50,\r\n\t},\r\n\t// 惯性回弹指数(值越大，幅度越大，惯性回弹距离越长);\r\n\treBoundExponent: {\r\n\t\ttype: Number,\r\n\t\tdefault: 10,\r\n\t\tvalidator(v: number) {\r\n\t\t\treturn v > 0;\r\n\t\t},\r\n\t},\r\n\t// 惯性滑动过程的持续时间，值越小，感知上阻力越大，可近似认为惯性滑动过程速度减为零所需的时间(ms);\r\n\tinertialDuration: {\r\n\t\ttype: Number,\r\n\t\tdefault: 1000,\r\n\t\tvalidator(v: number) {\r\n\t\t\treturn v > 0;\r\n\t\t},\r\n\t},\r\n\t// 回弹过程duration\r\n\treBoundingDuration: {\r\n\t\ttype: Number,\r\n\t\tdefault: 360,\r\n\t},\r\n});\r\n\r\n/* 验证：获取当前组件实例的名称，并输出到控制台 */\r\n// const instance = getCurrentInstance(); // 获取当前组件实例\r\n// const componentName = instance?.type.name; // 获取组件名称\r\n// console.log('componentName: ', componentName); // TabsHead\r\n\r\nconst emit = defineEmits(['update:modelValue', 'change']);\r\n\r\nlet refreshTask: Promise<void> | null = null;\r\nconst children: TabItemInstance[] = [];\r\n\r\n// refs\r\nconst viewAreaRef = ref<HTMLElement>() as Ref<HTMLElement>;\r\nconst listRef = ref<HTMLElement>() as Ref<HTMLElement>;\r\nconst activeValue = ref(props.modelValue);\r\nconst lineOffset = ref(0);\r\nconst activeLineWidth = ref(0);\r\n// 可视区宽度;\r\nconst viewAreaWidth = ref(0);\r\n// 可视区与可滑动元素宽度差值;\r\nconst offsetX = ref(0);\r\n// 滑动速度(正常滑动时一般不会超过 10);\r\nconst speed = ref(0);\r\n// 是否处于 touch 状态;\r\nconst touching = ref(false);\r\n// 是否处于回弹过程;\r\nconst reBounding = ref(false);\r\nconst translateX = ref(0);\r\nconst startX = ref(0);\r\nconst lastX = ref(0);\r\nconst currentX = ref(0);\r\nconst startMoveTime = ref(0);\r\nconst endMoveTime = ref(0);\r\n// 每个动画帧的 ms 数\r\nconst frameTime = ref(16.7);\r\nconst frameStartTime = ref(0);\r\nconst frameEndTime = ref(0);\r\nconst inertiaFrame = ref(0);\r\n// 当 speed 绝对值小于该值时认为速度为 0 (可用于控制惯性滚动结束期的顺滑度)\r\nconst zeroSpeed = ref(0.001);\r\n// 惯性滑动加速度;\r\nconst acceleration = ref(0.001);\r\n\r\nconst listStyle = computed(() => {\r\n\tconst duration = reBounding.value && !touching.value ? props.reBoundingDuration : 0;\r\n\r\n\treturn {\r\n\t\ttransitionTimingFunction: reBounding.value\r\n\t\t\t? 'cubic-bezier(0.25, 0.46, 0.45, 0.94)'\r\n\t\t\t: 'cubic-bezier(0.1, 0.57, 0.1, 1)',\r\n\t\ttransitionDuration: `${duration}ms`,\r\n\t\ttransform: `translate3d(${translateX.value}px, 0px, 0px)`,\r\n\t};\r\n});\r\n\r\nconst activeBarStyle = computed(() => {\r\n\treturn {\r\n\t\ttransition: `all 300ms`,\r\n\t\twidth: `${activeLineWidth.value}px`,\r\n\t\theight: `${props.lineHeight}px`,\r\n\t\ttransform: `translate3d(${lineOffset.value}px, 0, 0)`,\r\n\t\tbackgroundColor: props.activeColor,\r\n\t};\r\n});\r\n// 是否向左惯性滚动;\r\nconst isMoveLeft = computed(() => currentX.value <= startX.value);\r\n\r\nwatch(\r\n\t() => props.modelValue,\r\n\t(v) => {\r\n\t\tactiveValue.value = v;\r\n\t\trefreshState();\r\n\t}\r\n);\r\n\r\nconst refreshState = () => {\r\n\tif (refreshTask) {\r\n\t\treturn;\r\n\t}\r\n\r\n\t// 避免在单次事件循环中重复执行多次计算逻辑，造成不必要的性能浪费\r\n\trefreshTask = new Promise((resolve) => {\r\n\t\tnextTick(() => {\r\n\t\t\tresize();\r\n\t\t\tresolve();\r\n\t\t\trefreshTask = null;\r\n\t\t});\r\n\t});\r\n};\r\n\r\n/**\r\n * 设置激活值，供 TabItem 实例调用\r\n * @param {*} value\r\n */\r\nconst setActiveValue = (value: typeof props.modelValue): void => {\r\n\tactiveValue.value = value;\r\n\temit('update:modelValue', value);\r\n\temit('change', value);\r\n};\r\n\r\n/**\r\n * 供 TabItem 实例调用，用于注册 tab item\r\n */\r\nconst addItem = (tabItem: TabItemInstance): void => {\r\n\tchildren.push(tabItem);\r\n\trefreshState();\r\n};\r\n/**\r\n * 供 TabItem 实例调用，用于移除 tab item\r\n */\r\nconst removeItem = (tabItem: TabItemInstance): void => {\r\n\tconst index = children.findIndex((item) => item.name === tabItem.name);\r\n\tif (index === -1) return;\r\n\r\n\tchildren.splice(index, 1);\r\n\trefreshState();\r\n};\r\n\r\nconst injection: TabsHeadInjection = {\r\n\tactiveValue,\r\n\tactiveColor: toRef(props, 'activeColor'),\r\n\taddItem,\r\n\tremoveItem,\r\n\tsetActiveValue,\r\n\t// componentName: 'TabsHead',\r\n};\r\n\r\nprovide(tabsHeadInjectionKey, injection);\r\n\r\n/**\r\n * will be exposed\r\n */\r\nconst resize = () => {\r\n\t/*\r\n\t\tbugFix: \r\n\t\t\t路由切换到无 nav-tab 的页面时，触发 tab-item 的 onUnmounted 事件，\r\n\t\t\t最终会在 Promise 回调函数中调用的 nextTick 的回调函数中，执行 resize() 函数。\r\n\t\t\t即便 onUnmounted 是在组件 DOM 销毁前执行的，但是异步操作将导致 resize() 函数执行时机晚于组件 DOM 销毁，\r\n\t\t\t导致报错：\r\n\t\t\t\tUncaught (in promise) TypeError: Cannot read properties of null (reading 'offsetWidth')\r\n\t\t\t因此，这里添加判断，若组件 DOM 已销毁，则不执行后续逻辑，避免报错。\r\n\t*/\r\n\t// if(!viewAreaRef.value) return;\r\n\t// 增加组件实例检查\r\n\tif (!instance.isMounted || !viewAreaRef.value) return;\r\n\t// 重新计算可视区宽度\r\n\tviewAreaWidth.value = viewAreaRef.value.offsetWidth;\r\n\toffsetX.value = listRef.value.offsetWidth - viewAreaWidth.value;\r\n\tcheckPosition();\r\n\tcalcLineOffset();\r\n};\r\n\r\n/**\r\n * 如果需要回弹则进行回弹操作，并返回true;\r\n */\r\nconst reboundIfNeeded = () => {\r\n\treBounding.value = false;\r\n\tif (translateX.value > 0) {\r\n\t\treBounding.value = true;\r\n\t\ttranslateX.value = 0;\r\n\t} else if (translateX.value < -offsetX.value) {\r\n\t\treBounding.value = true;\r\n\t\ttranslateX.value = -offsetX.value;\r\n\t}\r\n\treturn reBounding.value;\r\n};\r\n\r\n/**\r\n * touch拖动\r\n */\r\nconst moveFollowTouch = () => {\r\n\t// 向左拖动\r\n\tif (isMoveLeft.value) {\r\n\t\tif (\r\n\t\t\t(translateX.value <= 0 && translateX.value + offsetX.value > 0) ||\r\n\t\t\ttranslateX.value > 0\r\n\t\t) {\r\n\t\t\ttranslateX.value += currentX.value - lastX.value;\r\n\t\t} else if (translateX.value + offsetX.value <= 0) {\r\n\t\t\ttranslateX.value +=\r\n\t\t\t\t(props.additionalX * (currentX.value - lastX.value)) /\r\n\t\t\t\t(viewAreaWidth.value + Math.abs(translateX.value + offsetX.value));\r\n\t\t}\r\n\t} else {\r\n\t\t// 向右拖动\r\n\t\tif (translateX.value >= 0) {\r\n\t\t\ttranslateX.value +=\r\n\t\t\t\t(props.additionalX * (currentX.value - lastX.value)) /\r\n\t\t\t\t(viewAreaWidth.value + translateX.value);\r\n\t\t} else if (\r\n\t\t\t(translateX.value <= 0 && translateX.value + offsetX.value >= 0) ||\r\n\t\t\ttranslateX.value + offsetX.value <= 0\r\n\t\t) {\r\n\t\t\ttranslateX.value += currentX.value - lastX.value;\r\n\t\t}\r\n\t}\r\n\tlastX.value = currentX.value;\r\n};\r\n\r\n/**\r\n * 惯性滑动\r\n */\r\nconst moveByInertia = () => {\r\n\tframeEndTime.value = Date.now();\r\n\tframeTime.value = frameEndTime.value - frameStartTime.value;\r\n\r\n\t// 向左惯性滑动;\r\n\tif (isMoveLeft.value) {\r\n\t\t// 超出边界的阶段;\r\n\t\tif (translateX.value <= -offsetX.value) {\r\n\t\t\t// 加速度指数变化;\r\n\t\t\tacceleration.value *=\r\n\t\t\t\t(props.reBoundExponent + Math.abs(translateX.value + offsetX.value)) /\r\n\t\t\t\tprops.reBoundExponent;\r\n\t\t\t// 为避免减速过程过短，此处加速度没有乘上frameTime;\r\n\t\t\tspeed.value = Math.min(speed.value - acceleration.value, 0);\r\n\t\t} else {\r\n\t\t\tspeed.value = Math.min(speed.value - acceleration.value * frameTime.value, 0);\r\n\t\t}\r\n\t} else {\r\n\t\t// 向右惯性滑动;\r\n\t\tif (translateX.value >= 0) {\r\n\t\t\tacceleration.value *= (props.reBoundExponent + translateX.value) / props.reBoundExponent;\r\n\t\t\tspeed.value = Math.max(speed.value - acceleration.value, 0);\r\n\t\t} else {\r\n\t\t\tspeed.value = Math.max(speed.value - acceleration.value * frameTime.value, 0);\r\n\t\t}\r\n\t}\r\n\ttranslateX.value += (speed.value * frameTime.value) / 2;\r\n\tif (Math.abs(speed.value) <= zeroSpeed.value) {\r\n\t\treboundIfNeeded();\r\n\t\treturn;\r\n\t}\r\n\tframeStartTime.value = frameEndTime.value;\r\n\tinertiaFrame.value = requestAnimationFrame(moveByInertia);\r\n};\r\n\r\n/**\r\n * 获取当前激活 item 的 dom 元素 $el\r\n */\r\nconst getActiveItemEl = () => {\r\n\tif (!children.length) {\r\n\t\treturn;\r\n\t}\r\n\tconst target = children.find((child) => child.name.value === activeValue.value);\r\n\treturn target && target.el.value;\r\n};\r\n\r\n/**\r\n * 计算activeBar的translateX\r\n */\r\nconst calcLineOffset = () => {\r\n\tconst itemEl = getActiveItemEl();\r\n\tif (!itemEl) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst itemWidth = itemEl.offsetWidth;\r\n\tconst itemLeft = itemEl.offsetLeft;\r\n\tconst { lineWidth } = props;\r\n\r\n\tif (lineWidth === 'auto') {\r\n\t\t// 等于当前激活item元素的宽度\r\n\t\tactiveLineWidth.value = itemWidth;\r\n\t} else if (Number(lineWidth) < 1) {\r\n\t\t// 0~1表示占当前激活item元素宽度的比例\r\n\t\tactiveLineWidth.value = itemWidth * (lineWidth as number);\r\n\t} else {\r\n\t\tactiveLineWidth.value = lineWidth as number;\r\n\t}\r\n\r\n\tlineOffset.value = itemLeft + (itemWidth - activeLineWidth.value) / 2;\r\n};\r\n\r\n/**\r\n * 点击切换item时，调整位置使当前item尽可能往中间显示\r\n */\r\nconst checkPosition = () => {\r\n\tconst activeItemEl = getActiveItemEl();\r\n\tif (!activeItemEl) {\r\n\t\treturn;\r\n\t}\r\n\tconst offsetLeft = activeItemEl.offsetLeft;\r\n\t// 让 activeItem 展示在正中间时，其距视图左右边距为 half\r\n\tconst half = (viewAreaWidth.value - activeItemEl.offsetWidth) / 2;\r\n\t// 在当前的translateX基础上需要调整的距离\r\n\tlet changeX = 0;\r\n\tconst absTransX = Math.abs(translateX.value);\r\n\r\n\t// item偏左，需要往右移（往中间靠）\r\n\tif (offsetLeft <= absTransX + half) {\r\n\t\t// 这种情况下translateX.value是负数\r\n\t\tchangeX = half - (offsetLeft + translateX.value);\r\n\t} else {\r\n\t\t// item偏右，需要往左移\r\n\t\tchangeX = -(offsetLeft - absTransX - half);\r\n\t}\r\n\tlet targetX = changeX + translateX.value;\r\n\t// 左边界\r\n\tif (targetX > 0) {\r\n\t\ttargetX = 0;\r\n\t}\r\n\t// 右边界\r\n\tif (targetX < -offsetX.value) {\r\n\t\ttargetX = -offsetX.value;\r\n\t}\r\n\treBounding.value = true;\r\n\ttranslateX.value = targetX;\r\n};\r\n\r\n/**\r\n * touchstart\r\n */\r\nconst handleTouchStart = (event: TouchEvent) => {\r\n\tevent.stopPropagation();\r\n\tcancelAnimationFrame(inertiaFrame.value);\r\n\tlastX.value = event.touches[0].clientX;\r\n};\r\n\r\n/**\r\n * touchmove\r\n */\r\nconst handleTouchMove = (event: TouchEvent) => {\r\n\tif (offsetX.value <= 0) {\r\n\t\treturn;\r\n\t}\r\n\tevent.preventDefault();\r\n\tevent.stopPropagation();\r\n\ttouching.value = true;\r\n\tstartMoveTime.value = endMoveTime.value;\r\n\tstartX.value = lastX.value;\r\n\tcurrentX.value = event.touches[0].clientX;\r\n\tmoveFollowTouch();\r\n\t// 此次touchmove事件触发的时间戳;\r\n\tendMoveTime.value = event.timeStamp;\r\n};\r\n\r\n/**\r\n * touchend\r\n * @param {*} event\r\n */\r\nconst handleTouchEnd = (event: TouchEvent) => {\r\n\ttouching.value = false;\r\n\tif (reboundIfNeeded()) {\r\n\t\tcancelAnimationFrame(inertiaFrame.value);\r\n\t} else {\r\n\t\tlet silenceTime = event.timeStamp - endMoveTime.value;\r\n\t\tlet timeStamp = endMoveTime.value - startMoveTime.value;\r\n\t\ttimeStamp = timeStamp > 0 ? timeStamp : 8;\r\n\r\n\t\t// 停顿时间超过100ms不产生惯性滑动;\r\n\t\tif (silenceTime > 100) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tspeed.value = (lastX.value - startX.value) / timeStamp;\r\n\t\tacceleration.value = speed.value / props.inertialDuration;\r\n\t\tframeStartTime.value = Date.now();\r\n\t\tinertiaFrame.value = requestAnimationFrame(moveByInertia);\r\n\t}\r\n};\r\n\r\nconst bindEvents = () => {\r\n\tconst el = viewAreaRef.value;\r\n\tel.addEventListener('touchstart', handleTouchStart, false);\r\n\tel.addEventListener('touchmove', handleTouchMove, false);\r\n\tel.addEventListener('touchend', handleTouchEnd, false);\r\n};\r\n\r\nconst removeEvents = () => {\r\n\tconst el = viewAreaRef.value;\r\n\tel.removeEventListener('touchstart', handleTouchStart);\r\n\tel.removeEventListener('touchmove', handleTouchMove);\r\n\tel.removeEventListener('touchend', handleTouchEnd);\r\n};\r\n\r\nonMounted(() => {\r\n\twindowInit();\r\n\tbindEvents();\r\n\trefreshState();\r\n});\r\n\r\nonBeforeUnmount(() => {\r\n\tremoveEvents();\r\n\r\n\t// 新增：取消未完成的异步操作\r\n\tif (refreshTask) refreshTask = null;\r\n  \tcancelAnimationFrame(inertiaFrame.value);\r\n});\r\n\r\ndefineExpose({\r\n\tresize,\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.tabs-head {\r\n\toverflow: hidden;\r\n\tposition: relative;\r\n\twidth: 100%;\r\n\tborder-bottom: 1px solid #eee;\r\n\tbackground: #fff;\r\n}\r\n\r\n.tabs-head__tab-list {\r\n\tposition: relative;\r\n\tdisplay: flex;\r\n\tflex-wrap: nowrap;\r\n\tmin-width: 100%;\r\n\twidth: min-content;\r\n}\r\n\r\n.tabs-head__active-line {\r\n\tposition: absolute;\r\n\tbottom: 3px;\r\n\tleft: 0;\r\n\twidth: 30px;\r\n\theight: 3px;\r\n\tborder-radius: 4px;\r\n}\r\n\r\n::v-slotted(.tabs-head .tab-item) {\r\n\tpadding: 10px 12px;\r\n\tflex: 1 1 auto;\r\n\tfont-size: 14px;\r\n\ttext-align: center;\r\n\twhite-space: nowrap;\r\n}\r\n</style>","<template>\r\n    <!-- <h1>TabsBottom</h1> -->\r\n    <div class=\"tabs-bottom\">\r\n        <div class=\"tabs-bottom-wrap\">\r\n            <slot />\r\n        </div>\r\n    </div>\r\n</template>\r\n\r\n<script lang=\"ts\" setup>\r\nimport { ref, toRef, watch, provide } from 'vue';\r\nimport { tabsBottomInjectionKey } from './injectionKeys';\r\nimport type { TabsBottomInjection } from './types';\r\n\r\ndefineOptions({\r\n    name: 'TabsBottom',\r\n});\r\n\r\nconst props = defineProps({\r\n    modelValue: {\r\n        type: [String, Number],\r\n        default: '',\r\n    },\r\n    activeColor: {\r\n        type: String,\r\n        default: '#1677ff',\r\n    },\r\n});\r\n\r\nconst emit = defineEmits(['update:modelValue', 'change']);\r\n\r\nconst activeValue = ref(props.modelValue);\r\n\r\nwatch(\r\n    () => props.modelValue,\r\n    (v) => {\r\n        activeValue.value = v;\r\n    }\r\n);\r\n\r\n/**\r\n * 设置激活值，供 TabItem 实例调用\r\n * @param {*} value\r\n */\r\nconst setActiveValue = (value: typeof props.modelValue): void => {\r\n    activeValue.value = value;\r\n    emit('update:modelValue', value);\r\n    emit('change', value);\r\n};\r\n\r\nconst injection: TabsBottomInjection = {\r\n    activeValue,\r\n    /*\r\n        toRef(reactiveObject, propsName) ：\r\n            toRef 函数，会将响应式对象（即参数1）的某个属性（即参数2）转换为 ref 对象，同时保持与源属性的响应式连接。\r\n        反例：\r\n            // ❌ 错误写法：解构出来的属性，会失去响应性\r\n            const { activeColor } = props;\r\n    */\r\n    // 保持对 props.activeColor 的响应式引用\r\n    activeColor: toRef(props, 'activeColor'),\r\n    setActiveValue,\r\n    // componentName: 'TabsBottom',\r\n};\r\n\r\nprovide(tabsBottomInjectionKey, injection);\r\n\r\n</script>\r\n\r\n<style scoped>\r\n.tabs-bottom-wrap {\r\n\tdisplay: flex;\r\n\tflex-wrap: nowrap;\r\n\talign-items: stretch;\r\n\tmin-height: 50px;\r\n\tbackground: #fff;\r\n}\r\n\r\n::v-slotted(.tabs-bottom .tab-item) {\r\n\tflex: 1 1;\r\n\tfont-size: 12px;\r\n}\r\n\r\n::v-slotted(.tabs-bottom .tab-item__badge) {\r\n\ttop: 2px;\r\n\tright: 0;\r\n}\r\n</style>","<template>\r\n    <!-- <h1>TabItem</h1> -->\r\n    <div ref=\"el\" :style=\"style\" class=\"tab-item\" @click=\"handleClick\">\r\n        <div class=\"tab-item__wrap\">\r\n            <slot name=\"icon\" />\r\n            <div class=\"tab-item__label\">\r\n                <slot>{{ title }}</slot>\r\n            </div>\r\n            <div v-if=\"badge\" class=\"tab-item__badge\">\r\n                {{ badge }}\r\n            </div>\r\n        </div>\r\n    </div>\r\n</template>\r\n\r\n<script lang=\"ts\" setup>\r\nimport { ref, computed, inject, onMounted, onUnmounted, toRef } from 'vue';\r\nimport type { TabsHeadInjection, TabsBottomInjection, TabItemInstance } from './types';\r\nimport { tabsHeadInjectionKey, tabsBottomInjectionKey } from './injectionKeys';\r\n\r\ndefineOptions({\r\n    name: 'TabItem',\r\n})\r\n\r\nconst props = defineProps({\r\n    title: String,\r\n    name: [String, Number],\r\n    badge: [String, Number],\r\n});\r\n\r\n/*\r\n    设默认值，且默认值要被判定为 false 。\r\n    目的：\r\n        1、不设默认值，当 TabsBottom 组件引用 TabItem 组件时，\r\n            问题描述：\r\n                const injection = inject<TabsHeadInjection>(tabsHeadInjectionKey) || inject<TabsBottomInjection>(tabsBottomInjectionKey); \r\n                在前面 tabsHeadInjectionKey 的 inject 不存在时，会有警告：\r\n\r\n                    [Vue warn]: injection \"Symbol(tabsHeadInjectionKey)\" not found. \r\n                    at <TabItem key=\"find\" title=\"发现\" name=\"find\"  ... > \r\n                    at <TabsBottom modelValue=\"home\" onUpdate:modelValue=fn onChange=fn<handleTabsBottomChange> > \r\n                    at <App>\r\n                    runtime-core.esm-bundler.js:51\r\n                    [Vue warn]: injection \"Symbol(tabsHeadInjectionKey)\" not found. \r\n                    at <TabItem key=\"mine\" title=\"我\" name=\"mine\"  ... > \r\n                    at <TabsBottom modelValue=\"home\" onUpdate:modelValue=fn onChange=fn<handleTabsBottomChange> > \r\n                    at <App>\r\n        2、默认值设为 null ，是为了触发逻辑或的 `||` 的短路原则\r\n*/\r\n// 自动识别注入源 ★★★\r\nconst injection = inject<TabsHeadInjection | null>(tabsHeadInjectionKey, null) || inject<TabsBottomInjection | null>(tabsBottomInjectionKey, null);\r\n\r\nif (!injection || !injection.activeValue || !injection.activeColor || !injection.setActiveValue) {\r\n    throw new Error('Injection Error: TabItem must be used in TabsHead or TabsBottom, please check the injection source.');\r\n}\r\n\r\nconst el = ref();\r\nconst style = computed(() => {\r\n    return injection?.activeValue.value ===\r\n        props.name ? {\r\n            color: injection?.activeColor.value,\r\n        } : {};\r\n});\r\nconst handleClick = () => {\r\n    injection?.setActiveValue(props.name);\r\n};\r\n\r\nconst instance: TabItemInstance = {\r\n    name: toRef(props, 'name'),\r\n    el,\r\n};\r\n\r\nonMounted(() => {\r\n    (injection as TabsHeadInjection).addItem?.(instance);\r\n});\r\nonUnmounted(() => {\r\n    (injection as TabsHeadInjection).removeItem?.(instance);\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.tab-item {\r\n    display: flex;\r\n    flex-direction: column;\r\n    justify-content: center;\r\n    align-items: center;\r\n}\r\n\r\n.tab-item__wrap {\r\n    position: relative;\r\n}\r\n\r\n.tab-item__badge {\r\n    position: absolute;\r\n    top: 4px;\r\n    right: -10px;\r\n    padding: 0 4px;\r\n    min-width: 8px;\r\n    height: 14px;\r\n    font-size: 9px;\r\n    line-height: 14px;\r\n    color: #fff;\r\n    background: #ff411c;\r\n    white-space: nowrap;\r\n    border-radius: 100px;\r\n    transform: translate(50%, -50%);\r\n    text-align: center;\r\n}\r\n</style>","import type { App, Component } from \"vue\";\r\n\r\nimport TabsHead from \"./TabsHead.vue\";\r\nimport TabsBottom from \"./TabsBottom.vue\";\r\nimport TabItem from \"./TabItem.vue\";\r\n\r\nconst components: Component[] = [TabsHead, TabsBottom, TabItem];\r\n\r\n// 定义「全局注册组件」回调函数，接收 Vue 实例作为参数，外部应用在执行 `app.use(当前插件库)` 时调用\r\nconst install = (app: App): void => {\r\n  components.forEach((component: Component) => {\r\n    console.log('component: ', component);\r\n    if (component.name) {\r\n      app.component(component.name, component);\r\n    } else {\r\n      throw new Error(`Component has no name: ${component}`);\r\n    }\r\n  });\r\n};\r\n\r\n// 默认导出 install，以供外部应用「全局注册」当前插件库\r\nexport default { install };\r\n\r\n// 命名导出，以供外部应用「按需导入」当前插件库的组件\r\nexport { TabsHead, TabsBottom, TabItem };\r\n"],"names":["tabsHeadInjectionKey","tabsBottomInjectionKey","win","windowInit","lastTime","vendors","x","callback","currTime","interval","timeToCall","id","instance","getCurrentInstance","props","__props","emit","__emit","refreshTask","children","viewAreaRef","ref","listRef","activeValue","lineOffset","activeLineWidth","viewAreaWidth","offsetX","speed","touching","reBounding","translateX","startX","lastX","currentX","startMoveTime","endMoveTime","frameTime","frameStartTime","frameEndTime","inertiaFrame","zeroSpeed","acceleration","listStyle","computed","duration","activeBarStyle","isMoveLeft","watch","v","refreshState","resolve","nextTick","resize","setActiveValue","value","addItem","tabItem","removeItem","index","item","injection","toRef","provide","checkPosition","calcLineOffset","reboundIfNeeded","moveFollowTouch","moveByInertia","getActiveItemEl","target","child","itemEl","itemWidth","itemLeft","lineWidth","activeItemEl","offsetLeft","half","changeX","absTransX","targetX","handleTouchStart","event","handleTouchMove","handleTouchEnd","silenceTime","timeStamp","bindEvents","el","removeEvents","onMounted","onBeforeUnmount","__expose","inject","style","handleClick","onUnmounted","components","TabsHead","TabsBottom","TabItem","install","app","component"],"mappings":"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"}