houzhongjian
2024-08-08 820397e43a0b64d35c6d31d2a55475061438593b
提交 | 用户 | 时间
820397 1 <script lang="ts" setup>
H 2 import { propTypes } from '@/utils/propTypes'
3 import { useConfigGlobal } from '@/hooks/web/useConfigGlobal'
4 import type { ZxcvbnResult } from '@zxcvbn-ts/core'
5 import { zxcvbn } from '@zxcvbn-ts/core'
6 import { useDesign } from '@/hooks/web/useDesign'
7
8 defineOptions({ name: 'InputPassword' })
9
10 const { getPrefixCls } = useDesign()
11
12 const prefixCls = getPrefixCls('input-password')
13
14 const props = defineProps({
15   // 是否显示密码强度
16   strength: propTypes.bool.def(false),
17   modelValue: propTypes.string.def('')
18 })
19
20 watch(
21   () => props.modelValue,
22   (val: string) => {
23     if (val === unref(valueRef)) return
24     valueRef.value = val
25   }
26 )
27
28 const { configGlobal } = useConfigGlobal()
29
30 const emit = defineEmits(['update:modelValue'])
31
32 // 设置input的type属性
33 const textType = ref<'password' | 'text'>('password')
34
35 const changeTextType = () => {
36   textType.value = unref(textType) === 'text' ? 'password' : 'text'
37 }
38
39 // 输入框的值
40 const valueRef = ref(props.modelValue)
41
42 // 监听
43 watch(
44   () => valueRef.value,
45   (val: string) => {
46     emit('update:modelValue', val)
47   }
48 )
49
50 // 获取密码强度
51 const getPasswordStrength = computed(() => {
52   const value = unref(valueRef)
53   const zxcvbnRef = zxcvbn(unref(valueRef)) as ZxcvbnResult
54   return value ? zxcvbnRef.score : -1
55 })
56
57 const getIconName = computed(() => (unref(textType) === 'password' ? 'ep:hide' : 'ep:view'))
58 </script>
59
60 <template>
61   <div :class="[prefixCls, `${prefixCls}--${configGlobal?.size}`]">
62     <ElInput v-model="valueRef" :type="textType" v-bind="$attrs">
63       <template #suffix>
64         <Icon :icon="getIconName" class="el-input__icon cursor-pointer" @click="changeTextType" />
65       </template>
66     </ElInput>
67     <div
68       v-if="strength"
69       :class="`${prefixCls}__bar`"
70       class="relative mb-6px ml-auto mr-auto mt-10px h-6px"
71     >
72       <div :class="`${prefixCls}__bar--fill`" :data-score="getPasswordStrength"></div>
73     </div>
74   </div>
75 </template>
76
77 <style lang="scss" scoped>
78 $prefix-cls: #{$namespace}-input-password;
79
80 .#{$prefix-cls} {
81   :deep(.#{$elNamespace}-input__clear) {
82     margin-left: 5px;
83   }
84
85   &__bar {
86     background-color: var(--el-text-color-disabled);
87     border-radius: var(--el-border-radius-base);
88
89     &::before,
90     &::after {
91       position: absolute;
92       z-index: 10;
93       display: block;
94       width: 20%;
95       height: inherit;
96       background-color: transparent;
97       border-color: var(--el-color-white);
98       border-style: solid;
99       border-width: 0 5px;
100       content: '';
101     }
102
103     &::before {
104       left: 20%;
105     }
106
107     &::after {
108       right: 20%;
109     }
110
111     &--fill {
112       position: absolute;
113       width: 0;
114       height: inherit;
115       background-color: transparent;
116       border-radius: inherit;
117       transition:
118         width 0.5s ease-in-out,
119         background 0.25s;
120
121       &[data-score='0'] {
122         width: 20%;
123         background-color: var(--el-color-danger);
124       }
125
126       &[data-score='1'] {
127         width: 40%;
128         background-color: var(--el-color-danger);
129       }
130
131       &[data-score='2'] {
132         width: 60%;
133         background-color: var(--el-color-warning);
134       }
135
136       &[data-score='3'] {
137         width: 80%;
138         background-color: var(--el-color-success);
139       }
140
141       &[data-score='4'] {
142         width: 100%;
143         background-color: var(--el-color-success);
144       }
145     }
146   }
147
148   &--mini > &__bar {
149     border-radius: var(--el-border-radius-small);
150   }
151 }
152 </style>