uni-app踩坑记录(持续更新)

2,938 阅读11分钟
  1. 关于 p 标签 text 标签解析出来的是 span 标签,有一些属性(例如首行缩进)是思想不了的,这个时候就需要使用<rich-text :nodes=""/> nodes 里面写的就是 html.

  2. 关于 v-for 里面调用方法的问题,@tap="do(item)"会报错 这里只要把相关的循环都写 key 为 index 就可以了(`v-for="(item,index) of list" :key="index")

  3. 关于 v-for 里面改变了 list, @click 事件失效 也是 key 的问题,把 key 改为 index 就可以了.

  4. 关于路由守卫 uniapp 里面是没有路由守卫的,需要使用插件来实现(uni-simple-router)

  5. 关于首页 如果 pages 里面没有配置'/',那么就会默认第一个 page 就是首页

  6. 在小程序里面,text 里面嵌套所有东西都会失效,就算显示出来了,都会出现其他问题,例如点击无效

  7. 在小程序里面,模板不能直接写太过复杂的表达式,可能会报错. 可以用一些方法 return 来代替. 例如&&

  8. uni-app 内使用 websocket 后导致安卓白屏(模板框架已解决) 部分安卓设备使用 websocket 后导致出现启动白屏,可以尝试以下临时解决方案:

    • 非首页在 onUnload 的时候关闭 socket 连接,首页在 onBackPress 的时候关闭 socket 连接。
    • 使用第三方 websocket 插件 plus-websocket
    • 使用非自定义组件编译模式(不推荐)
  9. 使用了 uni-simple-router 后,app 首页打开白屏问题 一定要注意!!!!!路由守卫钩子一定要用 next()来进行跳转,这次白屏的原因就是用了 router.push(),而不是 next(),违反了规范. 虽然 h5 和小程序端都没问题,但是 android 端就会白屏,因为违反了规范,下一次的 next()就失效了.

  10. 安卓端有可能会收不到消息 这个无解,问题怎么解决的我也不知道了.不过心跳开了应该能避免断线. 还有框架原有的代码不要随便注释.如果注释了发生什么打开看看

  11. 关于 pages 路由或 url 在 pages.json 里面配置的话,加了/就会报错(./不会,因为/表示当前根目录,而./表示当前目录) 但是 pages 以外使用 path 路径的时候,少写了/就会报错!!! 例如使用了 uni-simple-router 后,路由写少了/就会报错(这里使用还是按照 router 配置的写好)

  12. 使用了路由跳转报错 cannot set 'type' ... 注意: push 跳转的时候需要是 name+params 或者 path+query. 如果 name+query 的话会报错,path+params 可以会把参数忽略. path 要写对,搭配要正确,才能正常跳转

  13. 修复 v-for 中事件使用部分复杂的表达式编译报错的 Bug 以及修复 v-for 中事件 v-if 使用部分复杂的表达式编译报错的 Bug 20200814 版本已修复

  14. 到了 uniapp 下,变成了 flex,右对齐失效,float:right 不能使用. 设置 margin-left:auto;即可实现右对齐

  15. 从 vue 项目移植重构成 uniapp 项目的时候,有些组件用错了,不会报错,但是会让程序走不下去或者一些异常 例如用了 vant 的 Toast,不会报错,但是它后面的代码都会不执行.遇到这个问题,只要把对应用错的代码用正确的代码替换即可.

  16. 打包成 App 如果混入了 H5 专有的内容(例如微信 jssdk)的话,页面会白屏 使用条件注释注释掉就好了

  17. 本地改 host 指向调试出现 host header 问题 配置 json 文件,和端口同一层加入

    "h5" : {
        "template" : "template.h5.html",
        "router" : {
            "mode" : "history",
            "base" : "/"
        },
        "optimization" : {
            "treeShaking" : {
                "enable" : true
            }
        },
        "domain" : "mtest1.cenkon.com",
        "devServer" : {
            "port" : 80,
            "disableHostCheck" : true //解决127.0.0.1指向其他域名时出现"Invalid Host header"问题
            "https" : true
        }
    }
  1. 关于 slot 插槽,App 只能写在 root 根节点下使用,而且不能写 template

  2. 因为 iphone 的时间格式是'2020/02/02',所以要把所有-改成/

  3. date-picker 在 iphone 不能用'{y}-{m}'设置默认时间,要设置成{y}/{m}/{d} {h}:{i}:{s}

  4. 同样是 iphone 的 new Date()问题,在 iphone 的 new Date,传入的必须要年月日都有,只传年月进入会失败

  5. 微信小程序定义 data 的时候,有些表达式和方法不可以写到 data 里面的,例如 this.$Route,如果有的话会白屏报错

  6. 高度不齐整问题,例如 UI 组件用的高度是 rpx 为单位的,然后做了 fixed 吸顶,下面的容器需要做个 margin-top 避免重叠. 建议全局统一使用 rpx 作为单位. 页面上的话,可以先算出 1rpx 的 px 大小 this.rpxSize = uni.getSystemInfoSync()['windowWidth'] / 750; 然后 margin-top 的时候(例如有个 80rpx 高度的 tabs 吸顶了)就可以 80*rpxSize+'px'这样使用了 另外,不同端的状态栏也会有高度,所以就可以

    <u-tabs
      :style="{ top: statusBarHeight + 80 * rpxSize + 'px' }"
      style="position:fixed;width: 100%;z-index: 999;background: #fff;"
      :list="list"
      :is-scroll="false"
      :bold="false"
      :bar-width="200"
      :current="currentList"
      @change="change"
    >
    </u-tabs>
    <!-- 考勤汇总表 -->
    <view
      :style="{ marginTop: 80 * rpxSize + 'px' }"
      style="width:auto"
      v-show="currentList === 0"
    >
      ...
    </view>
    
  7. 其实 uniapp 也是很多都可以和 vue 一样用 import 来安装的,而且速度快很多 不用太局限,像 vConsole 那些都可以用 import 安装,node_modules 的东西也是可以正常引用,就是兼不兼容 App 和小程序的问题而已,H5 一般都没问题的.

  8. 企业微信(vue 开发,包括 uniapp)的 jssdk,在 ios 端引入调用失败 其实用 npm install weixin-js-sdk@1.2.0 来引入即可,剩下的和文档的一致.

  9. 关于上传下载 没有比较适合的组件和插件,和普通 PC 端做不到一致

  10. 样式修改 有时候改不了的话,可以试试在选择器前面加/deep/(scss)

  11. 在小程序真的不可以写复杂表达式!!!

  12. 微信小程序子组件样式会有问题 如果样式是从父组件传递进去的话,会有个#shadow-root,然后层级都变化了,样式就没有应用上去了. 解决:

  13. uni-app 是不支持一般的文件上传的(<input type="file">) uni-app 的文件上传是使用uni.uploadFile(OBJECT)这个 api 去实现的,这里直接传入 Object 包括了需要上传的文件服务器的 url,文件路径等信息(具体看文档).然后就可以实现上传操作了. 知道怎么上传文件,之后主要就是怎么获取到这个文件路径的问题了,如果是图片视频媒体的话,有 uni.chooseImage(),uni.chooseMedia(),uni.chooseVideo()来选择, 其他文件的话,文档(doc, xls, ppt, pdf, docx, xlsx, pptx)就是使用 uni.openDocument(OBJECT). 不过这个 H5 是不支持的.

    通用方法,要上传其他文件的话,需要新建一个页面,然后嵌入 web-view,在里面使用<input type="file">然后返回上传文件的路径. H5 还可以使用 js 去操作 dom 加入<input type="file">元素.

    <template>
      <view>
        <view ref="input" class="input"></view>
      </view>
    </template>
    <script>
    export default {
      mounted() {
        var input = document.createElement("input");
        input.type = "file";
        input.onchange = event => {
          console.log(event);
        };
        this.$refs.input.$el.appendChild(input);
      }
    };
    </script>
    <style></style>
    

    App 端 ext.dcloud.net.cn/plugin?id=1… IOS 端 ext.dcloud.net.cn/plugin?id=1… 参考链接

  14. 微信小程序 props 传参不支持传递 funciton,或者说,会过滤掉对象中的 funciton. 所以只能选择使用 methods 来传递 funciton.

    // 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
    onReady() {
    	this.$refs.uForm.setRules(this.rules);
    }
    
  15. webview 和 uniapp 页面传, H5 是不支持@message 事件的!!! 可以使用 windows.postMessage()或者 url 传参试试

  16. 弹窗里面有滚动滚动不了? uni 或者小程序是使用 scroll-view 来做滑动的,overflow 也没用.

  17. 小程序里不支持 table,tr,td 标签,或者其他端里有一些标签是不兼容的 这些标签在编译之后,都会转成 view 标签,然后 tr,那些原本是表格的就会失效, 所以如果有多端需求的话不推荐使用表格.例如表格的话,可以用 view 来模拟出来,或者找插件.(没有特殊要求就是找插件解决了.)

  18. 如果 uniapp 项目的页面代码,想要直接拷贝用回 vue 项目里面,view 标签一定要改回 div 不然会白屏,而且不报错,一时写习惯了 uniapp 没那么容易发现到. 还有生命周期也是要用回 vue 的声明周期.

  19. 在 uni-app 如果要兼容多端,就一定要避免使用单端的方法 例如不能使用 location.reload()来刷新,而要使用路由,或者路由插件提供的方法. 不然就会到其它端失效.

  20. 自己做的表单组件,第一次写值失败 设置值应该在生成了表单之后,原来的写值方法在 onLoad 运行了,那个时候还没有渲染出来(onReady),所以赋值就失败了(多关注生命周期吧,有时候这种异步的问题,写一个 setTimeout 没问题的话,就要考虑生命周期(包括组件和页面的生命周期)/执行的时机有没有问题) 其实 onLoad 是获取 url 参数,或者一些渲染之前做的事情, 需要渲染完成之后才去做的,都应该写在 onReady 里面. 组件也是同理(created 和 mounted) 如果是弹窗,没得在页面上写在 onReady 里面的话,那就直接修改表单对象的地方,也就是 setFieldsValue()方法的那个组件的 mounted(), 在 mounted()里面写一个 this.isMounted = true 告诉要调用的方法这个组件是否已经渲染完成了.然后写一个类似于递归的方法,没渲染完成就再次调用自己.

    // 写值s
    setFieldsValue(values) {
        // 避免未渲染完成,写值失败
        // 如果表单未渲染完成,500ms后直接再次调用一次本方法
        if (!this.isMounted) {
            setTimeout(() => {
                this.setFieldsValue(values)
            }, 500)
            return false
        }
        Object.keys(values).map((key) => {
            this.fields.map((item) => {
                if (item.item.name === key) {
                    item.setFieldValue(values[key]);
                }
            });
        });
    },
    
  21. Android 端 webview 返回到 vue 页面,页面卡死问题 webview 中有 alert,alert 还没有关闭就返回了 vue 页面,这样 vue 页面就会卡死了. 解决方法: 把 alert 去掉不用.

  22. uniapp 在 App 中不能使用 instanceof 来判断类型 都会返回 false,原因是 uni-app 接口返回的数据不支持使用 instanceof 来判断, 解决方法是使用其他方式判断类型,例如 typeof,Array.isArray(),Object.prototype.toString.call(arrayBuffer)==='[object ArrayBuffer]'

  23. uniapp 的 key 真的不可以乱写 如果一不小心写了个没有的进去,App 会报错;不是写 index,小程序会报错;不写都会报错. uniapp 写错了 key(小程序要求 key 是 index),在 App 会无端端报错的 cid unmatched TypeError: Invalid attempt to destructure non-iterable instance. In order to be iterable, non-array objects must have a Symbol.iterator method.

  24. 关于事件失效 vue 的事件失效有可能是因为事件名写成了驼峰法,然后低版本的 vue 在判断事件的时候会全部转成小写来匹配,所以可能导致识别不出来. uniapp 的事件失效, 例如这个项目的二维码这里, 用了全局的 uni.on,uni.off,uni.emit. 这里出现了一个 bug 就是从一个页面进入另外一个页面的时候 mounted 里面先 off 了前面那个页面的事件,然后 on 了这个页面的事件. 但是 back 路由返回的时候,并不会触发公共组件的 mounted(因为 uniapp 在 App 里面是有缓存的),所以导致 console.log 正常,但是事件没有触发 (打印正常是因为打印出来的 on 里面执行的根本不是这个页面的了, 所以对应的this.$emit也不会发送到当前页面.) (意思大概就是打印了 B 页面的事件响应,A 页面的早就 off 了,然后 emit 也是发送到 B 页面,但是当前打开的是 A 页面,所以就不会触发 A 页面的事件了) 这里的解决是,把 mounted 里面执行的封装成 init(),然后在 A 页面和 B 页面里面的 onShow()里面用 ref 去手动调用这个公共组件的 init()方法,这样去把 uni.on 绑定的事件刷新成当前页面. (这里或者先会不会又 activated 这个钩子可以用,毕竟是缓存,但是实测也不会触发)

  25. 打包 web 端失败,node 内存溢出,报错: API fatal error handler returned after process out of memory 解决方法 1(有一点点效,但不一定能成功): 安装依赖 npm install -D increase-memory-limit cross-env 配置脚本"fix-memory-limit": "cross-env LIMIT=10240 increase-memory-limit" 运行脚本 npm run fix-memory-limit 解决方法 2(有一点效,能降低内存,但是太大还是有可能溢出, 而且取消优化可能影响运行的性能): 取消摇摆优化 解决方法 3(最终解决方法): 替换 HbuilderX/plugins/node.exe (node v8.17, 注意:其他更高版本会出现与 node-sass 不兼容而报错也打包不了) 最后试过多次可行的是替换 node 为 v8.17,60 个路由打包 7 分钟(开启摇树的情况下, 不开启摇树可能会更快...摇树能减少打包后大小,提升网站性能, 但是有可能会带来其他 bug, 假如打包之前是正常的,打包之后报错了, 可以尝试关闭摇树)

  26. 路由跳转失败的坑 项目迁移,去掉了 tab,然后项目是用了 switchTab 来跳转的,所以就失效了(重点是还不会报错...就更坑了). 这里有个技巧就是用一个 fail 跳转可能是 tab 的页面.

    uni.navigateTo({
      url: attrs.href,
      fail() {
        uni.switchTab({
          url: attrs.href
        });
      }
    });
    
  27. 手机上扫码测试小程序联网失败(非合法域名) 点击右上角的...,然后打开排错(也就是 vConsole),然后就可以了.

  28. 小程序不能预览 小程序是有限制的,uni-app 打包成小程序很容易 vendor 这个文件很大,就算几个页面都很容易就超出限制. 这个时候可以尝试预览时开启压缩(运行-运行到小程序-运行时是否压缩代码),这样文件大小大概会是原来的一半甚至更小. 当然, 如果压缩了还是超出限制的话,那就要想办法优化或者分包了.

  29. 使用了 uView 的话, 很多样式都不能直接 style 那样传进去, 需要用 customStyle 的方式传递进去.

  30. 白屏 bug 和路由无法跳转 bug 也是因为用了 uni-simple-router,在小程序路由 push 有 5 层限制,所以需要用 replaceAll 来进行路由重置,或者想办法把一个路由先退出来. 但是在路由守卫中使用 replaceAll 在 App 端却是不生效的,就会导致白屏, 这个时候就需要写条件注释了.

  31. 底部 fixed,某些浏览器和手机上中间的 margin-bottom 会失效,这个时候需要用 padding-bottom 才能正常不然底部遮住 例如小米手机还有火狐浏览器就会失效

  32. 小米手机 onLoad 失效,如果场景不能用 onShow 来代替的话,那只能做多一个标记变量来判断是否 onLoad 进去了.

  33. Vue3组件通讯emit失效 setup写法时emit有概率失效,如果遇到,不要怀疑自己,请直接重新运行。

  34. 横屏应用失效 全局横屏的话,直接在page.json里设置全局横屏。不要在App.vue里调用api实现横屏。