修改带单位的输入框组件,解决转换精度问题。

This commit is contained in:
廖德云 2025-02-16 00:20:25 +08:00
parent c7b4db67bf
commit a57f1d6b6d
10 changed files with 869 additions and 339 deletions

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询单位换算列表
export function listSysUnitConvert(query) {
return request({
url: '/system/sysUnitConvert/list',
method: 'get',
params: query
})
}
// 查询单位换算详细
export function getSysUnitConvert(id) {
return request({
url: '/system/sysUnitConvert/' + id,
method: 'get'
})
}
// 新增单位换算
export function addSysUnitConvert(data) {
return request({
url: '/system/sysUnitConvert',
method: 'post',
data: data
})
}
// 修改单位换算
export function updateSysUnitConvert(data) {
return request({
url: '/system/sysUnitConvert',
method: 'put',
data: data
})
}
// 删除单位换算
export function delSysUnitConvert(id) {
return request({
url: '/system/sysUnitConvert/' + id,
method: 'delete'
})
}

View File

@ -1,43 +1,84 @@
<template>
<view class="content">
<image class="logo" src="@/static/logo.png"></image>
<view class="text-area">
<text class="title">Hello RuoYi</text>
</view>
</view>
</template>
<script>
export default {
onLoad: function() {
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
<template>
<view class="content">
<image class="logo" src="@/static/logo.png"></image>
{{ 'initialValue' + initialValue }}
{{ 'newValue' + newValue }}
{{ 'oldUnit' + oldUnit }}
{{ 'newUnit' + newUnit }}
{{ 'oldOrder' + oldOrder }}
{{ 'newOrder' + newOrder }}
<view class="text-area">
<yjly-inputunit
v-model="mylength"
:unit-type="'length'"
:unit-order.sync="myunitname"
:show-english-only="false"
:decimal-places="5"
:width="200"
:style="{ width: 200 + 'px' }"
@conversion="onchange"
></yjly-inputunit>
<text class="title">Hello RuoYi</text>
</view>
</view>
</template>
<script>
export default {
onLoad: function () {},
data() {
return {
mylength: 10,
myunitname: 1,
initialValue: 0,
newValue: 0,
oldUnit: '',
newUnit: '',
oldOrder: 0,
newOrder: 0
};
},
methods: {
onchange(e) {
this.initialValue = e.initialValue;
this.newValue = e.newValue;
this.oldUnit = e.oldUnit;
this.newUnit = e.newUnit;
this.oldOrder = e.oldOrder;
this.newOrder = e.newOrder;
}
}
};
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>

View File

@ -0,0 +1,6 @@
## 1.0.22025-02-19
修改单位转换精度,将原始单位和值暂存,换算到基准单位值,再换算到新单位值。
## 1.0.12025-02-15
修改单位类型默认值
## 1.0.02025-02-15
1.0.0

View File

@ -0,0 +1,430 @@
<template>
<view class="unit-converter" :style="{ width: width + 'px' }">
<!-- 数值输入框 -->
<input
v-model.number="inputValue"
class="input-field"
type="number"
:ref="'inputRef'"
:style="{
width: inputWidth + 'px',
height: height + 'px',
lineHeight: height + 'px'
}"
@input="handleInputChange"
/>
<!-- 单位标签 -->
<view
v-if="enableConvert"
:ref="'unitLabel'"
class="unit-label"
:style="{
color: 'blue',
height: height + 'px',
lineHeight: height + 'px'
}"
@tap="cycleUnit"
@longpress="handleLongPress"
>
{{ textUnitName }}
</view>
<view
v-else
class="unit-label"
:style="{
color: 'blue',
height: height + 'px',
lineHeight: height + 'px'
}"
>
{{ textUnitName }}
</view>
<!-- 单位选择弹出窗口 -->
<view
v-if="showUnitSelector"
class="unit-selector"
:style="{
left: unitSelectorLeft + 'px',
top: unitSelectorTop + 'px'
}"
>
<scroll-view scroll-y :style="{ maxHeight: '200px' }">
<view v-for="unit in sortedUnits" :key="unit.id" class="unit-option" @tap="selectUnit(unit)">
{{ showEnglishOnly ? unit.unitName.split('(')[0] : unit.unitName }}
</view>
</scroll-view>
</view>
</view>
</template>
<script>
// Vue2/Vue3
import unitDatalist from './yjlyUnitData';
export default {
name: 'UniUnitConverter',
emits: ['input', 'update:unitOrder', 'conversion'],
props: {
unitType: {
type: String,
required: true,
default: 'length'
},
unitOrder: {
type: Number,
default: 0
},
value: {
type: Number,
required: true
},
showEnglishOnly: {
type: Boolean,
default: false
},
decimalPlaces: {
type: Number,
default: 5,
validator: (v) => v >= 0 && v <= 10
},
width: {
type: Number,
default: 180
},
height: {
type: Number,
default: 32
},
enableConvert: {
type: Boolean,
default: true
},
userDefined: {
type: Boolean,
default: false
},
userDefinedunitName: {
type: String,
default: ''
}
},
data() {
return {
inputValue: this.value,
unitData: [],
showUnitSelector: false,
currentUnit: null,
baseUnit: null,
inputWidth: 100,
textUnitName: '',
unitSelectorLeft: 0,
unitSelectorTop: 0,
/* 新增三个数据项 */
originalValue: this.value, //
originalUnit: null, //
isInternalUpdate: false //
};
},
mounted() {
this.initComponent();
this.setGlobalClickHandler();
},
beforeDestroy() {
this.removeGlobalClickHandler();
unitOrder;
},
computed: {
sortedUnits() {
return this.unitData.filter((u) => u.unitType === this.unitType).sort((a, b) => a.unitOrder - b.unitOrder);
}
},
watch: {
unitType: {
immediate: true,
async handler(newType) {
if (this.userDefined) {
this.textUnitName = this.userDefinedunitName;
this.$nextTick(() => this.updateInputWidth());
} else {
await this.loadUnits(newType);
this.initCurrentUnit();
}
}
},
unitOrder(newOrder) {
if (this.userDefined) {
this.textUnitName = this.userDefinedunitName;
this.$nextTick(() => this.updateInputWidth());
} else {
const target = this.sortedUnits.find((u) => u.unitOrder === newOrder);
if (target) {
this.currentUnit = target;
this.textUnitName = this.showEnglishOnly ? target.unitName.split('(')[0].trim() : target.unitName;
this.$nextTick(() => this.updateInputWidth());
}
}
},
value(newVal) {
if (!this.isInternalUpdate) {
//
this.originalValue = newVal;
this.originalUnit = this.currentUnit;
this.inputValue = newVal;
}
this.isInternalUpdate = false;
}
},
methods: {
async initComponent() {
await this.$nextTick();
this.updateInputWidth();
},
setGlobalClickHandler() {
if (typeof document !== 'undefined') {
document.addEventListener('click', this.handleClickOutside);
}
},
removeGlobalClickHandler() {
if (typeof document !== 'undefined') {
document.removeEventListener('click', this.handleClickOutside);
}
},
handleClickOutside(event) {
if (!this.showUnitSelector) return;
const selector = this.$refs.unitSelector;
if (!selector) return;
const isOutside = !selector.$el.contains(event.target);
if (isOutside) {
this.showUnitSelector = false;
}
},
async loadUnits(unitType) {
try {
// APIjs
// const res = await listSysUnitConvert({ unitType: unitType, status: 'Y' });
// this.unitData = res.rows;
this.unitData = unitDatalist[unitType];
console.log(this.unitData);
this.baseUnit = this.unitData.find((u) => u.baseUnit === 'Y');
console.log(this.baseUnit);
} catch (e) {
console.error('单位数据加载失败:', e);
}
},
/* 初始化当前单位补充 */
initCurrentUnit() {
const target = this.sortedUnits.find((u) => u.unitOrder === this.unitOrder);
this.currentUnit = target || this.baseUnit || this.sortedUnits[0];
//
this.originalUnit = this.currentUnit;
this.textUnitName = this.showEnglishOnly ? this.currentUnit.unitName.split('(')[0].trim() : this.currentUnit.unitName;
this.$nextTick(() => this.updateInputWidth());
},
updateInputWidth() {
const query = uni.createSelectorQuery().in(this);
query
.select('.unit-label')
.boundingClientRect((res) => {
if (res) {
this.inputWidth = this.width - res.width - 4;
}
})
.exec();
},
handleLongPress() {
this.toggleUnitSelector();
this.positionUnitSelector();
},
positionUnitSelector() {
const query = uni.createSelectorQuery().in(this);
query
.select('.unit-label')
.boundingClientRect((res) => {
if (res) {
this.unitSelectorLeft = res.left;
this.unitSelectorTop = res.bottom + 5;
}
})
.exec();
},
/* 修改单位切换方法 */
cycleUnit() {
const index = this.sortedUnits.findIndex((u) => u === this.currentUnit);
const newUnit = this.sortedUnits[(index + 1) % this.sortedUnits.length];
this.currentUnit = newUnit;
this.textUnitName = this.showEnglishOnly ? newUnit.unitName.split('(')[0].trim() : newUnit.unitName;
this.$nextTick(() => {
this.updateInputWidth();
this.convertAndEmit();
});
},
toggleUnitSelector() {
this.showUnitSelector = !this.showUnitSelector;
if (this.showUnitSelector) {
this.positionUnitSelector();
}
},
/* 修改单位选择方法 */
selectUnit(unit) {
this.currentUnit = unit;
this.showUnitSelector = false;
this.$nextTick(() => {
this.updateInputWidth();
this.convertAndEmit();
});
},
/* 修改输入处理 */
handleInputChange() {
//
this.originalValue = this.inputValue;
this.originalUnit = this.currentUnit;
this.$emit('input', this.inputValue);
},
/* 优化后的转换方法 */
convertAndEmit() {
if (!this.currentUnit || !this.baseUnit || !this.originalUnit) return;
let newValue = 0;
if (this.unitType === 'temperature') {
newValue = this.handleTemperatureConversion();
} else {
//
const baseValue = this.originalValue / this.originalUnit.conversionFactor;
newValue = baseValue * this.currentUnit.conversionFactor;
}
const roundedValue = this.roundValue(newValue);
this.isInternalUpdate = true; //
this.inputValue = roundedValue;
this.$emit('input', roundedValue);
this.$emit('update:unitOrder', this.currentUnit.unitOrder);
this.$emit('conversion', {
initialValue: this.originalValue,
newValue: roundedValue,
oldUnit: this.originalUnit.unitName,
newUnit: this.currentUnit.unitName,
oldOrder: this.originalUnit.unitOrder,
newOrder: this.currentUnit.unitOrder
});
},
/* 优化温度转换方法 */
handleTemperatureConversion() {
const oldUnit = this.originalUnit;
const newUnit = this.currentUnit;
const oldOrder = oldUnit.unitOrder;
const newOrder = newUnit.unitOrder;
// 使
let celsius;
switch (oldOrder) {
case 0:
celsius = this.originalValue;
break;
case 1:
celsius = ((this.originalValue - 32) * 5) / 9;
break;
case 2:
celsius = this.originalValue - 273.15;
break;
default:
throw new Error('无效温度单位');
}
switch (newOrder) {
case 0:
return celsius;
case 1:
return (celsius * 9) / 5 + 32;
case 2:
return celsius + 273.15;
default:
throw new Error('无效温度单位');
}
},
//
roundValue(value) {
const multiplier = Math.pow(10, this.decimalPlaces);
const val = value * multiplier;
const intVal = Math.trunc(val);
const decimalPart = val - intVal;
if (decimalPart < 0.5) {
return intVal / multiplier;
} else if (decimalPart > 0.5) {
return (intVal + 1) / multiplier;
} else {
return intVal % 2 === 0 ? intVal / multiplier : (intVal + 1) / multiplier;
}
}
}
};
</script>
<style scoped>
.unit-converter {
display: flex;
align-items: center;
position: relative;
}
.input-field {
border: 1px solid #d6d5d5;
border-radius: 4px;
font-size: 14px;
padding: 0 8px;
}
.unit-label {
display: inline-flex;
align-items: center;
padding: 0 10px;
border: 1px solid #d6d5d5;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
margin-left: 2px;
}
.unit-selector {
position: fixed;
z-index: 9999;
background-color: #ffffff;
border: 1px solid #cccccc;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
min-width: 120px;
}
.unit-option {
padding: 8px 12px;
font-size: 14px;
}
.unit-option:hover {
background-color: #f0f0f0;
}
scroll-view {
max-height: 200px;
}
</style>

View File

@ -0,0 +1,122 @@
const unitData = {
pressure: [{
"id": 66,
"unitType": "pressure",
"unitName": "Pa(帕斯卡)",
"baseUnit": "Y",
"conversionFactor": 1,
"unitTypeName": "压力",
"status": "Y",
"unitOrder": 0
},
{
"id": 67,
"unitType": "pressure",
"unitName": "kPa(千帕)",
"baseUnit": "N",
"conversionFactor": 0.001,
"unitTypeName": "压力",
"status": "Y",
"unitOrder": 1
},
{
"id": 68,
"unitType": "pressure",
"unitName": "MPa(兆帕)",
"baseUnit": "N",
"conversionFactor": 0.000001,
"unitTypeName": "压力",
"status": "Y",
"unitOrder": 2
},
{
"id": 69,
"unitType": "pressure",
"unitName": "atm(标准大气压)",
"baseUnit": "N",
"conversionFactor": 0.0000098692326671601,
"unitTypeName": "压力",
"status": "Y",
"unitOrder": 3
},
{
"id": 70,
"unitType": "pressure",
"unitName": "bar(巴)",
"baseUnit": "N",
"conversionFactor": 0.00001,
"unitTypeName": "压力",
"status": "Y",
"unitOrder": 4
},
{
"id": 71,
"unitType": "pressure",
"unitName": "mbar(毫巴)",
"baseUnit": "N",
"conversionFactor": 0.01,
"unitTypeName": "压力",
"status": "Y",
"unitOrder": 5
}
],
length: [{
"id": 1,
"unitType": "length",
"unitName": "m(米)",
"baseUnit": "Y",
"conversionFactor": 1,
"unitTypeName": "长度",
"status": "Y",
"unitOrder": 0
},
{
"id": 2,
"unitType": "length",
"unitName": "dm(分米)",
"baseUnit": "N",
"conversionFactor": 10,
"unitTypeName": "长度",
"status": "Y",
"unitOrder": 1
},
{
"id": 3,
"unitType": "length",
"unitName": "cm(厘米)",
"baseUnit": "N",
"conversionFactor": 100,
"unitTypeName": "长度",
"status": "Y",
"unitOrder": 2
},
{
"id": 4,
"unitType": "length",
"unitName": "mm(毫米)",
"baseUnit": "N",
"conversionFactor": 1000,
"unitTypeName": "长度",
"status": "Y",
"unitOrder": 3
},
{
"id": 5,
"unitType": "length",
"unitName": "km(千米)",
"baseUnit": "N",
"conversionFactor": 0.001,
"unitTypeName": "长度",
"status": "Y",
"unitOrder": 4
}
]
}
export default unitData;

View File

@ -1,14 +1,15 @@
{
"id": "yjly-number_unit",
"displayName": "yjly-number_unit",
"version": "1.0.0",
"description": "yjly-number_unit",
"id": "yjly-inputunit",
"displayName": "单位转换组件,双向数值绑定,单位循环切换、弹窗选择,支持自定义单位显示",
"version": "1.0.2",
"description": "单位转换组件 支持双向数值绑定 内置单位换算逻辑 支持单位循环切换/弹窗选择两种模式 兼容 Vue2/Vue3 和 UniApp 多平台 支持自定义单位显示 可配置小数位数精度",
"keywords": [
"yjly-number_unit"
"单位转换组件",
"双向数值绑定",
"自定义单位显示"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
"engines": {
},
"dcloudext": {
"type": "component-vue",
@ -24,9 +25,9 @@
"qq": ""
},
"declaration": {
"ads": "",
"data": "",
"permissions": ""
"ads": "",
"data": "",
"permissions": ""
},
"npmurl": ""
},
@ -35,36 +36,37 @@
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u",
"alipay": "u"
"tcb": "y",
"aliyun": "y",
"alipay": "y"
},
"client": {
"Vue": {
"vue2": "u",
"vue3": "u"
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "u",
"app-nvue": "u",
"app-uvue": "u"
"app-vue": "y",
"app-nvue": "u",
"app-uvue": "u",
"app-harmony": "u"
},
"H5-mobile": {
"Safari": "u",
"Android Browser": "u",
"微信浏览器(Android)": "u",
"QQ浏览器(Android)": "u"
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "u",
"Chrome": "y",
"IE": "u",
"Edge": "u",
"Edge": "y",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "u",
"阿里": "u",
"微信": "y",
"阿里": "y",
"百度": "u",
"字节跳动": "u",
"QQ": "u",

View File

@ -0,0 +1,158 @@
# yjyl-input-unit 单位转换组件使用说明
功能特性
支持双向数值绑定
内置单位换算逻辑(含温度特殊处理)
支持单位循环切换/弹窗选择两种模式
兼容 Vue2/Vue3 和 UniApp 多平台
支持自定义单位显示
可配置小数位数精度
符合uni-modules标准直接使用
Props 配置
|属性名 |类型 |必填 |默认值 |说明 |
|:-: |:-: |:-: |:-: |:-: |
|unitType |String |是 |- |单位类型(例:'length', 'weight', 'temperature' |
|unitOrder |Number |否 |0 |当前单位序号(需配合 .sync 修饰符使用) |
|value |Number |是 |- |输入数值(使用 v-model 双向绑定) |
|showEnglishOnly |Boolean|否 |false |是否只显示英文单位(例:'kg' 代替 ' 千克 (kg)' |
|decimalPlaces |Number |否 |5 |小数位数0 - 10 |
|width |Number |否 |180 |组件总宽度px |
|height |Number |否 |32 |组件高度px |
|enableConvert |Boolean|否 |true |是否允许单位转换 |
|userDefined |Boolean|否 |false |是否使用自定义单位 |
|userDefinedunitName|String |否 |'' |自定义单位显示名称(需 userDefined = true 生效) |
事件说明
| 事件名称 | 说明 | 回调参数 |
| input | 数值变化时触发 | (newValue: number) |
| update:unitOrder | 单位序号变化时触发 | (newOrder: number) |
| conversion | 完成单位转换时触发 | { initialValue, newValue, oldUnit, newUnit, oldOrder, newOrder } 的 Object |
使用示例
基本用法
vue
<template>
<UniUnitConverter
v-model="value"
:unit-type="length"
:unit-order.sync="currentOrder"
/>
</template>
<script>
export default {
data() {
return {
value: 100,
currentOrder: 0
}
}
}
</script>
禁用转换模式
<UniUnitConverter
v-model="fixedValue"
:unit-type="weight"
:enable-convert="false"
user-defined
:user-definedunit-name="'特殊单位'"
/>
事件处理
vue
复制
<template>
<UniUnitConverter
v-model="tempValue"
:unit-type="temperature"
@conversion="handleConversion"
/>
</template>
<script>
export default {
methods: {
handleConversion({ oldUnit, newUnit, newValue }) {
console.log(`单位从 ${oldUnit} 转换为 ${newUnit},新值:${newValue}`)
}
}
}
</script>
API 需自己开发按照下面的数据格式进行组织参考unitData.js
组件依赖 listSysUnitConvert API 获取单位数据,需实现以下格式的接口:
javascript
{
rows: [
{
id: 1,
unitType: 'length',
unitName: '米(m)',
conversionFactor: 1,
baseUnit: 'Y',
unitOrder: 0
},
// ...其他单位数据
]
}
样式调整
可通过以下 CSS 类名自定义样式:
.unit-converter - 组件容器
.input-field - 输入框
.unit-label - 单位标签
.unit-selector - 单位选择器
.unit-option - 单位选项
平台差异
小程序端使用 longpress 事件触发选择器(长按代替双击)
H5 端自动适配点击事件
单位转换规则
温度单位需按约定顺序定义:
javascript
复制
[
{ unitOrder: 0, unitName: '℃' }, // 摄氏度
{ unitOrder: 1, unitName: '℉' }, // 华氏度
{ unitOrder: 2, unitName: 'K' } // 开尔文
]
自定义单位时需确保与现有换算逻辑兼容
常见问题
Q1: 单位选择器不显示
检查 enableConvert 是否为 true
确认单位数据加载成功
查看控制台是否有 API 错误
Q2: 数值更新不及时
确保使用 v-model 进行双向绑定
检查小数位数配置是否符合预期
确认没有在父组件中覆盖转换后的值
Q3: 样式显示异常
检查是否父容器有冲突的布局样式
确认单位标签宽度计算正确(通过 updateInputWidth 方法)
在小程序端添加 !important 覆盖默认样式

View File

@ -1,272 +0,0 @@
<template>
<view class="unit-converter">
<!-- 数值输入框 -->
<input v-model="inputValue" type="number" @input="handleInputChange" class="input-field" :style="{ width: width + 'px' }" />
<!-- 单位标签 -->
<text @click="toggleUnit" @dblclick="openUnitSelector" class="unit-label" :style="{ color: 'blue' }">
{{ displayUnitName }}
</text>
<!-- 单位选择弹出窗口 -->
<!-- uni-popup 弹窗 -->
<uni-popup ref="unitSelectorPopup" type="bottom" :show="showUnitSelector" @close="onPopupClose">
<view class="unit-selector">
<view v-for="unit in filteredUnitList" :key="unit.id" @click="selectUnit(unit)" class="unit-option">
{{ showEnglishOnly ? unit.unitName.split('(')[0] : unit.unitName }}
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import { listConversion } from '@/api/system/conversion.js';
export default {
props: {
//
unitType: {
type: String,
default: 'length'
},
//
showEnglishOnly: {
type: Boolean,
default: false
},
//
unitName: {
type: String,
required: false,
default: ''
},
//
value: {
type: Number,
required: true
},
//
decimalPlaces: {
type: Number,
default: 2
},
width: {
type: Number,
required: false,
default: 80
}
},
data() {
return {
inputValue: this.value, //
currentUnit: null, //
unitList: [], //
showUnitSelector: false //
};
},
onLoad() {
//
uni.$on('globalClick', this.handleClickOutside);
},
onUnload() {
//
uni.$off('globalClick', this.handleClickOutside);
},
computed: {
//
displayUnitName() {
if (!this.currentUnit) return '';
return this.showEnglishOnly ? this.currentUnit.unitName.split('(')[0] : this.currentUnit.unitName;
},
//
filteredUnitList() {
return this.unitList.filter((unit) => unit.unitName !== this.currentUnit?.unitName);
}
},
watch: {
// unitType
unitType: {
immediate: true,
handler(newVal) {
this.loadUnitList(newVal);
}
},
// unitName
unitName: {
immediate: true,
handler(newVal) {
console.log(newVal);
this.currentUnit = this.unitList.find((unit) => unit.unitName == newVal);
}
},
// value
value: {
immediate: true,
handler(newVal) {
this.inputValue = newVal;
}
}
},
methods: {
//
handleClickOutside(event) {
if (this.$refs.unitSelector && !this.$refs.unitSelector.contains(event.target)) {
this.showUnitSelector = false;
}
},
//
toggleUnitSelector() {
this.showUnitSelector = !this.showUnitSelector;
},
//
async loadUnitList(unitType) {
try {
const response = await listConversion({ pageSize: 100, unitType: unitType });
console.log(response);
this.unitList = response.rows;
if (this.unitName == '') {
//
this.currentUnit = this.unitList.find((unit) => unit.baseUnit == 1);
console.log(this.currentUnit);
} else {
this.currentUnit = this.unitList.find((unit) => unit.unitName == this.unitName);
console.log(this.currentUnit);
if (this.currentUnit === undefined) {
this.currentUnit = this.unitList.find((unit) => unit.baseUnit === 1);
}
}
} catch (error) {
console.error('Failed to load unit list:', error);
}
},
//
handleInputChange() {
this.$emit('input', this.inputValue); //
this.convertAndEmit();
},
//
toggleUnit() {
const currentIndex = this.unitList.indexOf(this.currentUnit);
const nextIndex = (currentIndex + 1) % this.unitList.length;
let oldUnit = this.currentUnit;
let newUnit = this.unitList[nextIndex];
this.currentUnit = newUnit;
// console.log('', currentIndex, nextIndex, this.currentUnit);
this.convertAndEmit(oldUnit, newUnit);
},
//
openUnitSelector() {
this.showUnitSelector = true;
},
//
selectUnit(unit) {
console.log('所选择的单位', unit);
let oldUnit = this.currentUnit;
let newUnit = unit;
this.currentUnit = unit;
this.showUnitSelector = false;
this.convertAndEmit(oldUnit, newUnit);
},
//
convertAndEmit(oldUnit, newUnit) {
if (!newUnit) return;
//
const baseUnit = this.unitList.find((unit) => unit.baseUnit === 1);
if (!baseUnit) return;
//
const baseValue = this.inputValue / oldUnit.conversionFactor;
//
const newValue = baseValue * newUnit.conversionFactor;
console.log('转换值', newUnit.unitName, this.inputValue, baseValue, newValue);
let roundedValue;
if (newUnit.unitName === 'ly(光年)') {
// 使
roundedValue = newValue.toExponential();
} else {
roundedValue = this.roundToDecimalPlaces(newValue);
}
//
this.$emit('conversion', {
initialValue: this.inputValue,
newValue: roundedValue,
oldUnit: oldUnit.unitName,
newUnit: newUnit.unitName
});
this.inputValue = parseFloat(roundedValue);
// unitName
this.$emit('update:unitName', this.currentUnit.unitName);
},
//
// conversionFactor
roundToDecimalPlaces(value) {
const multiplier = Math.pow(10, this.decimalPlaces);
const val = value * multiplier;
const intVal = Math.trunc(val);
const decimalPart = val - intVal;
if (decimalPart < 0.5) {
return intVal / multiplier;
} else if (decimalPart > 0.5) {
return (intVal + 1) / multiplier;
} else {
return intVal % 2 === 0 ? intVal / multiplier : (intVal + 1) / multiplier;
}
}
}
};
</script>
<style scoped>
.unit-converter {
display: flex;
align-items: center;
gap: 10px;
position: relative;
}
.input-field {
padding: 2px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
}
.unit-label {
cursor: pointer;
font-weight: bold;
font-size: 12px;
}
.unit-selector {
/* 设置容器的最大高度,当内容超出这个高度时会出现滚动条 */
max-height: 200px;
/* 超出内容时显示纵向滚动条 */
overflow-y: auto;
/* 横向内容不溢出,隐藏多余部分 */
overflow-x: hidden;
/* 其他样式保持不变 */
position: absolute;
z-index: 1000;
background-color: white;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
padding: 2px 0;
min-width: 100px;
list-style-type: none;
margin: 0;
}
.unit-option {
padding: 2px 10px;
cursor: pointer;
font-size: 14px;
}
.unit-option:hover {
background-color: #f0f0f0;
}
</style>

View File

@ -1 +0,0 @@
# yjly-number_unit