美文网首页
uni-app 填坑之旅

uni-app 填坑之旅

作者: 渚清与沙白 | 来源:发表于2023-10-11 09:45 被阅读0次

    H5

    • 下载文件
      h5下载文件使用uni.downloadFile()有跨域问题,导致无法下载文件
      可以使用window.location.href=url方式解决
    • token失效拦截并登录
      根据token是否存在进行判断,是否跳转登录页面。
           uni.request({
                ...defaultOpts,
                success(response) {
                    if (response.data.code === -1) { // token失效  跳转登录
                        // 避免一次请求多个接口,多次跳转登录页面
                        if (uni.getStorageSync('token')) {
                            uni.removeStorageSync('token');
                            uni.$emit('logout');
                            uni.navigateTo({
                                url: '../login/index',
                            });
                        }
                        reject(response.data);
                    } else if (response.data.code === 1) {
                        resolve(response.data);
                    } else {
                        if (!options.hasErrorTip) {
                            uni.showToast({
                                icon: 'none',
                                title: response.data.msg,
                            });
                        }
                        reject(response.data);
                    }
                },
                fail(err) {
                    console.log(err);
                    uni.showToast({
                        icon: 'none',
                        title: '服务响应失败',
                    });
                    reject(err);
                },
                complete() {
                    uni.hideLoading();
                },
            });
    
    注意:
    1. 谨慎使用uni.redirectTo(OBJECT),首页请求接口时,登录页会将首页替换掉,无法进入游客模式,因为返回按钮不会显示。
    2. 使用uni.navigateTo(OBJECT),要注意重复跳转登录页的问题,可以通过uni.getStorageSync('token')是否存在来判断,不存在就不需要再跳转登录。
    3. 在H5上,浏览器可以刷新页面;刷新后,路由中只存在当前页面一个路由。首页或者其他页面均不存在,这种情况要考虑登陆成功回到首页的使用uni.navigateBack(),还是使用uni.switchTab(OBJECT)
     // #ifndef APP-PLUS
     // 非APP平台
     const pages = getCurrentPages();
       if (pages.length === 1) {
          uni.switchTab({
             url: '../home/index',
          });
        return;
      }
    // #endif
    uni.navigateBack();
    
    • loading加载框表现丑陋
      uni.showLoading(OBJECT)显示加载弹窗,在App上样式表现正常,在h5上很丑陋,无法满足需求。
      需要使用自定义弹窗。
    • 事件监听注册问题
      在首页,特别是有TabBar的首页,每个tab页面都需要注册和取消注册事件,否则其他tab页无法收到消息。
      例如:更新用户信息
      1. 在App上只需要在一个tab页注册监听,获取用户信息即可更新UI。
      2. 在h5上,A、B、C三个都是tab页,只在A页面注册了user监听。当用户在B或者C页面时,同时刷新了页面,导致当前路由中没有A,在登录成功后,发送user消息获取用户信息,A无法收到消息,B、C都未注册user消息,也就无法获取用户信息。所以,需要每个tab页都需要注册监听才能正常收到消息。
        onLoad() {
            uni.$on('logout', this.loginEvent);
    
            // #ifndef APP-PLUS
            uni.$on('user', this.getUserInfo);
            // #endif
        },
        onUnload() {
            uni.off('logout', this.loginEvent);
    
            // #ifndef APP-PLUS
            uni.$off('user', this.getUserInfo);
            // #endif
        },
    
    • 检测手机端、PC端
      使用ismobilejs库,根据navigator.userAgent来检测当前是否是手机端。如果不是手机端,在PC端访问h5 ,直接跳转到PC端的站点。
      检测位置在App.vue中的onShow函数
    // 导入插件
      import isMobile from 'ismobilejs';
       onShow: function () {
            // #ifdef H5
            if (!isMobile(navigator.userAgent).phone) {
                // 重定向到另一个站点
                window.location.replace('https://www.xxx.com');
            }
            // #endif
            console.log('App Show');
        },
    
    • h5上,API uni.navigateBack() 的问题
      刷新一个二级页面,使用uniapp默认导航栏,右上角的按钮可以关闭页面同时回到首页。使用API uni.navigateBack();来关闭页面,无法回到首页,始终会跳转到当前页面。
      可以使用switchTab来回到首页,App也支持该API。
    • 浏览器自动填充账号和密码问题
      在页面中第一个密码框前面增加两个input组件,用于欺骗浏览器。这两个组件宽高设置为0,设置对应的type。
      第一个input组件用于填充账号,第二个组件用于填充密码。
                <!-- H5浏览器记住密码自动填充密码 -->
                <!-- #ifdef H5 -->
                <input class="w-0 h-0" type="text" />
                <input class="w-0 h-0" type="password" />
                <!-- #endif -->
    

    scroll-view滑动问题

    在带有TabBar的页面中使用scroll-view组件下拉刷新,出现上下滑动异常

    1. 在page.json文件中将该页面设置为禁止滑动disableScroll: true
    2. 指定scroll-view的高度

    scroll-view高度计算

    1. 页面template的根view设定高度100%
    2. 计算高度。记住:使用100%去计算
    // 第一步
    .container {
        height: 100%;
    }
    // 第二步
    .scroll-box {
       height: calc(100% - 258rpx);
    }
    

    uni-app中vh的理解

    • APP 和小程序的导航栏和 tabbar 均是原生控件,元素区域坐标是不包含原生导航栏和 tabbar的;而 H5 里导航栏和 tabbar 是 div 模拟实现的,所以元素坐标会包含导航栏和tabbar的高度
    • 为了优雅的解决多端高度定位问题,uni-app 新增了2个css变量:--window-top--window-bottom,这代表了页面的内容区域距离顶部和底部的距离
    • 举个实例,如果你想在原生tabbar 上方悬浮一个菜单,之前写 bottom:0。这样的写法编译到 h5 后,这个菜单会和 tabbar 重叠,位于屏幕底部。而改为使用 bottom:var(--window-bottom),则不管在 app 下还是在h5下,这个菜单都是悬浮在 tabbar 上浮的。这就避免了写条件编译代码。当然仍然也可以使用 H5 的条件编译处理界面的不同。
    • CSS 內使用 vh 单位的时候注意 100vh 包含导航栏,使用时需要减去导航栏和 tabBar 高度部分浏览器还包含浏览器操作栏高度,使用时请注意。

    CSS 变量

    --status-bar-height:系统状态栏高度
    --window-top:内容区域距离顶部的距离,NavigationBar 的高度
    --window-bottom:内容区域距离底部的距离,TabBar 的高度

    image.png

    App的包名

    mainifest文件中配置AppId是__UNI__9204D49,App的实际包名则是uni.UNI920D49

    页面滚动到目标view位置

    1. 给目标view设置id
      <view id="test" class="bg-bgColor">
    2. 给按钮添加事件
      @click="elementScroll('#test')"
    3. 根据id找到组件设置滚动距离
           elementScroll(selector) {
                const query = uni.createSelectorQuery();
                query
                    .select(selector)
                    .boundingClientRect((data) => {
                        let pageScrollTop = Math.round(data.top) + uni.upx2px(50);
                        uni.pageScrollTo({
                            scrollTop: pageScrollTop, //滚动的距离
                            duration: 100, //过渡时间
                        });
                    })
                    .exec();
            },
    
    1. 回到顶部
              uni.pageScrollTo({
                    scrollTop: 0,
                    duration: 100,
                });
    

    process.env对象

    uni-app中的process.env对象属性如下

    {
        "NODE_ENV": "development",
        "VUE_APP_DARK_MODE": "false",
        "VUE_APP_NAME": "测试",
        "VUE_APP_PLATFORM": "h5",
        "VUE_APP_INDEX_CSS_HASH": "97465e7b",
        "VUE_APP_INDEX_DARK_CSS_HASH": "e6047db7",
        "VUE_APP_BASE_URL": "http://api.test.com",
        "BASE_URL": "/"
    }
    

    时间排序iOS兼容性问题

    this.aar.sort((a, b) => {
      return new Date(b.createTime.replace(/-/g, '/')) - new Date(a.createTime.replace(/-/g, '/'));
    });
    

    媒体适配

    template中使用了class样式img-boximg-topcode-view

    <view class="flex justify-center img-box">
        <image class="img-top" src="@/static/imgs/img_ggyzm_ybd.png"></image>
    </view>
     <view class="text-44 text-white flex justify-center code-view">确定</view>
    <view class="text-32 text-898FA8 text-center mt-40 mx-40 pb-50">
          温馨提示: {{tips}}
    </view>
    

    使用media声明,注意screen是媒体的特性

    @media screen and (max-width: 375px) {
        .img-box {
            padding-top: 60rpx;
        }
        .img-top {
            height: 330rpx;
            width: 300rpx;
        }
        .code-view {
            margin-top: 50rpx;
        }
    }
    @media screen and (min-width: 375px) {
        .img-box {
            padding-top: 180rpx;
        }
        .img-top {
            height: 420rpx;
            width: 380rpx;
        }
        .code-view {
            margin-top: 100rpx;
        }
    }
    

    自定义弹窗组件无法遮挡Tabbar的事件

    方案:在Tabbar上层添加一层遮罩,禁止点击Tabbar。

    let maskView = null;
    export default {
      showMask() {
        if (!maskView) {
          maskView = new plus.nativeObj.View('maskTabarCar', {
            bottom: '0px',
            left: '0',  // 控制遮罩层起点
            height: '50px',
            width: '100%' // 设置遮罩层宽度
          })
          maskView.drawRect({
            color: 'rgba(255, 255, 255, 0)'
          })
          maskView.addEventListener('click', () => {
           // 遮罩层出发click事件
          }, false);
          //遮罩层显示
          maskView.show()
        } else {
          maskView.show()
        }
      },
      hideMask() {
        if (maskView) {
          //遮罩层关闭
          maskView.hide()
        }
      },
    }
    

    App多环境多域名打包

    方案:采用离线打包来实现。

    1. 使用脚本生成本地App打包资源,脚本配置多个环境的打包命令
     "scripts": {
            "dev:h5": "cross-env NODE_ENV=development TAILWIND_MODE=watch UNI_PLATFORM=h5 vue-cli-service uni-serve --mode dev",
            "build:dev:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode dev",
            "build:test:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode test",
            "build:pre:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode pre",
            "build:release:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode release",
            "build:dev:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build --mode dev",
            "build:test:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build --mode test",
            "build:pre:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build --mode pre",
            "build:release:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build --mode release"
        },
    
    1. 将打包出来的本地包资源拷贝到Android项目中,使用Android studio来打包。


      image.png

    启动页取消转圈

         "app-plus" : {
            "usingComponents" : true,
            //设置 启动界面
            "splashscreen" : {
                "alwaysShowBeforeRender" : true,
                "waiting" : false,
                "autoclose" : true, //自动关闭启动页
                "delay" : 0
         },
    

    alwaysShowBeforeRender:是否等待首页渲染完毕后再关闭启动界面
    autoclose:是否自动关闭启动界面,仅当alwaysShowBeforeRender设置为false时生效,如果需要手动关闭启动界面,需将 alwaysShowBeforeRender 及 autoclose 均设置为 false。
    waiting:是否在启动界面显示等待雪花

    底部安全距离

    在适配手机兼容问题上,有时需要处理底部安全距离。
    当使用scroll-view时,往往需要设置高度。此时,需要考虑安全距离问题。

    1. 模板view:在scroll-view后面,增加<u-safe-bottom></u-safe-bottom>
    2. css:指定scroll-view高度,height: calc(100vh - 120rpx - env(safe-area-inset-bottom));

    rich-text解析特殊符号‘<’出错

    在使用<rich-text>组件展示HTML文本内容时,遇到内容中有小于等于(<=)的具有特殊含义的符号时,解析会出错,导致无法显示内容。

    image.png
    解决方案:查找全局的小于等于符号,进行替换。
    err.msg.replace(/<=/g, '&lt;=')
    

    当内容中有小于符号时,则无法进行替换,否则会将破坏其他HTML标签结构。

    uQrcode 添加Logo

                  <uqrcode
                        ref="uqrcode"
                        canvas-id="uqrcode"
                        :value="qrCode"
                        @complete="qrcodeGenerFinished"
                        :options="{
                            foregroundImageSrc: '/static/imgs/tab_order_sel.png', //logo
                            foregroundImageWidth: size / 3, //logo宽
                            foregroundImageHeight: size / 3, //logo高
                            foregroundImageBorderRadius: 35, //logo圆角
                            margin: 15, //二维码外边距
                            backgroundPadding: 10, //二维码内边距
                            areaColor: 'rgba(100, 100, 100, 0.5)', //二维码绘制区域颜色、底部背景色
                            foregroundColor: 'rgba(25, 147, 227, 0.5)',//二维码前景色  
                            backgroundImageSrc :'/static/mycenter/tab_order_sel.png',//背景图片
                        }"
                        :size="size">
                    </uqrcode>
    

    scroll-view滑动报错

    image.png

    解决方案:在<scroll-view @touchmove.stop>标签上添加@touchmove.stop可避免。

    scroll-view水平滚动,子元素不能水平排列

    1 查看文档:

    • 使用竖向滚动时,需要给 <scroll-view> 一个固定高度,通过 css 设置 height
    • 使用横向滚动时,需要给<scroll-view>添加white-space: nowrap;样式。
      2 子元素样式添加属性:display: inline-block;;或者使用<block></block>包裹子元素

    相关文章

      网友评论

          本文标题:uni-app 填坑之旅

          本文链接:https://www.haomeiwen.com/subject/qapdddtx.html