weex 一个传说级巨坑-- 2018最新版weex踩坑指南(weex navigator 多界面跳转)

先说结论,本人极度非常

不推荐weex作为任何商用开发


有很多人会说了... 你瞎扯.. 你看别人阿里.. 啊飞猪... 啊那个支付宝... 人家不是用得好好的么...

当然这也是我们公司作为技术选型的考量.. 三端通用.. 阿里系的app全线在用.. 理论上是可以实现的.. 而且我们在编码过程中.. 可以把IOS工程师,安卓工程师和前端工程师以及部分熟悉一点前端的后端工程师都拉过来贡献一套代码.. 代码质量可以得到保障

现在想想只能说... 太天真了... 你也不想想人家阿里有多少大牛有多少人在做这个项目.. 再说淘宝都卡成啥样了大家还是愿意用.. 如果你的项目这样卡两下你的app是否还能像淘宝那样拉住顾客??

这就像你说你想写一篇巨著... 你打算用英文写... 翻译成中文 俄文 日文(ios android web)... 让人看了还能把别人国家的感动得稀里哗啦的.. 本身难度就会不小.. 

另外你在android中打开布局边界看一下天猫飞猪... 里面weex的界面已经只剩下很少的界面了.. 很多界面已经替换成了原生或者webview的混合界面... 做得那么杂用户体验还过得去.. 我只能说一句.. 阿里牛逼=.= ... 所以很明显的一个信息就是.. 这个技术连他们自己人都不广泛使用了.. 可见还是有很大的局限性的..

如果你们已经决定使用weex.. 或者正准备用它构建三端应用... 那么.. 希望我的踩坑指南可以帮到你.. 从入门到放弃...


一.开始准备

搭建开发环境

首先根据官网的提示安装node.js weex-toolkit  然后就可以开始创建项目了.. 你可以选择RN的rex 或者前端的VUE模式写代码都是可以的.. 但是我们用的是vue.. rex也考虑过.. 只是没人会写RN.. 加上网上weex+RN的例子很少.. 所以就放弃了.. 

如果是在windows上的话.. 安装的东西都是需要配置环境变量的... 

D:\nodeJs\npm;D:\nodeJs\node.exe;C:\Users\jupiter\AppData\Roaming\npm;C:\Users\jupiter\AppData\Roaming\npm\node_modules\weex-toolkit\bin\weex.js;C:\Users\jupiter\AppData\Roaming\npm\node_modules\weexpack\bin\weexpack.js;C:\Users\jupiter\AppData\Roaming\npm\node_modules\weex-toolkit\node_modules\weex-previewer\vue-template\template\assets\vue.js


分享一下我的环境变量里的东西.. node weex npm这些是必须要配置进去的... 如果不配置的都是用不了的.. jupiter是我windows的用户名 其他的大家自己看一下它给安装到什么路径下了.. 尤其是weex和weexpack是默认的一个路径 层级还很深.. 仔细找找配置进去..

另外推荐个飞猪开源的UI框架 weex-ui 

weex-ui

总体来说这个UI框架还是能帮上一些忙的.. 但是里面本身就有些问题.. 比如其中utils中的getPageHeight的高度.. 在web上是对的.. 但是手机上... emmmm... 会少一些高度.. 大约是88px... 原因不明.. 可能是android里面使用的默认的toolbar... 但是他自动帮你减掉了.. 但实际上没有toolbar.. 这个高度就少了..


二.开始踩坑


至于如何写vue代码或者简单的helloworld.. 百度上都能查到... 我就不再赘述了.. 这里只说些百度不到的坑或者旧坑解决方法已经无效的问题..  如果你觉得你会写vue到此就万事大吉了要开始构建三端应用了... 那么我得先给你泼一盆冷水了... 大哥.. 你跳个界面给我看下..

1.界面跳转

你会说:切 不就跳界面么.. 看我一手startActivi... vi... 

vi你个头..  

在这里的跳转需要使用navigator 去实现.. 原理上这个东西是做了各端的特殊处理的.. 在web上比较像vue router.. 也就是单页跳转.. 而在android上则是通过隐式去拦截对应的url类型.. 如果是http和https开头的.. 会用webview去打开.. 如果是files开头的... 呵呵.. 你就发现它没动静了...

这里再吐槽一手weex不适合商用的原因... 完全没有社区... 这是最骚的... 所以遇到很多问题只能自己去看源码或者百度... 而且百度好多东西都是基于旧版本的.. 你用上就发现.. 写得什么玩意 根本没效果嘛..


跳转就是我们遇到的第一个大坑.. 百度上都说.. 可以用vue router.. 然后我们试了之后发现.. vue router在移动端上根本不是真的界面跳转.. 只是一个单页面.. 每次都重新加载.. 没有跳转动画.. 这对于app的效果来说是完全不能接受的..

而另一方面网上说用navigator的实现.. 在跳转本地界面的时候都不生效.. 

我们编码的地方在src里.. 在使用npm build(npm run 或者weex run android等都会先build)后会生成一套JS文件存在dist里.. 而网上说的只要用navigator打开里面编译生成的js文件就可以实现跳转.. 实际上打开后.. 并不行..

那么在新版本的weex里要怎么做呢.. 我们试了好久后.. 受到首页的地址是index.html的启发.. 发现使用src对应目录下的vue文件地址把后缀改成html即可实现web跳转... 比如你首页的地址是http://192.168.2.17:8081/index.html... 那么你需要打开components下的home.vue界面  那地址就是 http://192.168.2.17:8081/components/home.html ...
网页跳转正常了 .. 当我们欢呼雀跃准备继续时.. 发现手机上又跳不了... 

在项目目录下运行

weex platform add android

你的项目就可以用 weex run android运行在安卓手机上了... 

网上好多说需要找到本地资源文件夹下的地址即可跳转.. 在android中.. 确实发现assets文件夹下有这些界面的js文件.. 


只要用 file://assets/dist/在安卓中找到这个文件跳转就可以了.. 然后再次发现是无效的.. 但是发现跳转http和https在手机上是有效的.. 那么也就是说隐式调用没有拦截到这file这个请求..


但是明明在android项目的manifast里是已经在拦截file的.. 最后发现确实file是拦截不到的.. 其他什么关键字都可以.. 那么怎么办呢.. 最后我只能在地址前面加上别的关键字local 但是让隐式拦截local关键字.. 最后再activity里再把local给去掉 用file地址去渲染..


最终获取三端对应跳转地址的方法 (注意安卓中前面添加了local是为了给拦截)

getJumpBaseUrl(toUrl) {

        var bundleUrl = weex.config.bundleUrl;

        var isnav = true
        bundleUrl = new String(bundleUrl);
        var nativeBase;
        var native;
        var isAndroidAssets = bundleUrl.indexOf('file://assets/') >= 0;
        var isiOSAssets = bundleUrl.indexOf('file:///') >= 0 && bundleUrl.indexOf('WeexDemo.app') > 0;
        if (isAndroidAssets) {
            nativeBase = "local://" + 'file://assets/dist/';
            native = nativeBase + toUrl + ".js";
        } else if (isiOSAssets) {
            nativeBase = bundleUrl.substring(0, bundleUrl.lastIndexOf('/') + 1);
            native = nativeBase + toUrl + ".js";
        } else {
            var host = 'localhost:8081';
            var matches = /\/\/([^\/]+?)\//.exec(bundleUrl);
            if (matches && matches.length >= 2) {
                host = matches[1];
            }

            //此处需注意一下,tabbar 用的直接是jsbundle 的路径,但是navigator是直接跳转到新页面上的.
            if (typeof window === 'object') {
                nativeBase = 'http://' + host + '/';
            } else {
                nativeBase = 'http://' + host + '/';
            }

            native = nativeBase + toUrl + ".html";
        }
        return native;
    }

android manifest 中拦截local

      <activity
            android:name="com.weex.app.WXPageActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
			
			>
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <action android:name="com.alibaba.weex.protocol.openurl"/>

                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="com.taobao.android.intent.category.WEEX"/>

                <data android:scheme="http"/>
                <data android:scheme="https"/>
                <data android:scheme="local"/>
            </intent-filter>



        </activity>

android java code中把local头给去掉 拿file地址去渲染


把local关键字给替换掉.. 然后其他的和原来操作一样

这样在android上的跳转才算解决了

如果你看到这个坑就已经准备放弃了.. 我只能说.. 施主 回头是岸.. 如果你觉得还想挑战一下.. 那么继续看后面的坑吧..

2.控件太少 基本只能实现最基本的效果

第二个大坑就是控件过于少.. 很多效果在weex中你是没法实现的.. 或者说不是一般人可以实现的... 除非你是真的精通三端的技术大牛.. 不然你要掂量一下自己的项目.. 是不是有地图.. 是不是有其他动画.. 是不是有weex-ui中没有的效果.. 如果有.. 那么是否有替代方案或者对UI的要求高不高..能不能接受替换.. 是否有自己封装控件的经验..


就算你要自己做.. 还有一个事情你必须知道..

那就是

什么意思呢.. 就是说滑动事件获取是不靠谱的.. 甚至在weex-ui的slide-nav(视窗增大)中看到了类似的备注


之前还考虑过希望封装个类似ios picker的效果... 看到这个之后就放弃了.. 滑动事件的监听都不靠谱的话.. 很多效果就算要自己封装也是不太可能呢..

3.滚动控件滑不动

在weex 中提供了好多种滚动控件 包括list scroller 但是一开始使用的时候发现都滑不动... 后来才发现.. 如果不给这些控件指定高度.. 那么它会包裹内容高度.. 那么内容高度和控件高度相同也就不可以滑动了... 控件已经顶出屏幕了你也不知道.. 那么对于这些滚动控件是必须指定高度的... 但是高度怎么拿呢...

weex的规则是屏幕宽度是750px 而高度是根据宽高比算出来的.. 也就是高度是不固定的.. weex-ui中的utils中有获取屏幕高度的方法.. 但是就是开头提到的问题.. android上回少88px;

所以只能自己封装个获取高度的方法

import {Utils} from 'weex-ui'       

 const screenHeight = Utils.env.getPageHeight() ;
        const androidNavHeight =  Utils.env.isAndroid() ? 88 : 0;
        return screenHeight +androidNavHeight;

用这样的方法获取的高度.. 再设置给scroller才可以使用.. 当然如果你的界面里还有其他控件.. 高度还要再减去那些.. 不然scroller会包裹内容高度..

4.前端代码不是全部可靠的


在官网上写出了几种不支持的样式, 百分比是不支持的.. 包括我之前用的border 50% 去绘制圆形.. 到app上会变成50px.. 另外用border绘制三角形之类的都是不可靠的.. 在web上可以实现.. 到手机上就雪崩了.. 所以如果你是前端过来的同学.. 不要什么vue的骚操作都往里套.. 它并不是真正意义上的前端代码.. 所以还要对不同系统去调整适配问题... 所以你的团队中最少的需要有三端都懂的人才可以用.. 而不是说你懂前端就闷头写.. 最后web没问题了.. 在android和ios上都运行不起来.. 最后debug都不知道从哪做起... 展开记录一下那些写法是不可以的..

1.dom document对象不可用

在前端中也许会有类似

         var mo = function(e) {
            e.preventDefault();
         };
         document.body.style.overflow = 'hidden';
         document.addEventListener("touchmove", mo, false); //禁止页面滑动

的代码来实现禁止页面滑动.. 在网页中如果内容超过了浏览器高度便可以滑动.. 如果你想禁用掉这个滑动便会涉及到以上的代码.. 但是这个代码在手机上会报 render error:-2013

实际上就是js中找不到这个对象.. 所以这个写法是不可用的

另外.. 所有的类似空指针的操作.. 在网页上是可以显示的.. 但是在android中.. 会报出上面所说的render error:-2013的错误... 而且不知道如何定位这个错误在哪.. 所以解决报错也是个比较头疼的问题.. 最好拿每天的代码都跑一下手机看看是否有类似报错.. 不然层级太多了都不知道这个错是哪里来的...

2.css代码如百分比不可用

在前端中画圆你可能会用到 border-width:50% 这样的代码来实现一个节点的圆形... 但是这在手机上也是不可用的... weex官网上有解释.. 类似width这种传数字的无论你传什么单位都会被转成px ... 所以以上代码的实际效果就是50px的圆角了... 如果要实现圆形.. 还是要自己传定死的半径进去..

具体还有不可用的css写法参考 :   css支持

3.list中必须使用cell标签才可以显示

在网页中.. list中的布局无论放什么都是可以正常展示的.. 但是在手机中... 不用<cell> 包裹的话.. 内容是不予展示的.. 这样设计的考虑可能是涉及到一个复用机制... 在手机中无论是IOS的TableView还是android的listview Recyclerview中的item都是要复用的.. 不然在手机中反复生成item会导致oom.. 所以cell包裹的内容会被复用.. 没被cell包裹的将不会被复用.. 且在list中不显示.. 主要是防止未复用的item过多导致oom所以强制使用的吧

4.很多标签在手机上不支持部分基础css属性

现在发现的主要是在android上margin属性在<cell>标签中是无效的.. 所以要使用margin需要在cell中再使用div包裹一层.. 

讲道理margin这种基础css属性应该在所有标签上都是生效的.. 但是实际却不是.. 文档中也没有相关提示

5.vue的mvvm控件内部双向绑定问题

vue对于前端的同学可能不会陌生... 这是一个类似mvvm思想的框架,也就是说.. 视图直接和数据绑定了... 在数据改变时直接改变控件对应的视图状态,如下


前面也说过weex是用vue完成代码再在手机上去用原生控件渲染的...

但是vue中会涉及到一个内部控件去改外部参数的问题...如 点击打开链接

控件内部希望修改props中传进来的参数去控制外部状态时.. 会报出 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "xxxx"(参数名) 

然后外部参数并没有改变.. 只是内部的变量改变了..

那么怎么办呢.. 其实在vue中可以传入对象作为参数... 而props中的参数是不可变的.. 也就是传入的对象是不可被改变的 但是对象中的参数是可变的..


我的做法就是传入data整个对象.. 里面包含了checkPosition属性... 这样就可以在js中对外部的属性进行修改了

6.android中picasso版本太旧导致部分https地址图片加载有问题

在android项目中对image标签中的地址图片.. 实际上是在用picasso加载的.. 但是它的版本已经比较旧了.. 好像是2.5.2的... 之前还以为是服务器上的图片处理有问题..  后来在排错之后发现是picasso旧版本对https支持不太好 ... 只要把旧版本的picasso升级.. 再extend下的ImageAdapter的代码用picasso的新版api加载图片.. 就可以解决这个问题了.. 不过也许你也遇不到这个问题.. 并不是所有的https下的图片都不可加载..

三.结论

暂时遇到的坑就这些 .. 但是还是那句话..

别拿weex来做商用!! 坑太多!!!

我这个项目已经入坑了只能硬着头皮做下去.. 后面有新坑我还会回来更新的..

比较完整的学习项目目前只找到

网易严选demo

这个项目是用vue router做的跳转.. 没有用navigator实现真正的多页应用.. 不过里面的vue+js+css代码还是有很多可以参考的地方的...

猜你喜欢

转载自blog.csdn.net/Jupiterxx/article/details/80026909