调整generate输入框出现滚动条问题

This commit is contained in:
X1627315083
2026-01-13 16:16:02 +08:00
parent d75e956fbf
commit bc7099cce2
12 changed files with 379 additions and 177 deletions

View File

@@ -0,0 +1,9 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="24" height="24" fill="url(#pattern0_2641_12790)"/>
<defs>
<pattern id="pattern0_2641_12790" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_2641_12790" transform="scale(0.0078125)"/>
</pattern>
<image id="image0_2641_12790" width="128" height="128" preserveAspectRatio="none" xlink:href="data:image/png;base64,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"/>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -163,7 +163,7 @@
/> />
</template> </template>
<div class="btn"> <div class="btn">
<i class="iconfont icon-gengduo"></i> <SvgIcon name="overallMore" size="18" />
</div> </div>
</a-popover> </a-popover>
</div> </div>

View File

@@ -42,15 +42,14 @@
</div> </div>
</div> </div>
<div v-show="stateOverallSingle != 'single'" class="habit_System_Designer"> <div v-show="stateOverallSingle != 'single'" class="habit_System_Designer">
<div class="habit_System_Designer_text">{{ $t('DesignPrintOperation.Scale') }}</div> <!-- <a-slider id="system_silder"
<a-slider id="system_silder"
class="system_silder" class="system_silder"
:min="20" :min="20"
:max="1000" :max="1000"
v-model:value="systemDesignerPercentage" v-model:value="systemDesignerPercentage"
:tip-formatter="formatter" :tip-formatter="formatter"
> >
</a-slider> </a-slider> -->
<a-popover <a-popover
trigger="click" trigger="click"
destroyTooltipOnHide destroyTooltipOnHide
@@ -67,7 +66,7 @@
/> />
</template> </template>
<div class="btn"> <div class="btn">
<i class="iconfont icon-gengduo"></i> <SvgIcon name="overallMore" size="20" />
</div> </div>
</a-popover> </a-popover>
</div> </div>

View File

@@ -102,23 +102,36 @@
<style scoped lang="less"> <style scoped lang="less">
.repeat-setting { .repeat-setting {
user-select: none; user-select: none;
width: 228px;
> .title {
line-height: 35px;
font-size: 14px;
text-align: center;
margin-top: -12px;
margin-bottom: 3px;
}
> .repeat-setting-item { > .repeat-setting-item {
display: flex; display: flex;
align-items: center; align-items: center;
//虚线 margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
&.offset {
justify-content: center;
}
> .label { > .label {
min-width: 50px; min-width: 68px;
font-size: 14px; font-size: 12px;
} }
> .angle-tool { &:not(.offset) > div {
width: 120px; width: 120px;
flex: 1;
}
> .slider {
--slider-thumb-color1: #000;
--slider-thumb-color2: #eee;
} }
}
> p {
margin: 10px 0;
width: 100%;
height: 0;
border-bottom: 1px dashed #e5e5e5;
} }
} }
</style> </style>

View File

@@ -1,38 +1,73 @@
<template> <template>
<div class="angle-tool"> <div class="angle-tool" :disabled="disabled">
<div <template v-if="styleType === '1'">
ref="dishRef" <div
class="dish" ref="dishRef"
@mousedown.stop="mousedown" class="dish"
@touchmove.stop="mousedown" @mousedown.stop="mousedown"
> @touchmove.stop="mousedown"
<div class="pointer" :style="{ transform: `rotate(${angle}deg)` }"> >
<span></span> <div
class="pointer"
:style="{ transform: `rotate(${angle}deg)` }"
>
<span></span>
</div>
</div> </div>
</div> <div class="input">
<div class="input"> <input
<input type="number" v-model="angle" @input="onInput" @change="onChange" /> type="number"
</div> v-model="angle"
@input="onInput"
@change="onChange"
:disabled="disabled"
/>
</div>
</template>
<my-input
v-if="styleType === '2'"
v-model="angle"
@input="onInput"
@change="onChange"
:disabled="disabled"
type="number"
after="°"
icon="icon-angle"
/>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue"; import { ref, defineProps, defineEmits, watch } from "vue";
import { calculateAngle } from "@/component/Canvas/CanvasEditor/utils/helper"; import { calculateAngle } from "@/component/Canvas/CanvasEditor/utils/helper";
import MyInput from "./MyInput.vue";
// Props // Props
const props = defineProps({ const props = defineProps({
styleType: {
type: String,
default: "1",
},
angle: { angle: {
type: Number, type: Number,
default: 0, default: 0,
}, },
disabled: {
type: Boolean,
default: false,
},
}); });
const emit = defineEmits(["change", "input"]); const emit = defineEmits(["change", "input"]);
const angle = ref(props.angle); const angle = ref(props.angle);
watch(() => props.angle, (value) => { watch(
angle.value = value; () => props.angle,
}); (value) => {
angle.value = value;
}
);
const dishRef = ref<HTMLDivElement>(); const dishRef = ref<HTMLDivElement>();
const mousedown = (e: MouseEvent | TouchEvent) => { const mousedown = (e: MouseEvent | TouchEvent) => {
if (props.disabled) return;
const mousemove = (e: MouseEvent | TouchEvent) => { const mousemove = (e: MouseEvent | TouchEvent) => {
if (!dishRef.value) return; if (!dishRef.value) return;
const { left, top, width, height } = const { left, top, width, height } =
@@ -41,7 +76,6 @@
const centerY = top + height / 2; const centerY = top + height / 2;
const { clientX, clientY } = e?.touches?.[0] || e; const { clientX, clientY } = e?.touches?.[0] || e;
angle.value = calculateAngle(centerX, centerY, clientX, clientY, true); angle.value = calculateAngle(centerX, centerY, clientX, clientY, true);
console.log(angle.value)
onInput(); onInput();
}; };
mousemove(e); mousemove(e);
@@ -57,9 +91,10 @@
document.addEventListener("mouseup", mouseup); document.addEventListener("mouseup", mouseup);
document.addEventListener("touchend", mouseup); document.addEventListener("touchend", mouseup);
}; };
const onInput = () => emit("input", angle.value); const onInput = () => !props.disabled && emit("input", angle.value);
var changeTime: any = null; var changeTime: any = null;
const onChange = () => { const onChange = () => {
if (props.disabled) return;
clearTimeout(changeTime); clearTimeout(changeTime);
changeTime = setTimeout(() => emit("change", angle.value), 500); changeTime = setTimeout(() => emit("change", angle.value), 500);
}; };
@@ -80,10 +115,17 @@
display: flex; display: flex;
align-items: center; align-items: center;
width: 100%; width: 100%;
--color: #000;
&[disabled="true"] {
--color: #b2b2b2;
> .dish {
cursor: not-allowed;
}
}
> .dish { > .dish {
width: 24px; width: 24px;
height: 24px; height: 24px;
border: 1px solid #000; border: 1px solid var(--color);
border-radius: 50%; border-radius: 50%;
cursor: pointer; cursor: pointer;
> .pointer { > .pointer {
@@ -99,7 +141,7 @@
transform: translate(-50%, 0); transform: translate(-50%, 0);
width: 35%; width: 35%;
height: 35%; height: 35%;
background-color: #000; background-color: var(--color);
border-radius: 50%; border-radius: 50%;
} }
} }
@@ -107,7 +149,7 @@
> .input { > .input {
margin-left: 5px; margin-left: 5px;
font-size: 14px; font-size: 14px;
color: #000; color: var(--color);
flex: 1; flex: 1;
// min-width: 45px; // min-width: 45px;
// max-width: 80px; // max-width: 80px;
@@ -118,5 +160,8 @@
outline: none; outline: none;
} }
} }
> .my-input {
flex: 1;
}
} }
</style> </style>

View File

@@ -0,0 +1,67 @@
<template>
<div class="my-input">
<span class="decorate"></span>
<span v-show="icon" :class="['iconfont', icon]"></span>
<span v-show="before" class="before">{{ before }}</span>
<input v-bind="$attrs" :value="modelValue" @input="onInput" />
<span v-show="after" class="after">{{ after }}</span>
</div>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue";
const props = defineProps({
modelValue: { type: Number, default: 0 },
icon: { default: "", type: String },
before: { default: "", type: String },
after: { default: "", type: String },
});
const emit = defineEmits(["update:modelValue", "input"]);
const onInput = (e) => {
const value = e.target.value;
emit("update:modelValue", value);
emit("input", value);
};
</script>
<style scoped lang="less">
.my-input {
display: flex;
align-items: center;
width: 100%;
border: 1px solid rgba(230, 230, 231, 1);
border-radius: 3px;
height: 20px;
padding: 0 4px 0 2px;
> .decorate {
width: 2px;
background-color: rgba(230, 230, 231, 1);
border-radius: 3px;
height: 85%;
margin-right: 4px;
}
> .iconfont {
font-size: 10px;
color: #000;
margin-right: 2px;
}
> .before {
font-size: 12px;
color: #000;
margin-right: 2px;
}
> .after {
font-size: 12px;
color: #000;
}
> input {
font-size: 12px;
width: 0;
flex: 1;
text-align: right;
outline: none;
border: none;
background-color: transparent;
padding: 0;
}
}
</style>

View File

@@ -5,6 +5,7 @@
@change="change" @change="change"
:defaultValue="defaultValue" :defaultValue="defaultValue"
@dropdownVisibleChange="dropdownVisibleChange" @dropdownVisibleChange="dropdownVisibleChange"
:disabled="disabled"
> >
<a-select-option <a-select-option
v-for="v in list" v-for="v in list"
@@ -21,6 +22,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue"; import { ref, defineProps, defineEmits, watch } from "vue";
const props = defineProps({ const props = defineProps({
disabled: {
type: Boolean,
default: false,
},
defaultValue: { defaultValue: {
default: "", default: "",
}, },

View File

@@ -1,84 +1,100 @@
<template> <template>
<div class="offset-tool"> <div class="offset-tool">
<div class="input" v-show="showInput">
<my-input
v-model="left"
@input="onInput"
@change="onChange"
type="number"
before="X"
after="%"
:min="-100"
:max="100"
/>
<my-input
v-model="top"
@input="onInput"
@change="onChange"
type="number"
before="Y"
after="%"
:min="-100"
:max="100"
/>
</div>
<div <div
class="dish" class="dish"
@mousedown="mousedown" @mousedown="mousedown"
@touchstart="mousedown" @touchstart="mousedown"
ref="dishRef" ref="dishRef"
v-show="showDish"
> >
<span <img src="/src/assets/images/icon/xyz.png" />
:style="{ top: data.top + '%', left: data.left + '%' }" <span class="ball" :style="ballStyle"></span>
></span> <span class="tip x">X: {{ left }}%</span>
<span class="tip y">Y: {{ top }}%</span>
<span class="line x"></span>
<span class="line y"></span>
<span class="line z" :style="lineZStyle"></span>
</div> </div>
<input
class="top"
type="range"
:min="0"
:max="100"
:step="0.1"
v-model="data.top"
@input="onInput"
@change="onChange"
/>
<input
class="left"
type="range"
:min="0"
:max="100"
:step="0.1"
v-model="data.left"
@input="onInput"
@change="onChange"
/>
<span class="tip"
>x:{{ tofix(data.left) }}% y:{{ tofix(data.top) }}%</span
>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue"; import { ref, defineProps, defineEmits, watch, computed } from "vue";
import MyInput from "./MyInput.vue";
const props = defineProps({ const props = defineProps({
top: {
type: Number,
default: 50,
},
left: { left: {
type: Number, type: Number,
default: 50, default: 0,
},
top: {
type: Number,
default: 0,
},
showInput: {
type: Boolean,
default: true,
},
showDish: {
type: Boolean,
default: true,
}, },
}); });
const tofix = (v: number | string) => Number(Number(v).toFixed(1));
const emit = defineEmits(["change", "input"]); const emit = defineEmits(["change", "input"]);
const data = reactive({ // 工具的实际坐标 -100 ~ 100
top: tofix(props.top), const top = ref(Math.round(props.top));
left: tofix(props.left), const left = ref(Math.round(props.left));
});
watch( // 原点的坐标 0 ~ 100
() => props.top, const ballStyle = computed(() => ({
(v) => (data.top = tofix(v)) top: 50 + Number(top.value) / 2 + "%",
); left: 50 + Number(left.value) / 2 + "%",
}));
watch( watch(
() => props.left, () => props.left,
(v) => (data.left = tofix(v)) (v) => (left.value = Math.round(v))
);
watch(
() => props.top,
(v) => (top.value = Math.round(v))
); );
const dishRef = ref<HTMLDivElement>(); const dishRef = ref<HTMLDivElement>();
const mousedown = (e: MouseEvent | TouchEvent) => { const mousedown = (e: MouseEvent | TouchEvent) => {
if (!dishRef.value) return; if (!dishRef.value) return;
const mousemove = (e: MouseEvent | TouchEvent) => { const mousemove = (e: MouseEvent | TouchEvent) => {
if (!dishRef.value) return; if (!dishRef.value) return;
const { left, top, width, height } = const rect = dishRef.value.getBoundingClientRect();
dishRef.value.getBoundingClientRect();
const X = e.clientX || (e as TouchEvent).touches[0].clientX; const X = e.clientX || (e as TouchEvent).touches[0].clientX;
const Y = e.clientY || (e as TouchEvent).touches[0].clientY; const Y = e.clientY || (e as TouchEvent).touches[0].clientY;
var x = ((X - left) / width) * 100; var x = ((X - rect.left) / rect.width) * 100;
var y = ((Y - top) / height) * 100; var y = ((Y - rect.top) / rect.height) * 100;
if (x < 0) x = 0; if (x < 0) x = 0;
if (x > 100) x = 100; if (x > 100) x = 100;
if (y < 0) y = 0; if (y < 0) y = 0;
if (y > 100) y = 100; if (y > 100) y = 100;
data.left = tofix(x); left.value = Math.round((x - 50) * 2);
data.top = tofix(y); top.value = Math.round((y - 50) * 2);
onInput(); onInput();
}; };
mousemove(e); mousemove(e);
@@ -94,96 +110,125 @@
document.addEventListener("mouseup", mouseup); document.addEventListener("mouseup", mouseup);
document.addEventListener("touchend", mouseup); document.addEventListener("touchend", mouseup);
}; };
const onInput = () => emit("input", { ...data }); const onInput = () => {
emit("input", { left: left.value, top: top.value });
};
var changeTime: any = null; var changeTime: any = null;
const onChange = () => { const onChange = () => {
clearTimeout(changeTime); clearTimeout(changeTime);
changeTime = setTimeout(() => emit("change", { ...data }), 500); changeTime = setTimeout(() => {
emit("change", {
left: left.value,
top: top.value,
});
}, 500);
}; };
// var offsetTime = null; const lineZStyle = computed(() => ({
// watch(data, (v) => { "--rotateZ": calculateAngle(0, 0, left.value, top.value) + "deg",
// const obj = { ...v }; width: calculateDistance(0, 0, left.value, top.value) / 2 + "%",
// emit("input", obj); }));
// clearTimeout(offsetTime); // 计算角度
// offsetTime = setTimeout(() => emit("change", obj), 50); function calculateAngle(x1: number, y1: number, x2: number, y2: number) {
// }); const deltaX = x2 - x1;
const deltaY = y1 - y2;
// defineExpose({ let angle = Math.atan2(deltaX, deltaY) * (180 / Math.PI) - 90;
// open, return angle;
// close, }
// }); // 计算距离
function calculateDistance(x1: number, y1: number, x2: number, y2: number) {
const deltaX = x2 - x1;
const deltaY = y2 - y1;
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
return distance;
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.offset-tool { .offset-tool {
width: 125px;
height: 125px;
display: flex;
position: relative; position: relative;
overflow: hidden; > .input {
--gap: 15px; display: flex;
align-items: center;
justify-content: center;
> * {
flex: 1;
margin-right: 12px;
&:last-child {
margin-right: 0;
}
}
}
> .dish { > .dish {
margin: var(--gap) 0 0 var(--gap); width: 135px;
flex: 1; height: 135px;
border: 1px solid #000; border: 1px solid #eaeaea;
border-radius: 5px; border-radius: 4px;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
background-color: #fff; background-color: #f6f6f6;
> span { margin-top: 24px;
> * {
position: absolute;
pointer-events: none; pointer-events: none;
user-select: none; user-select: none;
position: absolute; }
top: 0%; > img {
left: 0%; width: 15px;
height: 15px;
bottom: 4px;
right: 4px;
}
> .ball {
top: 50%;
left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
width: 8px; width: 10px;
height: 8px; height: 10px;
background-color: #000; border: 1px solid #fff;
background-color: #333;
border-radius: 50%; border-radius: 50%;
box-shadow: 0px 0.68px 1.7px 0px rgba(0, 0, 0, 0.26);
} }
} > .tip {
> .tip { font-size: 10px;
position: absolute; color: #000;
right: 4px; line-height: 24px;
bottom: 0; &.x {
font-size: 10px; top: 50%;
pointer-events: none; right: 0%;
user-select: none; transform: translate(100%, -50%);
color: #666; padding-left: 6px;
} }
> input.left { &.y {
right: 0; top: 0%;
} left: 50%;
> input.top { transform: translate(-50%, -100%);
bottom: 0; }
left: 0;
transform-origin: left bottom;
transform: rotate(90deg) translateX(-100%);
}
> input {
position: absolute;
width: calc(100% - var(--gap));
-webkit-appearance: none;
appearance: none;
height: 8px;
border-radius: 8px;
background: rgba(0, 0, 0, 0.1); /* 更柔和的颜色 */
// outline: none;
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 8px;
height: 8px;
border-radius: 50%;
background: #4285f4; /* 蓝色滑块 */
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
} }
&::-webkit-slider-thumb:hover { > .line {
background: #3b77db; border-color: #d9d9d9;
transform: scale(1.1); border-style: dashed;
border-width: 0;
width: 0;
height: 0;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
&.x {
width: 100%;
border-top-width: 1px;
}
&.y {
height: 100%;
border-left-width: 1px;
}
&.z {
width: 50%;
border-top-width: 1px;
border-color: #454754;
transform: translate(0%, -50%) rotateZ(var(--rotateZ));
transform-origin: left center;
}
} }
} }
} }

View File

@@ -1,13 +1,12 @@
<template> <template>
<div class="slider"> <div class="slider" :disabled="disabled">
<div class="input-range"> <div
<span class="input-range"
class="tip" :style="{
:style="{ '--progress': (value - props.min) / (props.max - props.min),
'--progress': (value - props.min) / (props.max - props.min), }"
}" >
>{{ props.tipFormatter(value) }}</span <span class="tip">{{ props.tipFormatter(value) }}</span>
>
<input <input
type="range" type="range"
v-model="value" v-model="value"
@@ -16,17 +15,19 @@
:step="props.step" :step="props.step"
@input="onInput" @input="onInput"
@change="onChange" @change="onChange"
:disabled="disabled"
/> />
</div> </div>
<div class="input" v-show="isInput"> <div class="input" v-show="isInput">
<input <my-input
type="number"
v-model="value" v-model="value"
:min="props.min" :min="props.min"
:max="props.max" :max="props.max"
:step="props.step" :step="props.step"
@input="onInput" @input="onInput"
@change="onChange" @change="onChange"
:disabled="disabled"
type="number"
/> />
</div> </div>
</div> </div>
@@ -34,7 +35,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue"; import { ref, defineProps, defineEmits, watch } from "vue";
import MyInput from "./MyInput.vue";
const props = defineProps({ const props = defineProps({
disabled: {
type: Boolean,
default: false,
},
value: { value: {
type: Number, type: Number,
default: 0, default: 0,
@@ -66,9 +72,10 @@
() => props.value, () => props.value,
(v) => (value.value = v) (v) => (value.value = v)
); );
const onInput = () => emit("input", Number(value.value)); const onInput = () => !props.disabled && emit("input", Number(value.value));
var changeTime: any = null; var changeTime: any = null;
const onChange = () => { const onChange = () => {
if (props.disabled) return;
clearTimeout(changeTime); clearTimeout(changeTime);
changeTime = setTimeout(() => emit("change", Number(value.value)), 500); changeTime = setTimeout(() => emit("change", Number(value.value)), 500);
}; };
@@ -79,9 +86,10 @@
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
--input-thumb-size: 12px;
width: 150px; width: 150px;
// &:focus-within, --input-thumb-size: 10px;
--backcolor1: var(--slider-thumb-color1, #4285f4);
--backcolor2: var(--slider-thumb-color2, rgba(0, 0, 0, 0.1));
&:hover { &:hover {
> .input-range > .tip { > .input-range > .tip {
display: block; display: block;
@@ -96,21 +104,26 @@
appearance: none; appearance: none;
height: 5px; height: 5px;
border-radius: 5px; border-radius: 5px;
background: rgba(0, 0, 0, 0.1); /* 更柔和的颜色 */
outline: none; outline: none;
background: linear-gradient(
to right,
var(--backcolor1) 0%,
var(--backcolor1) calc(var(--progress) * 100%),
var(--backcolor2) calc(var(--progress) * 100%),
var(--backcolor2) 100%
);
&::-webkit-slider-thumb { &::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
width: var(--input-thumb-size); width: var(--input-thumb-size);
height: var(--input-thumb-size); height: var(--input-thumb-size);
border-radius: 50%; border-radius: 50%;
background: #4285f4; /* 蓝色滑块 */ background: var(--backcolor1); /* 蓝色滑块 */
cursor: pointer; cursor: pointer;
transition: all 0.2s; transition: all 0.2s;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
} }
&::-webkit-slider-thumb:hover { &::-webkit-slider-thumb:hover {
background: #3b77db;
transform: scale(1.1); transform: scale(1.1);
} }
} }

View File

@@ -640,6 +640,12 @@ export default defineComponent({
:deep(.moveable-origin){ :deep(.moveable-origin){
opacity: 0; opacity: 0;
} }
:deep(.moveable-control){
border-radius: 0;
}
:deep(.moveable-rotation-control){
border-radius: 50%;
}
} }
> .designOpenrtion_imgMask{ > .designOpenrtion_imgMask{
width: auto; width: auto;

View File

@@ -1074,10 +1074,10 @@ export default defineComponent({
const scrollTop = textarea.scrollTop const scrollTop = textarea.scrollTop
// 2. 计算单行高度 // 2. 计算单行高度
const lineHeight = parseInt(getComputedStyle(textarea).lineHeight) || 20 // 默认20px const lineHeight:any = parseInt(getComputedStyle(textarea).lineHeight) || 20 // 默认20px
// 3. 重置高度为1行 // 3. 重置高度为1行
textarea.style.height = lineHeight + 'px' textarea.style.height = (parseInt(lineHeight)+4) + 'px'
// 4. 计算实际需要的高度 // 4. 计算实际需要的高度
const newHeight = Math.max(lineHeight, textarea.scrollHeight) const newHeight = Math.max(lineHeight, textarea.scrollHeight)

View File

@@ -476,9 +476,9 @@ export default defineComponent({
if(!textarea)return if(!textarea)return
const scrollTop = textarea.scrollTop; const scrollTop = textarea.scrollTop;
// 2. 计算单行高度 // 2. 计算单行高度
const lineHeight = parseInt(getComputedStyle(textarea).lineHeight) || 20; // 默认20px const lineHeight:any = parseInt(getComputedStyle(textarea).lineHeight) || 20; // 默认20px
// 3. 重置高度为1行 // 3. 重置高度为1行
textarea.style.height = lineHeight + 'px'; textarea.style.height = (parseInt(lineHeight)+4) + 'px'
// 4. 计算实际需要的高度 // 4. 计算实际需要的高度
const newHeight = Math.max(lineHeight, textarea.scrollHeight); const newHeight = Math.max(lineHeight, textarea.scrollHeight);
textarea.style.height = newHeight + 'px'; textarea.style.height = newHeight + 'px';