index.vue
4.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<template>
<view class="min-h-screen flex flex-col bg-white">
<!-- <AppHeader title="加入家庭" /> -->
<view class="flex-1 px-4 pt-3 pb-6 flex flex-col">
<!-- Title -->
<h2 class="text-xl font-bold text-center mb-2">
输入家训口令
</h2>
<!-- Description -->
<view class="text-gray-600 text-center text-sm mb-6">
请输入家人提供的家训口令,加入家庭一起参与健康挑战
</view>
<!-- Input boxes -->
<view class="motto-input-container">
<view
v-for="(char, index) in mottoChars"
:key="index"
class="motto-input-box"
:style="{
borderColor: focusedIndex === index ? '#3b82f6' : '#d1d5db'
}"
>
<input
:ref="(el) => (inputRefs[index] = el)"
type="text"
v-model="mottoChars[index]"
@input="(e) => handleInputChange(index, e.target.value)"
@keydown="(e) => handleKeyDown(index, e)"
@focus="focusedIndex = index"
@blur="handleBlur(index)"
class="motto-input"
/>
</view>
</view>
<!-- Help text -->
<view class="text-gray-500 text-center text-sm mb-4">
没有口令?请联系您的大家长获取
</view>
<!-- Role selection -->
<view class="mb-6">
<h3 class="identity-title">
选择您的身份
</h3>
<view class="flex gap-2 flex-wrap">
<view
v-for="role in familyRoles"
:key="role.id"
@click="selectedRole = role.id"
:class="[
'w-[calc(49%-4rpx)] py-3 rounded-lg border text-center flex flex-col items-center gap-1',
selectedRole === role.id
? 'border-blue-500 bg-blue-50 text-blue-500'
: 'border-gray-200 text-gray-700'
]"
>
<My size="20" />
<span class="text-sm">{{ role.label }}</span>
</view>
</view>
</view>
<!-- Submit Button -->
<view
@click="handleJoinFamily"
:disabled="!isComplete"
:class="[
'w-full py-3 text-white text-lg font-medium rounded-lg mt-auto text-center',
isComplete ? 'bg-blue-500' : 'bg-gray-300'
]"
>
加入家庭
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, nextTick } from 'vue';
import Taro from '@tarojs/taro';
import { My } from '@nutui/icons-vue-taro';
import AppHeader from '../../components/AppHeader.vue';
const mottoChars = ref(['', '', '', '']);
const selectedRole = ref('');
const inputRefs = ref([]);
const focusedIndex = ref(-1);
const handleInputChange = (index, value) => {
// 允许输入多个字符,但只保留第一个有效字符(汉字、数字、大小写字母),兼容输入法
if (value) {
// 提取第一个有效字符(汉字、数字、大小写字母)
const firstChar = value.match(/[\u4e00-\u9fa5a-zA-Z0-9]/)?.[0] || '';
mottoChars.value[index] = firstChar;
// 如果输入了有效字符且不是最后一个输入框,自动聚焦下一个
if (firstChar && index < 3) {
focusedIndex.value = index + 1;
// 使用 nextTick 确保 DOM 更新后再聚焦
nextTick(() => {
if (inputRefs.value[index + 1]) {
inputRefs.value[index + 1].focus();
}
});
}
} else {
mottoChars.value[index] = '';
}
};
const handleKeyDown = (index, e) => {
if (e.key === 'Backspace' && !mottoChars.value[index] && index > 0) {
// 同样,在Taro中处理光标移动需要不同的方式
}
};
/**
* 处理输入框失焦事件
* @param {number} index - 输入框索引
*/
const handleBlur = (index) => {
// 重置焦点状态
focusedIndex.value = -1;
// 失焦时再次验证输入值,确保只保留有效字符(汉字、数字、大小写字母)
const currentValue = mottoChars.value[index];
if (currentValue) {
const firstChar = currentValue.match(/[\u4e00-\u9fa5a-zA-Z0-9]/)?.[0] || '';
mottoChars.value[index] = firstChar;
}
};
const familyRoles = [
{ id: 'husband', label: '丈夫' },
{ id: 'wife', label: '妻子' },
{ id: 'son', label: '儿子' },
{ id: 'daughter-in-law', label: '儿媳' },
{ id: 'son-in-law', label: '女婿' },
{ id: 'daughter', label: '女儿' },
{ id: 'grandson', label: '孙子' },
{ id: 'maternal-grandson', label: '外孙' },
{ id: 'granddaughter', label: '孙女' },
{ id: 'maternal-granddaughter', label: '外孙女' }
];
const isComplete = computed(() => {
return mottoChars.value.every((char) => char) && selectedRole.value;
});
const handleJoinFamily = () => {
if (isComplete.value) {
Taro.reLaunch({
url: '/pages/Dashboard/index'
});
}
};
</script>
<style lang="less">
@import './index.less';
</style>