Skip to content

uni-app 生命周期与适配(一) ​

本页对应 uni-app 生命周期与适配,共 7 段视频,约 1 小时 7 分。

学习目标 ​

  • 能够使用 env(safe-area-inset-*) 为页面设置安全区间距,并解释 H5 浏览器中该值为 0 的原因。
  • 能够使用 #ifdef、#ifndef、#endif 编写 uni-app 条件编译,并正确选择 APP、H5、MP-WEIXIN 等平台标识。
  • 能够在 JS、样式和模板中分别编写条件编译代码,并验证不同平台下的执行结果。
  • 能够按“创建查询器 → 查询节点 → 执行查询”三步获取节点宽高尺寸,并将查询逻辑放入合适的生命周期中。
  • 能够区分 select、selectAll、selectViewport 的查询结果,并使用 boundingClientRect、scrollOffset 获取节点位置或滚动信息。
  • 能够按 easycom 规范在 components 目录下创建组件,保证组件名与目录名一致,并实现免导入、免注册直接使用。

知识点 ​

一、先复现问题:内容为什么会被“小条”和“刘海”吃掉 ​

为什么需要:手机屏幕越来越不规则,顶部有刘海/状态栏,底部有 Home Indicator 小条。页面如果直接从屏幕最上、最下开始写,内容就可能被遮住。转写稿里先恢复代码复现:页面内容跑到了底部小条下面;如果这个位置恰好有 A 链接或 tabBar,点击时就会和小条手势冲突,甚至点不住。顶部同理,加文字后“111”会被截掉一部分。

怎么想:安全区不是“某一个固定高度”,而是屏幕留给内容的矩形区域。顶部刘海往下、底部小条往上,才是安全可写区域。既然遮挡来自边界,就应把页面内容往安全区内“挤”。

怎么做:先给页面容器加 padding-top / padding-bottom,必要时也可用 margin。转写稿提醒:margin 有可能把父级带下来,实际更常用 padding。

易错点:不要只处理底部或只处理顶部;不要以为页面“看起来没内容”就没问题,交互元素被盖住才是大坑。

二、解决思路:间距不能写死,要拿“变量” ​

为什么需要:知道加间距能解决,但写多少?写 20、40、50 还是 100?转写稿明确说:写 100 肯定能避开,但留白太大;有的手机没有小条就是 0,有的可能是 20,有的可能是 40。这个值随手机变化。

怎么想:既然间距是变化的,就不能写死固定值,而要获取一个“变量”。昨天通过 JS 获取,今天通过 CSS 获取;两种方式都要掌握。

怎么做:CSS 里使用安全区变量,例如:

css
/* 不推荐:写死间距,换手机可能不够或留白太大 */
.page {
  padding-top: 20px;
  padding-bottom: 20px;
}

/* 推荐:使用安全区变量,值由设备决定 */
.page {
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
}

转写稿里说 padding-top 后面给的不是 20px,而是一个“挺长的东西”,可以理解成变量:它的值可能是 10,也可能是 20,取决于手机。底部同理,padding-bottom 给安全区变量后,滚到底会出现一块空白,这块空白就是给底部小条让出来的。

易错点:不要写成 env(safe-area-inset-top)px;env() 返回的是长度值,直接使用。不要只记顶部,safe-area-inset-* 是矩形区域,有上下左右,按需处理。

三、真机与模拟器:为什么模拟器里“没生效” ​

为什么需要:转写稿里加 padding-top: env(safe-area-inset-top) 后,在模拟器里看不出来;改成固定 10px 又能看到。于是容易误判“变量没生效”。

怎么想:先验证固定值能否把内容挤下来,能,说明选择器和写法没问题;再换变量,模拟器没变化,就要怀疑环境差异。转写稿结论是:top 值绝对可以用,但模拟器里看不到效果,需要真机验证。

怎么做:用 iPhone 真机截图验证。转写稿展示:写了 safe-area-inset-top 后,上面出现空白,正好把天线/刘海区域让出来;也就是从显示信号往下写才是安全的。底部变量则让页面滚到底出现空白,避开小条。

易错点:开发工具模拟器本质上是浏览器/WebView,不能完全代表真机安全区。不要因为模拟器没变化就删掉变量;要真机看。

四、补充结论:浏览器里这个值为什么是 0 ​

为什么需要:转写稿最后补充:在浏览器中这个值永远是 0。学生容易问“那是不是没生效”。

怎么想:浏览器对手机来说本身也是一个 APP。浏览器 APP 已经帮你处理过安全区,页面不是从天线底下开始,而是从状态栏往下开始。因此页面再取 safe-area-inset-top 时,值就是 0。

怎么做:理解“浏览器已处理安全区”这个前提;在 H5 里看到 0 是正常现象,不代表真机小程序/App 里也是 0。开发工具模拟器类似浏览器,所以也常看到 0。

易错点:不要把“浏览器里为 0”当成“安全区变量没用”;也不要把安全区只当成小程序知识。转写稿强调:只要在手机上开发,H5、App、安卓、iOS 都有安全区概念,只是获取方式不同。

五、易错点清单 ​

  1. 写死间距:20/40/100 都不稳,设备不同值不同。
  2. 只处理底部:顶部刘海同样会截内容。
  3. 忽略点击冲突:A 链接、tabBar 被小条盖住时,先查安全区。
  4. 模拟器误判:safe-area-inset-top 在模拟器可能看不到,真机验证。
  5. 浏览器里为 0 就慌:浏览器已处理安全区,0 是正常结果。
  6. 忘记两种方式:JS 获取和 CSS 变量获取都要会;本节重点是 CSS 方式。

条件编译先当成“兼容处理”来理解 ​

在 uni-app 里,同一段代码可能运行在 H5、App、微信小程序等不同平台。页面样式会不一样,API 也可能不一样:比如微信登录相关 API 只能在小程序里用,浏览器里没有对应能力。为什么需要条件编译?因为如果不区分平台,代码要么在某个端报错,要么样式互相干扰。转写稿里反复强调:听到“条件编译”,可以先把它对等成“兼容处理”。它的作用就是让不同平台执行不同的代码,从而既兼容网页布局,也兼容不同端的 API 调用。

怎么想?不要把它想成高深编译器,它本质上是一个“带条件的特殊注释”:条件满足,注释包住的代码才参与运行;条件不满足,这段代码就不执行。先接受这个心智模型,再看语法。

基本语法:特殊注释包住代码 ​

怎么做?在 JS 中,普通注释是 //,但条件编译要在注释里写 #ifdef、#endif 这类标记。开始和结束必须成对出现:

js
// #ifdef APP-PLUS
console.log('运行在 APP')
// #endif

这里的 ifdef 可以理解为“如果定义了某平台”,endif 表示条件块结束。上面代码的意思是:如果运行在 App 平台,才执行 console.log。在 H5 中不会执行。转写稿中的验证过程是:先写 APP 条件,在 H5 页面看不到日志;把条件改成 H5 后,日志就出来了。

否定条件用 ifndef,n 可以理解为 no:

js
// #ifndef MP-WEIXIN
console.log('不是运行在微信小程序')
// #endif

它的意思是:如果不是微信小程序,才执行。转写稿中验证:H5 里能打印,微信小程序里不打印。还可以用两个竖线表示“或”:

js
// #ifdef H5 || APP-PLUS
console.log('运行在 H5 或 App')
// #endif

易错点:转写稿特别提醒,只有“或”,没有“且”。因为一段代码通常只运行在一个端里,不能既同时是 App 又是小程序,所以不要想当然写 &&。另外平台名不要凭感觉写,记不住就查官方文档;转写稿提到常见写法如 APP-PLUS、APP-ANDROID、APP-IOS、H5、MP、MP-WEIXIN、MP-ALIPAY,但不必死背。

样式和模板里也能条件编译 ​

为什么需要?因为兼容不只发生在 JS。比如 H5 希望标题往下一点,小程序里间距已经够了,这时就要让样式按平台生效。

怎么做?样式里不能写 //,要用 CSS 注释,但注释内部仍要写 #ifdef:

css
/* #ifdef H5 */
.padding-top {
  padding-top: 20rpx;
}
/* #endif */

转写稿中的调试过程是:给 H5 加 padding-top 后,H5 间距变大,小程序不变;说明样式条件编译生效。模板里同理,用 HTML 注释:

html
<!-- #ifdef H5 -->
<view class="search-icon">放大镜</view>
<!-- #endif -->

这样只有 H5 才显示这个图标,小程序里不显示。易错点:不要用编辑器快捷键直接生成普通注释,样式里必须是 /* ... */,模板里必须是 <!-- ... -->;注释内部的开头标记和结束标记要成对,平台名写错也会导致条件不生效。调试时先确认代码放在正确文件位置,再分别到 H5 和小程序端观察结果。

条件编译不是新语法,而是兼容处理 ​

为什么需要:uni-app 一套代码要跑在 H5、App、小程序等多个端,但不同端的样式、API 并不完全一样。转写稿里举的例子很直接:uni.login 是微信登录相关 API,浏览器里没有;页面布局在网页和小程序里也可能表现不同。所以必须有一种“按平台决定哪段代码生效”的机制。

怎么想:不要被“编译”两个字吓到。转写稿明确说,条件编译本质上就是“兼容处理”。它本身是注释,只是注释里写了特殊标记,编译器看到标记后决定这段代码在哪个端保留。

怎么做:基本语法是成对出现的特殊注释:

js
// #ifdef APP
console.log('运行在 APP')
// #endif

// #ifdef H5
console.log('运行在 H5')
// #endif

#ifdef 表示“如果定义了某平台”,#endif 表示结束。反着写用 #ifndef:

js
// #ifndef MP-WEIXIN
console.log('不是运行在微信小程序')
// #endif

易错点:第一,#ifdef 和 #endif 必须成对,少一个结束标记会出问题;第二,“或”是两个竖线 ||,转写稿里特意纠正过自己“画了一个竖线”,并强调“只有或,没有且”,因为一段代码不可能同时既跑在 App 又跑在小程序;第三,平台名不要凭感觉写,写错通常不报错,但代码不生效。

在样式中写条件编译:H5 标题下移 ​

为什么需要:转写稿里的实际需求是:H5 端觉得标题离顶部太近,想往下一点;但小程序里这个距离已经够了,不想再动。这时只改 JS 不够,需要让 CSS 也按平台生效。

怎么想:条件编译不仅能写在 JS 里,也能写在样式和模板里。样式里仍然用注释,但必须是 CSS 的标准注释 /* */,不能按快捷键生成 //。

怎么做:找到标题对应的类名,在样式里包一层条件:

css
/* #ifdef H5 */
.uni-title {
  margin-top: 20rpx;
}
/* #endif */

转写稿的调试过程值得注意:先写 padding-top,保存后 H5 没下来。检查发现组件自身有 style,优先级更高,把 padding 覆盖了;于是换 margin 试,结果“把父亲给拽下来了”,最后改为给父级容器加间距,H5 的间距才正常变大,而小程序不变。

易错点:样式条件编译的注释不要写成 //;遇到不生效先检查是不是被内置样式覆盖;改 margin 时注意可能影响父级布局,必要时给父元素加。

在模板中写条件编译:H5 才显示放大镜 ​

为什么需要:有些结构只希望在某个端出现。转写稿里用“放大镜小图标”演示:H5 端显示,小程序端不显示。

怎么想:模板里同样写特殊注释,把需要条件生效的结构包起来。

怎么做:

html
<!-- #ifdef H5 -->
<view class="search-icon">🔍</view>
<!-- #endif -->

保存后到 H5 看,小图标存在;切到小程序,图标消失,说明模板条件编译生效。

易错点:模板注释是 <!-- -->,不要和 JS、CSS 的注释混用;条件标记要包住完整结构,不要只包一半标签。

在 JS 中验证 #ifndef ​

为什么需要:前面写了 #ifndef MP-WEIXIN,需要确认它到底是不是“不是微信小程序才运行”。

怎么想:在 H5 里应该打印,在小程序里应该不打印。

怎么做:

js
// #ifndef MP-WEIXIN
console.log('不是运行在微信小程序')
// #endif

转写稿的验证结果是:H5 里这句话打印出来了,小程序里没有。说明 #ifndef 是否定判断。

易错点:不要把 #ifndef 理解成“所有平台都运行”;它只排除指定平台。

平台名称与查文档 ​

为什么需要:平台很多,名称没必要死记,但写错就不生效。

怎么想:知道常用写法,剩下的查官方文档。转写稿提到在“教程 → 编译器 → 条件编译”里能查到平台名称。

怎么做:常用写法包括 APP、APP-ANDROID、APP-IOS、H5、MP、MP-WEIXIN、MP-ALIPAY 等。MP 表示小程序大类,MP-WEIXIN 表示微信小程序。

易错点:平台名大小写和连字符要按文档写;不要自己发明名称。最后补充一个转写稿里的调试结论:安全区域的 safe-area-inset-top 在真机上有效,但在浏览器/模拟器里通常为 0,因为浏览器本身已经处理过安全区域,不能因为模拟器看不到就误判代码没生效。

代码示例 ​

示例一:用 CSS 变量处理屏幕安全区域(H5 / 真机通用) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
  <title>屏幕安全区域</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    html, body { height: 100%; }

    .page {
      min-height: 100%;
      display: flex;
      flex-direction: column;
      background: #f5f5f5;

      /* 顶部刘海区域:值由手机自己决定,不是固定值 */
      padding-top: constant(safe-area-inset-top);
      padding-top: env(safe-area-inset-top);

      /* 底部小条区域 */
      padding-bottom: constant(safe-area-inset-bottom);
      padding-bottom: env(safe-area-inset-bottom);
    }

    .content {
      flex: 1;
      padding: 20px;
    }

    .tabbar {
      height: 50px;
      line-height: 50px;
      text-align: center;
      background: #fff;
      border-top: 1px solid #ddd;
      /* 不做安全区处理时,小条会压住这个 tabBar,点不住 */
    }
  </style>
</head>
<body>
  <div class="page">
    <div class="content">
      <h3>页面内容</h3>
      <p>111 顶部文字如果不加安全区间距,会被刘海遮掉一部分。</p>
    </div>
    <div class="tabbar">tabBar 底部按钮</div>
  </div>
</body>
</html>

要点解释

  • padding-top: env(safe-area-inset-top) 这一行就是“通过样式拿到安全区域的边界值”,它不是固定数值,所以不用纠结写 20 还是 40,手机自己给值。
  • 一定要写成 constant(...) 再写一遍 env(...):老系统只认前者,新系统认后者,写两行是兼容写法。
  • 把间距加在最外层容器上,而不是加在某个子元素上,否则内容会被挤歪。
  • 易错点:在浏览器和 HBuilderX 的模拟器里,这个值永远是 0,因为浏览器本身就是一个 APP,已经帮你把安全区让出来了,页面从刘海下面才开始。看不到效果不是代码没生效,必须上真机验证。
  • 易错点:底部不加 padding-bottom 时,tabBar 或 A 链接会被底部小条盖住,点击会冲突,这就是必须处理的根本原因。

示例二:uni-app 条件编译(模板 / 样式 / JS 三处) ​

vue
<template>
  <view class="page-bar">
    <view class="title">uni-app 条件编译</view>

    <!-- #ifdef H5 -->
    <view class="h5-tip">这段模板只在 H5 渲染</view>
    <!-- #endif -->

    <!-- #ifndef MP-WEIXIN -->
    <view class="other-tip">这段模板在非微信小程序端渲染</view>
    <!-- #endif -->
  </view>
</template>

<script setup>
import { onMounted } from 'vue'

// #ifdef APP
console.log('运行在 APP')
// #endif

// #ifndef MP-WEIXIN
console.log('不是运行在微信小程序')
// #endif

// #ifdef H5 || APP
console.log('运行在 H5 或者 APP')
// #endif

onMounted(() => {
  // #ifdef H5
  console.log('H5 端 mounted 时才执行')
  // #endif
})
</script>

<style>
/* 注意:这里必须是 CSS 的块注释,不能用 // */
.page-bar {
  /* #ifdef H5 */
  padding-top: 20rpx;
  /* #endif */
}

/* #ifdef MP-WEIXIN */
.page-bar {
  padding-top: 0;
}
/* #endif */
</style>

要点解释

  • 条件编译的本质就是一段特殊的注释:// #ifdef 平台 开始,// #endif 结束,中间才是真正生效的代码,这就是“条件编译”名字的由来。
  • #ifdef 是“如果是这个平台才执行”,#ifndef 是“如果不是这个平台才执行”,#endif 负责收尾,少写结尾会导致整段代码被吞掉。
  • 多平台用两个竖线表示“或”:#ifdef H5 || APP。只有“或”、没有“且”,因为一段代码不可能同时跑在两个端上。
  • 常用平台名:APP、APP-ANDROID、APP-IOS、H5、MP(所有小程序)、MP-WEIXIN、MP-ALIPAY,记不住就查官方文档“教程 → 编译器 → 条件编译”。
  • 易错点(样式里最容易踩):在 <style> 中写条件编译,必须用 /* ... */,如果你按编辑器的注释快捷键,它可能给你生成 //,样式里会直接失效。
  • 易错点:样式条件编译要作用在父级容器上。给子元素写 margin-top 会把它父亲一起拽下来(外边距合并),所以示例里给 .page-bar 加 padding-top。
  • 易错点:如果组件自身配置里已经有 style,你外面再写同名属性会被覆盖,这时换一个不冲突的属性(比如用 margin 代替 padding)。

示例三:uni-app 节点信息获取(三步走 + 滚动位置) ​

vue
<template>
  <view class="container">
    <view class="box"></view>
    <button @click="getScroll">获取滚动位置</button>
  </view>
</template>

<script setup>
import { onMounted } from 'vue'

onMounted(() => {
  // 第一步:创建查询器
  const query = uni.createSelectorQuery()

  // 第二步:查询元素 + 第三步:exec 执行
  query
    .select('.box')
    .boundingClientRect(res => {
      console.log('单个盒子信息', res)   // width/height/top/left/right/bottom,单位 px
    })
    .exec()

  // 查询全部同名节点,结果一定是数组
  uni
    .createSelectorQuery()
    .selectAll('.box')
    .boundingClientRect(res => {
      console.log('全部盒子信息', res)
    })
    .exec()

  // 查询视口(不需要传参数)
  uni
    .createSelectorQuery()
    .selectViewport()
    .boundingClientRect(res => {
      console.log('视口信息', res)
    })
    .exec()
})

function getScroll() {
  uni
    .createSelectorQuery()
    .selectViewport()
    .scrollOffset(res => {
      console.log('滚动位置', res)       // scrollTop / scrollLeft
    })
    .exec()
}
</script>

<style>
/* 只是为了让页面能滚动 */
.container { padding-top: 1500rpx; }

.box {
  width: 300rpx;
  height: 200rpx;
  background-color: pink;
  margin-top: 100rpx;
  margin-left: 120rpx;
}
</style>

要点解释

  • 固定三步:uni.createSelectorQuery() 创建查询器 → .select('.box') 选择节点 → .exec() 执行。漏掉 exec() 回调一次都不会触发,这是最常见的坑。
  • 查询必须放在 onMounted 这类生命周期里执行。节点还没渲染完就查询,会拿不到属性(报读不到属性的错误),这跟网页里 DOM 未加载就 querySelector 是同一个道理。
  • .select() 取满足条件的第一个,.selectAll() 取全部且永远返回数组(哪怕只有一个),.selectViewport() 取视口,它唯一,所以不能传参数。
  • 回调里的 res 含 width / height / top / left / right / bottom,单位是 px,而你写样式用的 rpx,中间已经做过换算,300rpx/200rpx 拿到的是 150/100。
  • top、left 是相对“已定位的祖先元素”计算的;如果页面里谁都没定位,就是相对视口。
  • scrollOffset 只能用于视口和 scroll-view,因为它们才存在滚动;boundingClientRect 是万能的,谁都能用。
  • 易错点:把 scrollOffset 写在 onMounted 里,拿到的永远是 0,因为页面刚加载还没滚动。正确做法是绑到按钮点击事件,用户滚动一段距离后再动态获取,这时 scrollTop 才有值。

常见错误 ​

1. 安全区域间距写成固定像素

  • 现象:加了 padding-bottom: 20px,在有 Home 条的机型上仍被遮挡,在无 Home 条的机型上又凭空多出一块空白。
  • 原因:安全区域 inset 值随机型变化(可能是 0、20、34…),固定值无法自适应。
  • 修法:改用 env(safe-area-inset-bottom) / env(safe-area-inset-top) 这类变量值,并真机验证;不要用浏览器或模拟器"没变化"来判断是否失效。

2. 在 H5/模拟器里验证安全区域,得出"没生效"的错误结论

  • 现象:padding-top: env(safe-area-inset-top) 写完页面毫无变化,怀疑写错。
  • 原因:浏览器本身是宿主 App,已经把安全区域让出来了,所以视口内该值恒为 0;开发工具的内置 webview 同理。
  • 修法:结论类验证一律上真机;模拟器只用来调布局结构。

3. 条件编译注释写错位置或漏写结束标记

  • 现象:整段代码不执行,或者本该只在 H5 生效的代码在所有端都生效。
  • 原因:JS 里写成 /* #ifdef */、CSS 里写成 // #ifdef;或只写了 #ifdef 忘了 #endif,导致作用域一直延伸到文件末尾。
  • 修法:按文件类型选注释符——模板 <!-- #ifdef H5 -->、JS // #ifdef H5、样式 /* #ifdef H5 */;成对书写,写完立刻补 #endif。

4. 条件编译里写"且"条件

  • 现象:#ifdef APP || H5 手误写成单个 |,编译报错或条件失效。
  • 原因:条件编译只有"或",没有"且"(同一份代码不可能同时跑在两个端上)。
  • 修法:或写两个竖线 ||;确实需要"且"的场景,用嵌套的两层 #ifdef 或改写逻辑。

5. 节点查询写在 setup 顶层或忘记 exec

  • 现象:回调不执行、res 为 null,或控制台直接报"读不到属性"。
  • 原因:一是在节点尚未渲染时执行查询;二是 select().boundingClientRect(cb) 只是登记,不调 exec() 不会真正发起查询。
  • 修法:把整段查询放进 onMounted / onReady 里;三步链路末尾必须 .exec()。

6. 在页面加载时就取 scrollTop,结果永远是 0

  • 现象:scrollOffset 拿到的 scrollTop 始终为 0,滚动后重新打印还是 0。
  • 原因:onMounted 只执行一次,此时页面还没滚动。
  • 修法:放到滚动之后触发(按钮点击、滚动回调、onPageScroll)再查询;同时确认查询目标是 selectViewport() 或 scroll-view,其他元素拿不到滚动信息。

7. easycom 组件"不导入直接用"却报组件找不到

  • 现象:<custom-demo /> 提示组件未注册。
  • 原因:组件没放在根目录 components 下,或文件夹名与组件文件名不一致,或建组件时先写名字后选模板被工具清空。
  • 修法:根目录 components/组件名/组件名.vue 严格同名;用右键"新建组件"时先选模板再填名字。

练习 ​

练习 1(安全区域) 给一个带底部 tabBar 的页面做安全区适配:内容区底部留出 Home 条高度、顶部留出刘海高度。完成后说明:为什么在 Chrome 和 HBuilderX 模拟器里看到的都是"没效果",你用什么方式证明它是对的。

练习 2(条件编译三处落地) 在同一页面里完成三件事,每处都用条件编译: ① 页面主标题在 H5 下额外下移 20rpx,小程序不动; ② 模板中一个搜索图标只在 H5 显示; ③ JS 中一段 console.log('H5') 只在非 H5 环境打印。 要求写出三处各自的注释写法,并说明为什么不能都用 //。

练习 3(平台差异兼容) 用条件编译实现:微信小程序端调用 uni.login 走微信登录,H5 端改为打印"请使用微信打开"。写完后分别在两个端运行,确认另一端代码确实没有执行。

练习 4(节点信息三步) 页面上放一个 300rpx × 200rpx 的方块,要求:① 打印它相对视口的宽高与 left/top;② 给方块加 margin-top: 100rpx; margin-left: 60rpx 后再打印一次,对比数值变化;③ 在页面滚动一段距离后,通过按钮点击拿到 scrollTop。 自查:三步链路是否完整?查询放在哪个生命周期里?为什么滚动位置不能在加载时取?

练习 5(easycom 规范) 在根目录新建 components/custom-demo/custom-demo.vue,在首页不导入不注册直接使用,验证能正常渲染。然后故意把文件夹改名、把文件放到 pages 下各试一次,记录报错信息,总结规范的三条硬性要求。

课堂画面 ​

课堂画面 01

课堂画面 02

课堂画面 03

课堂画面 04

课堂画面 05

课堂画面 06

原视频对照 ​

#视频时长
1补充内容-屏幕安全区域10:39
2uni-app条件编译-基本语法13:11
3uni-app条件编译-实际应用08:41
4uni-app节点获取的步骤12:20
5uni-app节点获取方式06:36
6uni-app节点对象信息08:05
7uni-app组件规范easycom08:23

小结 ​

  1. 安全区域是"手机屏幕不规则"带来的通用问题,不是小程序专有;H5、App、原生开发都会遇到,区别只在获取方式。
  2. 安全区域间距的本质是"值不固定",所以固定像素一定错,必须用变量;样式侧和 JS 侧两条路都要会。
  3. 浏览器和模拟器里安全区域值恒为 0 是正常现象而非 bug——宿主 App 已代为处理,验证必须上真机。
  4. 条件编译 = 兼容处理:同一份源码按平台裁剪,是 uni-app 处理样式差异、API 差异的统一手段。
  5. 条件编译的载体永远是"特殊注释",注释符随文件类型变化(模板/JS/样式三种写法),漏写 #endif 是最常见的事故来源。
  6. 条件编译只有"或"没有"且",平台名以官方文档为准,不必背,用时查。
  7. 节点查询是"创建查询器 → 选择节点 → exec 执行"的三步链路,缺任何一步都拿不到结果;且必须放在节点渲染完成之后。
  8. boundingClientRect 管尺寸位置、scrollOffset 管滚动(仅 viewport 和 scroll-view 可用);滚动类信息要在"滚动之后"取,加载时取必然是 0。
  9. easycom 规范的本质是"用命名约定换取免导入",三条硬要求:根目录 components、文件夹与文件同名、按规范新建。