向大佬们偷师那么多技能后,终于我也能装一回大佬了!第一次发帖,有点激动,哈哈哈哈!
如题,不知道这个问题困扰各位WEBer多久了,反正我是跟它纠缠两三年了,最近开始真正学一下前端(本人赤脚医生,见笑了),终于找到了在Vue下彻底解决的方案,废话少说,先上代码:
// 注册Vue全局指令
Vue.directive('wx-blur-bug',{
bind:function(el){ //在绑定的时候,添加一次监听就够了
let agent=window.navigator.userAgent.toLowerCase()
if(agent.match(/\(i[^;]+;( U;)? cpu.+mac os x/)&&agent.match(/MicroMessenger/i)){ //判断是在ios端的微信环境中
el.addEventListener('focusin',()=>{ //注意,这里只能建听focusin,focus事件捕获到的时候屏幕已经滚动一小段距离,所以每操作一轮都异位一点点
// dom监听到focusin事件时,先读取当前滚动位置,并声明一个函数对象
let scroll=window.pageYOffset,handle=function(){
window.scrollTo(0,scroll) //回滚到前面读取的位置
el.removeEventListener('blur',handle) //滚完了再删除
// 需要注意的是,EventListener可以多次添加同一事件,如果不删除就会累加调用的次数
}
el.addEventListener('blur',handle) // 但是这玩意又不像setInterval会返回ID,要想删除成功,传入的第二个参数,也就是回调函数,必须是同一个内存,所以这里只能用声明函数对象的方法,把回调先存入内存,然后添加、删除
})
}
}
})
上面注释应该说的够详细了,大概原理就是在捕获focusin的时候读取当前滚动位置,用这个值作为参数去声明一个函数对象存入内存,然后作为EventListener的回调添加blur监听,页面滚回来后在函数对象内部自己把自己删掉,一轮结束。
由于Vue中有自定义指令这种操作,所以干脆添加一个全局指令,在要用的地方绑定一下就OK
<input v-wx-blur-bug type="datetime-local" name="end" v-model="end" />
<input v-wx-blur-bug type="text" name="user" placeholder="昵称/收货人/手机/邮箱" />
<select v-wx-blur-bug ><option value="">所有配送员</option></select>
<textarea v-wx-blur-bug ></textarea>
非Vue项目可以根据此逻辑大概改改就行。
另外附上早年用jQuery时找到的解决办法:
$("input,select,textarea").blur(function(){
var odiv=document.createElement('div');
odiv.style.height="999px"; // 创建一个高于半个屏幕的DIV
document.body.appendChild(odiv); //插入body最开始,把内容挤下去
setTimeout(()=>{odiv.parentNode.removeChild(odiv)},0); //瞬间撤除
});
不过这个方案资源浪费比较严重。
首先是监听blur,得判断页面中有没有相关元素。如果是js控制的动态页面,还得动态添加监听,或者直接用on监听到document中
其次是这里还要创建DOM,要setTimeout,还要删除DOM。只能说能解决问题,但不是长久之计。
最后,来自一个刚入门的小白的深情感叹:Vue大法果然好使!