每條游來游去的小魚,都是正在瀏覽這一頁的訪客,有一條是你自己 ( ´ ▽ ` )ノ 覺得干擾閱讀的話,可以把小魚關掉。
解碼輸入框
input輸入文字時會有酷酷的解碼效果。(⌐■_■)✧
| 名稱 | 描述 |
|---|---|
| Input 事件 | input 元素有 compositionstart、compositionupdate、compositionend 等事件,用於處理輸入法組字過程中的文字輸入 |
| Document activeElement | 取得目前擁有焦點的元素 |
不管是輸入還是貼上,都會有解碼效果,而且完全不會干擾輸入過程。
<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 light-dark(#ccc, #555) border-inline: 2px solid light-dark(#AAA, #666)</style>自定義解碼表
Section titled “自定義解碼表”自定義解碼表,玩出更多變化。
<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 light-dark(#ccc, #555) border-inline: 2px solid light-dark(#AAA, #666)</style>配合科幻卡片元件,打造未來感十足的輸入框。
codlin
<template> <div class="w-full flex flex-col items-center gap-4 example-wrap"> <div class="example-ctrl flex flex-col gap-4"> <base-checkbox v-model="visible" :label="t('showInput')" /> </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>透過 input 輸入事件偵測每個輸入文字,轉換每個字元為動態解碼效果。
輸入時,每個字元會轉換成 useChar 產生的物件,根據設定產生隨機變化的效果,讓字元像逐漸解碼一樣顯示。
說起來簡單,實際上還要考慮各種輸入情境,包括:
-
輸入、貼上、拖動文字
都是插入文字,但是有些微差別,需要分別在
onInput或onBeforeInput處理。 -
選取
第 1 點的操作加上選取,需特別注意 caret 位置或隱含的刪除行為。
-
刪除
有分
Forward與Backward兩個方向。 -
維持插入點(caret)
input內容變化時,插入點位置會被重置到最尾端,所以解碼動畫播放時,也要不斷維持插入點位置。 -
拼字與插入點(caret)
中文拼字時,
onInput與onBeforeInput中的input.selectionStart與input.selectionEnd與英文輸入不同,需要特別處理。 -
emoji
1 個 emoji 為 2 字元,需要謹慎處理。
已知 Bug
Section titled “已知 Bug”若文字內有 emoji,反白後編輯與段落中插入文字,都會有錯位問題。
主因是 emoji 會讓 selectionStart 與 selectionEnd 與實際文字長度不同,
目前還想不到甚麼好辦法。( ´•̥̥̥ ω •̥̥̥` )
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;}interface Emits { 'update:modelValue': [value: Props['modelValue']];}interface Slots { default?: () => unknown;}