airyland / vux

Mobile UI Components based on Vue & WeUI
https://vux.li
MIT License
17.59k stars 3.71k forks source link

需要和flexble.js一起使用,怎样自己维护一份vux还能保持更新 #1796

Open 54leibo opened 7 years ago

54leibo commented 7 years ago

我需要和flexble.js结合使用,框架中的px被转后出现了问题,所以现在想要自己维护一份,是需要这样吗:改动vux源码=》发布一个npm包=》安装使用 如果改动频繁需要不断发布npm包,好像会很麻烦,有更好的方式做这件事情吗

airyland commented 7 years ago

会很麻烦。你可以说说你的具体需求,看看能否直接在 vux 源码来支持。

54leibo commented 7 years ago

我想要实现视图自适应屏幕尺寸,目前想要采取的方案是淘宝的flexible.js(https://github.com/amfe/lib-flexible),但是在使用过程中发现,把px转化为rem的时候把vux的px转化成了rem(使用px2rem),这样造成的问题是:1.没能避免不需要转化的(比如:border:1px solid #000;中的1px);2.我们的设计图是750px的,而vux好像是375px,这也造成了转化结果不是想要的;

54leibo commented 7 years ago

补充:js计算的也无法转化为rem,这样在如弹窗组件中会出现部分单位是px,部分单位是rem,结果造成视图有点错乱

airyland commented 7 years ago

可否建个应用 flexible 的基础 repo,并能重现上面的问题,我来尝试在 vux 或者 vux-loader 里支持。

54leibo commented 7 years ago

可以

teshun commented 7 years ago

flexible.js的适配是会判断iphone端drp,然后设置viewport,而安卓端统一设置为1。vux的样式用的是px,导致在iphone会被缩小,而在安卓就没问题。

54leibo commented 7 years ago

是的,这两天有点忙,我接下来尽快弄一个能重现问题的rp

wg5945 commented 7 years ago

目前的处理方法是将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']
    }),
54leibo commented 7 years ago

搞了一个简单的重现:git@github.com:54leibo/54leibo.github.com.git

wg5945 commented 7 years ago

vux的ui是基于weui的,而weui本身并没有使用rem (why)

如果全局转rem的话,会使组件大小位置不正确,所以上面采用的是组件和页面分开处理

你那个demo,我跑了下,font-size都变成0了,原因未知

你上面说的没转成功的,我猜可能是less文件没转换

54leibo commented 7 years ago

之前是loader出了点问题,现在已经修复;我先研究下你目前给出的解决方案

54leibo commented 7 years ago

after-less-parser、style-parser这两个是在哪里配置的呢

wg5945 commented 7 years ago

vux-loader里面

https://vux.li/#/zh-CN/vux-loader?id=plugins

prettybot commented 7 years ago

可以按照如下方式兼容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
  }
xiaolongyuan commented 7 years ago

同样遇到这个问题 楼上哪个方案可行?

jun888 commented 7 years ago

同样遇到这个问题,求可行方案

Anehta commented 7 years ago

一样遇到了这个问题=。=,求可行方案。或者暂时的替代方案。

RenShine commented 7 years ago

同样遇到这个问题 目前使用的是上面贴出的after-less-parser的方案 但是要注意 那段代码有2个地方写的有问题 就是/vux/components那段 要改成vux/components 因为我把路径打印出来发现前面是@vux这种格式

airyland commented 7 years ago

@RenShine 感谢提醒,使用 cnpm 安装依赖后路径会是你说的这种情况 cc @wg5945

wg5945 commented 7 years ago

@RenShine 上面使用的是indexOf,多个/会有影响么?

原来是使用的cnpm导致vux路径变化哦,cnpm会导致一些不可期的问题,还是使用yarn吧

wg5945 commented 7 years ago

对于上面几位寻求解决方案的,方案已经给出了,为什么不自己尝试一下呢?

xiaolongyuan commented 7 years ago

@wg5945 感谢 目前正在尝试整合你的方案 good

525729985 commented 7 years ago

@wg5945 我也正好遇到这个问题,但是觉得好像上边方案不解决问题啊。首先flexble.js会根据不同dpr缩放整个页面,让border保持1像素,如果禁掉这个缩放那flexble就不好用一半。如果保持页面缩放,那vux就算px不转rem,那别的元素按750缩放正常看,vux按375的大小缩放小一半,还是存在问题。

wg5945 commented 7 years ago

@525729985 没太明白你的意思

其实上面的最终结果就是: 页面px转成rem,根据dpr缩放 vux组件px转成PX,不缩放

54leibo commented 7 years ago

我现在是这样使用的 1.使用after-less-parser、style-parser将vux中的px转为PX,这样在使用px2rem处理时就避免了vux被处理 2.阉割掉了flexible.js中根据dpr缩放的功能

agileago commented 7 years ago

上面几位使用flexible做适配的遇到这么多问题,为什么就不尝试用固定尺寸做适配么?

<meta name="viewport" content="width=375,user-scalable=no">

设计图是多少写多少就行了,没那多转来转去的,到最后效果还是一样,已在项目中使用快一年了

RenShine commented 7 years ago

@agileago 你这个方案我也用了有2年了 不过我是设置成640的 你这个375其实是有问题的(隐约记得在6P下好像是有点问题) 不过其实大部分场景下都不会有问题 简单粗暴

但是还是有一些特殊情况没有rem好处理 有一些情况下viewport缩放会导致元素有点糊

其实早期大家都是用这个来做适配的(包括天猫) rem的出现就是为了解决viewport解决不了的问题(也是天猫提出这个方案的)而且现在webpack很方便 用postcss平时设计图是多少我们也写多少 都是插件自动转的 所以一般都不使用viewport的方案了

agileago commented 7 years ago

@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;
}

这是我觉得他唯一的优点吧

RenShine commented 7 years ago

@agileago 设置viewport为固定宽度在很多那些不需要webpack的场景下肯定是OK的 不过问题是有的。 一个就是不能使用媒体查询 第二个就是1px边框的问题(时间太久了这一点存疑,但是媒体查询肯定是没法用的)

hminghe commented 7 years ago

原来那么多人用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放上去

agileago commented 7 years ago

@RenShine 哈哈,具体用哪个还是得考虑业务场景,如果真的碰上了那就用rem也行,两手准备,但我目前的项目大部分都是固定尺寸先行。不过我是用的hotcss来做rem适配的,走编译路线的,虽说不是什么大问题,但有时候真的很烦,就像你用coffeescript或者Typescript一样,写下的每行代码都要在脑海中自动转换成原生js,这个过程着实烧脑。😁😁😂

xiaolongyuan commented 7 years ago

flexible又来了 2.0版本

moahmn commented 7 years ago

我的情况是这样的,用的手淘rem,我的px转rem是用的(github.com/flashlizi/cssrem)插件,并没有使用postcss-px2rem插件,所以不存在所有的px被转换为rem。只有我自己的样式被转换为了rem,现在vux的组件在项目中显示的非常小,请问如何修改可以使用rem + vux?

wg5945 commented 7 years ago

@xiaolongyuan 2.0使用的vw,但是目前还是有好几款主流手机不支持,特别是华为的,因此还是要慎重一下

wg5945 commented 7 years ago

@moahmn 上面写过了,目前处理方案是不对vux组件进行转化,不管哪种转化方案都有不进行转化的方式,自行处理下就好

xiaolongyuan commented 7 years ago

@wg5945 关键是2.0使用方式让人有点摸不着头脑 https://github.com/amfe/lib-flexible/issues/159

wg5945 commented 7 years ago

这我倒没发现,按照他的教程一步步做就好了,在ios和支持的android手机上适配都很完美

xiaolongyuan commented 7 years ago

@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']
    // },

  ]
})
moahmn commented 7 years ago

@wg5945 我能直接采用你上面的方案?我发现按照上面的配置(没用postcss-px2rem转换,我自己在编辑器里转的,所以也不存在说vux的组件样式px被转换为rem)后组件还是比正常的转换rem的元素小很多 qq 20171101101844 qq 20171101101849

目前也实现了px转换为PX但是组件还是很小

wg5945 commented 7 years ago

@xiaolongyuan 这个要看看 postcss-px-to-viewport 里面有什么不转成vw的方案 当初postcss-px2rem是改成PX不转化

wg5945 commented 7 years ago

@moahmn 你再仔细看看吧 input组件的大小应该看 .weui-cells 这个样式,你看看呢

BlackEyeByLee commented 7 years ago

@wg5945 大大说的是vux里边的px转为PX,即避免了插件的px2rem,但其实flexibox的精髓即是根据dpr去缩放页面,即动态设置meta,所以就算是vux里的组件没被转换也会被缩放。现在已知的解决方案是默认设置meta,dpr为1,但感觉这样并不优雅,因为适配的字体方案也是根据dpr设置的

Amling2017 commented 7 years ago

各位大神,有没有完整的解决方案,求助!我发现vux的组件转换合适后,边框和字体缩放就发生了变化。该如何解决,求助大神!

moahmn commented 7 years ago

看了下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倍屏去缩放

bingyang519 commented 6 years ago

如果不用rem,移动端大家都是用什么做适配的呢?还可以很好的配合这些UI框架?

callmepinggege commented 6 years ago

https://github.com/callmepinggege/vux-lib-flexible 结合上述大神的方案 自己实现了一套 大家可以直接用

LuckyDing commented 6 years ago

用网易的解决方案

agileago commented 6 years ago

@RenShine 你说的定宽问题今天被我遇到了,果然是在PLUS上面有问题,这个问题是,当页面是整屏滚动的时候,并且页面的长度在1000px以内,然后你做了个弹窗,滚动了滚动条,这个弹窗上面的按钮的触发区域就上移了

image

我实在模拟器模拟的,弹窗的位置上移了,但显示还是正常的,真的让人很无语,你那边有没有啥好的解决方案

yangqin007 commented 6 years ago

@moahmn 我也遇到了同样的组件很小的问题。请问你解决了么?

moahmn commented 6 years ago

中括号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做字体的单位,你可以参考下。