前篇☞ 移動端適配及PC端適配心得總結體會(一) (可能比較全javascript
QQ瀏覽器 meta元素檢測 識別內核 規則介紹:css
例子:html
<!DOCTYPE html>
<html>
<head>
<!-- 下面3個meta中任選一個,便可正確識別 -->
<meta name="renderer" content="webkit" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<title>chrome core</title>
</head>
<body>
meta webkit
</body>
</html>
複製代碼
例子:前端
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<!-- 下面3個meta中任選一個,便可正確識別 -->
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<meta name="renderer" content="ie-comp" />
<meta name="renderer" content="ie-stand" />
<title>ie core</title>
</head>
<body>
meta ie
</body>
</html>
複製代碼
參考:qq瀏覽器文檔vue
出現的緣由:java
按照iPhone6的尺寸,一張750px寬的設計圖,這個750px其實就是iPhone6的設備像素,在測量設計圖時量到的1px實際上是1設備像素,而當咱們設置佈局視口等於理想視口等於375px,而且因爲iPhone6的DPR爲2,寫css時的1px對應的是2設備像素,因此看起來會粗一點。ios
解決辦法git
基於media
查詢判斷不一樣的設備像素比給定不一樣的border-image
:github
.border_1px{
border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px{
border-bottom: none;
border-width: 0 0 1px 0;
border-image: url(../img/1pxline.png) 0 0 2 0 stretch;
}
}
複製代碼
和border-image
相似,準備一張符合條件的邊框背景圖,模擬在背景上。web
.border_1px{
border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio:2{
.border_1px{
background: url(../img/1pxline.png) repeat-x left bottom;
background-size: 100% 1px;
}
}
複製代碼
上面兩種都須要單獨準備圖片,並且圓角不是很好處理,可是能夠應對大部分場景。
基於media
查詢判斷不一樣的設備像素比對線條進行縮放:
.border_1px:before{
content: '';
position: absolute;
top: 0;
height: 1px;
width: 100%;
background-color: #000;
transform-origin: 50% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px:before{
transform: scaleY(0.5);
}
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
.border_1px:before{
transform: scaleY(0.33);
}
}
複製代碼
這種方式能夠知足各類場景,若是須要知足圓角,只須要給僞類也加上border-radius
便可。
postcss-write-svg
)上面咱們border-image
和background-image
均可以模擬1px
邊框,可是使用的都是位圖,還須要外部引入。
藉助PostCSS
的postcss-write-svg
咱們能直接使用border-image
和background-image
建立svg
的1px
邊框:
@svg border_1px {
height: 2px;
@rect {
fill: var(--color, black);
width: 100%;
height: 50%;
}
}
.example { border: 1px solid transparent; border-image: svg(border_1px param(--color #00b1ff)) 2 2 stretch; }
複製代碼
編譯後:
.example { border: 1px solid transparent; border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch; }
複製代碼
咱們須要將頂部和底部合理的擺放在安全區域內,iOS11
新增了兩個CSS
函數env、constant
,用於設定安全區域與邊界的距離。
函數內部能夠是四個常量:
safe-area-inset-left
:安全區域距離左邊邊界距離safe-area-inset-right
:安全區域距離右邊邊界距離safe-area-inset-top
:安全區域距離頂部邊界距離safe-area-inset-bottom
:安全區域距離底部邊界距離注意:咱們必須指定viweport-fit
後才能使用這兩個函數:
<meta name="viewport" content="width=device-width, viewport-fit=cover">
複製代碼
constant
在iOS < 11.2
的版本中生效,env
在iOS >= 11.2
的版本中生效,這意味着咱們每每要同時設置他們,將頁面限制在安全區域內:
body {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
複製代碼
當使用底部固定導航欄時,咱們要爲他們設置padding
值:
{
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
複製代碼
具體細節
js識別
window.addEventListener("resize", ()=>{
if (window.orientation === 180 || window.orientation === 0) {
// 正常方向或屏幕旋轉180度
console.log('豎屏');
};
if (window.orientation === 90 || window.orientation === -90 ){
// 屏幕順時鐘旋轉90度或屏幕逆時針旋轉90度
console.log('橫屏');
}
});
複製代碼
css識別
@media screen and (orientation: portrait) {
/*豎屏...*/
}
@media screen and (orientation: landscape) {
/*橫屏...*/
}
複製代碼
咱們平時使用的圖片大多數都屬於位圖(png、jpg..
),位圖由一個個像素點構成的,每一個像素都具備特定的位置和顏色值:
理論上,位圖的每一個像素對應在屏幕上使用一個物理像素來渲染,才能達到最佳的顯示效果。
而在dpr > 1
的屏幕上,位圖的一個像素可能由多個物理像素來渲染,然而這些物理像素點並不能被準確的分配上對應位圖像素的顏色,只能取近似值,因此相同的圖片在dpr > 1
的屏幕上就會模糊:
爲了保證圖片質量,咱們應該儘量讓一個屏幕像素來渲染一個圖片像素,因此,針對不一樣DPR
的屏幕,咱們須要展現不一樣分辨率的圖片。
如:在dpr=2
的屏幕上展現兩倍圖(@2x)
,在dpr=3
的屏幕上展現三倍圖(@3x)
。
使用media
查詢判斷不一樣的設備像素比來顯示不一樣精度的圖片:
.avatar{
background-image: url(conardLi_1x.png);
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.avatar{
background-image: url(conardLi_2x.png);
}
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
.avatar{
background-image: url(conardLi_3x.png);
}
}
複製代碼
只適用於背景圖
使用image-set
:
.avatar {
background-image: -webkit-image-set( "conardLi_1x.png" 1x, "conardLi_2x.png" 2x );
}
複製代碼
只適用於背景圖
使用img
標籤的srcset
屬性,瀏覽器會自動根據像素密度匹配最佳顯示圖片:
<img src="conardLi_1x.png" srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">
複製代碼
使用window.devicePixelRatio
獲取設備像素比,遍歷全部圖片,替換圖片地址:
const dpr = window.devicePixelRatio;
const images = document.querySelectorAll('img');
images.forEach((img)=>{
img.src.replace(".", `@${dpr}x.`);
})
複製代碼
SVG
的全稱是可縮放矢量圖,不一樣於位圖的基於像素,SVG
則是屬於對圖像的形狀描述,因此它本質上是文本文件,體積較小,且無論放大多少倍都不會失真。
除了咱們手動在代碼中繪製svg
,咱們還能夠像使用位圖同樣使用svg
圖片:
<img src="conardLi.svg">
<img src="data:image/svg+xml;base64,[data]"> .avatar { background: url(conardLi.svg); } 複製代碼
參考:
H5 技術是一系列移動端 web 前端技術的集合
H5 技術自己是用於移動端的 web 網頁。因爲 App 自己有個 webview
的容器,在容器裏能夠運行 Web 前端相關代碼,由此 H5 和原生 App 結合又衍生出來了 Hybrid App 技術。
html
的font-size
。此時,根字體大小就會隨屏幕寬度而變化。px
轉換成 rem
, 常規方案有兩種,一種是利用sass
/less
中的自定義函數 pxToRem
,寫px
時,利用pxToRem
函數轉換成 rem
。另一種是直接寫px
,編譯過程利用插件所有轉成rem
。這樣 dom
中元素的大小,就會隨屏幕寬度變化而變化了。const MAX_FONT_SIZE = 420
// 定義最大的屏幕寬度
document.addEventListener('DOMContentLoaded', () => {
const html = document.querySelector('html')
let fontSize = window.innerWidth / 10
fontSize = fontSize > MAX_FONT_SIZE ? MAX_FONT_SIZE : fontSize
html.style.fontSize = fontSize + 'px'
})
複製代碼
px
轉 rem
pxToRem
方案一$rootFontSize: 375 / 10;
// 定義 px 轉化爲 rem 的函數
@function px2rem ($px) {
@return $px / $rootFontSize + rem;
}
.demo {
width: px2rem(100);
height: px2rem(100);
}
複製代碼
pxToRem
方案二在vue-cli3
中裝 postcss-pxtorem
插件就能夠了,其餘平臺也是大體差很少的思路。
const autoprefixer = require('autoprefixer')
const pxtorem = require('postcss-pxtorem')
module.exports = {
// ...
css: {
sourceMap: true,
loaderOptions: {
postcss: {
plugins: [
autoprefixer(),
pxtorem({
rootValue: 37.5,
propList: ['*']
})
]
}
}
}
}
複製代碼
繼續探索postcss-pxtorem插件源碼,查看它實現的原理。
function createPxReplace (rootValue, unitPrecision, minPixelValue) {
return function (m, $1) {
if (!$1) return m;
var pixels = parseFloat($1);
if (pixels < minPixelValue) return m;
var fixedVal = toFixed((pixels / rootValue), unitPrecision);
return (fixedVal === 0) ? '0' : fixedVal + 'rem';
};
}
複製代碼
px
變換成 rem
主要是這個函數,固然裏面有不少可配置的參數, 核心原理和咱們方案一差很少。方便在於,不須要每次寫px
都要加上一個函數,代碼也清晰不少。
是否是全部元素
px
都要轉換成rem
呢?那可不必定哦,border
中的px
不該該轉rem
,涉及到另一個1px
的問題,上一篇文章詳細論述過,避免px
轉rem
,將border
中的px
大寫成PX/Px/pX
vw
相對於視窗寬度的單位,隨寬度變化而變化。
與 rem 相似作法,直接使用 postcss-px-to-viewport 插件進行配置, 配置方式也是和 postcss-pxtorem 大同小異。插件的原理也相同
方案 | 缺陷 | |
---|---|---|
1 | 百分比 | 高度沒法百分比 |
2 | 媒體查詢 + meta 中 viewport |
不一樣設備寬度不一樣,縮放比沒法徹底肯定 |
3 | flex |
仍是沒法解決寬度超出問題 |
上面方案均存在致命缺陷,不推薦使用它完成移動端佈局計算。
flex
與rem
結合使用更佳
vant 組件庫中,默認採用 px
作計量單位,若是須要使用 rem
,直接使用插件完美適配。
對於 vw
方案,vant 也是能夠經過插件將 px
轉成 vw
,對於 vw
可能會存在一些坑點。
ant-design-mobile 組件庫仍然使用 px
單位
@hd: 1px; // 基本單位
// 字體尺寸
// ---
@font-size-icontext: 10 * @hd;
@font-size-caption-sm: 12 * @hd;
@font-size-base: 14 * @hd;
@font-size-subhead: 15 * @hd;
@font-size-caption: 16 * @hd;
@font-size-heading: 17 * @hd;
// 圓角
// ---
@radius-xs: 2 * @hd;
@radius-sm: 3 * @hd;
@radius-md: 5 * @hd;
@radius-lg: 7 * @hd;
@radius-circle: 50%;
// 邊框尺寸
// ---
@border-width-sm: 1PX;
@border-width-md: 1PX;
@border-width-lg: 2 * @hd;
複製代碼
上下滑動頁面會產生卡頓,手指離開頁面,頁面當即中止運動。總體表現就是滑動不流暢,沒有滑動慣性。
爲何 iOS 的 webview 中 滑動不流暢,它是如何定義的?
原來在 iOS 5.0 以及以後的版本,滑動有定義有兩個值 auto
和 touch
,默認值爲 auto
。
-webkit-overflow-scrolling: touch; /* 當手指從觸摸屏上移開,會保持一段時間的滾動 */
-webkit-overflow-scrolling: auto; /* 當手指從觸摸屏上移開,滾動會當即中止 */
複製代碼
將-webkit-overflow-scrolling
值設置爲 touch
.wrapper {
-webkit-overflow-scrolling: touch;
}
複製代碼
設置滾動條隱藏:
.container ::-webkit-scrollbar {display: none;}
可能會致使使用position:fixed;
固定定位的元素,隨着頁面一塊兒滾動
設置外部 overflow
爲 hidden
,設置內容元素 overflow
爲 auto
。內部元素超出 body 即產生滾動,超出的部分 body 隱藏。
body {
overflow-y: hidden;
}
.wrapper {
overflow-y: auto;
}
複製代碼
二者結合使用更佳!
手指按住屏幕下拉,屏幕頂部會多出一塊白色區域。手指按住屏幕上拉,底部多出一塊白色區域。
在 iOS 中,手指按住屏幕上下拖動,會觸發 touchmove
事件。這個事件觸發的對象是整個 webview
容器,容器天然會被拖動,剩下的部分會成空白。
移動端觸摸事件有三個,分別定義爲
1. touchstart :手指放在一個DOM元素上。
2. touchmove :手指拖曳一個DOM元素。
3. touchend :手指從一個DOM元素上移開。
複製代碼
顯然咱們須要控制的是 touchmove
事件
touchmove
事件的速度是能夠實現定義的,取決於硬件性能和其餘實現細節
preventDefault
方法,阻止同一觸點上全部默認行爲,好比滾動。
由此咱們找到解決方案,經過監聽 touchmove
,讓須要滑動的地方滑動,不須要滑動的地方禁止滑動。
值得注意的是咱們要過濾掉具備滾動容器的元素。
實現以下:
document.body.addEventListener('touchmove', function(e) {
if(e._isScroller) return;
// 阻止默認事件
e.preventDefault();
}, {
passive: false
});
複製代碼
在不少時候,咱們能夠不去解決這個問題,換一直思路。根據場景,咱們能夠將下拉做爲一個功能性的操做。
好比: 下拉後刷新頁面
雙擊或者雙指張開手指頁面元素,頁面會放大或縮小。
HTML 自己會產生放大或縮小的行爲,好比在 PC 瀏覽器上,能夠自由控制頁面的放大縮小。可是在移動端,咱們是不須要這個行爲的。因此,咱們須要禁止該不肯定性行爲,來提高用戶體驗。
HTML meta
元標籤標準中有個 中 viewport
屬性,用來控制頁面的縮放,通常用於移動端。以下圖 MDN 中介紹
<meta name="viewport" content="width=device-width, initial-scale=1.0">
複製代碼
所以咱們能夠設置 maximum-scale
、minimum-scale
與 user-scalable=no
用來避免這個問題
<meta name=viewport
content="width=device-width, initial-scale=1.0, minimum-scale=1.0 maximum-scale=1.0, user-scalable=no">
複製代碼
阻止頁面放大(meta不起做用時)
window.addEventListener(
"touchmove",
function (event) {
if (event.scale !== 1) {
event.preventDefault();
}
},
{ passive: false }
);
複製代碼
監聽元素 click
事件,點擊元素觸發時間延遲約 300ms
。
點擊蒙層,蒙層消失後,下層元素點擊觸發。
iOS 中的 safari,爲了實現雙擊縮放操做,在單擊 300ms 以後,若是未進行第二次點擊,則執行 click
單擊操做。也就是說來判斷用戶行爲是否爲雙擊產生的。可是,在 App 中,不管是否須要雙擊縮放這種行爲,click
單擊都會產生 300ms 延遲。
雙層元素疊加時,在上層元素上綁定 touch
事件,下層元素綁定 click
事件。因爲 click
發生在 touch
以後,點擊上層元素,元素消失,下層元素會觸發 click
事件,由此產生了點擊穿透的效果。
前面已經介紹了,移動設備不只支持點擊,還支持幾個觸摸事件。 那麼咱們如今基本思路就是用 touch
事件代替click
事件。
將 click
替換成 touchstart
不只解決了 click
事件都延時問題,還解決了穿透問題。由於穿透問題是在 touch
和 click
混用時產生。
在原生中使用
el.addEventListener("touchstart", () => { console.log("ok"); }, false);
複製代碼
在 vue 中使用
<button @touchstart="handleTouchstart()">點擊</button>
複製代碼
開源解決方案中,也是既提供了 click
事件,又提供了touchstart
事件。如 vant 中的 button
組件
那麼,是否能夠將 click
事件所有替換成 touchstart
呢?爲何開源框架還會給出 click
事件呢?
咱們想象一種情景,同時須要點擊和滑動的場景下。若是將 click
替換成 touchstart
會怎樣?
事件觸發順序:
touchstart
,touchmove
,touchend
,click
。
很容易想象,在我須要touchmove
滑動時候,優先觸發了touchstart
的點擊事件,是否是已經產生了衝突呢?
因此呢,在具備滾動的狀況下,仍是建議使用 click
處理。
在接下來的fastclick
開源庫中也作了以下處理。
主要目的就是,在使用 touchstart
合成 click
事件時,保證其不在滾動的父元素之下。
使用 npm/yarn
安裝後使用
import FastClick from 'fastclick';
FastClick.attach(document.body, options);
複製代碼
一樣,使用fastclick
庫後,click
延時和穿透問題都沒了
按照個人慣例,只要涉及開源庫,那麼咱們必定要去了解它實現的原理。主要是將現有的原生事件集合封裝合成一個兼容性較強的事件集合。
fastclick源碼 核心代碼不長, 1000 行不到。有興趣能夠了解一下!
Android 手機中,點擊 input
框時,鍵盤彈出,將頁面頂起來,致使頁面樣式錯亂。
移開焦點時,鍵盤收起,鍵盤區域空白,未回落。
咱們在app 佈局中會有個固定的底部。安卓一些版本中,輸入彈窗出來,會將解壓 absolute
和 fixed
定位的元素。致使可視區域變小,佈局錯亂。
監聽input失焦事件,失焦即回落
/iphone|ipod|ipad/i.test(navigator.appVersion) &&
document.addEventListener(
"blur",
(event) => {
// 當頁面沒出現滾動條時才執行,由於有滾動條時,不會出現這問題
// input textarea 標籤才執行,由於 a 等標籤也會觸發 blur 事件
if (
document.documentElement.offsetHeight <= document.documentElement.clientHeight &&
["input", "textarea"].includes(event.target.localName)
) {
document.body.scrollIntoView(); // 回頂部
}
},
true
);
複製代碼
軟鍵盤將頁面頂起來的解決方案,主要是經過監聽頁面高度變化,強制恢復成彈出前的高度。
//這裏應該改爲style,height屬性
// 記錄原有的視口高度
const originalHeight = document.body.clientHeight || document.documentElement.clientHeight;
window.onresize = function(){
var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
if(resizeHeight < originalHeight ){
// 恢復內容區域高度
// const container = document.getElementById("container")
// 例如 container.style.height = originalHeight;
}
}
複製代碼
鍵盤不能回落問題出如今 iOS 12+ 和 wechat 6.7.4+ 中,而在微信 H5 開發中是比較常見的 Bug。
兼容原理,1.判斷版本類型 2.更改滾動的可視區域
const isWechat = window.navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
if (!isWechat) return;
const wechatVersion = wechatInfo[1];
const version = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
// 若是設備類型爲iOS 12+ 和wechat 6.7.4+,恢復成原來的視口
if (+wechatVersion.replace(/\./g, '') >= 674 && +version[1] >= 12) {
window.scrollTo(0, Math.max(document.body.clientHeight, document.documentElement.clientHeight));
}
複製代碼
複製代碼
window.scrollTo(x-coord, y-coord)
,其中window.scrollTo(0, clientHeight)
恢復成原來的視口
頭部劉海兩側區域或者底部區域,出現劉海遮擋文字,或者呈現黑底或白底空白區域。
iPhone X 以及它以上的系列,都採用劉海屏設計和全面屏手勢。頭部、底部、側邊都須要作特殊處理。才能適配 iPhone X 的特殊狀況。
設置安全區域,填充危險區域,危險區域不作操做和內容展現。
危險區域指頭部不規則區域,底部橫條區域,左右觸發區域。
具體操做爲:viewport-fit
,meta
標籤設置爲 cover
,獲取全部區域填充。 判斷設備是否屬於 iPhone X,給頭部底部增長適配層
viewport-fit
有 3 個值分別爲:
auto
:此值不影響初始佈局視圖端口,而且整個web頁面都是可查看的。contain
: 視圖端口按比例縮放,以適合顯示內嵌的最大矩形。cover
:視圖端口被縮放以填充設備顯示。強烈建議使用safe area inset
變量,以確保重要內容不會出如今顯示以外。
cover
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes, viewport-fit=cover">
複製代碼
使用 safe area inset
變量
/* 適配 iPhone X 頂部填充*/
@supports (top: env(safe-area-inset-top)){
body,
.header{
padding-top: constant(safe-area-inset-top, 40px);
padding-top: env(safe-area-inset-top, 40px);
padding-top: var(safe-area-inset-top, 40px);
}
}
/* 判斷iPhoneX 將 footer 的 padding-bottom 填充到最底部 */
@supports (bottom: env(safe-area-inset-bottom)){
body,
.footer{
padding-bottom: constant(safe-area-inset-bottom, 20px);
padding-bottom: env(safe-area-inset-bottom, 20px);
padding-top: var(safe-area-inset-bottom, 20px);
}
}
複製代碼
safe-area-inset-top
,safe-area-inset-right
,safe-area-inset-bottom
,safe-area-inset-left
safe-area-inset-*
由四個定義了視口邊緣內矩形的top
,right
,bottom
和left
的環境變量組成,這樣能夠安全地放入內容,而不會有被非矩形的顯示切斷的風險。對於矩形視口,例如普通的筆記本電腦顯示器,其值等於零。
對於非矩形顯示器(如圓形錶盤,
iPhoneX
屏幕,在用戶代理設置的四個值造成的矩形內,全部內容都可見。
其中 env()
用法爲 env( <custom-ident>
, <declaration-value>
? ),第一個參數爲自定義的區域,第二個爲備用值。
其中 var()
用法爲 var(<custom-property-name> , <declaration-value>?)
,做用是在 env()
不生效的狀況下,給出一個備用值。
constant()
被 css
2017-2018 年爲草稿階段,是否已被標準化未知。而其餘iOS 瀏覽器版本中是否有此函數未知,做爲兼容處理而添加進去。
詳情請查看文章末尾的參考資料。
在工做中有須要將頁面生成圖片或者二維碼的需求。可能咱們第一想到的,交給後端來生成更簡單。可是這樣咱們須要把頁面代碼所有傳給後端,網絡性能消耗太大。
使用 QRCode 生成二維碼
import QRCode from 'qrcode';
// 使用 async 生成圖片
const options = {};
const url = window.location.href;
async url => {
try {
console.log(await QRCode.toDataURL(url, options))
} catch (err) {
console.error(err);
}
}
複製代碼
將 await QRCode.toDataURL(url, options)
賦值給 圖片 url
便可
主要是使用 htmlToCanvas
生成 canvas
畫布
import html2canvas from 'html2canvas';
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
});
複製代碼
可是不僅僅在此處就完了,因爲是 canvas
的緣由。移動端生成出來的圖片比較模糊。
咱們使用一個新的 canvas
方法多倍生成,放入一倍容器裏面,達到更加清晰的效果,經過超連接下載圖片 下載文件簡單實現,更完整的實現方式以後更新
const scaleSize = 2;
const newCanvas = document.createElement("canvas");
const target = document.querySelector('div');
const width = parseInt(window.getComputedStyle(target).width);
const height = parseInt(window.getComputedStyle(target).height);
newCanvas.width = width * scaleSize;
newCanvas.height = widthh * scaleSize;
newCanvas.style.width = width + "px";
newCanvas.style.height =width + "px";
const context = newCanvas.getContext("2d");
context.scale(scaleSize, scaleSize);
html2canvas(document.querySelector('.demo'), { canvas: newCanvas }).then(function(canvas) {
// 簡單的經過超連接設置下載功能
document.querySelector(".btn").setAttribute('href', canvas.toDataURL());
}
複製代碼
根據須要設置
scaleSize
大小
在微信公衆號 H5 開發中,頁面內部點擊分享按鈕調用 SDK,方法不生效。
添加一層蒙層,作分享引導。
由於頁面內部點擊分享按鈕沒法直接調用,而分享功能須要點擊右上角更多來操做。
原生與 H5 的通訊
使用 DSBridge
同時支持 iOS 與 Android
文檔見參考資料
bridge.register
bridge.register('enterApp', function() {
broadcast.emit('ENTER_APP')
})
複製代碼
bridge.call
export const getSDKVersion = () => bridge.call('BLT.getSDKVersion')
複製代碼
const broadcast = {
on: function(name, fn, pluralable) {
this._on(name, fn, pluralable, false)
},
once: function(name, fn, pluralable) {
this._on(name, fn, pluralable, true)
},
_on: function(name, fn, pluralable, once) {
let eventData = broadcast.data
let fnObj = { fn: fn, once: once }
if (pluralable && Object.prototype.hasOwnProperty.call(eventData, 'name')) {
eventData[name].push(fnObj)
} else {
eventData[name] = [fnObj]
}
return this
},
emit: function(name, data, thisArg) {
let fn, fnList, i, len
thisArg = thisArg || null
fnList = broadcast.data[name] || []
for (i = 0, len = fnList.length; i < len; i++) {
fn = fnList[i].fn
fn.apply(thisArg, [data, name])
if (fnList[i].once) {
fnList.splice(i, 1)
i--
len--
}
}
return this
},
data: {}
}
export default broadcast
複製代碼
方法調用前,必定要判斷 SDK 是否提供該方法 若是 Android 提供該方法,iOS 上調用就會出現一個方法調用失敗等彈窗。 怎麼解決呢?
提供一個判斷是否 Android、iOS。根據設備進行判斷
export const hasNativeMethod = (name) =>
return bridge.hasNativeMethod('BYJ.' + name)
}
export const getSDKVersion = function() {
if (hasNativeMethod('getSDKVersion')) {
bridge.call('BYJ.getSDKVersion')
}
}
複製代碼
同一功能須要iOS,Android方法名相同,這樣更好處理哦
調試代碼通常就是爲了查看數據和定位 bug。分爲兩種場景,一種是開發和測試時調試,一種是生產環境上調試。
爲何有生產環境上調試呢?有些時候測試環境上無法復現這個 bug,測試環境和生產環境不一致,此時就須要緊急生產調試。
在 PC 端開發時,咱們能夠直接掉出控制檯,使用瀏覽器提供的工具操做devtools或者查看日誌。可是在 App 內部咱們怎麼作呢?
vconsole
控制檯插件使用方法也很簡單
import Vconsole from 'vconsole'
new Vconsole()
複製代碼
有興趣看看它實現的基本原理,咱們關注的點應該在 vsconsole 如何打印出咱們全部 log 的 騰訊開源vconsole
上述方法僅用於開發和測試。生產環境中不容許出現,因此,使用時須要對環境進行判斷。
import Vconsole from 'vconsole'
if (process.env.NODE_ENV !== 'production') {
new Vconsole()
}
複製代碼
操做稍微有點麻煩,不過我會詳細寫出,大體分爲 4 個步驟
sudo npm install spy-debugger -g
複製代碼
設置手機的 HTTP 代理,代理 IP 地址設置爲 PC 的 IP 地址,端口爲spy-debugger
的啓動端口
spy-debugger 默認端口:9888
Android :設置 - WLAN - 長按選中網絡 - 修改網絡 - 高級 - 代理設置 - 手動
IOS :設置 - Wi-Fi - 選中網絡, 點擊感嘆號, HTTP 代理手動
這種方式能夠調試生成環境的頁面,不須要修改代碼,能夠應付大多數調試需求
問題描述:
在滾屏手機端要求全屏滾動(使用swiper),由於移動端高度不定,因此採用了100vh佈局,在模擬器裏很是和諧,結果在發如今移動端的 Chrome 和 微信/safari 瀏覽器中,由於瀏覽器欄和一些導航欄 標題欄 致使不同的呈現
呈現1: swiper插件的高設置爲innerHeight ,致使微信瀏覽器 在滾動的時候 會出現斷層
呈現2: 100vh 其實超出了屏幕高度,致使一些內容被擋住
出現的緣由:
最好避免100vh
,而是依賴javascript
來設置高度,以得到完整的視口體驗。
核心問題是移動瀏覽器(Chrome和Safari)有一個「幫助」功能,地址欄有時可見,有時隱藏,改變了視口的可見大小,
這些瀏覽器沒有將100vh
的高度調整爲視口高度變化時屏幕的可見部分,而是將100vh
設置爲隱藏地址欄的瀏覽器高度。結果是,當地址欄可見時,屏幕的底部部分將被切斷,從而破壞了100vh
的初衷。
呈現3:
在咱們使用iOS Safari的瀏覽器時,上劃頁面的時候工具欄和地址欄會隱藏起來。
當頁面向上滑動的時候,工具欄會隱藏,此時的window.innerHeight會發生變化,可是css中的vh是不會變的,100vh = 隱藏工具欄時的window.innerHeight。(在IphoneXR中,顯示工具欄的時候window.innerHeight = 719px,工具欄隱藏時候window.innerHeight = 833px)
若是你的頁面的原本設計就是能夠滑動的長頁面是沒有什麼影響的,可是若是你的頁面準備作成只有一個視口大小的單頁面應用,那就會出現問題。 由於就算你設置
width: 100%
,頁面仍是會出現滾動,而且向上滾動達到必定閾值的時候,工具欄會隱藏,佈局徹底混亂。而且且在橫屏和豎屏下,工具欄的高度也是不一樣的。此外若是咱們爲元素設置absolute或fixed屬性,想要將它們固定在底部位置的話,Safari也不能如咱們所願。如上文所講,實際上你的頁面有一部分被底部的工具欄擋住了,因此咱們設置在底部位置的元素也會被工具欄擋住。
解決的一些辦法:
min-height: calc(100vh - 0.9rem) //0.9rem是擋住的高度
複製代碼
將高度設置爲window.innerHeight
將正確地將高度設置爲窗口的可見部分。若是地址欄是可見的,那麼window.innerHeight
是全屏的高度。若是地址欄是隱藏的,那麼window.innerHeight
將是屏幕可見部分的高度,
${app}/src/app.vue
mounted() {
// First we get the viewport height and we multiple it by 1% to get a value for a vh unit
let vh = window.innerHeight * 0.01
// Then we set the value in the --vh custom property to the root of the document
document.documentElement.style.setProperty('--vh', `${vh}px`)
// We listen to the resize event
window.addEventListener('resize', () => {
// We execute the same script as before
let vh = window.innerHeight * 0.01
document.documentElement.style.setProperty('--vh', `${vh}px`)
})
},
複製代碼
${app}/views/foo.vue
<style lang="scss" scoped>
.container {
height: 100vh; /* 在以前設置爲100vh,能夠兼容某些不支持自定義屬性的瀏覽器。*/
height: calc(var(--vh, 1vh) * 100 - 46px);
</style>
複製代碼
height:100%
給body下的每一層級都設置高度100%
* {
padding: 0;
margin: 0;
border: 0;
outline: 0;
box-sizing: border-box;
}
html {
width: 100%;
height: 100%;
border: 5px solid red;
overflow: hidden;
//沒試驗 明天實驗一下
height:-webkit-fill-available;
}
複製代碼
工具欄高度75px,calc的計算屬性在低版本的safari中並不兼容 可使用方法4
給body下的每一層級都設置高度100%
calc(100vh - 75px)
複製代碼
場景描述:
<head>
<style>
.app { width: 100%;height: 100%;display: flex;flex: 1;flex-direction: column; }
header { width: 100%;height: 75px; }
main { flex: 1; }
iframe { width: 100%;height: 100%;}
</style>
</head>
<body>
<div class="app">
<header></header>
<main>
<iframe v-if="true"></iframe>
<div v-else></div>
</main>
</div>
複製代碼
具備百分比高度的元素的父級必須具備已定義的高度,而且必須具備height屬性.不然,具備百分比高度的元素必須默認爲height:auto(內容高度)
chrome會自動彌補這個問題,可是Safari會認爲這是一個缺陷,iframe的父級沒有給定的高度,直接致使iframe高度塌陷(隨內容高度)。因此在拉伸瀏覽器窗口的時候,iframe內容實際高度產生了變化,致使該問題的出現。
解決方案:
main { flex: 1;height: calc(100% - 75px); }
height: calc(100vh - calc(100vh - 100%))
複製代碼
iframe { width: 100%; height: calc(100vh - 75px); }
複製代碼
這裏不用100% - 75px,是由於100%依賴於父級指定高度,而vh是直接已瀏覽器但是窗口高度爲基準的。
(safari沒用)
的CSS
body {
min-height: 100vh;
/* mobile viewport bug fix */
min-height: -webkit-fill-available;
}
html {
height: -webkit-fill-available;
}
body {
display: flex;
flex-direction: column;
margin: 0;
min-height: 100vh;
}
main {
flex: 1;
}
複製代碼
<template>
<div class="module"> <div class="module__item">20%</div> <div class="module__item">40%</div> <div class="module__item">60%</div> <div class="module__item">80%</div> <div class="module__item">100%</div> </div>
</template>
<script> export default { mounted() { // First we get the viewport height and we multiple it by 1% to get a value for a vh unit const vh = window.innerHeight * 0.01 // Then we set the value in the --vh custom property to the root of the document document.documentElement.style.setProperty('--vh', `${vh}px`) // We listen to the resize event window.addEventListener('resize', () => { // We execute the same script as before const vh = window.innerHeight * 0.01 document.documentElement.style.setProperty('--vh', `${vh}px`) }) } } </script>
<style> body { background-color: #333; } .module { height: 100vh; /* Use vh as a fallback for browsers that do not support Custom Properties */ height: calc(var(--vh, 1vh) * 100); margin: 0 auto; max-width: 30%; } .module__item { align-items: center; display: flex; height: 20%; justify-content: center; } .module__item:nth-child(odd) { background-color: #fff; color: #f73859; } .module__item:nth-child(even) { background-color: #f73859; color: #f1d08a; } </style>
複製代碼
在作瀏覽器兼容的時候,發現input標籤在safari蘋果瀏覽器中的高度永遠都是默認的,這時候解決的辦法是加上line-height屬性就能夠設置;
若是Safari瀏覽器的input高度設置無論用,必定要設置line-height,而後去除iOS固有UI樣式:-webkit-appearance: none;
在容器中的每一個單元塊被稱之爲 flex item
主軸空間:main size
交叉軸空間:cross size
div{ display: flex | inline-flex; }
複製代碼
當時設置 flex 佈局以後,子元素的 float、clear、vertical-align 的屬性將會失效,
flex:1 所在div 高度自適應屏幕的剩餘高度
.container {
flex-direction: row(默認) | row-reverse | column | column-reverse;
}
複製代碼
2. flex-wrap: 決定容器內項目是否可換行
.container {
flex-wrap: nowrap(默認) | wrap(項目主軸總尺寸超出容器時換行,第一行在上方) | wrap-reverse;(反向)
}
複製代碼
4. justify-content:定義了項目在主軸的對齊方式。
.container {
justify-content:
flex-start(默認值 左對齊)
| flex-end(右對齊)
| center
| space-between(兩端對齊,只有兩行的時候,分別在首尾)
| space-around(每一個項目兩側的間隔相等,項目之間的間隔比項目與邊緣的間隔大一倍)
| space-evenly 子元素會均勻分佈在容器內,同時額外的空間將會被子元素的兩側所分享
}
複製代碼
記住 justify-content
只會在 盒子有剩餘空間能夠分配時 發揮做用。
5. align-items: 定義了項目在交叉軸上的對齊方式
.container {
align-items:
stretch(默認值):若是項目未設置高度或者設爲 auto,將佔滿整個容器的高度。
flex-start (頂點對齊)
flex-end (尾點對齊)
center
baseline (項目的第一行文字的基線對齊)
}
複製代碼
6. align-content: 定義了多根軸線的對齊方式,若是項目只有一根軸線,那麼該屬性將不起做用
.container {
align-content: flex-start | flex-end | center | space-between | space-around | stretch(默認值);
}
複製代碼
當你 flex-wrap 設置爲 nowrap 的時候,容器僅存在一根軸線,由於項目不會換行,就不會產生多條軸線。
當你 flex-wrap 設置爲 wrap 的時候,容器可能會出現多條軸線,這時候你就須要去設置多條軸線之間的對齊方式了。
對齊方式同justify-content 兩端/中間/等距對齊等
1. order: 定義項目在容器中的排列順序,數值越小,排列越靠前,默認值爲 0
設置了 order,使之可以排到最前面。
2. flex-basis: 定義了在分配多餘空間以前,項目佔據的主軸空間,瀏覽器根據這個屬性,計算主軸是否有多餘空間
默認值:auto,即項目原本的大小, 這時候 item 的寬高取決於 width 或 height 的值。
當主軸爲水平方向的時候,當設置了 flex-basis,項目的寬度設置值會失效,flex-basis 須要跟 flex-grow 和 flex-shrink 配合使用才能發揮效果。
3. flex-grow: 定義項目的放大比例
默認值爲 0,即若是存在剩餘空間,也不放大
當全部的項目都以 flex-basis 的值進行排列後,仍有剩餘空間,那麼這時候 flex-grow 就會發揮做用了。
若是全部項目的 flex-grow 屬性都爲 1,則它們將等分剩餘空間。(若是有的話)
若是一個項目的 flex-grow 屬性爲 2,其餘項目都爲 1,則前者佔據的剩餘空間將比其餘項多一倍。
固然若是當全部項目以 flex-basis 的值排列完後發現空間不夠了,且 flex-wrap:nowrap 時,此時 flex-grow 則不起做用了,這時候就須要接下來的這個屬性。
4. flex-shrink: 定義了項目的縮小比例
默認值: 1,即若是空間不足,該項目將縮小,負值對該屬性無效。
若是一個項目的 flex-shrink 屬性爲 0,其餘項目都爲 1,則空間不足時,前者不縮小。
5. flex: flex-grow, flex-shrink 和 flex-basis的簡寫
.item{
flex: <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
0 1 auto(默認)
}
複製代碼
分別以下:
1.當 flex 取值爲一個非負數字,則該數字爲 flex-grow 值,flex-shrink 取 1,flex-basis 取 0%
.item {flex: 1;} (等分剩餘空間)
//等價於
.item {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;
}
複製代碼
2.當 flex 取值爲 0 時,對應的三個值分別爲 0 1 0%
.item {flex: 0;}(存在剩餘空間,也不放大)
//等價於
.item {
flex-grow: 0;
flex-shrink: 1;
flex-basis: 0%;
}
複製代碼
最後求各位大佬多多關注
~~~ 我會一直努力更新的!! 作一個合格的搬運工(笑
這篇文章參考了不少其餘大佬的優秀文章~ 有些參考連接可能沒有指出來 若有遺漏 必定補上❤
(*^▽^*)
下個篇章打算分享一下最近面試出現的高頻考點和答案 ~!