You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
424 lines
10 KiB
424 lines
10 KiB
<template>
|
|
<div class="keyborad-container">
|
|
<TypeBtnList class="btn-group" :list="list" @change-type="change" />
|
|
|
|
<transition
|
|
enter-active-class="animate__animated animate__zoomIn animate__faster"
|
|
leave-active-class="animate__animated animate__zoomOut animate__faster"
|
|
>
|
|
<ul v-if="mode === 'keyboard'" key="keyboard" class="keyboard">
|
|
<li v-for="(item, index) in letterNum" :key="index" class="item" :data-key="item" @click="handleKeyLetter(item)">
|
|
{{ item }}
|
|
</li>
|
|
|
|
<li class="empty item" @click="handleKeyLetter(' ')">空格</li>
|
|
<li class="keyboard-del item" @click="delLetter">
|
|
<img src="@/assets/images/search/key-del.svg" alt="" />
|
|
</li>
|
|
<!-- <li class="switch-mode item" @click="handleChangeKeyboardMode('hand')">
|
|
<img src="@/assets/images/search/icon_hand.svg" alt="" />
|
|
!-- <p class="switchhand-txt">{{ $t('search.switchHand') }}</p> --
|
|
</li> -->
|
|
</ul>
|
|
|
|
<div v-else class="hand">
|
|
<!-- <div class="change-keyboard" @click="handleChangeKeyboardMode('keyboard')">
|
|
<img src="@/assets/images/search/icon_key.svg" alt="" />
|
|
</div> -->
|
|
<li class="keyboard-del" @click="delLetter">
|
|
<img src="@/assets/images/search/key-del.svg" alt="" />
|
|
</li>
|
|
<scroll-view
|
|
ref="wordsScrollRef"
|
|
:class="{ active: wordsList && wordsList.length }"
|
|
class="words-scroll"
|
|
:scroll-x="true"
|
|
:refresh-delay="100"
|
|
:list="wordsList"
|
|
>
|
|
<ul class="words-list" :style="{ width: getWidth }">
|
|
<li
|
|
v-for="(item, index) of wordsList"
|
|
:key="item"
|
|
class="word"
|
|
:class="{ active: isPress === index }"
|
|
@mousedown="() => (isPress = index)"
|
|
@mouseup="() => (isPress = -1)"
|
|
@touchstart="() => (isPress = index)"
|
|
@touchend="() => (isPress = -1)"
|
|
@click="handleWord(item)"
|
|
>
|
|
{{ item }}
|
|
</li>
|
|
</ul>
|
|
</scroll-view>
|
|
<div class="hand-wrapper">
|
|
<handWriting
|
|
ref="handWritingRef"
|
|
lang="CN"
|
|
:style="styles"
|
|
fill-text="手写输入区域"
|
|
fill-font-size="50px"
|
|
background-color="#fff"
|
|
border-radius="12px"
|
|
stroke-style="#D8B78A"
|
|
fill-style="rgba(0, 0, 0, 0.03)"
|
|
:width="700"
|
|
:height="214"
|
|
@result="result"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</transition>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import scrollView from '@/base/ScrollView/ScrollView.vue'
|
|
import handWriting from '@/components/Written/Written.vue'
|
|
import { ref, reactive, watch, nextTick, computed } from 'vue'
|
|
import { storeToRefs } from 'pinia'
|
|
import { useRootStore } from '@/store/root'
|
|
import TypeBtnList from '@/components/TypeBtnList/TypeBtnList.vue'
|
|
const store = useRootStore()
|
|
const { device } = storeToRefs(store)
|
|
|
|
const emit = defineEmits(['letterKey', 'mode'])
|
|
const isPress = ref(-1)
|
|
const handWritingRef = ref()
|
|
const styles = reactive({
|
|
background: '#fff',
|
|
borderRadius: '12px 12px 12px 12px',
|
|
marginTop: '0px'
|
|
})
|
|
const letterNum = ref('1234567890QWERTYUIOPASDFGHJKLZXCVBNM')
|
|
const letters = ref('')
|
|
const mode = ref('keyboard')
|
|
const INPUT_MAX_LEN = computed(() => (mode.value === 'hand' ? 5 : 7))
|
|
|
|
const wordsList = ref([])
|
|
const wordsScrollRef = ref()
|
|
const list = [
|
|
{
|
|
title: '键盘输入',
|
|
titleEn: 'Keyboard'
|
|
},
|
|
{
|
|
title: '手写输入',
|
|
titleEn: 'Handwriting'
|
|
}
|
|
]
|
|
|
|
const getWidth = computed(() => wordsList.value?.length * (66 + 5) + 'px')
|
|
defineExpose({
|
|
handleChangeKeyboardMode,
|
|
clear
|
|
})
|
|
|
|
function clear() {
|
|
letters.value = ''
|
|
wordsList.value = []
|
|
}
|
|
function delLetter() {
|
|
letters.value = letters.value.substring(0, letters.value.length - 1)
|
|
if (letters.value.length === 0) {
|
|
wordsList.value = []
|
|
}
|
|
}
|
|
function result(words: []) {
|
|
console.log('words :>> ', words)
|
|
wordsList.value = words
|
|
}
|
|
function handleChangeKeyboardMode(val: 'keyboard' | 'hand') {
|
|
mode.value = val
|
|
}
|
|
function handleKeyLetter(letter: string) {
|
|
if (letters.value.length > INPUT_MAX_LEN.value) {
|
|
return
|
|
}
|
|
letters.value += letter
|
|
}
|
|
function handleWord(word: string) {
|
|
if (letters.value.length > INPUT_MAX_LEN.value) {
|
|
return
|
|
}
|
|
letters.value += word
|
|
}
|
|
|
|
function change(params: any) {
|
|
if (params.order === 0) {
|
|
handleChangeKeyboardMode('keyboard')
|
|
} else {
|
|
handleChangeKeyboardMode('hand')
|
|
}
|
|
}
|
|
watch(letters, newVal => {
|
|
emit('letterKey', newVal)
|
|
})
|
|
watch(mode, newVal => {
|
|
letters.value = ''
|
|
// this.$emit('letterKey', this.letters)
|
|
emit('mode', newVal)
|
|
if (newVal === 'hand') {
|
|
wordsList.value = []
|
|
setTimeout(() => {
|
|
handWritingRef.value.setCanvasSize()
|
|
handWritingRef.value.updateBound()
|
|
handWritingRef.value.reload()
|
|
}, 200)
|
|
}
|
|
})
|
|
|
|
watch(wordsList, () => {
|
|
nextTick(() => {
|
|
if (wordsScrollRef.value) {
|
|
wordsScrollRef.value?.refresh()
|
|
}
|
|
})
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.keyborad-container {
|
|
position: absolute;
|
|
top: 700px;
|
|
left: 0;
|
|
z-index: 1;
|
|
display: flex;
|
|
// justify-content: center;
|
|
align-items: center;
|
|
width: 1080px;
|
|
// padding: 48px 64px;
|
|
background: rgb(255 255 255 / 0%);
|
|
border-radius: 0;
|
|
.btn-group {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
left: 0;
|
|
width: 428px;
|
|
margin: 0 auto;
|
|
}
|
|
.keyboard {
|
|
position: absolute;
|
|
top: 145px;
|
|
left: 264px;
|
|
display: flex;
|
|
width: 552px;
|
|
height: 228px;
|
|
background: #fff0;
|
|
border-radius: 0;
|
|
opacity: 1;
|
|
// box-shadow: 0px 4px 20px 0px rgba(110,82,53,0.15);
|
|
animation-duration: 50ms;
|
|
// padding: 33px;
|
|
// justify-content: center;
|
|
flex-wrap: wrap;
|
|
.item {
|
|
width: 48px;
|
|
height: 48px;
|
|
margin-right: 8px;
|
|
margin-bottom: 12px;
|
|
font-size: 18px;
|
|
font-family: 'font_bold';
|
|
text-align: center;
|
|
color: rgb(0 0 0 / 90%);
|
|
background: #f4f4f4;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 8px rgb(0 0 0 / 3%), inset 0 -1px 0 rgb(177 189 220 / 10%);
|
|
line-height: 48px;
|
|
&:active {
|
|
color: #fff;
|
|
background: linear-gradient(180deg, #d8b78a 0%, #e9dbc4 102.5%);
|
|
}
|
|
&[data-key='0'] {
|
|
margin-right: 0;
|
|
}
|
|
&[data-key='P'] {
|
|
margin-right: 0;
|
|
}
|
|
&[data-key='Q'] {
|
|
margin-left: 0;
|
|
}
|
|
&[data-key='A'] {
|
|
margin-left: 25px;
|
|
}
|
|
&[data-key='L'] {
|
|
margin-right: 30px;
|
|
}
|
|
}
|
|
.keyboard-del {
|
|
// position: absolute;
|
|
// right: 16px;
|
|
// top: 33px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 104px;
|
|
margin-right: 0;
|
|
|
|
img {
|
|
width: 21px;
|
|
object-fit: scale-down;
|
|
}
|
|
}
|
|
.empty {
|
|
width: 48px;
|
|
font-size: 14px;
|
|
font-family: 'font_bold';
|
|
}
|
|
.switch-mode {
|
|
position: absolute;
|
|
top: 374px;
|
|
left: 0;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 520px;
|
|
height: 111px;
|
|
font-size: 14px;
|
|
font-family: 'font_bold';
|
|
text-align: center;
|
|
color: rgb(0 0 0 / 60%);
|
|
background: rgb(36 36 36 / 5%);
|
|
border-radius: 16px;
|
|
flex-direction: column;
|
|
|
|
// .switchhand-txt {
|
|
// }
|
|
img {
|
|
width: 52px;
|
|
object-fit: scale-down;
|
|
}
|
|
&::before {
|
|
position: absolute;
|
|
left: -50px;
|
|
width: 0;
|
|
height: 164px;
|
|
// background: #f4f4f4;
|
|
background-repeat: 4px;
|
|
content: '';
|
|
}
|
|
}
|
|
}
|
|
.hand {
|
|
position: absolute;
|
|
top: 145px;
|
|
left: 190px;
|
|
width: 700px;
|
|
height: 270px;
|
|
padding-top: 0;
|
|
padding-left: 0;
|
|
background: #fff;
|
|
border-radius: 12px;
|
|
opacity: 1;
|
|
animation-duration: 50ms;
|
|
.keyboard-del {
|
|
position: absolute;
|
|
right: 8px;
|
|
bottom: 8px;
|
|
z-index: 10;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 104px;
|
|
height: 48px;
|
|
padding: 8px;
|
|
font-size: 14px;
|
|
font-family: 'font_regular';
|
|
text-align: center;
|
|
color: #4d4846;
|
|
background: rgb(0 0 0 / 3%);
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 8px rgb(0 0 0 / 3%), inset 0 -1px 0 rgb(177 189 220 / 10%);
|
|
line-height: 48px;
|
|
&:active {
|
|
color: #fff;
|
|
background: linear-gradient(180deg, #d8b78a 0%, #e9dbc4 102.5%);
|
|
}
|
|
img {
|
|
flex-shrink: 0;
|
|
width: 25px;
|
|
// object-fit: scale-down;
|
|
}
|
|
}
|
|
.change-keyboard {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 520px;
|
|
height: 111px;
|
|
padding: 8px;
|
|
background: rgb(38 36 36 / 5%);
|
|
border-radius: 16px;
|
|
// box-shadow: 2px 4px 16px rgba(255, 171, 124, 0.4);
|
|
img {
|
|
// width: 24px;
|
|
object-fit: scale-down;
|
|
}
|
|
}
|
|
.words-scroll {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
left: 0;
|
|
overflow: hidden;
|
|
height: 56px;
|
|
padding-top: 0;
|
|
background: #f4f4f4;
|
|
box-shadow: 0 8px 16px rgb(0 0 0 / 4%);
|
|
border-top-left-radius: 12px;
|
|
border-top-right-radius: 12px;
|
|
&.active {
|
|
background: #fafafa;
|
|
&::after {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
width: 66px;
|
|
width: 3px;
|
|
height: 40px;
|
|
border-radius: 8px;
|
|
opacity: 0.37;
|
|
// background: #eb7736;
|
|
box-shadow: 2px 4px 16px rgb(255 171 124 / 40%);
|
|
content: '';
|
|
// filter: blur(4px);
|
|
border-top-left-radius: 16px;
|
|
}
|
|
}
|
|
.words-list {
|
|
display: flex;
|
|
align-items: center;
|
|
height: 56px;
|
|
.word {
|
|
display: inline-block;
|
|
width: 66px;
|
|
height: 56px;
|
|
margin-right: 5px;
|
|
font-size: 18px;
|
|
font-family: 'font_bold';
|
|
text-align: center;
|
|
color: rgb(0 0 0 / 80%);
|
|
border-radius: 12px;
|
|
opacity: 1;
|
|
// flex-shrink: 0;
|
|
line-height: 56px;
|
|
// background: #fff;
|
|
&.active {
|
|
color: #fff;
|
|
background: linear-gradient(180deg, #d8b78a 0%, #e9dbc4 102.5%);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.hand-wrapper {
|
|
width: 700px;
|
|
height: 270px;
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
|