H5嵌入原生----兼容安卓與ios

主要分UI展示,鍵盤,輸入框等等。解決bug最苦惱的問題不是沒有解決方案,而是你沒有找到真正的原因。再就是現象難以重現,每次都要發布代碼,然后到手機app中去測試,模擬。這些地方會耗費大量的精力。

一、UI相關

  1. 安卓4.4以下不支持fixed布局。
    fixed布局的作用之一就是在手機鍵盤彈起來的時候,可以自動把頁面頂起來。如果不支持的話,換絕對定位也是可以的。但是絕對定位某些機型比如sm-n7508,華為m7上還是沒有能頂起來。IOS沒有這個問題。
  2. 小于1px顯示問題
    部分安卓機器(比如小米)的分辨率低,如果border的寬度小于1px。安卓機出現一種邊框消失了的現象。樣式上有點奇怪,IOS沒有這個問題。
    在這里插入圖片描述

一開始以為是別的元素擋住了,但是調了半天無解。最后突然意識到是不是計算出來的高度有小數導致的。然后馬上取整:

$target.css(“height”, Math.ceil(maxline * lineHeight));

但是,華為的某些類型的是上面顯示不正常,出來一排點點。
在這里插入圖片描述

再修正一下:

$target.css(“height”, Math.ceil(maxline * lineHeight) - 1);

或者用floor。你好奇為什么會有小數高度呢,因為這個功能設計一個折疊,需要重新計算dom的高度。

二、鍵盤相關

  1. ios鍵盤擋住輸入框。
    這個發生的頻率很高,中文輸入法或者輸入法切換的時候會遮擋。
    在這里插入圖片描述

解決的辦法如下:

setInterval(function () { if (document.activeElement.className.indexOf('inputcontent') >= 0) {document.activeElement.scrollIntoViewIfNeeded();     }}, 300);

這是最管用的辦法,inputcontent為輸入框的樣式。activeElement表示獲得焦點的元素。但是這個方法只在app中有用,如果是在瀏覽器中還是會失效。

  1. 鍵盤收下留下空白陰影。
    這個在部分安卓機上比較明顯,當鍵盤在激活狀態,突然來一個模態彈框,很明顯的看到鍵盤收下去之后出現了一個短暫(不到1秒的樣子)的空白,然后頁面再收下去,讓人感覺閃了下。比如華為P7。但是ios上沒有關系,這個問題沒招,系統不流暢。
  2. 無法保持鍵盤在彈出狀態。
    web其實無法直接控制鍵盤,只有通過讓輸入框獲focus來讓手機的鍵盤彈出來,但是三星SM-N8507v 這款就是不聽話。我也無解了。
  3. 確保彈出來的是數字鍵盤
<input type="number" pattern="[0-9]*" />
<input type="password" pattern="[0-9]*" />

只有number或者tel還是不夠,只有加入正則,ios才會出現九宮格。

三、輸入框相關

  1. fastClick 鎖住輸入框。
    在ios中,會出現幾秒的輸入框沒有反應,開始也怎么想不明白,各種嘗試,推測,搜索發現原來是使用的輕框架中用到了fastClik引起的,解決的辦法就是加上一個樣式。
  <div id="content" class="inputcontent needsclick" ></div>

解決方法到是簡單,但是當初為找到這個原因,費了好大勁,把框架的模塊一個一個刪,最后才定位到。如果不加這個,不單會鎖住輸入框,每次調用focus都會設置光標跑在最前面,無法移動到后面。這個體驗很糟糕。

  1. 模擬placeholder。
    div作為輸入框,本身加入placeholder是無效的。得借助于偽元素。
<div id="content" class="inputcontent needsclick" placeholder="有問題就盡管提問吧" contenteditable="true"></div>

.tools .inputcontent:after {
display: inline-block;
width: 100%;
color: #999;
content: attr(placeholder);
}

然后在獲得焦點和失去焦點的時候對這個屬性進行移除和添加操作。這樣做的好處在于,分離用戶輸入的內容,如果把placeholder的值直接在寫輸入框中這樣會多一些判斷,讓代碼不太干凈。

  1. div的換行是div
    在div中觸發換行,會得到一個div。這個就相當于是在編輯器中。而不是我們認為的
    或者換行符。
    在這里插入圖片描述

所以,需要對div進行過濾替換。

 var replace = /<div.*?>(.*?)<\/div>/g;txt = txt.replace(replace, function(a) {if (a != "<br>") {return "<br>" + delHtmlTag(a);}return delHtmlTag(a);}
  1. 粘貼莫名奇妙帶了樣式
    在輸入框中粘貼會以這樣的形式出現:
<font style='font-size:30px;color:#999'><span>粘貼內容</span></font>

不清楚是系統還是app定義的。所以也得過濾。 用戶還可以粘貼其他文章,容易搞亂輸入框中的樣式,需要加上:

.tools .inputcontent *{font-size: 0.50rem !important; color: #000 !important;line-height: 22px !important;font-weight: normal !important;
}

因為如果從粘貼事件里面處理的話,容易搞亂焦點,讓焦點在最前面。這樣很不爽。所以還是樣式控制,在發送的時候過濾掉所有的標簽。

  1. 超出遮擋/換行遮擋
    這是一個神奇的bug,當內容超過div的最大高度后,最后一行出現一個神奇的現象,頭兩個字顯示了,后面的內容不見了(快快后面其實有內容),直到下一次換行才會出現。
    在這里插入圖片描述

我alert里面的內容,發現并沒有其他的元素,不斷嘗試,發現div overflow: hidden;的時候字都會顯示出來,但是為了讓用戶能夠在內容框里面上下滾動。我得讓y軸是可以滾動的:overflow-y: auto; 所以應該是滾動條引起的。但不知道如何修改。后來試出一個hack的方法。只要有一個換行就不會出現這種情況。所以,我就在用戶輸入到特定行的時候就塞進一個1px的換行:

  if ($("#content").height() == 88 && isIOS() && !haveAppendBr) {$("#content").append("<div style='height:1px;border-top:1px solid #fff' ><br></div>");haveAppendBr = true;}
  1. 安卓第一次不能換行
    這個現象是消息發送成功之后,用戶(小米)一來就是點換行,卻無法換行,懷疑是安卓系統阻止了這樣的行為。但是在輸入一個字之后,換行就是正常的了(哪怕再刪掉這個字)。ios里面沒有這個問題。開始我嘗試去人為加一個換行,又發現焦點沒了。想想這樣問題不改也罷。

  2. 輸入框光標閃動
    這個是translate3d屬性引起,修改sm框架中的一段代碼設置useTranslate為false。位于handleTouchMove方法中。

四、圖片相關

  1. 安卓不能上傳。
    安卓很多時候都不能觸發input type='file’的彈框,上傳就得走原生的幫助。原生攔截到鏈接后就會彈出圖片選擇框。
window.location = 'xxapp:h5Upload({"openType":2,"needChop":false,"uploadUrl": '+fileUploadUrl+',"key":' + totalFiles + ',"callbackMethodName": "uploadComplete"})';

key是為了記住是第幾張圖片,便于在原生上傳結束之后把地址和key一起傳到uploadComplete方法中。這樣界面上才可以做相應的修改。但這不是我說的重點。重點是Url不要帶中文啊或者特殊符號之類的。一方面很多手機里面的圖片命名很奇怪,一大堆,像在uc上面保存下來的圖片后面跟了幾個類型。這種名稱沒啥用,非常建議服務器端像微信一樣處理上傳圖片,成功之后得到一個唯一的字符串就行。不然有的系統會自動解碼你得區分的用上了encodeURI或者encodeURIComponent。測試會說這個手機可以,那個不可以。

  1. 圖片轉了90度。
    安卓部分機型(小米2A,三星N7,三星G9)對于拍照的圖片上傳之后居然左轉了90度。
    拍攝的圖片本身會帶有一個exifdata,這個對象里面包含了拍攝的時間、方向、曝光時間等一些信息。用exif.js可以看出來。也有網站可以直接查看。
 function getdata(id) {EXIF.getData(document.getElementById(id), function () {var data = EXIF.getTag(this, 'Orientation');console.log(data);});}

思路就是通過這個方向來判斷是否給圖片來個再旋轉。
this.style.transform = ‘rotate(’ + current + ‘deg)’;
實際沒有使用exif.js,因為exif還需要再請求一次,而且這個圖片有驗證,居然還讀不到方向信息。最后讓后端對上傳圖片進行方向旋轉糾正

public static Bitmap RotateImage(Stream sm){Image img = Image.FromStream(sm);var exif = img.PropertyItems;byte orien = 0;var item = exif.Where(m => m.Id == 274).ToArray();if (item.Length > 0)orien = item[0].Value[0];switch (orien){case 2:img.RotateFlip(RotateFlipType.RotateNoneFlipX);//horizontal flip  break;case 3:img.RotateFlip(RotateFlipType.Rotate180FlipNone);//right-top  break;case 4:img.RotateFlip(RotateFlipType.RotateNoneFlipY);//vertical flip  break;case 5:img.RotateFlip(RotateFlipType.Rotate90FlipX);break;case 6:img.RotateFlip(RotateFlipType.Rotate90FlipNone);//right-top  break;case 7:img.RotateFlip(RotateFlipType.Rotate270FlipX);break;case 8:img.RotateFlip(RotateFlipType.Rotate270FlipNone);//left-bottom  break;default:break;}return (Bitmap)img;}[HttpPost]public ActionResult UploadImg(HttpPostedFileBase file, string dir = "UserImg"){if (CheckImg(file) != "ok") return Json(new { Success = false, Message = "文件格式不對!" }, JsonRequestBehavior.AllowGet);if (file != null){var path = "~/Content/UploadFiles/" + dir + "/";var uploadpath = Server.MapPath(path);if (!Directory.Exists(uploadpath)){Directory.CreateDirectory(uploadpath);}string fileName = Path.GetFileName(file.FileName);// 原始文件名稱string fileExtension = Path.GetExtension(fileName); // 文件擴展名//string saveName = Guid.NewGuid() + fileExtension; // 保存文件名稱 這是個好方法。string saveName = Encrypt.GenerateOrderNumber() + fileExtension; // 保存文件名稱 這是個好方法。var saveUrl = uploadpath + saveName;// file.SaveAs(saveUrl);System.Drawing.Image image = ImageManageHelper.RotateImage(file.InputStream);image.Save(saveUrl);if (file.ContentLength / 1024 > 500)//大于0.5M{var _saveName = Encrypt.GenerateOrderNumber() + "_thumbnailUrl" + fileExtension;var thumbnailUrl = uploadpath + _saveName;var maxh = 400;var maxw = 400;if (image.Width>maxw){maxh = 400*image.Height/image.Width;}ImageManageHelper.GetPicThumbnail(saveUrl, thumbnailUrl, maxh, maxw, 90);return Json(new { Success = true, SaveName = "/Content/UploadFiles/Mobile/"  +_saveName });}return Json(new { Success = true, SaveName = "/Content/UploadFiles/Mobile/" + saveName });}return Json(new { Success = false, Message = "請選擇要上傳的文件!" }, JsonRequestBehavior.AllowGet);}
  1. 圖片半截
    這個問題在安卓上面會有,不是加載的問題。正確的效果圖片應該是垂直居中的。但不知道為什么偶爾的會只出來個半截。而且我發現,給圖片設置百分比,手機和pc不一樣,手機圖片的百分比并不是相對于其父類元素,而是它自己。
    在這里插入圖片描述

所以圖片的寬度會超出其父類,即使div img的寬度都是100%。overflow:hidden吧,圖片可能顯示不全。超出的部分會導致用戶可以在圖片上面左右滑動,這在ios中有個搞笑的現象,就是對彈出的圖片不斷的左右滑動,再恢復后居然能讓原先綁定的點擊事件失效,不確定是框架的原因還是系統的原因。當時是用一個模態框改造的

Client.modalImg = function (src) {if (!src) return;if ($(".img-overlay").length) {$(".img-overlay").remove();};var modal = '<div class="img-overlay"> <div class="imgheader"></div> <div class="imgbox"><img οnlοad="reCalcuImg();" src="' + src + '" /></div>';$("body").append(modal);
};//校準位置
function reCalcuImg() {var headerH = $(".imgheader").height();var boxH = $(".imgbox").height();var imgH = $(".imgbox img").height();var realMaxH = boxH - headerH;// console.log("headerH", headerH, "boxH", boxH, "imgH", imgH, "realMaxH", realMaxH);if (imgH > realMaxH) {$(".imgbox img").css("height", realMaxH + "px");console.log("大于最大高度,realMaxH", realMaxH);} else {var gap = (realMaxH - imgH) / 2;// console.log("小于最大高度,margintop",(realMaxH - imgH), gap);$(".imgbox img").css("margin-top", gap + "px");}
}

寫在onload事件結束后是確保圖片已經加載完成。這樣才能計算,如果直接在modalimg中計算,圖片的高度可能為0。然后如果圖片的高度大于最大高度則設置為最大高度,否則的話在進行margin,讓其垂直居中。
現在使用的是photoSwipe插件。需要結合圖片的onload事件先存下圖片的原始寬高。

//圖片加載完成后調用
function imgloading(img,srcoll) {
console.log("imgloading", img.height);var cached = {height: img.naturalHeight,width: img.naturalWidth,src: img.src};imClient.imgCache[img.src] = cached;srcoll&&imClient.scroll();
}獲取原始寬高是為了顯示時候的比例自然://圖片放大imClient.imgCache = {};var ispop = false;function getaimg(src) {if (ispop) return;function loadaction(w,h) {imClient.debugSay("圖片加載:w" + w + " h:" + h);loadimg(src, w, h);ispop = false;}var cached = imClient.imgCache[src];if (cached) {ispop = true;loadaction(cached.height, cached.width);return;}console.log("未加載");}$(document).on("click", ".bubbleimgright img,.bubbleimgleft img", function (e) {if ($(this).hasClass("msgfailimg")) return;var url = $(this).attr("src");//就放大縮略圖getaimg(url);});function loadimg(url, hei, width) {var pswpElement = document.querySelectorAll('.pswp')[0];var maxH = $("#historylist").height();var maxW = $("#historylist").width();var fH = 400;var fW = 400;//如果都比默認的小if (hei <= maxH && width <= maxW) {fH = hei;fW = width;}if (hei > maxH && width < maxW) {fH = maxH;fW = Math.ceil((maxH * width) / hei);}if (width > maxW) {fW = maxW;fH = Math.ceil((maxW * hei) / width);}// build items arrayvar items = [{src: url,w: fW,h: fH}];// define options (if needed)var options = {index: 0 // start at first slide};var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, options);gallery.init();}

五、消息

  1. websocket是脆弱但又頑強的。
    websocket很容易受到網絡的影響而中斷,但網絡一恢復能自動重連。而手機會有切到后臺運行的這種情況,比如小米系統會在手機黑屏之后把網絡斷掉,用戶進入應用的時候,你得有重連的機制,確保消息沒有遺漏。
	socket.on("reconnect", function () {isConneted = true;eventManger.trigger("reconnect");listenChannel();});

在listenChannel中通過 socket.emit 告之node后端重連了,拿消息的姿勢調整下。
but紅米手機有一款socketio老是重連,所以手機上也要準備輪詢的機制。重連三次關掉socket,直接輪詢。
2. 消息先發后到。
先發的消息后到,這是很有可能的,但是用戶就會奇怪。比如一條長消息分成幾次發,前端可以在前一條發完了再發第二條。

       var limit = 1000;function loop(i) {if (i < num) {send(content.substr(i * limit, limit), function () {i++;loop(i);});}};loop(0);

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/11623.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/11623.shtml
英文地址,請注明出處:http://en.pswp.cn/web/11623.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【軟設】常見易錯題匯總

目錄 計算機系統基礎 程序語言基礎 數據結構 算法設計與分析 計算機網絡與信息安全 軟件工程基礎 開發方法&#xff08;結構化與面向對象&#xff09; 數據庫 操作系統 知識產權相關的法律法規 &#x1f92f;&#x1f92f;&#x1f92f;&#x1f92f;&#x1f92f;&#x1f9…

《系統架構設計師教程(第2版)》第10章-軟件架構的演化和維護-07-軟件架構維護

文章目錄 1. 軟件架構知識管理1.1 概念1.2 架構知識的獲取1.3 作用1.4 架構知識管理的現狀 2 軟件架構修改管理3 軟件架構版本管理4. 示例4.1 背景4.2 數據獲取4.3 數據計算4.4 結果分析4.4.1 圈復雜度 (CCN)4.4.2 扇入扇出度 (FFC)4.4.3 模塊間耦合度 (CBO)4.4.4 模塊的響應 (…

mysql group by 細節介紹

mysql中group by的用法是配合聚合函數&#xff0c;利用分組信息進行統計&#xff0c;語句如“select name,sum(id) from test group by name,number”。 先來看下表1&#xff0c;表名為test&#xff1a; 執行如下SQL語句&#xff1a; SELECT name FROM test GROUP BY name 你…

OFDM802.11a的FPGA實現(十四)data域的設計優化,擠掉axi協議傳輸中的氣泡

原文鏈接&#xff08;相關文章合集&#xff09;&#xff1a;OFDM 802.11a的xilinx FPGA實現 目錄 1.前言 2.data域的時序要求 3.Debug 1.前言 前面12篇文章詳細講述了&#xff0c;OFDM 802.11a發射部分data域的FPGA實現和驗證&#xff0c;今天對data域的設計做一個總結。在…

electron 多窗口 vuex/pinia 數據狀態同步簡易方案(利用 LocalStorage)

全局 stroe 添加 mutations 狀態同步方法 // 用于其他窗口同步 vuex 中的 DeviceTcpDataasyncDeviceTcpData(state: StateType, data: any) {state.deviceTcpData data},App.vue 里 onMounted(() > {console.log("App mounted");/*** vuex 多窗口 store 同步*//…

springboot306基于Java的民宿管理系統(源碼+包運行+配套LW+技術指導)

項目描述 臨近學期結束&#xff0c;開始畢業設計制作&#xff0c;你還在做java程序網絡編程&#xff0c;期末作業&#xff0c;老師的作業要求覺的困難嗎?不知道畢業設計該怎么辦?網頁功能的數量是否太多?沒有合適的類型或系統?等等。今天給大家介紹一篇基于Java的民宿管理…

python篇-cmd 執行pip命令失敗,但執行pyhon命令正常

當你在CMD中可以正常執行python命令&#xff0c;但執行pip命令失敗時&#xff0c;這通常意味著pip沒有被正確地添加到系統的環境變量中。這里有一些步驟來解決這個問題&#xff1a; 檢查環境變量&#xff1a; 打開系統的環境變量設置&#xff08;右擊“此電腦”>“屬性”>…

CoSeg: Cognitively Inspired Unsupervised Generic Event Segmentation

名詞解釋 1.特征重建 特征重建是一種機器學習中常用的技術&#xff0c;通常用于自監督學習或無監督學習任務。在特征重建中&#xff0c;模型被要求將輸入數據經過編碼器&#xff08;encoder&#xff09;轉換成某種表示&#xff0c;然后再經過解碼器&#xff08;decoder&#x…

c/c++對于char*的理解(聯合string容器)

在C和C中&#xff0c;char*是一個指向字符&#xff08;char&#xff09;的指針。它經常被用來處理C風格的字符串&#xff0c;這種字符串是以空字符&#xff08;\0&#xff09;結尾的字符數組。以下是關于char*的一些關鍵點&#xff1a; C風格的字符串&#xff1a; C風格的字符…

升級Microsoft 365后,SAP GUI中無法打開Excel的解決方案

最近&#xff0c;我們遇到了一個棘手的問題&#xff0c;一位客戶在升級到Microsoft 365后&#xff0c;無法在SAP GUI中打開Excel。這個問題不僅影響了工作效率&#xff0c;也給用戶的日常操作帶來了不便。在本文中&#xff0c;我們將探討問題的成因&#xff0c;并提供一種解決方…

泛微E9開發 添加多個多選框,實現單選框的效果

利用多個多選框實現單選框的效果 1、功能背景2、展示效果3、實現效果 1、功能背景 如下圖所示&#xff0c;在表單中新增四個“選擇框-復選框”類型的字段&#xff0c;并且設置其中的選項&#xff0c;每個多選框都只有一個選項&#xff0c;通過代碼塊實現單選框的效果 1.顯示模…

鄧閑小——生存、生活、生命|真北寫作

人生有三個層次∶生存、生活、生命。 生存就是做必須做的事。生存的模式是鄧&#xff0c;是交易&#xff0c;是買賣。別人需要的東西&#xff0c;你生產出來&#xff0c;賣給他。哪怕這個東西沒啥用&#xff0c;也可以賣&#xff0c;情緒也可以賣。你需要的東西&#xff0c;你花…

分布式與一致性協議之POW算法

POW算法 概述 談起比特幣&#xff0c;你應該并不陌生。比特幣是基于區塊鏈實現的&#xff0c;而區塊鏈運行在因特網上&#xff0c;這就存在有人試圖作惡的情況。有些讀者可能已經發現了&#xff0c;口信消息型拜占庭問題之解、PBFT算法雖然能防止壞人作惡&#xff0c;但只能防…

代碼隨想錄算法訓練營第二十三天 | 530.二叉搜索樹的最小絕對差、501.二叉搜索樹中的眾數、236. 二叉樹的最近公共祖先

目錄 530.二叉搜索樹的最小絕對差 思路 代碼 501.二叉搜索樹中的眾數 思路 代碼 236. 二叉樹的最近公共祖先 思路 代碼 530.二叉搜索樹的最小絕對差 需要領悟一下二叉樹遍歷上雙指針操作&#xff0c;優先掌握遞歸 題目鏈接/文章講解&#xff1a;代碼隨想錄 視頻講解…

Java Spring的定時任務的配置和使用

在Spring框架中&#xff0c;配置和使用定時任務主要涉及Scheduled注解以及Spring的異步任務執行能力。以下是詳細步驟&#xff1a; 1. 引入依賴 對于Spring Boot項目&#xff0c;通常已經包含了Spring框架&#xff0c;因此不需要額外添加定時任務的依賴。如果使用的是Spring框…

AI大模型測評系統opencompass源碼解析

1 注冊器(Registry) 為了管理功能相似的模塊,MMEngine實現了注冊器。注冊器可以被視作這些類或函數的抽象。例如注冊器 MODELS 可以被視作所有模型的抽象。 1.1 什么是注冊器 MMEngine 實現的注冊器可以看作一個映射表和模塊構建方法(build function)的組合。 映射表:…

八、e2studio VS STM32CubeIDE之內存使用情況窗口

目錄 一、概述/目的 二、STM32CubeIDE Build Analyzer 三、e2studio Memory Usage 八、e2studio VS STM32CubeIDE之內存使用情況窗口 一、概述/目的 1、嵌入開發最大特點之一就是資源受限&#xff0c;關注芯片資源使用詳情是優秀工程師的技能之一 2、Keil和IAR都不支持內存…

CTFshow 信息搜集

第一題1 進入靶場 直接看源碼發現flag 第二題 1 按右鍵沒辦法看源碼 按ctrlu可以查看源碼 第三題 0 查看源碼 發現還是什么都沒有 用bp抓包發現flag 第四題1 直接進robots.txt 訪問flagishere.txt獲得flag 第五題 0 提示了phps源碼泄露 用目錄掃描工具沒掃出來 看wp 發現有…

網絡編程套接字詳解

目錄 1. 預備介紹 2.網絡字節序 3.udp網絡程序 4.地址轉換函數 5.udp網絡編程 1.預備介紹 1.1源IP地址和目標IP地址 舉個例子: 從北京出發到上海旅游, 那么源IP地址就是北京, 目標IP地址就是上海. 1.2 端口號 作用: 標識一個進程, 告訴OS這個數據交給那個進程來處理; (1)…

Oracle: 一個用戶多個表空間處理

1.場景描述 今天工作中&#xff0c;同事說建了一個用戶&#xff0c;往里面導入數據時提示表空間不存在&#xff0c;建了表空間后&#xff0c;部分仍然導不進去。期望幫忙創建表空間&#xff0c;并指定默認表空間&#xff0c;成功將數據導入。 &#xff08;1&#xff09;創建好的…