Skip to content

首页模板布局(一) ​

本页对应 首页模板布局,共 7 段视频,约 1 小时 12 分。

学习目标 ​

  • 能够说明请求拦截器中“白名单”的作用,并实现登录相关接口不携带 token、其他接口自动携带 token 的判断逻辑。
  • 能够封装 custom-section 组件,通过 props 支持自定义标题、右侧插槽、箭头显示控制及外部样式传入。
  • 能够为 scroll-page 组件扩展背景色属性,并在“我的”页面模板中隐藏原生导航栏、完成布局接入。
  • 能够调用用户信息接口获取并渲染头像、昵称等个人信息,且能通过调试确认请求与数据状态。
  • 能够实现退出登录逻辑:清空 token、重置跳转页面与打开方式,并使用 reLaunch 跳转到登录页。
  • 能够创建分包目录与页面,在配置文件中声明分包及页面路径,并通过“我的”页面链接跳转到分包页面。

知识点 ​

先厘清白名单:拦截器要知道“谁不需要 token” ​

为什么需要:发起请求时,并不是所有接口都要带 token。转写里反复强调一个大前提:有的接口需要 token,有的不需要;跟登录相关的接口一定不需要。因为登录相关接口的作用就是获取 token——用户没有 token 或 token 已失效,才需要登录;此时再传 token 没有意义。

怎么想:拦截器在发请求前要判断“这个请求路径是否需要 token”。前端和后端要沟通清楚哪些接口不需要,然后把它们放进一个数组里。这个数组被形象地叫作“白名单”,本质就是“不需要传 token 的接口路径集合”。

怎么做:转写中的思路是定义一个白名单数组,在请求拦截器里判断请求路径是否包含在白名单中;如果不在白名单里,才把 token 加到请求头。关键判断可以概括为:

js
// 路径名以项目实际为准
if (!whiteList.includes(path)) {
  // 不在白名单,才添加 token
}

易错点:不要把所有接口都无脑加 token;白名单路径要和真实请求路径一致;不要被“白名单”这个名词吓到,它就是一个数组;哪些接口不需要必须和后端确认,不能猜。

scroll-page:用盒子“冒充页面”做增强 ​

为什么需要:不封装 scroll-page,页面也能滚动、下拉刷新,但要做统一增强就不方便,比如给 tabBar 上方加一条线、隐藏滚动条、适配苹果手机底部小条、统一背景色。转写里用画图解释:做一个固定高度的盒子,把内容放进盒子里滚动,看起来像整个页面在滚动,实质是盒子里滚动。

怎么想:组件内部仍然用 scroll-view,高度设置成和页面一致,让它“假装”是页面最大容器。这样就能在盒子层面加下边框、控制滚动条、处理底部安全区。组件属性不要写死,要允许外部配置,比如 refresh-enable、下拉动画、事件名、背景色。

怎么做:组件外层包一个容器,内部放 scroll-view;把是否刷新、下拉动画、事件通过 props 变量控制;再补一个 background-color 属性并绑到组件样式上。转写中调试时发现“标题出来了,但底色和页面一样,看不出圆角”,原因就是 scroll-page 少封装了背景色属性,补上后层次感才出来。

易错点:属性写死会导致组件不灵活;事件名写死也不利于复用;改完 easycom 组件后有时不立即生效,需要重启项目;背景色不传时,白底盒子放在白底页面上会看不出圆角和层次。

我的页面模板与 custom-section 组件 ​

为什么需要:设计稿里“问诊中”“药品订单”等区块长得相似:都有标题、圆角、间距,右侧还可能有文字和小箭头。写多份不如抽成组件,保证统一风格,改的时候只改一处。

怎么想:组件要满足三个要求:能自定义标题;能接收外部样式;右侧小箭头可显示可不显示。右侧文字用插槽传入。组件要符合 easycom 规范,目录和组件名必须一致,转写中强调 components 单词不能错,组件名要和模板里使用的一致。

怎么做:在 components/custom-section/custom-section.vue 中写 <script setup>,定义 title、showArrow、customStyle 等 props;结构分成 header、左侧 title、右侧 right,right 里放插槽和 uni-icons 箭头;最外层绑定 customStyle。页面模板里复制布局后,在 pages.json 的 my 页面配置里隐藏导航栏,转写中对应的是设置 navigationStyle 为自定义模式。

易错点:组件名、目录名写错导致不生效;忘记写 <script setup>;外部样式属性名写错;先写配置后建目录容易报路径错误;页面白底和组件白底重叠时,要检查背景色和圆角是否真的生效。

个人信息:先封装 API,再包函数,最后调试 ​

为什么需要:我的页面加载时要获取头像、昵称和数字信息;未登录时拦截器会引导去登录。怎么想:先在 service 目录封装获取用户信息的 API,遵循文档用 GET,并把结果 return 出去;页面里不要直接裸调 API,最好再包一个 getUserInfo 函数,方便使用 async/await,也方便以后做参数二次处理。

怎么做:页面 setup 中调用函数,拿到结果后先判断接口是否成功,失败直接 return;成功再把数据赋给 userInfo。转写中特别强调调试:写完先看 userInfo 是不是空,如果是空,后面渲染都是白渲染。调试时发现“封装了方法却没调用”,这是低级但常见的错误。

易错点:只封装不调用;不判断成功码;数据没拿到就写渲染;onMounted 不是必须的,单纯取数据在 setup 里直接调会更早发出请求。

退出登录与分包 ​

为什么需要:退出登录要清 token,同时把 Pinia 里保存的跳转方式、跳转地址恢复默认,否则下次登录可能还跳到旧页面。跳登录页要用 reLaunch,因为它会清空页面栈,左上角没有返回按钮;而且只有登录页不需要 token。

怎么做:先 useUserStore() 拿到 store,再把 token 置空,重置 openType、redirectUrl,最后 uni.reLaunch 到登录页。分包用于家庭档案这类患者信息模块,能提升小程序打开速度。先在 subPackages 中配置 root 和 pages,每个页面用 path 指定,path 不写根目录;要先建目录和页面,再写配置,避免找不到路径报错。列表跳转时地址要带分包根目录。

易错点:只清 token 不重置跳转信息;退出登录用普通跳转留下返回按钮;分包 path 写错;先写配置后建页面导致报错;课堂项目目录名要统一,否则跳转地址对不上。

本节说明 ​

原始笔记只给出“优医咨询-我的页面模板”标题,未附图片和完整代码,因此不补造图片与代码;下面保留转写稿中明确出现的组件名、属性名与配置名,并把同音字纠正为 token、scroll-view、scroll-page、easycom、Pinia、reLaunch、subPackages、navigationStyle 等。

白名单与 token 传递 ​

为什么需要:接口并非都要 token。登录相关接口的作用是获取 token,往往发生在“没有 token”或“token 已失效”时,再传 token 没有意义。
怎么想:把不需要 token 的接口路径放进数组,这个数组就是“白名单”;请求拦截器判断当前请求路径是否在白名单中,不在白名单才加 token。
怎么做:维护白名单数组;在请求拦截器里判断路径是否包含于白名单,取反后决定是否添加 token。转写稿强调“有的需要、有的不需要”是大前提。
易错点:不要所有接口无脑加 token;白名单本质只是数组,不是复杂机制;哪些接口不需要要与后端确认;判断方向别写反——在白名单中反而不加 token。

我的页面模板与隐藏导航栏 ​

为什么需要:我的页面顶部绿色区域要顶到头,默认导航栏会占位,导致页面看起来“不正常”。
怎么想:这是页面级配置问题,不应靠样式硬压;应使用页面配置隐藏导航栏。
怎么做:把布局模板放入 my 页面,新建对应样式文件;在 pages.json 中找到 my 页面,添加 navigationStyle 为 custom。保存后顶部导航条消失。
易错点:样式文件后缀和路径要写对;代码要保存;配置要加在 my 页面而不是别的页面;转写稿还提醒不要依赖自动保存,避免频繁编译和误以为已保存。

custom-section 组件 ​

为什么需要:问诊中、药品订单等区块都有标题、圆角、间距和右侧箭头,结构相似;重复写多份不如抽组件,保证统一风格。
怎么想:组件要支持自定义标题、是否显示小箭头、外部传入样式;按 easycom 规范命名,便于直接使用。
怎么做:在 components 下建立 custom-section/custom-section.vue;定义 title、showArrow、customStyle 等 props;结构为 header 中包含 title 和右侧区域,右侧用插槽放文字、用 uni-icons 控制箭头;外层盒子绑定 customStyle。
易错点:目录名、文件名必须与模板中使用的一致,否则 easycom 不生效;props 名与模板绑定要一致;customStyle 忘记接收或绑定会无效;组件写完不生效时可重启项目验证。转写稿中组件文字已出现但底色不明显,说明还要继续查样式。

scroll-page 支持背景色 ​

为什么需要:封装滚动容器可增强页面:给顶栏加下边线、隐藏移动端滚动条、统一适配底部安全区;页面内容在容器内滚动,看起来像整页滚动。
怎么想:my 页面给 scroll-page 传了 background-color,但组件未声明该属性,所以不生效;需要让组件接收并应用背景色。
怎么做:在 scroll-page 的 props 中增加 backgroundColor,类型为字符串,默认白色;在组件最外层绑定背景色;保存重启后查看层次感是否出来。
易错点:只在页面传属性、组件不接收,不会生效;属性名与绑定名要一致;对象中漏逗号会报错;背景色与页面底色相同会看不出圆角。

获取个人信息与退出登录 ​

为什么需要:我的页面加载时要展示头像、昵称和数字;退出登录要清除登录态。
怎么想:个人信息先封装 API,再在页面中包一层函数,便于使用 await 和二次处理参数;退出登录不必调接口,清 token 并重置跳转状态即可。
怎么做:service 中封装获取用户信息 API;页面 setup 中调用函数,判断 code 是否成功,不成功直接 return;用 ref 对象接收 userInfo 并渲染。退出时清空 token,重置 redirectUrl、openType,再用 reLaunch 跳登录页。
易错点:转写稿调试时发现 userInfo 为空,原因是“封装了方法却忘记调用”;应先看 Network 和组件数据再渲染;未登录调接口会 401 并跳登录;退出登录只清 token 不重置跳转状态,下一次登录可能不回首页;reLaunch 会清页面栈,没有返回按钮。

创建分包 ​

为什么需要:家庭档案即患者信息,适合放分包;分包可减小主包首次下载体积,提升小程序打开速度。
怎么想:先建分包根目录和页面,再写 pages.json 配置,避免配置指向不存在路径而报错。
怎么做:建分包根目录,下面建 form/index.vue、list/index.vue;在 pages.json 配 subPackages 数组,每项含 root 和 pages,pages 中用 path 指定相对路径,用 style 配 navigationBarTitleText;在我的页面“家庭档案”链接上写跳转地址。
易错点:先写配置后建页面容易报错;path 不包含 root 目录;目录名、页面名要一致;链接路径写错会跳不过去。转写稿中点击家庭档案能跳到患者列表,说明分包配置和跳转已打通。

需求来源:为什么要把“我的”页面区块抽成 custom-section ​

为什么需要: 打开设计稿对比后会发现,“问诊中”“药品订单”“快捷工具”这些区块长得很像:都有标题、圆角、白色背景、间距,右侧还可能有一行文字和小箭头。当前页面模板只贴了基础结构,代付款上面缺少“药品订单”“全部订单”等公共头部,如果每个区块都手写一遍,结构会重复,后续统一改样式也容易漏。

怎么想: 转写稿里的判断是“写好几个,不如直接搞成一个组件”。把公共外壳抽成 custom-section,标题文字、右侧箭头是否显示、外部样式都做成可配置项,页面只负责传内容。

怎么做: 组件名按 easycom 规范创建:components/custom-section/custom-section.vue,目录名和文件名保持一致。组件至少满足三个要求:可自定义标题、可接收外部样式、右侧小箭头可显示/隐藏。

易错点: 转写稿里的“ECom”指 easycom 规范,components 单词和组件名都不能写错;组件名要和模板里使用的一致,否则不生效。

属性设计:标题、箭头、自定义样式 ​

为什么需要: 不同区块标题不同,例如“问诊中”“药品订单”;右侧小箭头不是每个区块都必须显示;外部页面还可能追加圆角、间距等样式。如果写死,组件就失去复用意义。

怎么想: 用 props 接收外部数据。转写稿明确提到三个属性:title 接收标题,类型为字符串,默认空;showArrow 控制小箭头,布尔类型,默认 false;customStyle 接收组件外部传入的样式。

怎么做: 按转写稿整理关键代码:

js
props: {
  title: {
    type: String,
    default: ''
  },
  showArrow: {
    type: Boolean,
    default: false
  },
  customStyle: {
    // 接收外部传入的样式
  }
}

易错点: showArrow 默认值要想清楚:默认显示就写 true,默认不显示就写 false;customStyle 定义后必须真正绑定到组件最外层,否则外部样式传进来也不会生效。

模板结构:header 分左右,右侧插槽加条件图标 ​

为什么需要: 组件需要一个稳定结构:外层盒子负责圆角和背景,header 负责左右布局,左边标题,右边文字和小箭头。右侧文字不同页面不一样,所以要用插槽。

怎么想: 转写稿中把结构拆成:外层 custom-section,里面 header;header 里放 title 和右侧盒子。右侧盒子中文字用插槽出现,小箭头用 uni-icons,是否显示由 showArrow 控制。

怎么做: 简化结构如下,图标具体类型以项目代码为准:

vue
<view class="custom-section" :style="customStyle">
  <view class="header">
    <view class="title">{{ title }}</view>
    <view class="right">
      <slot />
      <uni-icons v-if="showArrow" />
    </view>
  </view>
</view>

易错点: title 要绑定变量,不要写成静态文字;小箭头要加 v-if="showArrow";插槽内容由使用方决定,不要在组件里写死“全部订单”。

使用与调试:easycom 不生效先重启,背景色导致圆角看不见 ​

为什么需要: 组件写完后页面不一定立刻变化。转写稿中保存后标题没出现,重启项目后才生效。随后又发现圆角“看不见”,原因是页面背景和组件盒子背景都是白色,层次感没有出来。

怎么想: 先判断 easycom 是否即时生效,重启项目验证;再检查视觉问题,不是组件没渲染,而是背景色相同。转写稿中给 scroll-page 补了 backgroundColor 属性,默认白色,并绑定到组件最外层。

怎么做: 在“我的”页面使用组件,例如:

vue
<custom-section title="药品订单" show-arrow>
  <text>全部订单</text>
</custom-section>

给 scroll-page 增加背景色属性,并应用到根节点:

js
props: {
  backgroundColor: {
    type: String,
    default: '#fff'
  }
}
vue
<view :style="{ backgroundColor }">
  <!-- 页面内容 -->
</view>

易错点: 组件名、目录名不一致会导致 easycom 找不到;改完组件页面无变化先重启;backgroundColor 要真正绑定到最外层;写对象属性时注意逗号,转写稿中漏逗号就报过错。转写稿里的“头肯/偷坑/扣啃”应统一为 token,“s配置/s刻配置”按项目实际是 scroll-page,以代码为准。

代码示例 ​

1. 请求拦截器 + 白名单(不需要 token 的接口) ​

js
// utils/request.js
// 白名单:不需要传 token 的接口路径(本质就是一个数组)
// 跟登录相关的接口一定在这里,因为它的作用就是"获取 token"
const whiteList = ['/login', '/login/password']

const request = (options) => {
  return new Promise((resolve, reject) => {
    const config = { ...options }

    // 取反判断:不在白名单里(没有"特权")才需要带 token
    if (!whiteList.includes(config.url)) {
      config.header = {
        ...config.header,
        token: uni.getStorageSync('token') || ''
      }
    }

    uni.request({
      ...config,
      success: (res) => resolve(res.data),
      fail: (err) => reject(err)
    })
  })
}

export default request

关键行 / 易错点

  • whiteList 只是个数组,装"不需要 token 的接口路径",叫白名单是因为这些接口有"特权"。
  • 取反不能写错:!whiteList.includes(...) 表示"没在白名单里 → 才加 token"。写成 whiteList.includes(...) 就变成只给登录接口带 token,全反了。
  • 哪些接口需要、哪些不需要,是跟后端约定的,看接口文档有没有标注要 token。
  • 数组里的路径必须和 config.url 完全一致,多一个斜杠、少一个 / 都匹配不上。
  • 登录相关接口不带 token 的原因:此时要么没有 token、要么 token 已失效,传了没有任何意义。

2. scroll-page 组件(scroll-view 二次封装,支持背景色) ​

vue
<!-- components/scroll-page/scroll-page.vue -->
<script setup>
defineProps({
  // 是否允许下拉刷新
  refreshEnable: {
    type: Boolean,
    default: true
  },
  // 下拉刷新的小动画,触发后要让它消失
  refresherTriggered: {
    type: Boolean,
    default: false
  },
  // 背景色,允许外部修改(不写死成白色)
  background: {
    type: String,
    default: '#ffffff'
  }
})

const emit = defineEmits(['refresh', 'scrolltolower'])
</script>

<template>
  <scroll-view
    class="scroll-page"
    :style="{ height: '100vh', backgroundColor: background }"
    scroll-y
    :show-scrollbar="false"
    :refresher-enabled="refreshEnable"
    :refresher-triggered="refresherTriggered"
    @refresherrefresh="emit('refresh')"
    @scrolltolower="emit('scrolltolower')"
  >
    <slot></slot>
  </scroll-view>
</template>

<style lang="scss" scoped>
.scroll-page {
  width: 100%;
}
</style>

页面中使用:

vue
<!-- pages/my/index.vue -->
<template>
  <scroll-page background="#f5f5f5">
    <!-- 页面内容全部丢进来,滚动的是这个盒子,不是页面 -->
  </scroll-page>
</template>

关键行 / 易错点

  • 高度写成 100vh,跟页面高度一致,才能"假装"是整页在滚动,实际是在盒子里滚动——效果一样,但盒子可加下边框、可让出底部小条、可统一处理适配。
  • :refresher-enabled、:refresher-triggered 是 scroll-view 自己的属性,只是加了个变量让它可配置。写成 refresher-enabled="true" 就把组件写死了。
  • 事件名也不能写死,@refresherrefresh 里 emit 出去,外部传什么名字就触发什么。
  • background 属性是后补的:不加这个属性时,组件和页面同色,圆角、层次完全看不出来(页面看着"没生效"其实是颜色撞了)。同理,页面的背景色也要通过它来改,就像给 body 改色。
  • easycom 规范:目录和文件名必须是 components/scroll-page/scroll-page.vue,单词错一个就不自动生效;改完组件页面没反应,先点编译器的重启按钮。

3. custom-section 组件(我的页面里的公共区块) ​

vue
<!-- components/custom-section/custom-section.vue -->
<script setup>
defineProps({
  // 需求一:标题可自定义(问诊中 / 药品订单 ...)
  title: {
    type: String,
    default: ''
  },
  // 需求二:右侧小箭头显示 / 隐藏
  showArrow: {
    type: Boolean,
    default: false
  },
  // 需求三:接收外部传入的样式
  customStyle: {
    type: String,
    default: ''
  }
})
</script>

<template>
  <view class="custom-section" :style="customStyle">
    <!-- 整个标题条 -->
    <view class="header">
      <!-- 左边:标题 -->
      <view class="header-title">{{ title }}</view>
      <!-- 右边:插槽文字 + 小箭头 -->
      <view class="header-right">
        <slot name="right"></slot>
        <uni-icons v-if="showArrow" type="right" size="14" color="#999" />
      </view>
    </view>
    <!-- 内容区:药品订单的那些图标、我的问诊等 -->
    <slot></slot>
  </view>
</template>

<style lang="scss" scoped>
.custom-section {
  background-color: #fff;
  border-radius: 20rpx;
  padding: 24rpx;
  margin: 20rpx;

  .header {
    display: flex;
    justify-content: space-between;
    align-items: center;

    .header-title {
      font-size: 30rpx;
      font-weight: 600;
    }

    .header-right {
      display: flex;
      align-items: center;
      font-size: 26rpx;
      color: #999;
    }
  }
}
</style>

页面中使用:

vue
<custom-section title="药品订单" :show-arrow="true" custom-style="margin-top: 20rpx">
  <template #right>全部订单</template>
  <!-- 代付款、待发货、待收货、待评价 等入口 -->
</custom-section>

关键行 / 易错点

  • 结构就两层:外层盒子(圆角、白底、间距)→ header(header-title + header-right)。圆角必须加在外层盒子上,加在 header 上就切不出整体卡片效果。
  • :style="customStyle" 是"允许外部传样式"的落点,加在最外层盒子上。属性定义了却忘了在模板里接,外部传进来的样式就全丢了。
  • 右侧文字用具名插槽 #right,箭头用 v-if="showArrow",为 false 时整个图标不渲染。
  • easycom 规范:目录名/文件名 custom-section 必须和模板里用的标签名一致,写错单词组件就不生效。
  • 组件写完页面没变化时:先重启项目;再检查是不是背景色和页面同色导致圆角看不出来(把 scroll-page 的 background 调成 #f5f5f5 层次就出来了)。

常见错误 ​

  1. 现象:登录/验证码接口仍携带 token → 原因:白名单未覆盖或 includes 判断取反写错 → 修法:核对免 token 路径数组,命中白名单时不注入 token。
  2. 现象:给 scroll-page 传背景色不生效 → 原因:组件未声明对应 prop 或未绑定到根容器 → 修法:补充 prop 类型/默认值,并在根节点样式中使用。
  3. 现象:custom-section 不显示或样式异常 → 原因:Ecom 目录/组件名不一致,或新增组件后未重启 → 修法:按规范命名,核对 title、arrow、customStyle,必要时重启项目。
  4. 现象:“我的”页面用户信息为空 → 原因:封装 API 后忘记在 setup 中调用,或未判断业务码 → 修法:页面加载时调用取数方法,先校验 code 再赋值,并用调试确认 ref 数据。
  5. 现象:退出登录后仍能返回原页,或再次登录不回首页 → 原因:只清 token,未重置 openType/redirectUrl,或未使用 reLaunch → 修法:清空用户状态并重置跳转配置,reLaunch 到登录页。
  6. 现象:分包跳转 404 或配置报错 → 原因:先写配置后建页面,或 path 多写/漏写分包 root → 修法:先建 root 与页面,再配 subPackages;path 相对 root 写 form/index、list/index。

练习 ​

  1. 检查请求拦截器白名单:列出登录相关路径,验证命中与未命中时 token 注入行为。
  2. 为 scroll-page 增加背景色可配置能力,并在“我的”页面传入非白色验证层次效果。
  3. 使用 custom-section 完成“问诊中/药品订单”两个区块,验证标题、右箭头、右侧插槽和自定义样式。
  4. 在“我的”页面实现加载用户信息:先封装 API,再在 setup 调用,处理失败分支并完成头像/昵称渲染。
  5. 实现退出登录,并创建家庭档案分包及“家庭档案”入口跳转,检查返回栈与登录后回首页。

课堂画面 ​

课堂画面 01

课堂画面 02

课堂画面 03

课堂画面 04

课堂画面 05

课堂画面 06

原视频对照 ​

#视频时长
1学习反馈16:40
2优医咨询-我的页面模板06:35
3优医咨询-custom-section组件12:52
4优医咨询-scroll-page支持背景色03:28
5优医咨询-个人信息11:12
6优医咨询-退出登录08:27
7优医咨询-创建分包13:05

小结 ​

  1. 白名单是“免 token 路径数组”,拦截器按命中结果决定是否注入 token。
  2. 登录相关接口不传 token,是因为此时 token 不存在或已失效。
  3. scroll-page 的二次封装用于统一处理背景、滚动条、底部安全区等页面级增强。
  4. custom-section 通过 props、slot、条件渲染和外部样式实现可复用区块。
  5. 页面数据请求宜先封装 API,再在 setup 中尽早调用,并先校验业务码。
  6. 退出登录不仅是清 token,还要重置跳转状态并 reLaunch 到登录页。
  7. 分包应先建目录和页面,再写 subPackages 配置,页面 path 相对分包 root。
  8. 组件命名、路径、保存与重启是 Ecom 组件和分包配置生效的高频检查点。