一、IOS中h5页面输入框无法自动获焦
作为一名码农,最怕的应该就是BUG了.不过我们也正是在项目和bug中成长的.
然而IOS中h5页面的输入框自动获焦问题,困扰了我很久,用过autofocus属性、focus()方法、甚至是用过vue.js的自定义指令去模拟点击输入框:
directives: {
trigger: {
inserted(el, binging) {
setTimeout(() => {
el.click();
}, 200);
}
}
},
但问题依然没有得到完美解决.
既然安卓是可以的,为什么IOS中就不行了呢?是IOS不支持?那么可以让IOS支持吗?咱是新员工,也不敢贸然去和IOS老员工"抬杠"啊.和别人理论是需要依据的,首先从webView开始研究,发现webView常用的控件有UIWebView和WKWebView等.
UIWebView有一个 keyboardDisplayRequiresUserAction属性,默认为YES。如果设置为YES,用户必须明确的点击页面上的元素或者相关联的输入页面来显示键盘;如果设置为NO,一个元素的焦点事件导致输入视图的显示和自动关联这个元素。那么,如果我们加载一个Web页面时,想一开始就唤起键盘,我们除了需要设置输入框的focus外,还需要IOS同事将webView中的keyboardDisplayRequiresUserAction设置为false.然而到此还没有结束,因为WKWebView是没有这个属性的,但又想做到以上效果,怎么办呢?只能通过runtime处理了,添加如下代码并调用:
#import <objc/runtime.h>
@implementation WebViewInjection
+ (void)allowDisplayingKeyboardWithoutUserAction {
Class class = NSClassFromString(@"WKContentView");
NSOperatingSystemVersion iOS_11_3_0 = (NSOperatingSystemVersion){11, 3, 0};
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_11_3_0]) {
SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:");
Method method = class_getInstanceMethod(class, selector);
IMP original = method_getImplementation(method);
IMP override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
((void (*)(id, SEL, void*, BOOL, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3, arg4);
});
method_setImplementation(method, override);
} else {
SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:");
Method method = class_getInstanceMethod(class, selector);
IMP original = method_getImplementation(method);
IMP override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, id arg3) {
((void (*)(id, SEL, void*, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3);
});
method_setImplementation(method, override);
}
}
@end
然后就可以让输入框自动获焦了.
到此,输入框的自动获焦问题也就解决了.
二、输入框错位
页面中输入框是使用fixed悬浮在页面底部的,当输入框获焦后,会被键盘顶起,悬浮在键盘上方.然而,又是在IOS中出了问题,有时候输入框并没有被顶起,通过不断换行(用的textarea)撑起高度发现输入框位置依然在底部并没有被顶起.
解决办法:
输入框父元素使用fixed悬浮在顶部,输入框obsolute定位在父元素底部,监听窗口改变事件,把父元素高度绑定为获取的浏览器窗口可视高度
<div class="textBox" :style="{'height':height}">
<textarea class="textInput" id="textarea"></textarea>
</div>
.textBox
position fixed
top 0
left 0
width 100%
height 100%
z-index 30
.textInput
background #FFFFFF
border 2px solid #C8C8C8
border-radius 36px
line-height 33px
font-family PingFangSC-Regular
font-size 24px
color #333333
outline none
padding 12px 30px
width 620px
height 62px
overflow-y scroll
resize none
window.addEventListener("resize", function() {
var viewHeight =
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight;
this.height = viewHeight;
});
三、textarea根据内容自动调整高度
网上找的,直接贴代码吧:
var text = document.getElementById("textarea");
this.autoHeight(text, 24);
autoHeight(elem, extra, maxHeight) {
//elem:textarea
//extra:
//maxHeight:最大高度,如不需要可不传
extra = extra || 0;
var isFirefox = !!document.getBoxObjectFor || "mozInnerScreenX" in window,
isOpera = !!window.opera && !!window.opera.toString().indexOf("Opera"),
addEvent = function(type, callback) {
elem.addEventListener
? elem.addEventListener(type, callback, false)
: elem.attachEvent("on" + type, callback);
},
getStyle = elem.currentStyle
? function(name) {
var val = elem.currentStyle[name];
if (name === "height" && val.search(/px/i) !== 1) {
var rect = elem.getBoundingClientRect();
return (
rect.bottom -
rect.top -
parseFloat(getStyle("paddingTop")) -
parseFloat(getStyle("paddingBottom")) +
"px"
);
}
return val;
}
: function(name) {
return getComputedStyle(elem, null)[name];
},
minHeight = parseFloat(getStyle("height"));
elem.style.resize = "none";
var change = function() {
var scrollTop,
height,
padding = 0,
style = elem.style;
if (elem._length === elem.value.length) return;
elem._length = elem.value.length;
if (!isFirefox && !isOpera) {
padding =
parseInt(getStyle("paddingTop")) +
parseInt(getStyle("paddingBottom"));
}
elem.style.height = minHeight + "px";
if (elem.scrollHeight > minHeight) {
if (maxHeight && elem.scrollHeight > maxHeight) {
height = maxHeight - padding;
style.overflowY = "auto";
} else {
height = elem.scrollHeight - padding;
style.overflowY = "hidden";
}
style.height = height + extra + "px";
elem.currHeight = parseInt(style.height);
}
};
addEvent("propertychange", change);
addEvent("input", change);
addEvent("focus", change);
change();
}
四、框架中输入框绑定focus、blur事件无效
<mt-search v-model="searchValue" cancel-text="取消" placeholder="请输入关键字" @focus="searchList"></mt-search>
项目中使用的mintUI,输入框组件使用@focus没有生效。
focus、blur事件一般只对input、textarea等标签起作用。检查元素可以发现使用的输入框组件的input外面还有几层div元素,使用@focus只是把事件绑定到了组件的最外层元素。那么我们可以通过事件捕获来解决问题。
<mt-search v-model="searchValue" cancel-text="取消" placeholder="请输入关键字" @focus.native.capture="searchList"></mt-search>