主题
团队开发准备与登录(二)
本页对应 团队开发准备与登录,共 7 段视频,约 57 分钟。
学习目标
- 能按项目目录结构完成小程序启动,并正确配置合法域名,或说明临时关闭校验与正式配置合法域名的区别。
- 能封装轻提示工具函数并挂载到全局
wx对象,在页面生命周期中调用并验证提示效果。 - 能安装并构建
wechat-http,分别使用完整路径、baseURL和 Promise 方式发送请求,并说明其相较原生wx.request的优势。 - 能封装 HTTP 模块,配置请求基地址与响应拦截器,简化返回数据层级,并挂载到全局后完成调用验证。
- 能使用
wx:for、wx:key渲染公告列表,并通过路径参数跳转到公告详情页。 - 能在
onLoad中获取页面参数,按 ID 请求并渲染公告详情,使用rich-text渲染 HTML 内容,并能通过 npmjs 与类型声明文件获得代码提示。
知识点
拉取代码:先确认任务边界
享+社区小程序项目的静态页面已经完成,本节的任务不是重做页面,而是把静态页面接到接口上,联调接口并处理业务逻辑。原笔记给出的代码仓库地址如下;原稿中该代码块内容为空,这里按原样保留,不擅自补写地址:
bash
为什么需要:先拉取课程代码,才能保证后续封装的目录、页面结构和接口调用位置与讲解一致。怎么想:把项目分成“静态页面已就绪”和“业务逻辑待联调”两部分,后续所有改动都围绕工具封装、请求发送、数据渲染展开。怎么做:拉取代码后在微信开发者工具中打开项目,确认首页、公告列表页和公告详情页存在,再开始写工具函数。易错点:不要在没有确认项目根目录的情况下安装依赖;npm 包必须装在项目根目录,才会记录到根目录的 package.json,否则后续“构建 npm”容易找不到包。
轻提示 Toast 封装与全局挂载
为什么需要:项目里经常需要“轻提示”,很多提示不需要图标,只显示文字即可;下单等场景还希望出现提示时遮住页面,防止用户高频点击。怎么想:把 wx.showToast 包一层,调用方只传提示文字,图标和遮罩由工具函数统一设置。怎么做:在 utils 目录新建工具文件,例如:
js
// utils/toast.js
function toast(title) {
wx.showToast({
title,
icon: 'none',
mask: true
})
}
export default toast然后在 app.js 中导入并挂到全局 wx 上,项目启动时自动执行挂载。页面里就可以在 onLoad 中调用,例如打印验证 hello world 是否弹出。易错点:icon 设为 'none' 才是无图标;mask: true 才是遮罩;全局挂载要放在小程序启动会执行的 app.js 中,不要写到某个页面里。
wechat-http:安装、构建 npm 与基本使用
为什么需要:原生 wx.request 不支持 Promise 风格调用,多个请求容易写成回调嵌套;每次请求还要手写完整基地址,路径冗长。怎么想:用第三方模块 wechat-http 在 wx.request 基础上获得 Promise 能力和统一配置。怎么做:在项目根目录终端执行安装命令,安装后在开发者工具中点击“构建 npm”。转写稿特别强调:npm 包不能直接在小程序里使用,必须构建,构建后会生成 miniprogram_npm 相关目录。基本用法可以先写完整 URL 对照原生写法,再配置 baseURL,只写核心路径。易错点:安装目录必须是项目根目录;安装后不构建会导入失败;构建失败时可尝试关闭编辑器再重启,这是转写稿中实际遇到的调试办法。
请求封装与响应拦截器
为什么需要:页面里每次都导入 wechat-http、每次设置基地址、每次取 res.data.data 很零碎。怎么想:把基地址和响应拦截器收进独立文件,并挂到全局,页面只关心业务路径。怎么做:新建 utils/http.js,导入 wechat-http,设置基地址;用该库的拦截器写法处理响应,把默认返回结果中多余的一层 data 过滤掉,再导出并挂到 wx 上。页面调用时用 wx.http.get(...) 之类的便捷写法。易错点:不要照搬 axios 的拦截器写法,转写稿明确说这个库的写法不同,要看对应文档;拦截器里要 return 处理后的数据,否则页面拿不到结果。
公告列表渲染
为什么需要:接口已经能返回公告数据,下一步是把数据渲染到首页列表。怎么想:请求成功后把列表保存到页面 data,模板里用 wx:for 循环,wx:key 用数据中的 id。怎么做:在 index.wxml 中删除多余静态项,绑定列表;跳转详情时在路径后拼 ?id={{item.id}}。转写稿中调试时看到三条公告成功渲染。易错点:小程序模板绑定用 {{}},不是 Vue 的写法;wx:key 要选稳定唯一字段;路径传参要手动拼问号。
公告详情、页面参数与富文本
为什么需要:详情页必须知道用户点的是哪一条公告。怎么想:列表页通过路径传 id,详情页在 onLoad 的形参中取页面参数,再按 id 发请求。怎么做:转写稿验证了 onLoad 能拿到 id=2、id=3 等参数;请求成功后保存详情对象,再渲染标题、作者、日期和内容。内容里有 HTML 标签时,用 rich-text 的 nodes 绑定 HTML 字符串。易错点:页面参数只在 onLoad 形参中取,其他生命周期拿不到;富文本标签是 rich-text,不是 Vue 的 v-html。
调试补充:合法域名、SCSS 与代码提示
请求报“合法域名”错误时,要把开发服务器域名加入合法域名,并在详情里刷新到能看到为止;勾选“不校验合法域名”只是临时方案。项目使用 Sass 预处理器时,.sass 和 .scss 都支持,但一般用 .scss,因为 .sass 的缩进写法看起来别扭。查第三方包文档可用 npmjs 官网,搜索包名后看说明和仓库地址;若 wx.http 代码提示不好,可在根目录加类型声明文件改善提示。转写稿中这些都属于实际调试经验,按上述步骤排查即可。
2.2.1 消息反馈:把重复提示收口到 utils
为什么需要: 项目里很多提示只需要一句文字,不需要成功/失败图标,还常常要加遮罩,防止用户在提示期间继续高频点击。如果每个页面都手写 wx.showToast,参数容易漏、文案风格不统一,后面想统一调整也很麻烦。
怎么想: 这类通用能力应该收口到工具模块里。调用方只关心“提示什么”,不关心 icon、mask 怎么配;同时把工具挂到全局对象 wx 上,后续页面不用反复导入。
怎么做: 新建 utils/utils.js,封装 toast,设置默认文案、mask: true、icon: 'none',并同时做模块导出和全局挂载:
javascript
// utils/utils.js
const utils = {
/**
* 用户消息反馈
* @param {string} title 文字提示的内容
*/
toast(title = '数据加载失败...') {
wx.showToast({
title,
mask: true,
icon: 'none',
})
}
}
// 挂载到全局对象 wx
wx.utils = utils
// 模块导出
export default utils然后在入口中执行这个文件,让挂载动作在小程序启动时完成:
javascript
// 在入口中执行 utils.js
import './utils/utils.js'
App({
// ...
})调试时可以按转写稿思路,在页面 onLoad 里调用 wx.utils.toast('hello world'),重新打开首页看是否弹出轻提示。
易错点: 只写了 export default utils 却没有在入口 import './utils/utils.js',全局 wx.utils 不会自动出现;默认参数要放在形参上,调用方不传时才有兜底;mask 是为了防止提示期间继续操作,不是所有场景都必须加,但下单、提交这类场景很实用。转写稿里提到的“修透/ s透”就是 toast 轻提示,不要写成别的名字。
2.2.2 网络请求:用 wechat-http 二次封装
为什么需要: 原生 wx.request 不支持 Promise 风格调用,多个请求串联时容易写成层层回调;每次请求还要手写完整基地址,路径很长;拦截器、统一响应处理也不方便。转写稿里对比过:原生写法要在 success 里拿结果,还常要处理 this 指向,比较零碎。
怎么想: 选一个基于 wx.request 包装的第三方模块,把基地址、请求方法、拦截器统一配置;再把封装后的 http 挂到 wx 上,页面里直接 wx.http.get(...)。
怎么做: 先安装:
bash
npm install wechat-http注意:安装完成后还必须“构建 npm”才能在小程序里使用。转写稿特别强调,node_modules 里的包不能直接导入,构建后会生成小程序可用的包目录;如果工具构建异常,可以按转写稿经验重启开发者工具再试。
新建 utils/http.js:
javascript
// 导入 http 模块
import http from 'wechat-http'
// 基础路径
http.baseURL = 'https://live-api.itheima.net'
// 挂载到全局对象
wx.http = http
// 普通的模块导出
export default http入口中执行:
javascript
// 执行 uitls/http.js
import './utils/http.js'
App({
// ...
})wechat-http 的用法与 axios 类似:http.baseURL 配基础路径,http.get/post/put/delete 发请求,http.intercept 配拦截器,http 本身也可作为函数调用。页面里可以写 wx.http.get('/path'),并用 await 接收结果。转写稿中还提到可在响应拦截器里把 res.data.data 这一层直接返回,减少页面里反复写两级 data;其拦截器写法与 axios 不完全一样,要以该库文档为准。
【享+生活】接口文档地址
易错点: 忘记构建 npm 是最常见问题;baseURL 和接口路径拼接时注意斜杠,不要重复或缺失;请求报“合法域名”错误时,要按转写稿提醒把开发服务器加入合法域名,并在详情里刷新,临时勾选“不校验合法域名”只能应急;不要手写长接口路径,容易错,优先从接口文档复制;想查第三方包说明可去 npmjs 官网搜索包名,比搜索引擎里翻广告更稳。
公告列表:先请求数据,再循环渲染
为什么需要: 首页要展示社区公告,接口每次只返回 3 条,不需要处理分页。核心目标是把接口返回的 notices 渲染到模板中。
怎么想: 页面加载时调用 getNotices,接口成功条件为 code === 10000,成功后把 data 保存到 notices,模板用 wx:for 循环。转写稿中的调试过程是先请求并打印结果,在 AppData 中确认拿到 3 条数据,再改模板循环。
怎么做: 接口文档见 公告列表接口。参考代码如下:
javascript
Page({
onLoad() {
// 获取公告列表数据
this.getNotices()
},
// 调用公告列表接口
async getNotices() {
// 请求接口
const {code, data: notices} await wx.http.get('/announcement')
// 检测接口是否调用成功
if(code !== 10000) return wx.utils.toast()
// 渲染数据
this.setData({notices})
}
})模板中渲染数据:
xml
<view class="notices-body">
<navigator
wx:for="{{notices}}"
wx:key="id"
hover-class="none"
url="/pages/notify/index"
class="notice"
>
<view class="notice-title">{{item.title}}</view>
<view class="notice-brief">{{item.content}}</view>
<view class="notice-date">{{item.createdAt}}</view>
</navigator>
</view>易错点: 上面的参考代码中 const {code, data: notices} await ... 少了等号,实际应写成 const {code, data: notices} = await ...;wx:key 用接口返回的 id;跳转详情时原模板还需要在 url 后拼参数,转写稿中的做法是拼成 ?id={{item.id}},否则详情页不知道展示哪一条。
列表跳详情:用 URL 参数携带公告 ID
为什么需要: 详情页必须知道用户点击的是哪一条公告,最直接的方式是把列表项的 id 通过路由参数传过去。
怎么想: 小程序页面跳转可以在路径后手动拼 ?id=...,详情页再从 onLoad 的形参中读取。转写稿中强调:只有 onLoad 能通过形参拿到页面参数,其他生命周期拿不到。
怎么做: 在 navigator 的 url 后拼接 ?id={{item.id}},点击后进入详情页。调试时可先在详情页 onLoad 中打印参数,确认第一条公告传过来的是 id=2,再请求详情。
易错点: 不要手写接口路径;模板插值在小程序中直接写 {{item.id}};如果 url 不拼 id,详情页请求就没有依据。
公告详情:onLoad 取参并请求详情
为什么需要: 详情页要展示标题、作者、时间、正文等内容,必须根据公告 id 请求对应详情。
怎么想: 在 onLoad({id}) 中拿到参数,调用 /announcement/{id},成功后将返回数据保存到 noticeDetail。转写稿中的验证过程是:点击列表第一条,控制台打印页面参数 id=2,请求后得到对应公告;再点击另一条 id=1,得到不同内容,说明参数传递和请求都正确。
怎么做: 接口文档见 公告详情接口。参考代码如下:
javascript
Page({
data: {
noticeDetail: {}
},
onLoad({id}) {
// 获取公告详情数据
this.getNoticeDetail(id)
},
// 调用公告详情接口
async getNoticeDetail(id) {
// 检测 id 是否存在
if(typeof id === undefined) return
// 调用接接口
const {code, data: noticeDetail} = await wx.http.get('/announcement/' + id)
// 验证接口调用是否成功
if(code !== 10000) return wx.utils.toast()
// 渲染数据
this.setData({noticeDetail})
}
})在模板中渲染数据:
xml
<scroll-view enhanced show-scrollbar="{{false}}" scroll-y>
<view class="notify-meta">
<view class="title">{{noticeDetail.title}}</view>
<view class="extra">
<view class="author">{{noticeDetail.creatorName}}</view>
<view class="datetime">{{noticeDetail.createdAt}}</view>
</view>
</view>
<view class="notify-content">
<rich-text nodes="{{noticeDetail.content}}"></rich-text>
</view>
</scroll-view>易错点: typeof id === undefined 永远不成立,应改成 if (!id) return 或 typeof id === 'undefined';拼接路径时不要手写完整域名,前文已通过 wx.http 配置基地址;请求成功后要 setData,否则页面不会更新。
富文本正文:用 rich-text 解析 HTML
为什么需要: 公告 content 中可能包含 HTML 标签,小程序普通文本节点不会解析这些标签,直接渲染会显示成字符串。
怎么想: 小程序提供 rich-text 组件,职责类似 Vue 中的 v-html。把 HTML 字符串绑定到 nodes 属性即可解析。
怎么做: 详情模板中已经使用 <rich-text nodes="{{noticeDetail.content}}"></rich-text>。示例:
xml
<!-- rich-text 使用示例 -->
<rich-text nodes="{{'<h1>这里的 h1 标签可以被小程序解析</h1>'}}"></rich-text>易错点: 不要用普通 view 直接输出 content;nodes 绑定的是 HTML 字符串;调试时先确认接口返回的 content 确实包含标签,再检查 rich-text 是否绑定正确。
课件图示





代码示例
示例一:封装全局轻提示 utils/utils.js
javascript
// utils/utils.js
const utils = {
/**
* 用户消息反馈(轻提示)
* @param {string} title 文字提示的内容
*/
toast(title = '数据加载失败...') {
wx.showToast({
title,
mask: true, // 出现提示时加遮罩,防止用户高频点击
icon: 'none', // 不需要图标
})
},
}
// 挂载到全局对象 wx 上,后续使用无需再 import
wx.utils = utils
// 正常模块导出(按需导入也能用)
export default utilsjavascript
// app.js
// 入口中执行一次 utils.js,完成全局挂载
import './utils/utils.js'
App({
onLaunch() {},
})javascript
// pages/index/index.js
Page({
onLoad() {
// 已全局挂载,直接通过 wx.utils 调用
wx.utils.toast('Hello World')
},
})要点说明
wx.showToast中icon: 'none'表示纯文字提示,mask: true会加透明遮罩,避免用户在下单/提交等场景里重复点击。- 函数参数写成
title = '数据加载失败...',调用方不传参时也有兜底文案,这是封装通用工具函数的常见做法。 - 关键一行是
wx.utils = utils:wx是小程序内置的全局对象,挂上去之后任何页面都能wx.utils.toast(),不必每个文件import。 - 挂载动作必须在入口
app.js中通过import './utils/utils.js'执行一次,否则页面里访问不到;export default utils与全局挂载可以并存,两种用法都支持。 - 易错点:注释(JSDoc)不是可有可无的装饰,按
/** */+ 回车可自动根据函数体生成参数结构,企业项目通常要求写全。
示例二:封装网络请求 utils/http.js + 公告列表渲染
javascript
// utils/http.js
import http from 'wechat-http'
// 配置接口基础路径,后续只写核心路径
http.baseURL = 'https://live-api.itheima.net'
// 响应拦截器(注意:wechat-http 的写法与 axios 不同,不是 .use)
http.intercept.response = (res) => {
console.log(res)
return res.data // 保留 { code, data } 结构,页面按需解构
}
// 挂载到全局对象
wx.http = http
// 模块导出
export default httpjavascript
// app.js
import './utils/utils.js'
import './utils/http.js'
App({
onLaunch() {},
})javascript
// pages/index/index.js
Page({
data: {
notices: [],
},
onLoad() {
this.getNotices()
},
// 调用公告列表接口
async getNotices() {
const { code, data: notices } = await wx.http.get('/announcement')
// 检测接口是否调用成功
if (code !== 10000) return wx.utils.toast()
this.setData({ notices })
},
})xml
<!-- pages/index/index.wxml -->
<view class="notices-body">
<navigator
wx:for="{{notices}}"
wx:key="id"
hover-class="none"
url="/pages/notify/index?id={{item.id}}"
class="notice"
>
<view class="notice-title">{{item.title}}</view>
<view class="notice-brief">{{item.content}}</view>
<view class="notice-date">{{item.createdAt}}</view>
</navigator>
</view>要点说明
- 安装依赖后必须先「构建 npm」(工具菜单 → 构建 npm),否则
import http from 'wechat-http'会报找不到模块;构建会生成miniprogram_npm目录。 http.baseURL只配一次,页面里写/announcement这种核心路径即可,避免每条请求都手拼域名(手写路径出错风险高)。- 拦截器写法易错:
wechat-http是http.intercept.response = (res) => {},不是axios的http.intercept.response.use(...),照 AI 提示写成.use会直接失效。 - 拦截器返回值决定了页面拿到的数据层级:示例里
return res.data,页面就是const { code, data } = ...;若写成return res.data.data(转写稿的写法),页面要改成const notices = await wx.http.get('/announcement')。两处必须保持一致,混用会拿到undefined。 wx.request原生 API 不支持 Promise,也没有拦截器、基地址能力,所以用wechat-http二次封装后可用async/await,不必再写success回调、不必bind处理this。wx:key="id"必须写,且用接口返回的唯一字段;url中拼参用?id={{item.id}},小程序模板插值直接写花括号即可。
示例三:公告详情页(路由传参 + rich-text)
javascript
// pages/notify/index.js
Page({
data: {
noticeDetail: {},
},
// 只有 onLoad 能通过形参拿到页面参数
onLoad({ id }) {
this.getNoticeDetail(id)
},
// 调用公告详情接口
async getNoticeDetail(id) {
// 检测 id 是否存在
if (!id) return
const { code, data: noticeDetail } = await wx.http.get('/announcement/' + id)
// 验证接口调用是否成功
if (code !== 10000) return wx.utils.toast()
this.setData({ noticeDetail })
},
})xml
<!-- pages/notify/index.wxml -->
<scroll-view enhanced show-scrollbar="{{false}}" scroll-y>
<view class="notify-meta">
<view class="title">{{noticeDetail.title}}</view>
<view class="extra">
<view class="author">{{noticeDetail.creatorName}}</view>
<view class="datetime">{{noticeDetail.createdAt}}</view>
</view>
</view>
<view class="notify-content">
<!-- 富文本必须用 rich-text 渲染,nodes 绑定 HTML 字符串 -->
<rich-text nodes="{{noticeDetail.content}}"></rich-text>
</view>
</scroll-view>要点说明
- 获取路由参数只能靠
onLoad的形参解构onLoad({ id }),onShow、onReady等其他生命周期拿不到页面参数,这是最容易踩的坑。 - 参数判断写成
if (!id) return;笔记里if (typeof id === undefined)是错误写法,typeof返回的是字符串'undefined',与undefined恒不相等,条件永远不成立。 - 便捷方法
wx.http.get('/announcement/' + id)等价于把url传进http函数,比wx.http({ url, method: 'GET' })更简洁;路径建议从接口文档复制,避免手写拼错。 - 接口返回的
content是带 HTML 标签的富文本,小程序模板不会解析 HTML,直接{{}}输出只会显示标签文本,必须交给<rich-text nodes="...">渲染。 scroll-view需要scroll-y才能纵向滚动,enhanced show-scrollbar="{{false}}"用于隐藏滚动条;data中先给noticeDetail: {}占位,避免首屏取noticeDetail.title报错。
常见错误
- 现象:请求接口时报“合法域名”相关错误;原因:开发工具未配置或未刷新 request 合法域名,临时勾选“不校验合法域名”掩盖问题;修法:在小程序后台配置开发服务器域名,回到开发者工具详情中刷新域名配置,必要时重启工具后重试。
- 现象:安装
wechat-http后仍提示找不到模块;原因:未在项目根目录安装,或安装后未执行“构建 npm”;修法:确认终端位于项目根目录,重新安装后点击工具“构建 npm”,检查miniprogram_npm是否生成。 - 现象:页面中
wx.utils或wx.http为undefined;原因:只在utils文件中挂载,未在app.js入口导入执行;修法:在入口文件导入./utils/utils.js、./utils/http.js,确认小程序启动时完成挂载。 - 现象:公告详情页拿不到列表传过来的
id;原因:未在跳转地址拼接参数,或未在onLoad形参中接收,或参数名不一致;修法:列表跳转使用?id={{item.id}},详情页用onLoad({ id })接收,并在请求前判空。 - 现象:公告详情中的 HTML 内容直接显示标签源码;原因:使用普通
view/text渲染富文本;修法:使用rich-text,将内容绑定到nodes属性。 - 现象:响应拦截器处理后数据结构仍多一层,或页面拿不到预期数据;原因:拦截器写法混用
axios风格,或未正确return处理后的响应;修法:按wechat-http文档使用intercept.response(...),明确返回所需数据层级,并核对控制台输出。
练习
- 在
utils/utils.js中封装toast,挂载到wx.utils,并在首页onLoad中调用一次,验收页面出现无图标轻提示。 - 安装并构建
wechat-http,新建utils/http.js配置baseURL与响应拦截器,挂载到wx.http,验收页面可通过wx.http.get发起请求。 - 完成公告列表接口调用与模板渲染,要求设置
wx:key="id",点击列表项跳转详情页并携带id参数。 - 完成公告详情页:在
onLoad中接收id,调用详情接口并保存数据,使用rich-text渲染正文。 - 在项目中添加类型声明文件,验证
wx.http.get、wx.http.post等是否有代码提示,并避免自动补全成错误调用形式。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 基础封装-轻提示 | 08:40 |
| 2 | 基础封装-wechat-http基本使用 | 14:20 |
| 3 | 练习问题解答 | 03:28 |
| 4 | 基础封装-wechat-http拦截器 | 08:07 |
| 5 | 公告管理-公告列表渲染 | 05:42 |
| 6 | 公告管理-公告详情 | 12:11 |
| 7 | 补充-npmjs官网和代码提示 | 05:12 |
小结
- 通用能力应先封装再复用,入口统一挂载可减少页面重复导入。
- 小程序使用第三方 npm 包时,安装后必须构建 npm,否则不能直接导入使用。
- 请求层封装应统一基础路径、响应处理和全局调用方式,便于后续扩展 token 等业务逻辑。
- 页面参数应在
onLoad形参中获取,列表跳详情时要保证参数拼接与接收名称一致。 - 列表渲染需要稳定且唯一的
key,详情请求前应对关键参数做存在性校验。 - 富文本内容不能按普通文本渲染,应使用
rich-text的nodes属性。 - 遇到请求失败先排查域名、构建 npm、入口挂载等环境配置,再排查业务代码。
- 类型声明能改善代码提示,但不能替代运行时参数校验和接口返回校验。