Commit 6c87e93495dc021f6894bec7af4ab640c2908f15

Authored by fengtao
1 parent 3ede27b7

fix: DEFECT-415 修复app端密码无法点击

@@ -16,8 +16,10 @@ @@ -16,8 +16,10 @@
16 16
17 <view class="form-row u-flex"> 17 <view class="form-row u-flex">
18 <u-input v-model="loginForm.password" :password="showPassword" placeholder="请输入登录密码" border="bottom"> 18 <u-input v-model="loginForm.password" :password="showPassword" placeholder="请输入登录密码" border="bottom">
19 - <template slot="suffix" @click="showPasswordMode">  
20 - <view style="padding:10rpx"><u-icon width="18" height="14" :name="showPassword ? '/static/eye-hide.png' : '/static/eye.png'"></u-icon></view> 19 + <template slot="suffix">
  20 + <view @click="showPasswordMode" style="padding:10rpx">
  21 + <u-icon width="18" height="14" :name="showPassword ? '/static/eye-hide.png' : '/static/eye.png'"></u-icon>
  22 + </view>
21 </template> 23 </template>
22 </u-input> 24 </u-input>
23 </view> 25 </view>
1 <template> 1 <template>
2 - <view class="u-input" :class="inputClass" :style="[wrapperStyle]">  
3 - <view class="u-input__content">  
4 - <view  
5 - class="u-input__content__prefix-icon"  
6 - v-if="prefixIcon || $slots.prefix"  
7 - >  
8 - <slot name="prefix">  
9 - <u-icon  
10 - :name="prefixIcon"  
11 - size="18"  
12 - :customStyle="prefixIconStyle"  
13 - ></u-icon>  
14 - </slot>  
15 - </view>  
16 - <view class="u-input__content__field-wrapper" @tap="clickHandler"> 2 + <view class="u-input" :class="inputClass" :style="[wrapperStyle]">
  3 + <view class="u-input__content">
  4 + <view class="u-input__content__prefix-icon" v-if="prefixIcon || $slots.prefix">
  5 + <slot name="prefix"><u-icon :name="prefixIcon" size="18" :customStyle="prefixIconStyle"></u-icon></slot>
  6 + </view>
  7 + <view class="u-input__content__field-wrapper" @tap="clickHandler">
17 <!-- 根据uni-appinput组件文档,H5APP中只要声明了password参数(无论true还是false)type均失效,此时 8 <!-- 根据uni-appinput组件文档,H5APP中只要声明了password参数(无论true还是false)type均失效,此时
18 为了防止type=number时,又存在password属性,type无效,此时需要设置passwordundefined 9 为了防止type=number时,又存在password属性,type无效,此时需要设置passwordundefined
19 --> 10 -->
20 - <input  
21 - class="u-input__content__field-wrapper__field"  
22 - :style="[inputStyle]"  
23 - :type="type"  
24 - :focus="focus"  
25 - :cursor="cursor"  
26 - :value="innerValue"  
27 - :auto-blur="autoBlur"  
28 - :disabled="disabled || readonly"  
29 - :maxlength="maxlength"  
30 - :placeholder="placeholder"  
31 - :placeholder-style="placeholderStyle"  
32 - :placeholder-class="placeholderClass"  
33 - :confirm-type="confirmType"  
34 - :confirm-hold="confirmHold"  
35 - :hold-keyboard="holdKeyboard"  
36 - :cursor-spacing="cursorSpacing"  
37 - :adjust-position="adjustPosition"  
38 - :selection-end="selectionEnd"  
39 - :selection-start="selectionStart"  
40 - :password="password || type === 'password' || undefined"  
41 - @input="onInput"  
42 - @blur="onBlur"  
43 - @focus="onFocus"  
44 - @confirm="onConfirm"  
45 - @keyboardheightchange="onkeyboardheightchange"  
46 - />  
47 - </view>  
48 - <view  
49 - class="u-input__content__clear"  
50 - v-if="isShowClear"  
51 - @tap="onClear"  
52 - >  
53 - <u-icon  
54 - name="close"  
55 - size="11"  
56 - color="#ffffff"  
57 - customStyle="line-height: 12px"  
58 - ></u-icon>  
59 - </view>  
60 - <view  
61 - class="u-input__content__subfix-icon"  
62 - v-if="suffixIcon || $slots.suffix"  
63 - >  
64 - <slot name="suffix">  
65 - <u-icon  
66 - :name="suffixIcon"  
67 - size="18"  
68 - :customStyle="suffixIconStyle"  
69 - ></u-icon>  
70 - </slot>  
71 - </view>  
72 - </view>  
73 - </view> 11 + <input
  12 + class="u-input__content__field-wrapper__field"
  13 + :style="[inputStyle]"
  14 + :type="type"
  15 + :focus="focus"
  16 + :cursor="cursor"
  17 + :value="innerValue"
  18 + :auto-blur="autoBlur"
  19 + :disabled="disabled || readonly"
  20 + :maxlength="maxlength"
  21 + :placeholder="placeholder"
  22 + :placeholder-style="placeholderStyle"
  23 + :placeholder-class="placeholderClass"
  24 + :confirm-type="confirmType"
  25 + :confirm-hold="confirmHold"
  26 + :hold-keyboard="holdKeyboard"
  27 + :cursor-spacing="cursorSpacing"
  28 + :adjust-position="adjustPosition"
  29 + :selection-end="selectionEnd"
  30 + :selection-start="selectionStart"
  31 + :password="password === undefined ? undefined : password ? true : type === 'password' ? true : false"
  32 + @input="onInput"
  33 + @blur="onBlur"
  34 + @focus="onFocus"
  35 + @confirm="onConfirm"
  36 + @keyboardheightchange="onkeyboardheightchange"
  37 + />
  38 + </view>
  39 + <view class="u-input__content__clear" v-if="isShowClear" @tap="onClear"><u-icon name="close" size="11" color="#ffffff" customStyle="line-height: 12px"></u-icon></view>
  40 + <view class="u-input__content__subfix-icon" v-if="suffixIcon || $slots.suffix">
  41 + <slot name="suffix"><u-icon :name="suffixIcon" size="18" :customStyle="suffixIconStyle"></u-icon></slot>
  42 + </view>
  43 + </view>
  44 + </view>
74 </template> 45 </template>
75 46
76 <script> 47 <script>
77 -import props from "./props.js"; 48 +import props from './props.js';
78 /** 49 /**
79 * Input 输入框 50 * Input 输入框
80 * @description 此组件为一个输入框,默认没有边框和样式,是专门为配合表单组件u-form而设计的,利用它可以快速实现表单验证,输入内容,下拉选择等功能。 51 * @description 此组件为一个输入框,默认没有边框和样式,是专门为配合表单组件u-form而设计的,利用它可以快速实现表单验证,输入内容,下拉选择等功能。
@@ -118,207 +89,199 @@ import props from "./props.js"; @@ -118,207 +89,199 @@ import props from "./props.js";
118 * @example <u-input v-model="value" :password="true" suffix-icon="lock-fill" /> 89 * @example <u-input v-model="value" :password="true" suffix-icon="lock-fill" />
119 */ 90 */
120 export default { 91 export default {
121 - name: "u-input",  
122 - mixins: [uni.$u.mpMixin, uni.$u.mixin, props],  
123 - data() {  
124 - return {  
125 - // 输入框的值  
126 - innerValue: "",  
127 - // 是否处于获得焦点状态  
128 - focused: false,  
129 - // value是否第一次变化,在watch中,由于加入immediate属性,会在第一次触发,此时不应该认为value发生了变化  
130 - firstChange: true,  
131 - // value绑定值的变化是由内部还是外部引起的  
132 - changeFromInner: false, 92 + name: 'u-input',
  93 + mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
  94 + data() {
  95 + return {
  96 + // 输入框的值
  97 + innerValue: '',
  98 + // 是否处于获得焦点状态
  99 + focused: false,
  100 + // value是否第一次变化,在watch中,由于加入immediate属性,会在第一次触发,此时不应该认为value发生了变化
  101 + firstChange: true,
  102 + // value绑定值的变化是由内部还是外部引起的
  103 + changeFromInner: false,
133 // 过滤处理方法 104 // 过滤处理方法
134 innerFormatter: value => value 105 innerFormatter: value => value
135 - };  
136 - },  
137 - watch: {  
138 - value: {  
139 - immediate: true,  
140 - handler(newVal, oldVal) {  
141 - this.innerValue = newVal;  
142 - /* #ifdef H5 */  
143 - // 在H5中,外部value变化后,修改input中的值,不会触发@input事件,此时手动调用值变化方法  
144 - if (  
145 - this.firstChange === false &&  
146 - this.changeFromInner === false  
147 - ) {  
148 - this.valueChange();  
149 - }  
150 - /* #endif */  
151 - this.firstChange = false;  
152 - // 重置changeFromInner的值为false,标识下一次引起默认为外部引起的  
153 - this.changeFromInner = false;  
154 - },  
155 - },  
156 - },  
157 - computed: {  
158 - // 是否显示清除控件  
159 - isShowClear() {  
160 - const { clearable, readonly, focused, innerValue } = this;  
161 - return !!clearable && !readonly && !!focused && innerValue !== "";  
162 - },  
163 - // 组件的类名  
164 - inputClass() {  
165 - let classes = [],  
166 - { border, disabled, shape } = this;  
167 - border === "surround" &&  
168 - (classes = classes.concat(["u-border", "u-input--radius"]));  
169 - classes.push(`u-input--${shape}`);  
170 - border === "bottom" &&  
171 - (classes = classes.concat([  
172 - "u-border-bottom",  
173 - "u-input--no-radius",  
174 - ]));  
175 - return classes.join(" ");  
176 - },  
177 - // 组件的样式  
178 - wrapperStyle() {  
179 - const style = {};  
180 - // 禁用状态下,被背景色加上对应的样式  
181 - if (this.disabled) {  
182 - style.backgroundColor = this.disabledColor;  
183 - }  
184 - // 无边框时,去除内边距  
185 - if (this.border === "none") {  
186 - style.padding = "0";  
187 - } else {  
188 - // 由于uni-app的iOS开发者能力有限,导致需要分开写才有效  
189 - style.paddingTop = "6px";  
190 - style.paddingBottom = "6px";  
191 - style.paddingLeft = "9px";  
192 - style.paddingRight = "9px";  
193 - }  
194 - return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle));  
195 - },  
196 - // 输入框的样式  
197 - inputStyle() {  
198 - const style = {  
199 - color: this.color,  
200 - fontSize: uni.$u.addUnit(this.fontSize), 106 + };
  107 + },
  108 + watch: {
  109 + value: {
  110 + immediate: true,
  111 + handler(newVal, oldVal) {
  112 + this.innerValue = newVal;
  113 + /* #ifdef H5 */
  114 + // 在H5中,外部value变化后,修改input中的值,不会触发@input事件,此时手动调用值变化方法
  115 + if (this.firstChange === false && this.changeFromInner === false) {
  116 + this.valueChange();
  117 + }
  118 + /* #endif */
  119 + this.firstChange = false;
  120 + // 重置changeFromInner的值为false,标识下一次引起默认为外部引起的
  121 + this.changeFromInner = false;
  122 + }
  123 + }
  124 + },
  125 + computed: {
  126 + // 是否显示清除控件
  127 + isShowClear() {
  128 + const { clearable, readonly, focused, innerValue } = this;
  129 + return !!clearable && !readonly && !!focused && innerValue !== '';
  130 + },
  131 + // 组件的类名
  132 + inputClass() {
  133 + let classes = [],
  134 + { border, disabled, shape } = this;
  135 + border === 'surround' && (classes = classes.concat(['u-border', 'u-input--radius']));
  136 + classes.push(`u-input--${shape}`);
  137 + border === 'bottom' && (classes = classes.concat(['u-border-bottom', 'u-input--no-radius']));
  138 + return classes.join(' ');
  139 + },
  140 + // 组件的样式
  141 + wrapperStyle() {
  142 + const style = {};
  143 + // 禁用状态下,被背景色加上对应的样式
  144 + if (this.disabled) {
  145 + style.backgroundColor = this.disabledColor;
  146 + }
  147 + // 无边框时,去除内边距
  148 + if (this.border === 'none') {
  149 + style.padding = '0';
  150 + } else {
  151 + // 由于uni-app的iOS开发者能力有限,导致需要分开写才有效
  152 + style.paddingTop = '6px';
  153 + style.paddingBottom = '6px';
  154 + style.paddingLeft = '9px';
  155 + style.paddingRight = '9px';
  156 + }
  157 + return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle));
  158 + },
  159 + // 输入框的样式
  160 + inputStyle() {
  161 + const style = {
  162 + color: this.color,
  163 + fontSize: uni.$u.addUnit(this.fontSize),
201 textAlign: this.inputAlign 164 textAlign: this.inputAlign
202 - };  
203 - return style;  
204 - },  
205 - },  
206 - methods: { 165 + };
  166 + return style;
  167 + }
  168 + },
  169 + methods: {
207 // 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用 170 // 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用
208 setFormatter(e) { 171 setFormatter(e) {
209 - this.innerFormatter = e 172 + this.innerFormatter = e;
  173 + },
  174 + // 当键盘输入时,触发input事件
  175 + onInput(e) {
  176 + let { value = '' } = e.detail || {};
  177 + // 格式化过滤方法
  178 + const formatter = this.formatter || this.innerFormatter;
  179 + const formatValue = formatter(value);
  180 + // 为了避免props的单向数据流特性,需要先将innerValue值设置为当前值,再在$nextTick中重新赋予设置后的值才有效
  181 + this.innerValue = value;
  182 + this.$nextTick(() => {
  183 + this.innerValue = formatValue;
  184 + this.valueChange();
  185 + });
  186 + },
  187 + // 输入框失去焦点时触发
  188 + onBlur(event) {
  189 + this.$emit('blur', event.detail.value);
  190 + // H5端的blur会先于点击清除控件的点击click事件触发,导致focused
  191 + // 瞬间为false,从而隐藏了清除控件而无法被点击到
  192 + uni.$u.sleep(50).then(() => {
  193 + this.focused = false;
  194 + });
  195 + // 尝试调用u-form的验证方法
  196 + uni.$u.formValidate(this, 'blur');
210 }, 197 },
211 - // 当键盘输入时,触发input事件  
212 - onInput(e) {  
213 - let { value = "" } = e.detail || {};  
214 - // 格式化过滤方法  
215 - const formatter = this.formatter || this.innerFormatter  
216 - const formatValue = formatter(value)  
217 - // 为了避免props的单向数据流特性,需要先将innerValue值设置为当前值,再在$nextTick中重新赋予设置后的值才有效  
218 - this.innerValue = value  
219 - this.$nextTick(() => {  
220 - this.innerValue = formatValue;  
221 - this.valueChange();  
222 - })  
223 - },  
224 - // 输入框失去焦点时触发  
225 - onBlur(event) {  
226 - this.$emit("blur", event.detail.value);  
227 - // H5端的blur会先于点击清除控件的点击click事件触发,导致focused  
228 - // 瞬间为false,从而隐藏了清除控件而无法被点击到  
229 - uni.$u.sleep(50).then(() => {  
230 - this.focused = false;  
231 - });  
232 - // 尝试调用u-form的验证方法  
233 - uni.$u.formValidate(this, "blur");  
234 - },  
235 - // 输入框聚焦时触发  
236 - onFocus(event) {  
237 - this.focused = true;  
238 - this.$emit("focus");  
239 - },  
240 - // 点击完成按钮时触发  
241 - onConfirm(event) {  
242 - this.$emit("confirm", this.innerValue);  
243 - },  
244 - // 键盘高度发生变化的时候触发此事件  
245 - // 兼容性:微信小程序2.7.0+、App 3.1.0+ 198 + // 输入框聚焦时触发
  199 + onFocus(event) {
  200 + this.focused = true;
  201 + this.$emit('focus');
  202 + },
  203 + // 点击完成按钮时触发
  204 + onConfirm(event) {
  205 + this.$emit('confirm', this.innerValue);
  206 + },
  207 + // 键盘高度发生变化的时候触发此事件
  208 + // 兼容性:微信小程序2.7.0+、App 3.1.0+
246 onkeyboardheightchange() { 209 onkeyboardheightchange() {
247 - this.$emit("keyboardheightchange");  
248 - },  
249 - // 内容发生变化,进行处理  
250 - valueChange() {  
251 - const value = this.innerValue;  
252 - this.$nextTick(() => {  
253 - this.$emit("input", value);  
254 - // 标识value值的变化是由内部引起的  
255 - this.changeFromInner = true;  
256 - this.$emit("change", value);  
257 - // 尝试调用u-form的验证方法  
258 - uni.$u.formValidate(this, "change");  
259 - });  
260 - },  
261 - // 点击清除控件  
262 - onClear() {  
263 - this.innerValue = "";  
264 - this.$nextTick(() => {  
265 - this.valueChange();  
266 - this.$emit("clear");  
267 - });  
268 - },  
269 - /**  
270 - * 在安卓nvue上,事件无法冒泡  
271 - * 在某些时间,我们希望监听u-from-item的点击事件,此时会导致点击u-form-item内的u-input后  
272 - * 无法触发u-form-item的点击事件,这里通过手动调用u-form-item的方法进行触发  
273 - */  
274 - clickHandler() {  
275 - // #ifdef APP-NVUE  
276 - if (uni.$u.os() === "android") {  
277 - const formItem = uni.$u.$parent.call(this, "u-form-item");  
278 - if (formItem) {  
279 - formItem.clickHandler();  
280 - }  
281 - }  
282 - // #endif  
283 - },  
284 - }, 210 + this.$emit('keyboardheightchange');
  211 + },
  212 + // 内容发生变化,进行处理
  213 + valueChange() {
  214 + const value = this.innerValue;
  215 + this.$nextTick(() => {
  216 + this.$emit('input', value);
  217 + // 标识value值的变化是由内部引起的
  218 + this.changeFromInner = true;
  219 + this.$emit('change', value);
  220 + // 尝试调用u-form的验证方法
  221 + uni.$u.formValidate(this, 'change');
  222 + });
  223 + },
  224 + // 点击清除控件
  225 + onClear() {
  226 + this.innerValue = '';
  227 + this.$nextTick(() => {
  228 + this.valueChange();
  229 + this.$emit('clear');
  230 + });
  231 + },
  232 + /**
  233 + * 在安卓nvue上,事件无法冒泡
  234 + * 在某些时间,我们希望监听u-from-item的点击事件,此时会导致点击u-form-item内的u-input后
  235 + * 无法触发u-form-item的点击事件,这里通过手动调用u-form-item的方法进行触发
  236 + */
  237 + clickHandler() {
  238 + // #ifdef APP-NVUE
  239 + if (uni.$u.os() === 'android') {
  240 + const formItem = uni.$u.$parent.call(this, 'u-form-item');
  241 + if (formItem) {
  242 + formItem.clickHandler();
  243 + }
  244 + }
  245 + // #endif
  246 + }
  247 + }
285 }; 248 };
286 </script> 249 </script>
287 250
288 <style lang="scss" scoped> 251 <style lang="scss" scoped>
289 -@import "../../libs/css/components.scss"; 252 +@import '../../libs/css/components.scss';
290 253
291 .u-input { 254 .u-input {
292 - @include flex(row);  
293 - align-items: center;  
294 - justify-content: space-between;  
295 - flex: 1; 255 + @include flex(row);
  256 + align-items: center;
  257 + justify-content: space-between;
  258 + flex: 1;
  259 +
  260 + &--radius,
  261 + &--square {
  262 + border-radius: 4px;
  263 + }
296 264
297 - &--radius,  
298 - &--square {  
299 - border-radius: 4px;  
300 - } 265 + &--no-radius {
  266 + border-radius: 0;
  267 + }
301 268
302 - &--no-radius {  
303 - border-radius: 0;  
304 - } 269 + &--circle {
  270 + border-radius: 100px;
  271 + }
305 272
306 - &--circle {  
307 - border-radius: 100px;  
308 - } 273 + &__content {
  274 + flex: 1;
  275 + @include flex(row);
  276 + align-items: center;
  277 + justify-content: space-between;
309 278
310 - &__content {  
311 - flex: 1;  
312 - @include flex(row);  
313 - align-items: center;  
314 - justify-content: space-between; 279 + &__field-wrapper {
  280 + position: relative;
  281 + @include flex(row);
  282 + margin: 0;
  283 + flex: 1;
315 284
316 - &__field-wrapper {  
317 - position: relative;  
318 - @include flex(row);  
319 - margin: 0;  
320 - flex: 1;  
321 -  
322 &__field { 285 &__field {
323 line-height: 26px; 286 line-height: 26px;
324 text-align: left; 287 text-align: left;
@@ -327,27 +290,27 @@ export default { @@ -327,27 +290,27 @@ export default {
327 font-size: 15px; 290 font-size: 15px;
328 flex: 1; 291 flex: 1;
329 } 292 }
330 - } 293 + }
331 294
332 - &__clear {  
333 - width: 20px;  
334 - height: 20px;  
335 - border-radius: 100px;  
336 - background-color: #c6c7cb;  
337 - @include flex(row);  
338 - align-items: center;  
339 - justify-content: center;  
340 - transform: scale(0.82);  
341 - margin-left: 4px;  
342 - } 295 + &__clear {
  296 + width: 20px;
  297 + height: 20px;
  298 + border-radius: 100px;
  299 + background-color: #c6c7cb;
  300 + @include flex(row);
  301 + align-items: center;
  302 + justify-content: center;
  303 + transform: scale(0.82);
  304 + margin-left: 4px;
  305 + }
343 306
344 - &__subfix-icon {  
345 - margin-left: 4px;  
346 - } 307 + &__subfix-icon {
  308 + margin-left: 4px;
  309 + }
347 310
348 - &__prefix-icon {  
349 - margin-right: 4px;  
350 - }  
351 - } 311 + &__prefix-icon {
  312 + margin-right: 4px;
  313 + }
  314 + }
352 } 315 }
353 </style> 316 </style>