mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-10-15 17:32:58 +08:00
fix: 输入框相关问题
This commit is contained in:
parent
c9a8113d86
commit
b782aee922
1
.gitignore
vendored
1
.gitignore
vendored
@ -53,3 +53,4 @@ docs/.vitepress/cache
|
|||||||
docs/.vitepress/dist
|
docs/.vitepress/dist
|
||||||
docs/.vitepress/apiSidebar.ts
|
docs/.vitepress/apiSidebar.ts
|
||||||
_docs
|
_docs
|
||||||
|
template
|
||||||
|
@ -10,10 +10,11 @@ import {
|
|||||||
Transform
|
Transform
|
||||||
} from '@motajs/render-core';
|
} from '@motajs/render-core';
|
||||||
import { Font } from '@motajs/render-style';
|
import { Font } from '@motajs/render-style';
|
||||||
import { transitionedColor } from '../use';
|
import { transitionedColor, useKey } from '../use';
|
||||||
import { linear } from 'mutate-animate';
|
import { linear } from 'mutate-animate';
|
||||||
import { Background, Selection } from './misc';
|
import { Background, Selection } from './misc';
|
||||||
import { GameUI, IUIMountable, SetupComponentOptions } from '@motajs/system-ui';
|
import { GameUI, IUIMountable, SetupComponentOptions } from '@motajs/system-ui';
|
||||||
|
import { KeyCode } from '@motajs/client-base';
|
||||||
|
|
||||||
export interface InputProps extends DefaultProps, Partial<TextContentProps> {
|
export interface InputProps extends DefaultProps, Partial<TextContentProps> {
|
||||||
/** 输入框的提示内容 */
|
/** 输入框的提示内容 */
|
||||||
@ -49,7 +50,16 @@ export type InputEmits = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const inputProps = {
|
const inputProps = {
|
||||||
props: ['placeholder', 'value', 'multiline'],
|
props: [
|
||||||
|
'loc',
|
||||||
|
'placeholder',
|
||||||
|
'value',
|
||||||
|
'multiline',
|
||||||
|
'border',
|
||||||
|
'circle',
|
||||||
|
'borderWidth',
|
||||||
|
'pad'
|
||||||
|
],
|
||||||
emits: ['change', 'input', 'update:value']
|
emits: ['change', 'input', 'update:value']
|
||||||
} satisfies SetupComponentOptions<InputProps, InputEmits, keyof InputEmits>;
|
} satisfies SetupComponentOptions<InputProps, InputEmits, keyof InputEmits>;
|
||||||
|
|
||||||
@ -92,6 +102,10 @@ export const Input = defineComponent<InputProps, InputEmits, keyof InputEmits>(
|
|||||||
width.value - padding.value * 2,
|
width.value - padding.value * 2,
|
||||||
height.value - padding.value * 2
|
height.value - padding.value * 2
|
||||||
]);
|
]);
|
||||||
|
const rectLoc = computed<ElementLocator>(() => {
|
||||||
|
const b = props.borderWidth ?? 1;
|
||||||
|
return [b, b, width.value - b * 2, height.value - b * 2];
|
||||||
|
});
|
||||||
|
|
||||||
const borderColor = transitionedColor(
|
const borderColor = transitionedColor(
|
||||||
props.border ?? '#ddd',
|
props.border ?? '#ddd',
|
||||||
@ -112,6 +126,9 @@ export const Input = defineComponent<InputProps, InputEmits, keyof InputEmits>(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
ele.addEventListener('blur', () => {
|
ele.addEventListener('blur', () => {
|
||||||
|
if (ele) {
|
||||||
|
updateInput(ele.value);
|
||||||
|
}
|
||||||
ele?.remove();
|
ele?.remove();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -143,42 +160,52 @@ export const Input = defineComponent<InputProps, InputEmits, keyof InputEmits>(
|
|||||||
if (!ele) createInput(props.multiline ?? false);
|
if (!ele) createInput(props.multiline ?? false);
|
||||||
if (!ele) return;
|
if (!ele) return;
|
||||||
// 计算当前绝对位置
|
// 计算当前绝对位置
|
||||||
const renderer = MotaRenderer.get('render-main');
|
|
||||||
const canvas = renderer?.getCanvas();
|
|
||||||
if (!canvas) return;
|
|
||||||
|
|
||||||
const chain: RenderItem[] = [];
|
const chain: RenderItem[] = [];
|
||||||
let now: RenderItem | undefined = root.value;
|
let now: RenderItem | undefined = root.value;
|
||||||
|
let renderer: MotaRenderer | undefined;
|
||||||
if (!now) return;
|
if (!now) return;
|
||||||
while (now) {
|
while (now) {
|
||||||
chain.unshift(now);
|
chain.unshift(now);
|
||||||
|
if (now?.isRoot) {
|
||||||
|
renderer = now as MotaRenderer;
|
||||||
|
}
|
||||||
now = now.parent;
|
now = now.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 应用内边距偏移
|
const canvas = renderer?.getCanvas();
|
||||||
const { clientLeft, clientTop } = canvas;
|
if (!canvas) return;
|
||||||
const trans = new Transform();
|
|
||||||
trans.translate(clientLeft, clientTop);
|
const w = width.value;
|
||||||
trans.scale(core.domStyle.scale);
|
const h = height.value;
|
||||||
|
|
||||||
|
const border = props.borderWidth ?? 1;
|
||||||
|
const inputWidth = w - border * 2;
|
||||||
|
const inputHeight = h - border * 2;
|
||||||
|
|
||||||
|
// 应用根画布偏移
|
||||||
|
const box = canvas.getBoundingClientRect();
|
||||||
|
let trans = new Transform();
|
||||||
|
trans.translate(box.x, box.y);
|
||||||
|
trans.scale(renderer?.getScale() ?? 1);
|
||||||
for (const item of chain) {
|
for (const item of chain) {
|
||||||
const { anchorX, anchorY, width, height } = item;
|
const { anchorX, anchorY, width, height } = item;
|
||||||
trans.translate(-anchorX * width, -anchorY * height);
|
trans.translate(-anchorX * width, -anchorY * height);
|
||||||
trans.multiply(item.transform);
|
trans = trans.multiply(item.transform);
|
||||||
}
|
}
|
||||||
trans.translate(padding.value, padding.value);
|
trans.translate(border, border);
|
||||||
|
|
||||||
// 构建CSS transform的matrix字符串
|
// 构建CSS transform的matrix字符串
|
||||||
const [a, b, , c, d, , e, f] = trans.mat;
|
const [a, b, , c, d, , e, f] = trans.mat;
|
||||||
const str = `matrix(${a},${b},${c},${d},${e},${f})`;
|
const str = `matrix(${a},${b},${c},${d},${e},${f})`;
|
||||||
|
|
||||||
const w = width.value * core.domStyle.scale;
|
|
||||||
const h = height.value * core.domStyle.scale;
|
|
||||||
const font = props.font ?? Font.defaults();
|
const font = props.font ?? Font.defaults();
|
||||||
ele.style.transform = str;
|
ele.style.transform = str;
|
||||||
ele.style.width = `${w - padding.value * 2}px`;
|
ele.style.width = `${inputWidth}px`;
|
||||||
ele.style.height = `${h - padding.value * 2}px`;
|
ele.style.height = `${inputHeight}px`;
|
||||||
ele.style.font = font.string();
|
ele.style.font = font.string();
|
||||||
ele.style.color = String(props.fillStyle ?? 'white');
|
ele.style.color = String(props.fillStyle ?? 'white');
|
||||||
|
ele.style.zIndex = '100';
|
||||||
document.body.appendChild(ele);
|
document.body.appendChild(ele);
|
||||||
ele.focus();
|
ele.focus();
|
||||||
};
|
};
|
||||||
@ -191,6 +218,14 @@ export const Input = defineComponent<InputProps, InputEmits, keyof InputEmits>(
|
|||||||
borderColor.set(props.border ?? '#ddd');
|
borderColor.set(props.border ?? '#ddd');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [key] = useKey();
|
||||||
|
key.realize('confirm', (_, code) => {
|
||||||
|
if (code === KeyCode.Enter) {
|
||||||
|
// 特判回车键
|
||||||
|
ele?.blur();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.value,
|
() => props.value,
|
||||||
newValue => {
|
newValue => {
|
||||||
@ -214,6 +249,7 @@ export const Input = defineComponent<InputProps, InputEmits, keyof InputEmits>(
|
|||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<container
|
<container
|
||||||
|
loc={props.loc}
|
||||||
ref={root}
|
ref={root}
|
||||||
cursor="text"
|
cursor="text"
|
||||||
onClick={click}
|
onClick={click}
|
||||||
@ -221,11 +257,14 @@ export const Input = defineComponent<InputProps, InputEmits, keyof InputEmits>(
|
|||||||
onLeave={leave}
|
onLeave={leave}
|
||||||
>
|
>
|
||||||
<g-rectr
|
<g-rectr
|
||||||
loc={[0, 0, width.value, height.value]}
|
loc={rectLoc.value}
|
||||||
circle={props.circle}
|
circle={props.circle}
|
||||||
lineWidth={props.borderWidth}
|
lineWidth={props.borderWidth ?? 1}
|
||||||
|
fill
|
||||||
|
stroke
|
||||||
|
fillStyle="#111"
|
||||||
strokeStyle={borderColor.ref.value}
|
strokeStyle={borderColor.ref.value}
|
||||||
zIndex={10}
|
zIndex={0}
|
||||||
/>
|
/>
|
||||||
<TextContent
|
<TextContent
|
||||||
{...attrs}
|
{...attrs}
|
||||||
@ -233,8 +272,9 @@ export const Input = defineComponent<InputProps, InputEmits, keyof InputEmits>(
|
|||||||
loc={textLoc.value}
|
loc={textLoc.value}
|
||||||
width={width.value - padding.value * 2}
|
width={width.value - padding.value * 2}
|
||||||
text={showText.value}
|
text={showText.value}
|
||||||
|
fillStyle="white"
|
||||||
alpha={value.value.length === 0 ? 0.6 : 1}
|
alpha={value.value.length === 0 ? 0.6 : 1}
|
||||||
zIndex={0}
|
zIndex={10}
|
||||||
/>
|
/>
|
||||||
</container>
|
</container>
|
||||||
);
|
);
|
||||||
@ -353,12 +393,12 @@ export const InputBox = defineComponent<
|
|||||||
const noText = computed(() => props.noText ?? '取消');
|
const noText = computed(() => props.noText ?? '取消');
|
||||||
const text = computed(() => props.text ?? '请输入内容:');
|
const text = computed(() => props.text ?? '请输入内容:');
|
||||||
const padding = computed(() => props.pad ?? 8);
|
const padding = computed(() => props.pad ?? 8);
|
||||||
const inputHeight = computed(() => props.inputHeight ?? 16);
|
const inputHeight = computed(() => props.inputHeight ?? 24);
|
||||||
const inputLoc = computed<ElementLocator>(() => [
|
const inputLoc = computed<ElementLocator>(() => [
|
||||||
padding.value,
|
padding.value,
|
||||||
padding.value * 2 + contentHeight.value,
|
padding.value * 2 + contentHeight.value,
|
||||||
props.width - padding.value * 2,
|
props.width - padding.value * 2,
|
||||||
inputHeight.value - padding.value * 2
|
inputHeight.value
|
||||||
]);
|
]);
|
||||||
const yesLoc = computed<ElementLocator>(() => {
|
const yesLoc = computed<ElementLocator>(() => {
|
||||||
const y = height.value - padding.value;
|
const y = height.value - padding.value;
|
||||||
@ -379,10 +419,17 @@ export const InputBox = defineComponent<
|
|||||||
return [x, y + 4, width + 8, height + 8, 0.5, 1];
|
return [x, y + 4, width + 8, height + 8, 0.5, 1];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const boxLoc = computed<ElementLocator>(() => {
|
||||||
|
const [x = 0, y = 0, , , ax = 0, ay = 0] = props.loc;
|
||||||
|
return [x, y, props.width, height.value, ax, ay];
|
||||||
|
});
|
||||||
|
|
||||||
const updateHeight = (h: number) => {
|
const updateHeight = (h: number) => {
|
||||||
contentHeight.value = h;
|
contentHeight.value = h;
|
||||||
height.value = h + inputHeight.value + padding.value * 4;
|
const [, yh] = yesSize.value;
|
||||||
|
const [, nh] = noSize.value;
|
||||||
|
const buttonHeight = Math.max(yh, nh);
|
||||||
|
height.value = h + inputHeight.value + padding.value * 4 + buttonHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
const change = (value: string) => {
|
const change = (value: string) => {
|
||||||
@ -411,11 +458,11 @@ export const InputBox = defineComponent<
|
|||||||
};
|
};
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<container>
|
<container loc={boxLoc.value}>
|
||||||
<Background
|
<Background
|
||||||
loc={[0, 0, props.width, height.value]}
|
loc={[0, 0, props.width, height.value]}
|
||||||
winskin={props.winskin}
|
winskin={props.winskin}
|
||||||
color={props.color}
|
color={props.color ?? '#333'}
|
||||||
border={props.border}
|
border={props.border}
|
||||||
zIndex={0}
|
zIndex={0}
|
||||||
/>
|
/>
|
||||||
@ -426,12 +473,14 @@ export const InputBox = defineComponent<
|
|||||||
width={props.width - padding.value * 2}
|
width={props.width - padding.value * 2}
|
||||||
zIndex={5}
|
zIndex={5}
|
||||||
onUpdateHeight={updateHeight}
|
onUpdateHeight={updateHeight}
|
||||||
|
autoHeight
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
{...(props.input ?? {})}
|
{...(props.input ?? {})}
|
||||||
loc={inputLoc.value}
|
loc={inputLoc.value}
|
||||||
v-model={value.value}
|
v-model={value.value}
|
||||||
zIndex={10}
|
zIndex={10}
|
||||||
|
circle={[4]}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
onInput={input}
|
onInput={input}
|
||||||
/>
|
/>
|
||||||
|
Loading…
Reference in New Issue
Block a user