前言
前段时间写了一个数据可视化大屏的项目,从纯 h5c3+js 的一个页面改成一个 vue3 的小项目,因为是数据可视化大屏这种需要适配更大的屏幕,所以单位应该设置适配从而在大屏上进行显示.
flexible.js 移动端自适应方案
一、官方文档:
flexible.js 是手淘开发出的一个用来适配移动端的 js 框架。手淘框架的核心原理就是根据制不同的 width 给网页中 html 根节点设置不同的 font-size,然后所有的 px 都用 rem 来代替,这样就实现了不同大小的屏幕都适应相同的样式了。其实它就是一个终端设备适配的解决方案,也就是说它可以让你在不同的终端设备中实现页面适配。
github 地址:https://github.com/amfe/lib-flexible
官方文档地址:https://github.com/amfe/article/issues/17
二、使用方式
1 <script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.2/??flexible_css.js,flexible.js" ></script>
1 2 3 4 5 <meta name ="viewport" content ="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /> <script src ="./node_modules/amfe-flexible/index.js" > </script >
三、源码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 (function (win, lib ) { var doc = win.document ; var docEl = doc.documentElement ; var metaEl = doc.querySelector ('meta[name="viewport"]' ); var flexibleEl = doc.querySelector ('meta[name="flexible"]' ); var dpr = 0 ; var scale = 0 ; var tid; var flexible = lib.flexible || (lib.flexible = {}); if (metaEl) { console .warn ("将根据已有的meta标签来设置缩放比例" ); var match = metaEl .getAttribute ("content" ) .match (/initial\-scale=([\d\.]+)/ ); if (match) { scale = parseFloat (match[1 ]); dpr = parseInt (1 / scale); } } else if (flexibleEl) { var content = flexibleEl.getAttribute ("content" ); if (content) { var initialDpr = content.match (/initial\-dpr=([\d\.]+)/ ); var maximumDpr = content.match (/maximum\-dpr=([\d\.]+)/ ); if (initialDpr) { dpr = parseFloat (initialDpr[1 ]); scale = parseFloat ((1 / dpr).toFixed (2 )); } if (maximumDpr) { dpr = parseFloat (maximumDpr[1 ]); scale = parseFloat ((1 / dpr).toFixed (2 )); } } } if (!dpr && !scale) { var isAndroid = win.navigator .appVersion .match (/android/gi ); var isIPhone = win.navigator .appVersion .match (/iphone/gi ); var devicePixelRatio = win.devicePixelRatio ; if (isIPhone) { if (devicePixelRatio >= 3 && (!dpr || dpr >= 3 )) { dpr = 3 ; } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2 )) { dpr = 2 ; } else { dpr = 1 ; } } else { dpr = 1 ; } scale = 1 / dpr; } docEl.setAttribute ("data-dpr" , dpr); if (!metaEl) { metaEl = doc.createElement ("meta" ); metaEl.setAttribute ("name" , "viewport" ); metaEl.setAttribute ( "content" , "initial-scale=" + scale + ", maximum-scale=" + scale + ", minimum-scale=" + scale + ", user-scalable=no" ); if (docEl.firstElementChild ) { docEl.firstElementChild .appendChild (metaEl); } else { var wrap = doc.createElement ("div" ); wrap.appendChild (metaEl); doc.write (wrap.innerHTML ); } } function refreshRem ( ) { var width = docEl.getBoundingClientRect ().width ; if (width / dpr > 540 ) { width = 540 * dpr; } var rem = width / 10 ; docEl.style .fontSize = rem + "px" ; flexible.rem = win.rem = rem; } win.addEventListener ( "resize" , function ( ) { clearTimeout (tid); tid = setTimeout (refreshRem, 300 ); }, false ); win.addEventListener ( "pageshow" , function (e ) { if (e.persisted ) { clearTimeout (tid); tid = setTimeout (refreshRem, 300 ); } }, false ); if (doc.readyState === "complete" ) { doc.body .style .fontSize = 12 * dpr + "px" ; } else { doc.addEventListener ( "DOMContentLoaded" , function (e ) { doc.body .style .fontSize = 12 * dpr + "px" ; }, false ); } refreshRem (); flexible.dpr = win.dpr = dpr; flexible.refreshRem = refreshRem; flexible.rem2px = function (d ) { var val = parseFloat (d) * this .rem ; if (typeof d === "string" && d.match (/rem$/ )) { val += "px" ; } return val; }; flexible.px2rem = function (d ) { var val = parseFloat (d) / this .rem ; if (typeof d === "string" && d.match (/px$/ )) { val += "rem" ; } return val; }; })(window , window ["lib" ] || (window ["lib" ] = {}));
简化方案
为了简化移动端自适应的实现,我提供了一种更简单的方案。以下是该方案的具体实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 (function flexible (window , document ) { var docEl = document .documentElement ; var dpr = window .devicePixelRatio || 1 ; function setBodyFontSize ( ) { if (document .body ) { document .body .style .fontSize = 12 * dpr + "px" ; } else { document .addEventListener ("DOMContentLoaded" , setBodyFontSize); } } setBodyFontSize (); function setRemUnit ( ) { var rem = docEl.clientWidth / 24 ; docEl.style .fontSize = rem + "px" ; } setRemUnit (); window .addEventListener ("resize" , setRemUnit); window .addEventListener ("pageshow" , function (e ) { if (e.persisted ) { setRemUnit (); } }); if (dpr >= 2 ) { var fakeBody = document .createElement ("body" ); var testElement = document .createElement ("div" ); testElement.style .border = ".5px solid transparent" ; fakeBody.appendChild (testElement); docEl.appendChild (fakeBody); if (testElement.offsetHeight === 1 ) { docEl.classList .add ("hairline" ); } docEl.removeChild (fakeBody); } })(window , document );
使用
项目中使用的话,可以放在src/utils/flexible.js
文件中,在main.js
文件中直接引入即可使用
1 import "./utils/flexible" ;
此时在 css 样式中,可以用 rem 单位代替 px,其中项目页面是以 1920px 为宽度,适配之后 1rem = 80px,示例如下:
1 2 3 4 5 6 header h1 { font-size : 0.475rem ; color : #fff ; text-align : center; line-height : 1rem ; }
注意事项
在使用此简化方案时,请注意以下几点:
设置页面宽度: 我们默认将页面宽度设置为 1920px
作为基准进行适配,你可以根据实际情况调整该值。
兼容性考虑: 该方案在大多数现代浏览器和设备上都能良好运行,但仍需进行充分测试以确保在不同环境下的兼容性。
适用场景: 此方案适用于大多数移动端项目,特别是对于需要快速实现自适应的小型项目来说,是一个不错的选择。
推荐工具
另外,推荐一个 VSCode 插件可以帮助你更方便地进行 px 到 rem 的单位转换,提高开发效率。尤其在移动端适配过程中,能够帮助你快速计算合适的 rem 值。
需要进行扩展设置,设置好相应的宽度,就可以进行快速转换了
用JavaScript创建一个灵活且响应迅速的网页设计