index.vue
2.81 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
<!-- PasswordStrengthPopover.vue -->
<template>
<div class="password-wrapper">
<el-popover
v-model:visible="popoverVisible"
placement="top"
:width="300"
trigger="manual"
popper-class="password-strength-popper"
:disabled="!internalValue"
>
<template #reference>
<el-input
ref="inputRef"
:model-value="internalValue"
:placeholder="placeholder"
type="password"
clearable
showPassword
:disabled="disabled"
autocomplete="new-password"
@update:model-value="onInput"
@focus="onFocus"
@blur="onBlur"
@click="focusInput"
/>
</template>
<PasswordStrengthContent
ref="strengthRef"
:storeKey="storeKey"
:password="internalValue"
/>
</el-popover>
</div>
</template>
<script setup lang="ts">
import { ref, watch, nextTick } from 'vue';
import { ElInput } from 'element-plus';
import PasswordStrengthContent from './PasswordStrengthContent.vue';
const props = defineProps({
modelValue: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请输入密码'
},
// 新增:用于表单校验的字段名(可选)
name: {
type: String,
default: 'password'
},
storeKey: {
type: String,
default: 'firstUnmetRequirement'
},
disabled: {
type: Boolean,
default: false
}
});
const emit = defineEmits(['update:modelValue','change']);
const internalValue = ref(props.modelValue);
watch(
() => props.modelValue,
(newVal) => {
internalValue.value = newVal;
}
);
const onInput = (val) => {
internalValue.value = val;
emit('update:modelValue', val);
emit('change', val);
};
const popoverVisible = ref(false);
const inputRef = ref(null);
const strengthRef = ref(null);
const onFocus = () => {
if (internalValue.value) {
popoverVisible.value = true;
}
};
const onBlur = () => {
setTimeout(() => {
const activeEl = document.activeElement;
const popoverEl = document.querySelector('.password-strength-popper');
if (!popoverEl?.contains(activeEl)) {
popoverVisible.value = false;
}
}, 200);
};
const focusInput = () => {
nextTick(() => {
inputRef.value?.focus();
});
};
watch(internalValue, (newVal) => {
if (newVal) {
if (document.activeElement === inputRef.value?.$el?.querySelector('input')) {
popoverVisible.value = true;
}
} else {
popoverVisible.value = false;
}
});
// 暴露给 el-form 使用
defineExpose({
});
</script>
<style scoped lang="scss">
.password-wrapper {
width: 100%;
// max-width: 400px;
}
.password-strength-popper {
padding: 14px !important;
background: #fff;
border: 1px solid #ddd;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
border-radius: 8px;
}
</style>