Decoding Input input
A cool decoding effect when typing text. (⌐■_■)✧
Usage Examples
Basic Usage
Whether typing or pasting, you get a decoding effect without interfering with the input process.
View example source code
<template>
<div class="w-full flex flex-col items-center gap-4 p-6">
<input-decoding
v-model="text"
class="input-decoding px-3 py-2"
/>
<span class="break-all border-b px-3 pb-1">
{{ text }}
</span>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import InputDecoding from '../input-decoding.vue'
const text = ref('')
</script>
<style scoped lang="sass">
.input-decoding
border: 1px solid #ccc
border-inline: 2px solid #AAA
</style>Custom Charset
Customize the decoding charset for more variations.
View example source code
<template>
<div class="w-full flex flex-col items-center gap-4 p-6">
<input-decoding
v-model="text"
class="input-decoding px-3 py-2"
:charset
:decode-interval="40"
/>
<span class="break-all border-b px-3 pb-1">
{{ text }}
</span>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import InputDecoding from '../input-decoding.vue'
const text = ref('')
const charset = [
/** 數字 */
(char: string) => char.match(/\d/)
? '¥$¢€£'
: undefined,
/** 中文 */
(char: string) => char.match(/[\u4E00-\u9FA5]/)
? 'ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦ'
: undefined,
/** emoji */
(char: string) => char.match(/\p{Emoji}/u)
? '♩♪♫♬𝄞'
: undefined,
/** 其他 */
() => 'ᚠᚢᚦᚨᚱᚳᚷᚹᚻᚾᛁᛂᛇᛈᛉᛊᛏᛒᛖᛗᛚᛝᛟᛡᛢᛣᛤᛥᛦᛧᛨ',
]
</script>
<style scoped lang="sass">
.input-decoding
border: 1px solid #ccc
border-inline: 2px solid #AAA
</style>Futuristic Input
Combine with the Futuristic Card component to create a futuristic input field.
View example source code
<template>
<div class="w-full flex flex-col items-center gap-4 border border-gray-200 rounded-xl p-6">
<div class="flex flex-col gap-4 border rounded">
<base-checkbox
v-model="visible"
:label="t('showInput')"
class="p-4"
/>
</div>
<div class="flex flex-col items-center gap-4 py-6">
<card-futuristic
:visible
v-bind="cardParams"
>
<input-decoding
v-model="text"
class="font-orbitron px-3 py-2"
:class="{ 'pointer-events-none': !visible }"
charset="ᚠᚢᚦᚨᚱᚳᚷᚹᚻᚾᛁᛂᛇᛈᛉᛊᛏᛒᛖᛗᛚᛝᛟᛡᛢᛣᛤᛥᛦᛧᛨ"
@focus="cardParams.selected = true"
@blur="cardParams.selected = false"
/>
</card-futuristic>
<div class="font-orbitron break-all">
{{ text }}
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type { Writable } from 'type-fest'
import type { ExtractComponentProps } from '../../../types'
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import BaseCheckbox from '../../base-checkbox.vue'
import CardFuturistic from '../../card-futuristic/card-futuristic.vue'
import InputDecoding from '../input-decoding.vue'
type CardParams = Writable<ExtractComponentProps<typeof CardFuturistic>>
const { t } = useI18n()
const visible = ref(false)
const text = ref('codlin')
const cardParams = ref<CardParams>({
selected: false,
corner: {
type: 'square',
size: 4,
},
bg: null,
content: {
type: 'typical',
class: 'p-1',
},
border: {
type: 'typical',
color: '#BBB',
},
animeSequence: {
visible: {
corner: { delay: 0 },
border: { delay: 400 },
content: { delay: 500 },
},
hidden: {
corner: { delay: 400 },
border: { delay: 0 },
content: { delay: 0 },
},
},
})
</script>
<style lang="sass">
</style>How It Works
Detects each input character through the input event and transforms each character into a dynamic decoding effect.
How is Chinese character composition handled?
Developing this component taught me something new: the compositionstart and compositionend events of input, which ensure Chinese input works correctly without mistaking composition as multiple inputs.
When typing, each character is converted into an object generated by useChar, which produces random variations to make characters appear as if they are being "decoded" gradually.
Sounds simple, but you also need to handle various input scenarios:
Typing, pasting, dragging text
All involve inserting text, but with subtle differences that need to be handled separately in
onInputoronBeforeInput.Selection
Combined with the operations in point 1, special attention is needed for caret position or implicit delete behavior.
Deletion
There are two directions:
ForwardandBackward.Maintaining the caret position
When
inputcontent changes, the caret position resets to the end, so during the decoding animation, the caret position must be continuously maintained.Composition and caret
During Chinese character composition,
input.selectionStartandinput.selectionEndinonInputandonBeforeInputdiffer from English input and require special handling.Emoji
One emoji equals 2 characters, requiring careful handling.
Known Bugs
If the text contains emoji, editing after selecting and inserting text mid-paragraph will cause offset issues.
The main reason is that emoji causes selectionStart and selectionEnd to differ from the actual text length.
No good solution has been found yet. ( ´•̥̥̥ ω •̥̥̥` )
Source Code
API
Props
interface Props {
modelValue?: string;
/** 解碼效果的字元集
*
* 可以根據 char 來決定字元集,依矩陣順序判斷
*
* @default 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
*/
charset?: string | Array<(char: string) => string | undefined>;
/** 字符變化間隔毫秒數
*
* @default 20
*/
decodeInterval?: number;
/** 解碼次數
*
* @default 10
*/
decodeTimes?: number;
/** 每個字符的延遲毫秒數
*
* @default 20
*/
perCharDecodeDelay?: number;
/** 最大延遲毫秒數
*
* @default 1000
*/
maxDecodeDelay?: number;
}Emits
interface Emits {
'update:modelValue': [value: Props['modelValue']];
}Slots
interface Slots {
default?: () => unknown;
}