标签 uni-app 下的文章

相信大家肯定都遇到过题目中所说的那种需求,在 app.onLaunch 中获取一些信息,在 Page 中使用。然而这些生命周期钩子都是异步执行的,并没有特定的执行顺序。这就需要开发者自己控制生命周期钩子的执行顺序。

小程序设计得已经比较糟糕,性能低的同时还有许多不可知的奇怪的 bug (关于性能,他们推出了 SkyLine,暂时没有使用过)。而 uni-app 在小程序的基础上,还要兼容更多不同厂家的小程序,还要能够编译成各端代码,莫名其妙的 bug 就更多了。

关于题目中的需求,我尝试了 2 种方法,一是回调函数法,就是在 app.onLaunch 执行完毕后执行一个回调函数,用来初始化页面;二是 Promise.resolve 法,就是在 Page.onLoad 中使用 await 执行一个函数,将其 Promise 的 resovle 回调函数存储起来,这样一来,await 之后的代码就处于等待状态;在 app.onLaunch 的最后调用那个 resolve,结束 Page.onLoadawait 的等待状态。

遗憾的是,虽然网上有很多成功案例,但经过尝试,截止到本文发表的时刻,在最新的 HBuilder X 环境下,这两种方法并不能保证 app.onLaunchpage.onLoad/onShow 先后执行。

除了这两种方法,网上还有诸多神奇的解决方案,但我并没有尝试。最后我使用了最“笨”的方法,但感觉是最稳妥的办法,那就是 setInterval 大法!

setInterval 平常总是被嫌弃,就连实现倒计时,也要用 setTimeout 代替它。没想到最后它解决了我的问题,而且非常稳健!

思路非常简单:
app.globalData 中声明一个变量,比如叫 launched,初始值是 false,用来表示 app.onLaunch 是否执行完毕。然后,在 app.onLaunch 的最后,把它设置为 true
与此同时,页面中的 onLoad 或者 onShow 中设置一个 interval,一旦检查到 getApp().globalData.launched === true,则取消定时器,并执行初始化。

由于 uni-app 使用的是 Vue,所以可以在 main.js 中添加全局的 mixin 来执行 onLoad/onShow,若符合条件,则在 onLoad/onShow 中执行页面中约定好的方法,例如,若 mixin 中的 onLoad 检测到小程序已经执行完 onLaunch,则进一步检查当前页面中是否有约定好的方法,如 _onLoad,若有则执行。这样,就不用在每个页面中的 onLoad/onShow 中写重复的代码了。

由于比较简单,就不上代码了。

以前觉得写小程序简单,因为只需要在小程序那“简单的”框架中写代码,所能做的东西有限。现在终于明白,想要实现一些在 H5 中普通的功能,小程序需要更多的尝试。


End

有时候需要修改页面对象(PageObject)中的 data,直接修改是无效的:

const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];

currentPage.bar = 1; //PageObject上不存在bar
currentPage.data.bar = 1; //不会触发页面渲染

正确修改 data 的方式是使用setData

currentPage.setData({ bar: 1 })

End

最近在开发 uni-app 过程中,发现页面布局会闪烁:页面先是显示错乱,然后又恢复正常。

刚开始以为是页面过于复杂,导致性能降低,渲染速度变慢,但由于时间关系,没有来得及详细研究。今天偶然间发现了导致页面布局闪烁的元凶:image 组件。

我新建了一个很简单的页面,只有一个简单列表,每个列表项包含一个标题和一个子列表。其中标题包含两个 image 组件,用来显示图标,子列表高度设置为0,用来实现高度动画。

在调试过程中,发现每次刷新页面,布局都会先错乱,一闪而过后变得正常。实际上这个问题严重影响用户体验,所以我打算研究一下是什么导致了这个现象。

打开 Chrome 浏览器的性能工具,录制页面刷新过程,出现了布局偏移(Layout Shift)一栏,鼠标移动到代表布局便宜的紫色条上,发现页面上的标题部分会高亮。

布局偏移(Layout Shift)指的是元素突然改变位置,会严重影响体验。

标题的结构如下:

<view class="title">
    <image mode="heightFix" src="xxx.svg"></image>
    <text>Title</text>
    <image mode="heightFix" src="xxx.svg"></image>
</view>

其中有两个 SVG 图片,只给它们设置了高度,其宽度自适应:

.title {
    image {
        height: 20px;
    }
}

显示结果是符合预期的,但正是这两个 image 导致了布局偏移!

因为水平有限,具体原因还没有详细研究,不过可以猜测:image 在应用我们自己的 CSS 之前,应该经历了 uni-app 的处理,导致其位置和样式变化。如果有大神了解其中原理,请不吝赐教。

解决办法就是,为 image 设置明确的宽高:

.title {
    image {
        height: 20px;
        width: 20px;
    }
}

End

0、前言

uni-app 项目经过编译、压缩后的打包资源,如果其大小超出了 40M,就需要付费,每次云打包需要花费 10 元,如果打包频繁,这是一笔不小的花费,所以,配置本地离线打包才是最终的选择。

配置本地打包一共有两个主要步骤:

  1. 配置 Android Studio
  2. 从 XBuilder 导出打包资源

未完待续

注意,这里使用的是 HTML+ 提供的 SQLite 方法。

const dbName = 'dbName';
const tableName = 'tablename';
const sql = `select count(1) as count from sqlite_master where type='table' and name='${tableName}'`;

plus.sqlite.selectSql({
    name: dbName,
    sql,
    success(r) {
        //r是一个数组,如果没有查询的表,则是空数组
    },
    fail(err) {
        //do something
    }
});

这个报错后面会跟着一些更加详细的错误描述,比如

request:fail abort statusCode:-1 Expected URL scheme ‘http‘ or ‘https‘ but was ‘file

其实解决起来不难,如果你的电脑和手机连接的是同一个网络,只要把请求的 baseUrl 设置为你电脑的 IP 地址就好了,也就是让手机连上你的电脑,才能访问你电脑中的开发服务器。

uni-app的坑还是挺多的,这是今天遇到的一个坑,话不多说,上代码:

<view v-if="condition1"> 1 </view>
<template v-else-if="condition2">
    <view> 2 </view>
</template>

上面的代码中,template中的内容即使条件为 true,也可能在真机上不会显示出来。

解决的办法就是不要混用,如果确实要用到 template,那就全部用 template:

<template v-if="condition1">
    <view> 1 </view>
</template>
<template v-else-if="condition2">
    <view> 2 </view>
</template>

在 uni-app 中使用自定义 tabBar,需要注意的一共有 3 点:app.json的配置、custom-tab-bar目录的建立、tab 页中getTabBar方法的调用。

首先根据官方文档,配置app.json。在 uni-app 项目中,app.json对应的是pages.json,每个页面的.json文件,需要写在pages.jsonpages-style段中:

{
    "tabBar": {
        "custom": true,
        "color": "#000000",
        "selectedColor": "#000000",
        "backgroundColor": "#000000",
        "list": [
            {
               "pagePath": "pages/index/index",
                "text": "首页"
            },
            {
                "pagePath": "pages/me/index",
                "text": "我的"
            }
        ]
    },
    "pages": [
        {
            "path": "pages/index/index",
            "style": {
                "navigationBarTitleText": "首页",
                "usingComponents": {}
            }
        },
        {
            "path": "pages/me/index",
           "style": {
                "navigationBarTitleText": "我的",
                "usingComponents": {}
            }
        }
    ],
    ......
}

然后需要在根目录下新建custom-tab-bar目录,在这个目录中手动新建小程序四件套,即index.wxmlindex.jsindex.wxssindex.json。这个文件夹会被原封不动地复制到编译好的项目中。接着就是编写 tabBar 的样式和逻辑,这和原生开发是一样的,这里不再赘述。

最后需要在 tab 页面中调用getTabBar方法。uni-app 的页面是.vue文件。在onShow事件中,添加如下代码:
onShow() {
this.$mp.page.getTabBar().setData({
selectdIndex: 1
});
}
注意,getTabBar方法并不是直接在this上,而是在this.$mp.page上。

还有一点需要注意的是,tabBar 会占用一部分页面高度,tab 页最下方的内容会被遮住,需要处理一下这个问题,比如给 tab 页增加一个与 tabBar 高度一样的padding-bottom