主题
微信小程序指令与页面跳转(Day2 2/2)
本页对应 day2,共 5 段视频,约 1 小时 46 分。
学习目标
- 能够在小程序后台完成服务器域名配置,并说明 HTTPS、域名备案、端口限制等规则,能通过“本地设置忽略 HTTPS 校验”解决开发阶段域名不合法警告。
- 能够搭建首页“猜你喜欢”和“热门推荐”的静态结构,并将商品卡片封装为可复用组件,在页面中完成引入、注册和使用。
- 能够调用猜你喜欢与热门推荐接口获取数据,通过页面给组件传参、组件 props 接收的方式完成商品图片、标题、价格等字段渲染。
- 能够搭建分类页左右布局,使用 scroll-view 实现左侧菜单纵向滚动,并通过点击事件切换 active 索引实现高亮效果。
- 能够使用 scroll-view 实现横向滚动导航,配置 scroll-x、enable-flex、scroll-into-view 和滚动动画,实现点击导航项后自动滚动定位到对应位置。
- 能够结合 Page 生命周期函数在页面加载时发起请求,并说明页面跳转、Page 函数其他参数在小程序页面开发中的基本使用方式。
知识点
先定位本节:指令要落到真实页面里
本节笔记只有一句核心:列表渲染 wx:for;显示与隐藏 wx:if、wx:else、hidden。转写稿虽然没有单独讲指令语法,但后面搭首页、分类页时一直在用这些指令。所以学习时不要孤立背语法,而要把它放回“商品列表、分类菜单、高亮切换”这些真实结构里。本节笔记未附图片和完整代码,下面代码是按转写稿字段整理的示意,字段名以你实际接口为准。
列表渲染 wx:for:把重复的商品卡片交给数据
为什么需要:猜你喜欢、热门推荐、分类左侧菜单、右侧商品列表,结构都高度重复。手写六份、十份既慢又容易漏,数据一变还要改模板。
怎么想:先把“一个商品长什么样”写出来,再让 wx:for 按数组重复。转写稿里首页请求到猜你喜欢数据后,存到 likeArr,页面把 list="{{likeArr}}" 传给 card 组件,组件里再遍历。分类左侧菜单也是同理,用索引和高亮状态配合。
怎么做:模板只写一项,wx:for 遍历,wx:key 指定唯一字段。转写稿反复强调“别忘了写 wx:key”,否则列表更新容易错乱。
html
<view wx:for="{{list}}" wx:key="id" class="item">
<image src="{{item.imageUrl}}" class="goods" />
<view class="title">{{item.name}}</view>
<view class="subtitle">{{item.subTitle}}</view>
<view class="bottom">
<text class="price">{{item.price}}</text>
<text class="origin">¥{{item.originPrice}}</text>
</view>
</view>易错点:默认项名是 item、索引是 index,不要自己写错;wx:key 不要省;组件接收页面数据时写 list="{{likeArr}}",小程序里不要写成 Vue 的 :list。转写稿还遇到子标题高度不固定导致卡片不对齐,最后给子标题固定高度、超出用省略号解决。
显示与隐藏 wx:if / wx:else / hidden:高亮与条件展示
为什么需要:分类左侧菜单只有当前项要高亮,某些标记只在选中时出现;滚动条、提示块也常需要条件显示。不能把所有节点都永久显示。
怎么想:wx:if 是“条件成立才创建节点”,适合不常切换的结构;wx:else 必须紧跟 wx:if,中间不要插别的节点;hidden 是节点还在、只是隐藏,适合频繁切换。转写稿里分类高亮就是用 activeIndex 记录当前索引,点击菜单时通过 data-index 取索引并更新,模板里用 wx:if="{{index === activeIndex}}" 控制高亮线/标记。转写稿没有展开 hidden 的调试,这里只按笔记说明概念,不虚构实验现象。
html
<view
wx:for="{{menus}}"
wx:key="id"
class="item"
data-index="{{index}}"
bindtap="handleMenu"
>
{{item.name}}
<view wx:if="{{index === activeIndex}}" class="active-line"></view>
</view>易错点:wx:if 和 wx:else 必须相邻;频繁切换不要全用 wx:if,否则反复销毁重建;hidden 不是 wx:else 的替代品;点击事件里取索引用 e.currentTarget.dataset.index,不要写成 e.target 取错层。
数据从哪来:wx.request 域名配置不能绕
为什么需要:wx:for 要有数组。转写稿里首页一加载就请求猜你喜欢和热门推荐,若不先解决 wx.request 的域名合法性,控制台一直提示“域名不合法”,列表数据拿不到。
怎么想:微信小程序要求提前配置服务器域名。转写稿演示:小程序后台 → 开发管理 → 开发设置 → 服务器域名,扫码后配置 HTTPS 域名并保存提交;配置后详情项目配置里能看到合法域名。开发阶段也可在本地设置勾选“不校验合法域名/HTTPS 证书”,但上线不能靠它。
怎么做:域名必须是 HTTPS,不能写 IP、localhost;可配端口,配了端口就只能向该端口发请求;域名要备案。请求回来后判断 code === 200,把数据存到 likeArr/hotArr,再传给组件渲染。
易错点:拿到别人代码一直报域名不合法,多半是没配服务器域名;不要把开发阶段的“忽略校验”当成上线方案;接口字段名要和模板一致,先打印数据再写渲染。
组件与滚动容器:wx:for 的常见配套
为什么需要:猜你喜欢和热门推荐结构一样,转写稿把它们封装成 card 组件复用;分类左侧菜单多时要用 scroll-view 滚动,否则内容会把页面顶出去。
怎么想:页面负责请求数据,组件负责展示列表;组件没有路由,只是页面的一部分。scroll-view 纵向滚动必须写 scroll-y 并给固定高度;横向滚动写 scroll-x;转写稿调试发现 scroll-view 里用 flex 还要开 enable-flex,空间不足时子项会等比缩小,需要 flex-shrink: 0。
易错点:scroll-view 不给高度会失效;只写 scroll-view 不写 scroll-y 不滚;组件属性传参不要加冒号;分类高亮用索引切换后要记得 setData 更新 activeIndex。
先厘清本节边界:页面跳转的两种方式
本节笔记只给出一句结论:微信小程序页面跳转方式有声明式导航和编程式导航。转写稿并没有继续展开这两个词对应的具体标签或 API,而是先讲网络请求域名配置、首页“猜你喜欢/热门推荐”的静态与数据渲染、分类页静态,以及 scroll-view 的滚动效果。因此这里不能臆造跳转代码;能确认的是:页面跳转之前,必须先把“目标页面”和“触发入口”准备好。转写稿明确提到,“查看更多”会进入商品列表页,点击商品会进入商品详情页。
为什么需要:跳转不是孤立动作,目标页不存在、入口没搭好,跳转就无从谈起。
怎么想:先区分页面与组件。一个应用可以有多个页面,一个页面可以有多个组件;页面有路由,组件没有路由。
怎么做:把商品卡片封装成 components/card,在首页页面中引入、注册、使用;后续“查看更多”和商品卡片就是跳转入口。
易错点:把 card 当页面去配置路由;组件里写页面生命周期;只做“查看更多”样式却不绑定后续跳转。
网络请求域名配置是跳转目标页的数据基础
为什么需要:商品列表页、详情页、首页推荐都要发请求;转写稿中 wx.request 一直提示“域名不合法”,因为小程序只能向已配置的域名通信。
怎么想:先看警告,再读规则:服务器域名要在小程序后台“开发管理 → 开发设置”里配置;域名必须是 HTTPS,不能直接用 IP,也不能用 localhost;配置端口后只能向该端口发请求。
怎么做:后台配置服务器域名;开发阶段若不想配置,可在开发者工具“本地设置”勾选忽略 HTTPS 校验,但这是开发调试方案,不是上线方案。
易错点:拿到别人代码后一直报域名不合法;把 192.168.x.x 或 localhost 当合法域名;以为勾了忽略校验就等于线上可用。
首页静态:猜你喜欢与热门推荐复用卡片组件
为什么需要:首页底部商品区结构重复,猜你喜欢和热门推荐都要展示商品卡片,复用组件能减少重复代码。
怎么想:标题、“查看更多”属于页面结构;商品卡片属于可复用组件。转写稿特别说明:不要把“标题 + 查看更多 + 商品列表”整体封成一个组件,因为热门推荐上方没有同样的标题和按钮。
怎么做:新建 components/card,在页面 JSON 中引入注册:
json
{
"usingComponents": {
"card": "/components/card/card"
}
}页面中使用:
html
<card list="{{likeArr}}"></card>组件里接收:
js
properties: {
list: {
type: Array
}
}易错点:组件没有路由;页面给组件传参时不要写成 list:="{{likeArr}}",转写稿强调小程序这里不要加冒号;组件属性、自身 data、方法要分清。
数据渲染与布局调试
为什么需要:静态卡片只是占位,真正展示要靠接口数据。
怎么想:页面加载时发请求,拿到数据后存到页面 data,再通过属性传给 card 组件。转写稿中首页加载调用 this.getLikeData(),热门推荐调用 this.getHot(),返回 code === 200 后分别存入 likeArr、hotArr。
怎么做:先打印确认数据,再渲染;图片地址用 item.imageUrl,标题用 item.title,子标题用 item.subTitle,现价和原价分别替换。
易错点:子标题不固定高度会导致卡片上下不对齐;标题过长要省略;图片默认缩放可能模糊,应固定宽度、让高度自适应;不要没拿到数据就先写复杂渲染。
分类页与 scroll-view:跳转落地页的常见容器
为什么需要:分类页左侧导航可能很多,不能把页面撑高,需要固定区域内滚动。
怎么想:左侧用 scroll-view 做纵向滚动,右侧展示对应分类内容;横向导航则用 scroll-x。
怎么做:纵向滚动要固定高度并加 scroll-y;隐藏滚动条可用 enhanced 与 show-scrollbar="{{false}}";点击切换高亮用 activeIndex。横向滚动还要开启 enable-flex,子项加 flex-shrink: 0,否则空间不足会等比缩小。
易错点:scroll-view 不给固定高度,内容会顶出去;只写 scroll-x 不写 enable-flex,flex 布局不生效;scroll-into-view 的目标 id 不能以数字开头;想要滚动动画要加 scroll-with-animation。
回到页面跳转:本节能确认的结论
为什么需要:页面跳转的两种方式名称已经给出,但转写稿没有展开具体写法,所以不能编造 API。
怎么想:先把“目标页面”准备好:商品列表页、商品详情页;再把“入口”准备好:“查看更多”和商品卡片。页面负责路由,组件只负责页面中的一部分。
怎么做:后续补声明式导航、编程式导航时,应分别绑定到“查看更多”和商品卡片点击上;当前先保证页面结构、组件复用、数据渲染和滚动容器正确。
易错点:把“页面跳转”误写成组件切换;组件当页面加路由;入口只做视觉不接逻辑;在材料未给出具体 API 时凭空补代码。
先分清应用级和页面级
本节笔记只列了两组生命周期函数名:应用级 onLaunch、onShow、onHide、onError,页面级 onLoad、onShow、onReady、onHide、onUnload。学习时先不要急着背,先想清楚它们分别挂在谁身上:应用级写在 App() 里,整个小程序只有一份;页面级写在 Page() 里,每个页面各有一份。转写稿里反复出现“App 是创建应用、Page 是创建页面、Component 是创建组件”,这句话很关键:生命周期函数放错文件,就不会按预期触发。
应用级生命周期
为什么需要:小程序从启动、切前台、切后台到报错,需要一个全局入口做初始化、日志和兜底。
怎么想:onLaunch 是“第一次启动”,只触发一次;onShow 是“每次看到小程序”,可能多次;onHide 是“每次退到后台”;onError 是“出错时收错误信息”。
怎么做:在 app.js 的 App({...}) 中写:
js
App({
onLaunch() {
// 全局只做一次:初始化、读取本地配置
},
onShow() {
// 每次进入前台:可刷新全局状态
},
onHide() {
// 每次进入后台:暂停定时器、保存草稿
},
onError(error) {
console.error('小程序错误:', error)
}
})易错点:onLaunch 不要写“每次显示都要做”的逻辑;onShow 会多次触发,别重复注册事件;onError 不是业务 try/catch 的替代品,业务异常仍要自己处理。
页面级生命周期
为什么需要:页面有加载、渲染、显示、隐藏、卸载的过程,不同阶段要做不同的事。
怎么想:onLoad 只一次,适合拿路由参数、发首次请求;onShow 每次显示都触发,适合刷新;onReady 只一次,表示初次渲染完成;onHide 是页面隐藏但没销毁;onUnload 是页面卸载。
怎么做:在页面 Page({...}) 中按阶段放置:
js
Page({
onLoad(options) {
// 只执行一次:取参数、发首次请求
},
onShow() {
// 每次显示:从其他页返回也会触发
},
onReady() {
// 只执行一次:初次渲染完成
},
onHide() {
// 页面隐藏:暂停动画、定时器
},
onUnload() {
// 页面卸载:清理定时器、解绑事件
}
})易错点:onLoad 不等于 onShow,从详情页返回列表页时,列表页通常触发 onShow 而不是 onLoad;onReady 只一次,不要拿它做每次刷新;onHide 不是销毁,onUnload 才是;tab 页切换一般只触发 onHide/onShow,不会触发 onUnload。
结合网络请求调试理解触发时机
转写稿里讲师配置 wx.request 时,开发工具一直提示“域名不合法”。解决路径是:到小程序后台“开发管理 → 开发设置 → 服务器域名”配置 request 合法域名;开发阶段也可在开发者工具“详情 → 本地设置”勾选“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”。注意纠正同音字:是 HTTPS,不是“HTTS/HTDPS”;是服务器域名,不是“福器玉米”;域名不能使用 IP 地址或 localhost,需要 HTTPS 且通常要备案;端口范围是 0–65535,HTTPS 默认 443,不要记成 80。
这和生命周期有什么关系?转写稿说“页面一加载的时候,要拿到猜你喜欢的数据”,这类首次请求通常放 onLoad;如果页面每次显示都要刷新,才考虑 onShow。页面拿到数据后再通过属性传给 card 组件,因为“组件没有路由”,组件只是页面的一部分。不要把页面生命周期和组件生命周期混在一起,也不要把只在页面加载时做一次的请求放到 onShow 里造成重复请求。
易错点清单
onLaunch只一次,onShow可多次;不要互相替代。onLoad只一次,onShow每次显示都触发;返回页面时优先检查onShow。onReady只一次,表示初次渲染完成,不是“每次渲染完成”。onHide不是销毁,onUnload才是;定时器、事件监听要在onHide暂停、在onUnload清理。- 页面有路由,组件没有路由;生命周期函数要写在正确的
App/Page/Component配置里。 - 网络请求报“域名不合法”时,先查后台服务器域名配置,再查本地设置是否勾选忽略校验,不要误以为是生命周期写错。
本节定位:别只背“Page参数”
本节笔记标题是“Page函数其他参数”,但转写稿实际把几条线串在一起:wx.request 前的域名配置、页面加载后取数据、页面给组件传值、商品卡片复用,以及 scroll-view 的纵向/横向滚动。转写稿没有展开“分享”API,下面只整理可确认的内容。核心思路是:页面负责取数和组织,组件负责展示和复用。
网络请求与合法域名配置
为什么需要: 直接调用 wx.request 时,控制台提示“域名不合法”,请求发不出去。小程序不是浏览器,不能随意请求任意地址。
怎么想: 先判断是代码错还是配置错。转写中请求地址本身能写,但微信要求提前登记通讯域名,所以先看后台有没有配。
怎么做: 到小程序后台“开发管理→开发设置→服务器域名”配置请求域名;域名要 HTTPS,不能用 localhost、192.168 这类 IP,通常还需备案;配置端口后只能向该端口发请求。调试阶段也可在开发者工具本地设置里勾选“不校验合法域名”等选项,先让项目跑起来。
易错点: 拿到别人代码一直提示域名不合法,多半是没配域名;勾选不校验只是开发调试,不是上线方案。
页面加载取数,再传给组件
为什么需要: 猜你喜欢、热门推荐的数据要由页面请求,再交给卡片组件渲染。组件只负责展示,不应该自己乱发请求。
怎么想: 转写中先确认接口:猜你喜欢不需要 token,是 GET;页面一加载就取数。拿到 result.data 后先 setData 存到页面,再通过属性传给组件。
怎么做: 页面配置里用 usingComponents 注册 card 组件;模板中写 <card list="{{like}}"></card>。注意转写反复强调:小程序属性绑定不要写成 :list 这种 Vue 冒号写法。组件里用 properties 接收 list,类型为 Array,再在组件模板里 wx:for 渲染。
易错点: 数据请求到了但页面不显示,先看控制台有没有数据、setData 是否执行、属性名是否一致;组件没有路由,别把组件当页面跳。
商品卡片组件与静态布局
为什么需要: 猜你喜欢和热门推荐下面的商品结构一样,封装成组件才能复用。
怎么想: 转写中先搭静态:外层灰色底、标题居中加粗、卡片两列、每个 item 白底、图片、标题、子标题、现价/原价、购物车小图。
怎么做: 卡片根节点用 display:flex 并允许换行;item 给固定宽度,左右用 justify-content: space-between 留缝;图片固定宽高;子标题用 display:-webkit-box、-webkit-line-clamp、overflow:hidden 做两行省略;原价加删除线。
易错点: 转写中商品没对齐,原因是子标题没固定高度,一行和两行把下面撑得不一致;给子标题固定或最小高度后对齐。组件文件是 Component 构造,不是 Page,且组件没有路由。
分类页左右布局与 scroll-view
为什么需要: 分类页左侧导航多时不能把页面撑长,要在固定区域内滚动。
怎么想: 外层左右 flex;左侧固定宽、右侧 flex:1 占剩余空间。左侧项目多时用 scroll-view,但必须给固定高度,否则内容会把容器顶开。
怎么做: 左侧 scroll-view 设高度为父容器高度,开启 scroll-y 才能纵向滚动;转写中还尝试隐藏滚动条,并给当前项加 active 类,用索引控制高亮。
易错点: 只写 scroll-view 不设高度,滚动不生效;不写 scroll-y,默认不是纵向滚动。点击切换高亮时,要通过事件对象取 currentTarget.dataset.index,再更新当前索引。
横向导航与 scroll-into-view 拓展
为什么需要: 顶部导航项很多时要横向滚动,点击某一项还要自动滚到对应位置。
怎么想: 转写中先给 scroll-view 开 scroll-x,并给固定高度;子项横向排列要开 enable-flex,否则 flex 不生效。空间不足时 flex 子项会等比缩小,所以子项要加 flex-shrink:0。
怎么做: 每个子项给唯一 id,但 id 不能以数字开头,转写中拼成 A0、A1 这类形式;scroll-into-view 绑定当前项 id,配合 scroll-with-animation 出现滚动动画。
易错点: 不设高度内容会顶下去;不开 scroll-x 横向不动;不开 enable-flex 横向布局不生效;子项不加 flex-shrink:0 会被压缩;scroll-into-view 的值要和子项 id 对应。
收束:调试顺序
先看控制台请求和域名,再看 setData 与属性名,最后看样式高度和滚动方向。转写里多次出现“先看有没有数据,再干活”,这是本节最稳的调试习惯。
课堂画面





代码示例
1. 猜你喜欢 / 热门推荐卡片组件(组件传参 + wx:for + 两行省略)
components/card/card.json
json
{
"component": true,
"usingComponents": {}
}components/card/card.js
js
Component({
properties: {
list: {
type: Array,
value: []
}
}
})components/card/card.wxml
wxml
<view class="card">
<view class="item" wx:for="{{list}}" wx:key="id">
<image class="goods" src="{{item.imgUrl}}" mode="widthFix"></image>
<view class="title">{{item.name}}</view>
<view class="sTitle">{{item.sTitle}}</view>
<view class="bottom">
<view class="price">¥{{item.price}}</view>
<view class="right">
<text class="oldPrice">¥{{item.oldPrice}}</text>
<image class="cardIcon" src="{{item.cartIcon}}" mode="aspectFit"></image>
</view>
</view>
</view>
</view>components/card/card.wxss
wxss
.card {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.item {
width: 360rpx;
background: #fff;
margin: 20rpx 0;
}
.goods {
width: 360rpx;
height: 180rpx;
}
.title {
font-size: 26rpx;
font-weight: 900;
}
.sTitle {
font-size: 24rpx;
color: #666;
min-height: 80rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
}
.right {
display: flex;
align-items: center;
}
.oldPrice {
color: #ccc;
text-decoration: line-through;
margin-left: 22rpx;
}
.cardIcon {
width: 48rpx;
height: 48rpx;
margin-left: 22rpx;
}pages/index/index.json
json
{
"usingComponents": {
"card": "/components/card/card"
}
}pages/index/index.wxml
wxml
<view class="footer">
<view class="like">猜你喜欢</view>
<card list="{{likeList}}" />
<button class="more">查看更多</button>
</view>
<view class="footer">
<view class="like">热门推荐</view>
<card list="{{hotList}}" />
<button class="more">查看更多</button>
</view>pages/index/index.js
js
Page({
data: {
likeList: [
{ id: 1, imgUrl: '', name: '浪漫情人节音乐球', sTitle: '浪漫情人节音乐球', price: '1999', oldPrice: '1299', cartIcon: '' },
{ id: 2, imgUrl: '', name: '香水护体', sTitle: '香水护体', price: '1999', oldPrice: '1299', cartIcon: '' },
{ id: 3, imgUrl: '', name: '浪漫情人节音乐球', sTitle: '浪漫情人节音乐球', price: '1999', oldPrice: '1299', cartIcon: '' },
{ id: 4, imgUrl: '', name: '香水护体', sTitle: '香水护体', price: '1999', oldPrice: '1299', cartIcon: '' },
{ id: 5, imgUrl: '', name: '浪漫情人节音乐球', sTitle: '浪漫情人节音乐球', price: '1999', oldPrice: '1299', cartIcon: '' },
{ id: 6, imgUrl: '', name: '香水护体', sTitle: '香水护体', price: '1999', oldPrice: '1299', cartIcon: '' }
],
hotList: [
{ id: 7, imgUrl: '', name: '浪漫情人节音乐球', sTitle: '浪漫情人节音乐球', price: '1999', oldPrice: '1299', cartIcon: '' },
{ id: 8, imgUrl: '', name: '香水护体', sTitle: '香水护体', price: '1999', oldPrice: '1299', cartIcon: '' }
]
}
})pages/index/index.wxss
wxss
.footer {
width: 750rpx;
background: #f5f5f5;
}
.like {
text-align: center;
font-size: 40rpx;
font-weight: 900;
margin-top: 10rpx;
}
.more {
width: 200rpx;
height: 42rpx;
line-height: 42rpx;
font-size: 24rpx;
border-radius: 20rpx;
margin: 20rpx auto;
}要点解释:
- 组件里用
properties.list接收页面传入的数组,页面用list="{{likeList}}"传参,注意小程序里不要写成:list。 wx:for="{{list}}"渲染商品,wx:key="id"避免列表更新问题。- 子标题必须固定
min-height,否则一行/两行内容会导致卡片底部价格不对齐。 -webkit-line-clamp: 2实现两行省略,必须配合display: -webkit-box和overflow: hidden。- 组件没有路由,页面才需要通过
usingComponents引入并注册组件。
2. scroll-view 横向滚动导航 + scroll-into-view 动画定位
pages/scroll-nav/scroll-nav.json
json
{}pages/scroll-nav/scroll-nav.wxml
wxml
<scroll-view
class="scroll"
scroll-x
enable-flex
scroll-into-view="A{{currentIndex}}"
scroll-with-animation
>
<view
class="item"
wx:for="{{navList}}"
wx:key="*this"
id="A{{index}}"
data-index="{{index}}"
bindtap="handleNav"
>
{{item}}
</view>
</scroll-view>pages/scroll-nav/scroll-nav.wxss
wxss
page {
height: 100%;
}
.scroll {
width: 100%;
height: 80rpx;
display: flex;
}
.item {
flex-shrink: 0;
width: 100rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
white-space: nowrap;
}pages/scroll-nav/scroll-nav.js
js
Page({
data: {
currentIndex: 0,
navList: [
'军事', '军事1', '军事2', '军事3', '军事4', '军事5',
'军事6', '军事7', '军事8', '军事9', '军事10', '军事11',
'军事12', '军事13', '军事14', '军事15'
]
},
handleNav(e) {
this.setData({
currentIndex: e.currentTarget.dataset.index
})
}
})要点解释:
- 横向滚动必须写
scroll-x,纵向滚动写scroll-y。 enable-flex开启后,scroll-view上的display: flex才生效。- 子项必须写
flex-shrink: 0,否则空间不足时 flex 会等比例缩小,宽度失效。 scroll-into-view="A{{currentIndex}}"要和子节点id="A{{index}}"对应,且 id 不能以数字开头。scroll-with-animation控制滚动到指定位置时是否有动画。scroll-view无论横向还是纵向,都必须有固定高度,否则内容会撑开或滚动异常。
3. 分类左右布局 + 左侧 scroll-view 纵向滚动 + active 高亮
pages/category/category.json
json
{}pages/category/category.wxml
wxml
<view class="category">
<scroll-view class="left" scroll-y enhanced show-scrollbar="{{false}}">
<view
class="item {{currentIndex === index ? 'active' : ''}}"
wx:for="{{cateList}}"
wx:key="*this"
data-index="{{index}}"
bindtap="handleCate"
>
{{item}}
</view>
</scroll-view>
<view class="right">
<view class="title">香水护体</view>
<view class="box">
<view class="item" wx:for="{{rightList}}" wx:key="*this">
<image class="img" src="" mode="aspectFit"></image>
<view class="kttle">香水有毒</view>
</view>
</view>
</view>
</view>pages/category/category.wxss
wxss
page {
height: 100%;
}
.category {
width: 100%;
height: 100%;
display: flex;
}
.left {
width: 180rpx;
height: 100%;
background: #f5f5f5;
}
.left .item {
height: 80rpx;
line-height: 80rpx;
text-align: center;
font-size: 28rpx;
}
.left .active {
background: #fff;
color: #000;
font-weight: 900;
}
.right {
flex: 1;
height: 100%;
}
.right .title {
text-align: center;
font-size: 30rpx;
margin: 20rpx 0;
}
.box {
display: flex;
flex-wrap: wrap;
}
.box .item {
width: 33.33%;
display: flex;
flex-direction: column;
align常见错误
一发请求,控制台就刷“域名不合法” 现象:
wx.request能发出、也能拿到数据,但底部一直黄字警告,换台电脑/换个人跑代码就报得更凶。 原因:小程序只允许向“已配置的服务器域名”通信;开发时很多人勾了“不校验合法域名”本地能跑,代码一交出去别人没勾就炸。 修法:后台 → 开发管理 → 开发设置 → 服务器域名,把接口域名(HTTPS、不能是 IP/localhost、已备案)配进去;只在本地调试才用“忽略 HTTPS 校验”,且不要把它当成解决方案交付。组件建出来了,页面里就是不显示 现象:标签写了、样式也写了,页面上什么都没有,控制台还报“未找到组件”。 原因:三个环节缺一个——组件文件是用“新建 Page”建的(该用 Component)、页面 json 里没在
usingComponents注册、或者路径写错(components/card/card少个前导/)。 修法:组件必须Component()创建;页面 json 里"card": "/components/card/card"注册后才能用<card />;组件没有路由,别想着跳转到它。给组件传值,子组件收到的永远是空 现象:父页面数据明明有,
properties里打印是undefined或[]。 原因:属性写成了 Vue 的:list="likeArr"或list="{{likeArr}}"——小程序没有:语法,冒号会被当成字符串的一部分;或者properties里 key 名和父级写的对不上。 修法:写成list="{{likeArr}}",键名两边逐字对齐;父级数据要先用setData落到data上,子组件才有值可接。scroll-view里内容一大堆,就是滚不动 现象:内容全被撑开或者直接溢出到屏幕外,手指划不动;有时候横着能滚、竖着不能。 原因:scroll-view必须有固定高度(或宽高受限)才能产生滚动区域,光给内容高度没用;竖滚还要显式加scroll-y,横滚加scroll-x。 修法:给scroll-view一个确定高度(百分比要保证父级有高度),补scroll-y/scroll-x;不想要滚动条加show-scrollbar="{{false}}"。flex子项宽度设了 360rpx,实际被压扁 现象:写了width: 360rpx,渲染出来却窄了一截,几个卡片挤在一起。 原因:父容器空间不足时,flex 项目默认flex-shrink: 1会等比缩小,你写的宽度只是“期望值”。 修法:flex-shrink: 0锁死尺寸,或者父级flex-wrap: wrap让它换行;scroll-view里用 flex 还要额外开enable-flex,否则display:flex根本不生效。scroll-into-view点了没反应 / 没动画 现象:点击导航项,列表不滚动到对应位置,或者“啪”地跳过去没有过渡。 原因:目标子节点的id用了数字开头(如0、1),属性值不合法;或者只改了值没加动画属性。 修法:id用字母开头拼接,如a{{index}};scroll-into-view="a{{currentIndex}}",并加scroll-with-animation。卡片区标题、副标题高低不齐,一排看着“狗啃” 现象:有的卡片两行文字、有的一行,底部价格对不齐。 原因:副标题容器高度由内容撑开,行数不同高度就不同。 修法:给副标题固定(或最小)高度 + 多行省略(
-webkit-box+line-clamp+overflow:hidden),让每张卡片骨架一致。列表渲染后勾选/高亮状态乱串 现象:点第 3 项,第 1 项也亮了,或者删除一项后剩下的状态全错位。 原因:
wx:for没写wx:key,或用了index当 key 又对数组做了增删。 修法:用数据里的唯一字段(如商品 id)做wx:key;只有纯静态、不重排的列表才允许用index。
练习
域名配置排障:拿一个线上 HTTPS 接口,在“不校验合法域名”关闭的状态下让它跑通;记录你改了哪几处配置,并说明如果接口是
http://192.168.x.x:8080为什么必须换域名。组件拆分:把“猜你喜欢”里的单个商品卡片抽成
card组件,父页面通过properties传一个数组进去;要求父页面在onLoad拿到数据后setData再渲染,并验证子组件能正确收到 6 条数据。两列布局:用 flex 实现商品两列排布,卡片间距 20rpx、左右各留 15rpx;故意把某个标题写超长,验证你的省略与对齐方案在“一行标题”和“两行标题”混排时底部价格仍然对齐。
左侧分类滚动:分类列表造 100 条数据,用
scroll-view做纵向滚动并隐藏滚动条;点击某一项时该项高亮,且列表自动滚到可视区域并带过渡动画。生命周期辨析:在首页
onLoad、onShow里各打一条日志,然后从详情页返回首页,观察打印顺序;据此回答:如果需求是“每次回到首页都刷新猜你喜欢数据”,请求应该放在哪个钩子里,为什么。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 小程序网络配置 | 10:04 |
| 2 | 首页猜你喜欢与热门推荐的静态的搭建 | 30:32 |
| 3 | 获取猜你喜欢与热门推荐的数据并且渲染出来 | 14:42 |
| 4 | 分类的静态搭建 | 32:53 |
| 5 | scroll-view顶部导航效果---拓展的技能点 | 18:40 |
小结
- 域名配置是交付级问题,不是本地开关问题——“忽略校验”只能救你自己,救不了别人的电脑。
- 组件三件套缺一不可:
Component()创建、usingComponents注册、标签使用;路径前导/是排查高频点。 - 小程序模板语法是
{{}}世界,Vue 的:绑定在这里是错的,属性名和值都要逐字核对。 scroll-view的心智模型是“固定窗口 + 可滚动内容”,没有确定尺寸就没有滚动,方向必须显式声明。- flex 的默认收缩行为会悄悄改写你写的宽度,凡是“宽度不对”先怀疑
flex-shrink。 - 列表类 UI 的观感一致,靠的是骨架固定(高度、行数、省略规则),不是靠调字体大小。
wx:key、id命名、scroll-into-view这类细节,单看都是小语法,凑在一起就是“点了没反应”和“状态串台”。- 请求放
onLoad还是onShow,取决于“数据是否需要每次可见时刷新”,这是业务判断而非语法判断。