Open 54leibo opened 7 years ago
会很麻烦。你可以说说你的具体需求,看看能否直接在 vux 源码来支持。
我想要实现视图自适应屏幕尺寸,目前想要采取的方案是淘宝的flexible.js(https://github.com/amfe/lib-flexible),但是在使用过程中发现,把px转化为rem的时候把vux的px转化成了rem(使用px2rem),这样造成的问题是:1.没能避免不需要转化的(比如:border:1px solid #000;中的1px);2.我们的设计图是750px的,而vux好像是375px,这也造成了转化结果不是想要的;
补充:js计算的也无法转化为rem,这样在如弹窗组件中会出现部分单位是px,部分单位是rem,结果造成视图有点错乱
可否建个应用 flexible 的基础 repo,并能重现上面的问题,我来尝试在 vux 或者 vux-loader 里支持。
可以
flexible.js的适配是会判断iphone端drp,然后设置viewport,而安卓端统一设置为1。vux的样式用的是px,导致在iphone会被缩小,而在安卓就没问题。
是的,这两天有点忙,我接下来尽快弄一个能重现问题的rp
目前的处理方法是将vux组件中px转化为PX,避免被转成rem
https://github.com/airyland/vux/issues/932#issuecomment-280260234
如果引入了1px的话,还要做些特殊处理
目前我是这么搞得,可以参考下
{
name: 'after-less-parser',
fn: function (source) {
if (this.resourcePath.replace(/\\/g, '/').indexOf('/vux/src/components') > -1) {
source = source.replace(/px/g, 'PX')
}
// 自定义的全局样式大部分不需要转换
if (this.resourcePath.replace(/\\/g, '/').indexOf('App.vue') > -1) {
source = source.replace(/px/g, 'PX').replace(/-1PX/g, '-1px')
}
return source
}
},
{
name: 'style-parser',
fn: function (source) {
if (this.resourcePath.replace(/\\/g, '/').indexOf('/vux/src/components') > -1) {
source = source.replace(/px/g, 'PX')
}
// 避免转换1PX.less文件路径
if (source.indexOf('1PX.less') > -1) {
source = source.replace(/1PX.less/g, '1px.less')
}
return source
}
}
转换rem使用的是postcss-plugin-px2rem,当然 postcss-px2rem 也可以
require('postcss-plugin-px2rem')({
rootValue: 75, // 这里对应的是750的设计图尺寸
selectorBlackList: ['html'],
mediaQuery: true,
propBlackList: ['border-radius'] // 如果要保持font-size不转换,替换为 ['font-size']
}),
搞了一个简单的重现:git@github.com:54leibo/54leibo.github.com.git
vux的ui是基于weui的,而weui本身并没有使用rem (why)
如果全局转rem的话,会使组件大小位置不正确,所以上面采用的是组件和页面分开处理
你那个demo,我跑了下,font-size都变成0了,原因未知
你上面说的没转成功的,我猜可能是less文件没转换
之前是loader出了点问题,现在已经修复;我先研究下你目前给出的解决方案
after-less-parser、style-parser这两个是在哪里配置的呢
vux-loader里面
可以按照如下方式兼容VUX和手淘flexible适配方案: 将js文件中涉及到data-dpr与缩放scale的代码改写,默认所有设备的data-dpr为1.
if (!i && !j) {
//将p直接置为false,这样缩放比例都为1,dpr也都设置为了1
let p = false,
q = a.devicePixelRatio;
i = p ? q >= 3 && (!i || i >= 3) ? 3 : q >= 2 && (!i || i >= 2) ? 2 : 1 : 1, j = 1 / i
}
同样遇到这个问题 楼上哪个方案可行?
同样遇到这个问题,求可行方案
一样遇到了这个问题=。=,求可行方案。或者暂时的替代方案。
同样遇到这个问题 目前使用的是上面贴出的after-less-parser的方案 但是要注意 那段代码有2个地方写的有问题 就是/vux/components那段 要改成vux/components 因为我把路径打印出来发现前面是@vux这种格式
@RenShine 感谢提醒,使用 cnpm 安装依赖后路径会是你说的这种情况 cc @wg5945
@RenShine 上面使用的是indexOf,多个/会有影响么?
原来是使用的cnpm导致vux路径变化哦,cnpm会导致一些不可期的问题,还是使用yarn吧
对于上面几位寻求解决方案的,方案已经给出了,为什么不自己尝试一下呢?
@wg5945 感谢 目前正在尝试整合你的方案 good
@wg5945 我也正好遇到这个问题,但是觉得好像上边方案不解决问题啊。首先flexble.js会根据不同dpr缩放整个页面,让border保持1像素,如果禁掉这个缩放那flexble就不好用一半。如果保持页面缩放,那vux就算px不转rem,那别的元素按750缩放正常看,vux按375的大小缩放小一半,还是存在问题。
@525729985 没太明白你的意思
其实上面的最终结果就是: 页面px转成rem,根据dpr缩放 vux组件px转成PX,不缩放
我现在是这样使用的 1.使用after-less-parser、style-parser将vux中的px转为PX,这样在使用px2rem处理时就避免了vux被处理 2.阉割掉了flexible.js中根据dpr缩放的功能
上面几位使用flexible做适配的遇到这么多问题,为什么就不尝试用固定尺寸做适配么?
<meta name="viewport" content="width=375,user-scalable=no">
设计图是多少写多少就行了,没那多转来转去的,到最后效果还是一样,已在项目中使用快一年了
@agileago 你这个方案我也用了有2年了 不过我是设置成640的 你这个375其实是有问题的(隐约记得在6P下好像是有点问题) 不过其实大部分场景下都不会有问题 简单粗暴
但是还是有一些特殊情况没有rem好处理 有一些情况下viewport缩放会导致元素有点糊
其实早期大家都是用这个来做适配的(包括天猫) rem的出现就是为了解决viewport解决不了的问题(也是天猫提出这个方案的)而且现在webpack很方便 用postcss平时设计图是多少我们也写多少 都是插件自动转的 所以一般都不使用viewport的方案了
@RenShine 还好吧,暂时没发现有什么问题,除了横竖屏切换的时候有时候没有正常切过来到时页面变得很大(这个加个监听事件重置一下就解决了),现在荔枝fm还在用 http://m.lizhi.fm ,设置成375或者640看你的设计图了,我以前也是用rem的方案,主要那个时候大家都吹嘘着移动端要用rem,稀里糊涂的就用了,然后使用了之后团队很多人就说这东西还得再转一下,并且当时有的人的设计图是320,还有的人是375的,导致一些人觉得这玩意挺麻烦的(有些小项目是不用webpack的,比如有的人只写css),后来发现viewport的方案更简单也没什么大的问题,然后大家都喜欢用,其实viewport比较不好的一点就是不能设置字体在每个分辨率下显示一样大小,而rem就可以
a {
margin-top: px2rem(120);
font-size: 14px;
}
这是我觉得他唯一的优点吧
@agileago 设置viewport为固定宽度在很多那些不需要webpack的场景下肯定是OK的 不过问题是有的。 一个就是不能使用媒体查询 第二个就是1px边框的问题(时间太久了这一点存疑,但是媒体查询肯定是没法用的)
原来那么多人用flexble.js阿, 我说下我的几个项目睬的坑后用的方案吧。
index.html: 加上
<meta name="flexible" content="initial-dpr=1">
在build加个js文件, 防止1px的给转换 mycss.js
const postcss = require('postcss')
const cssObj = require('css')
const onePxRegExp = /\b1px\b/;
module.exports = postcss.plugin('mycss', function (options) {
return function (css, result) {
let oldCssText = css.toString()
if(oldCssText.indexOf('font-size') === -1) return
let astObj = cssObj.parse(oldCssText)
let rules = astObj.stylesheet.rules
rules.forEach((rule, i) => {
if(Array.isArray(rule.declarations)) {
rule.declarations.forEach((declaration, j) => {
if (declaration.type === 'declaration' && onePxRegExp.test(declaration.value)) {
let newRule = {
type: 'comment',
comment: 'no'
}
rule.declarations.splice(j + 1, 0, newRule)
}
})
}
})
let newCssText = cssObj.stringify(astObj)
result.root = postcss.parse(newCssText);
};
});
安装postcss-px2rem 在vue-loader的postcss加上 require('./mycss')(), 和 require('postcss-px2rem')({remUnit: 37.5}) 用37.5是因为weui都是这个尺寸的, 所有你要按你自己设计稿转换 例如:设计稿是750, 24px 你在项目里 要用12px
postcss: function () {
return [
require('./mycss')(),
require('autoprefixer')({
browsers: ['iOS >= 7', 'Android >= 4.1']
}),
require('postcss-px2rem')({remUnit: 37.5})
]
}
最后要加个公用方法
getRealPx (px, remUnit = 37.5) {
return px * (parseFloat(document.getElementsByTagName('html')[0].style.fontSize) / remUnit)
}
你要在js里用px 都要用这个方法来转变
例如用 ViewBox
<view-box :body-padding-top="getRealPx(50) + 'px'"></view-box>
注意: 不要在style="width:100px" 这样写px 是不用自动转换的 一定要在下面写写
<style>
div {width:100px}
</style>
有空开个git放上去
@RenShine 哈哈,具体用哪个还是得考虑业务场景,如果真的碰上了那就用rem也行,两手准备,但我目前的项目大部分都是固定尺寸先行。不过我是用的hotcss来做rem适配的,走编译路线的,虽说不是什么大问题,但有时候真的很烦,就像你用coffeescript或者Typescript一样,写下的每行代码都要在脑海中自动转换成原生js,这个过程着实烧脑。😁😁😂
flexible又来了 2.0版本
我的情况是这样的,用的手淘rem,我的px转rem是用的(github.com/flashlizi/cssrem)插件,并没有使用postcss-px2rem插件,所以不存在所有的px被转换为rem。只有我自己的样式被转换为了rem,现在vux的组件在项目中显示的非常小,请问如何修改可以使用rem + vux?
@xiaolongyuan 2.0使用的vw,但是目前还是有好几款主流手机不支持,特别是华为的,因此还是要慎重一下
@moahmn 上面写过了,目前处理方案是不对vux组件进行转化,不管哪种转化方案都有不进行转化的方式,自行处理下就好
@wg5945 关键是2.0使用方式让人有点摸不着头脑 https://github.com/amfe/lib-flexible/issues/159
这我倒没发现,按照他的教程一步步做就好了,在ios和支持的android手机上适配都很完美
@wg5945 你竟然成功了 我整合后 VUX有问题 vw 单位转换倒是没问题 能帮我看看?
vue-loader.conf.js
module.exports = {
loaders: utils.cssLoaders({
sourceMap: isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap,
extract: isProduction
}),
transformToRequire: {
video: 'src',
source: 'src',
img: 'src',
image: 'xlink:href'
},
postcss: [
// require('autoprefixer')({
// browsers: ['last 2 versions']
// }),
require('postcss-cssnext')({
// browsers: ['last 2 versions']
'browsers':'ios >= 7,android >= 4'
}),
require('precss')(),
require('postcss-write-svg')({ /* options */ }),
require('postcss-aspect-ratio-mini')(),
// require('postcss-px2rem')({
// remUnit: 75,
// threeVersion: true
// }),
require('postcss-px-to-viewport')({
viewportWidth: 750,
viewportHeight: 1334,
unitPrecision: 5,
viewportUnit: 'vw',
selectorBlackList: [],
minPixelValue: 1,
mediaQuery: false
}),
// require('postcss-adaptive')({
// // autoRem:true
// })
]
}
webpack.base.conf.js
module.exports = vuxLoader.merge(webpackConfig, {
plugins: [
{
name: 'vux-ui'
},
{
name: 'progress-bar'
},
{
name: 'duplicate-style',
// options: {
// canPrint: true
// }
},
{
name: 'after-less-parser',
fn: function (source) {
if (this.resourcePath.replace(/\\/g, '/').indexOf('/vux/src/components') > -1) {
source = source.replace(/px/g, 'PX')
}
// 自定义的全局样式大部分不需要转换
if (this.resourcePath.replace(/\\/g, '/').indexOf('App.vue') > -1) {
source = source.replace(/px/g, 'PX').replace(/-1PX/g, '-1px')
}
return source
}
},
{
name: 'style-parser',
fn: function (source) {
if (this.resourcePath.replace(/\\/g, '/').indexOf('/vux/src/components') > -1) {
source = source.replace(/px/g, 'PX')
}
// 避免转换1PX.less文件路径
if (source.indexOf('1PX.less') > -1) {
source = source.replace(/1PX.less/g, '1px.less')
}
return source
}
}
// {
// name: 'less-theme',
// path: 'src/styles/theme.less'
// },
// {
// name: 'i18n',
// vuxStaticReplace: false,
// staticReplace: false,
// extractToFiles: 'src/locales/components.yml',
// localeList: ['en', 'zh-CN']
// },
]
})
@wg5945 我能直接采用你上面的方案?我发现按照上面的配置(没用postcss-px2rem转换,我自己在编辑器里转的,所以也不存在说vux的组件样式px被转换为rem)后组件还是比正常的转换rem的元素小很多
目前也实现了px转换为PX但是组件还是很小
@xiaolongyuan 这个要看看 postcss-px-to-viewport 里面有什么不转成vw的方案 当初postcss-px2rem是改成PX不转化
@moahmn 你再仔细看看吧 input组件的大小应该看 .weui-cells 这个样式,你看看呢
@wg5945 大大说的是vux里边的px转为PX,即避免了插件的px2rem,但其实flexibox的精髓即是根据dpr去缩放页面,即动态设置meta,所以就算是vux里的组件没被转换也会被缩放。现在已知的解决方案是默认设置meta,dpr为1,但感觉这样并不优雅,因为适配的字体方案也是根据dpr设置的
各位大神,有没有完整的解决方案,求助!我发现vux的组件转换合适后,边框和字体缩放就发生了变化。该如何解决,求助大神!
看了下flexible的源码 如果使用了0.3.4的flexible也同时希望使用vux,可以手动设置meta头,在header头部加入 中括号meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"中括号(中括号自己替换下,打不出来)
下面是flexible的部分源码
var metaEl = doc.querySelector('meta[name="viewport"]');
var flexibleEl = doc.querySelector('meta[name="flexible"]');
var dpr = 0;
var scale = 0;
//如果有手动设置的meta头部进入这个逻辑
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));
}
}
}
// dpr 和sacle默认是0,如果上面两个逻辑都没进去的话进入这一步,这就是为什么与vux配合会出现缩放的原因, 根据几倍屏去分别设置不同的meta头
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) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
手动设置下meta头就可以不根据IOS 2/3倍屏去缩放
如果不用rem,移动端大家都是用什么做适配的呢?还可以很好的配合这些UI框架?
https://github.com/callmepinggege/vux-lib-flexible 结合上述大神的方案 自己实现了一套 大家可以直接用
用网易的解决方案
@RenShine 你说的定宽问题今天被我遇到了,果然是在PLUS上面有问题,这个问题是,当页面是整屏滚动的时候,并且页面的长度在1000px以内,然后你做了个弹窗,滚动了滚动条,这个弹窗上面的按钮的触发区域就上移了
我实在模拟器模拟的,弹窗的位置上移了,但显示还是正常的,真的让人很无语,你那边有没有啥好的解决方案
@moahmn 我也遇到了同样的组件很小的问题。请问你解决了么?
中括号meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"中括号 在head中加入这个meta就行了。这是我目前的做法。但手淘的font-dpr那个宏就不起作用了,因为现在的dpr被永久设置为1了。字体的设置我还是使用px,你也可以使用rem做单位虽然说作者是不推荐的,但是我看网易移动端也用rem做字体的单位,你可以参考下。
我需要和flexble.js结合使用,框架中的px被转后出现了问题,所以现在想要自己维护一份,是需要这样吗:改动vux源码=》发布一个npm包=》安装使用 如果改动频繁需要不断发布npm包,好像会很麻烦,有更好的方式做这件事情吗