微信小程序demo实战:今日头条风格资讯页从零搭建指南
2026/9/14 4:51:30 网站建设 项目流程

简介:一款面向微信小程序初学者的今日头条风格 Demo,用于快速掌握资讯类小程序的信息展示思路,可作为前端自学、课程设计或毕业设计的入门参考。资源压缩包约10KB,共11个文件,包括3个wxss样式文件、3个js逻辑文件、2个wxml页面结构文件、1个json配置文件、1个md说明文档及1张png截图,核心文件一应俱全,便于直接导入小程序开发者工具查看运行效果。阅读源码可以学习小程序的目录组织、WXML模板渲染、WXSS样式编写、页面与全局配置,以及数据绑定、事件交互等基础开发技能;代码轻量、结构清晰,适合逐行拆解,也能在此之上增加网络请求、详情页等能力,扩展成更完整的资讯应用。目前已有1051人学习下载,对于希望快速上手微信小程序开发的初学者而言,是一份不错的练手与参考资源。

1. 微信小程序demo:今日头条,从一个可跑通的页面开始

如果你搜过“微信小程序demo 源代码”,大概率见过一堆用官方模板拼出来的待办清单、计算器,它们能编译但离真实项目太远。这次我们做一个“今日头条”风格的资讯小程序demo,不是为了仿产品,而是为了把微信小程序最常踩的坑提前碾一遍:tabBar 配置、列表渲染、详情页跳转、下拉刷新与上拉加载。这类 demo 最适合两拨人——刚学小程序、想看得见效果的初级开发者,以及需要在两天内搭出“有点样子”的原型给业务方看的全栈工程师。它不需要服务器,数据用本地 Mock,源代码全部贴出,截图也能直接用微信开发者工具自带的模拟器截图导出。下面按我实际搭这个 demo 的路径走一遍,每个文件都给你能直接复制的版本。

2. 微信小程序demo初始化:app.json 与 tabBar 的配置顺序

2.1 先建项目还是先写配置

新建项目时,微信开发者工具会让你选“小程序”还是“小游戏”,我们选小程序,后端服务选“不使用云服务”,这会生成一个纯净的模板目录。很多人一上来就删掉 pages/index/index 想换结构,结果 app.json 里路径没改,编译直接报app.json: tabBar.list[0].pagePath找不到页面。正确的顺序是:先改 app.json 定义页面列表,再创建对应的目录和文件。

一个今日头条 demo 至少要四个 Tab:首页、视频、微头条、我的。对应页面路径pages/index/indexpages/video/videopages/wenzhang/wenzhangpages/mine/mine(这里故意不用相同前缀,模拟真实项目里不同业务模块的命名习惯)。

{ "pages": [ "pages/index/index", "pages/video/video", "pages/wenzhang/wenzhang", "pages/mine/mine" ], "window": { "navigationBarTextStyle": "black", "navigationBarTitleText": "今日头条demo", "navigationBarBackgroundColor": "#f5f5f5", "backgroundColor": "#f5f5f5" }, "tabBar": { "color": "#999999", "selectedColor": "#ff4040", "backgroundColor": "#ffffff", "borderStyle": "black", "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/video/video", "text": "视频" }, { "pagePath": "pages/wenzhang/wenzhang", "text": "微头条" }, { "pagePath": "pages/mine/mine", "text": "我的" } ] } }

这段配置里最容易被忽略的是borderStyle,它只支持blackwhite,写成"#e0e0e0"会被直接忽略,边界线颜色由微信默认决定。另外navigationBarBackgroundColor也接受 hex 值,但会同时影响下拉 loading 的背景色,如果你后续要自定义下拉刷新样式,注意别和页面背景色冲突。

2.2 tabBar 图标能用图片吗

真正上线的小程序 tabBar 需要 iconPath 和 selectedIconPath,但 demo 阶段可以不放。一旦配置了其中一个字段,另一个也必须存在,否则编译报错。图片推荐 81px * 81px 的 PNG,放在images/tab/目录。常见误区是直接放网络图片地址,tabBar 不接受远程 URL,必须使用本地包内路径。如果图省事,可以像上面这样只写文字,在选中颜色上做区分,视觉上接近今日头条的红色强调。

2.3 demo 的全局配置边界

为了更像今日头条,很多人会去配navigationStyle: custom自定义导航栏——这会立刻引入状态栏高度适配问题,包括wx.getSystemInfoSync().statusBarHeight。我的建议是第一次搭 demo 先别用,保留默认导航栏,把精力放在内容呈现上。顶部导航栏高度在基础库 2.x 之后是固定值,但不同机型胶囊按钮位置有差异,等你的 demo 跑通基础列表后再去折腾自定义导航才是正确节奏。HBuilderX 开发微信小程序场景下,navigationStyle写法一样,只是编译时由 HBuilderX 转成微信格式,这里我们直接用微信开发者工具,兼容性最好。

3. 今日头条demo首页骨架:列表渲染、Mock 数据和跳转参数

3.1 页面结构与数据流

首页是所有资讯类小程序的主战场。先看pages/index/index.wxml,我们把整个页面拆成“顶部频道 Tab + 新闻列表”。频道 Tab 用scroll-view横向滚动,列表用wx:for渲染。

<view class="channel-bar"> <scroll-view scroll-x="true" class="channel-scroll" enhanced="true" show-scrollbar="false"> <view class="channel-item {{selectedChannel === item ? 'active' : ''}}" wx:for="{{channels}}" wx:key="index" bindtap="onChannelTap">Page({ data: { channels: ['推荐', '热点', '科技', '体育', '财经', '娱乐', '汽车'], selectedChannel: '推荐', newsList: [ { id: 1, title: '微信小程序demo:前端工程师的周末实践', source: '程序员周刊', commentCount: 128, publishTime: '10分钟前', content: '这是详情页内容...' }, { id: 2, title: '从0到1搭建资讯类小程序,这5个坑最常见', source: '移动开发前线', commentCount: 56, publishTime: '32分钟前', content: '详情页内容...' }, { id: 3, title: '今日头条风格的卡片布局,用flex就够了', source: 'UI设计笔记', commentCount: 89, publishTime: '1小时前', content: '详情页内容...' } ] }, onChannelTap(e) { const channel = e.currentTarget.dataset.channel; this.setData({ selectedChannel: channel }); // 真实项目在这里重新请求列表,demo 阶段仅切换选中态 }, onNewsTap(e) { const { id, title } = e.currentTarget.dataset; wx.navigateTo({ url: `/pages/detail/detail?id=${id}&title=${title}` }); } });

这段代码有几个点要说明。wx.navigateTo的 URL 里直接拼title容易遇到中文编码问题,虽然微信会自动 encode,但某些低版本基础库会截断长标题。稳妥做法是在onNewsTap里先encodeURIComponent(title)再拼到 URL。另外,detail页面不需要注册到 tabBar,只需在pages数组里声明路径。

3.3 列表样式与两栏/单栏抉择

今日头条首页是单栏大标题卡片,下面常配一张或多张图。demo 为了代码简洁,先做纯文字卡片。wxss注意display: flex配合justify-content: space-between让内容两端对齐,卡片之间用margin-bottom分隔,不要用border-bottom加间距,会出现双线视觉。

.news-card { background: #ffffff; padding: 20rpx 30rpx; margin: 16rpx 24rpx; border-radius: 16rpx; box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); } .news-title { font-size: 34rpx; font-weight: 500; line-height: 1.5; color: #222222; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; } .news-meta { margin-top: 16rpx; font-size: 24rpx; color: #999999; display: flex; justify-content: space-between; }

这里-webkit-line-clamp是微信小程序裁剪多行文本的标准姿势,-webkit-box必须配合使用。rpx 是微信响应单位,屏幕宽度固定 750rpx,所以 24rpx 在多数手机上约等于 12px。如果直接把网页用的 px 搬过来,小屏幕上字会显得特别大。这次截图导出就能明显看出 rpx 适配带来的视觉一致性。

4. 让今日头条demo可交互:下拉刷新、上拉加载与搜索页

4.1 开启页面下拉刷新

资讯列表必须支持下拉刷新,微信小程序页面级下拉刷新需要两步。第一步在pages/index/index.json里开启:

{ "enablePullDownRefresh": true, "backgroundTextStyle": "dark" }

第二步在index.js里监听onPullDownRefresh。注意这个函数不写Page配置里,而是和onLoad平级作为一个生命周期方法。

onPullDownRefresh() { // 模拟重新拉取数据 const mockNewItem = { id: Date.now(), title: '刚下拉刷新出来的新内容', source: '今日头条demo', commentCount: 0, publishTime: '刚刚', content: '刷新获取的最新一条' }; this.setData({ newsList: [mockNewItem, ...this.data.newsList] }); wx.stopPullDownRefresh(); }

wx.stopPullDownRefresh()必须调用,否则 loading 动画会一直转。更好的做法是把它放在setData回调里:

this.setData({ newsList: newList }, () => { wx.stopPullDownRefresh(); });

这样能确保 UI 更新完成后再收掉动画。真机调试时,下拉动作经常因为页面最外层view没有撑满屏幕而失灵,检查page根样式是否设置min-height: 100vh

4.2 上拉加载更多与防抖处理

上拉加载的触发函数是onReachBottom,它在页面滚动到底部时自动执行。但有一个经典问题:用户快速连续滑动触底时,这个函数会短时间内触发多次,导致重复请求。demo 里可以用一个loadingMore锁:

data: { page: 1, pageSize: 10, loadingMore: false, hasMore: true }, onReachBottom() { if (this.data.loadingMore || !this.data.hasMore) return; this.setData({ loadingMore: true }); // 模拟分页拉取 const moreList = Array.from({ length: 5 }, (_, i) => ({ id: Date.now() + i, title: `加载更多第${this.data.page + 1}页 - 条目${i + 1}`, source: '今日头条demo', commentCount: 0, publishTime: '刚刚', content: '分页内容' })); this.setData({ newsList: this.data.newsList.concat(moreList), page: this.data.page + 1, loadingMore: false, hasMore: this.data.page < 5 }); }

这里把loadingMore置回false放在setData回调里会更稳,但为了代码可读性我简化放在同一次setData中。实战中建议使用真正的防抖工具函数,或者用wx.vibrateShort给用户一个触底反馈,增强“今日头条”那种刷不完的手感。

4.3 搜索框与历史记录

资讯小程序总要有个搜索入口。首页顶部加一个navigator跳转搜搜页,或者直接在首页放一个假的搜索框。为了 demo 不额外建页面,我在频道栏上方加一个只读的搜索框,点击跳到同一个search/search页面。该页面核心代码是输入监听与历史记录存储。

// pages/search/search.js const HISTORY_KEY = 'toutiao_search_history'; Page({ data: { keyword: '', historyList: [], resultList: [] }, onLoad() { const historyList = wx.getStorageSync(HISTORY_KEY) || []; this.setData({ historyList }); }, onInput(e) { this.setData({ keyword: e.detail.value }); }, onSearch() { const keyword = this.data.keyword.trim(); if (!keyword) return; let historyList = wx.getStorageSync(HISTORY_KEY) || []; if (!historyList.includes(keyword)) { historyList.unshift(keyword); historyList = historyList.slice(0, 10); wx.setStorageSync(HISTORY_KEY, historyList); } // 本地过滤模拟搜索 const list = wx.getStorageSync('toutiao_news') || []; const resultList = list.filter(item => item.title.includes(keyword)); this.setData({ historyList, resultList }); } });

这个搜索逻辑很简单,但用到了wx.getStorageSyncwx.setStorageSync两个本地存储 API,它们适合存 KV 数据,容量上限 10MB。注意不要把搜索历史存在全局变量里,否则重新冷启动就丢了。这里没有用防抖,因为 demo 是本数据过滤;如果接入后端接口,必须用setTimeout进行 300ms 防抖,否则每敲一个字母就发一次请求。你可以在onInput里先clearTimeout(this.searchTimer),再设置新的延时执行。

4.4 更符合今日头条视觉的图片轮播

头条首页顶部是轮播图推荐位。微信内置swiper组件,配置indicator-dotsautoplayinterval即可。下面是一个标准示例:

<swiper class="banner-swiper" indicator-dots="true" indicator-color="#ffffff" indicator-active-color="#ff4040" autoplay="true" interval="4000" circular="true"> <swiper-item wx:for="{{banners}}" wx:key="id"> <image src="{{item.imageUrl}}" mode="aspectFill" class="banner-image" /> </swiper-item> </swiper>

swiper-item内不要直接放图片,应该包一层view,否则图片的圆角在 iOS 上会被裁切。border-radiusoverflow: hidden加上才能让轮播圆角生效。image组件默认有 300px * 150px 的默认尺寸,建议同时在 wxss 里用width: 750rpx; height: 300rpx;覆盖,否则不同设备上高度不一致。

4.5 频道切换与数据过滤的联动

频道切换目前仅仅是修改selectedChannel的视觉状态,没有真正过滤列表。为了让 demo 更像真实产品,我们给每个频道配一组过滤规则。修改上面的onChannelTap

onChannelTap(e) { const channel = e.currentTarget.dataset.channel; this.setData({ selectedChannel: channel }); if (channel === '推荐') { this.setData({ newsList: this.allNewsList }); return; } const filtered = this.allNewsList.filter(item => item.category === channel); this.setData({ newsList: filtered }); }

前提是在onLoad里保存一份完整列表this.allNewsList = this.data.newsList;,并且每条 Mock 数据加上category字段。注意,这里给 every 条目手动添加 category 字段很容易忘记,一不留神就把所有新闻都变成“推荐”。这个坑我第一次做时踩过,所有的过滤结果都是空数组,页面白屏。建议以console.log打印过滤结果来确认。

5. 今日头条demo的详情页与代码截图导出技巧

5.1 详情页接收参数并渲染

跳转是资讯产品最核心的交互。查看pages/detail/detail.jsonLoad

Page({ data: { id: null, title: '', content: '' }, onLoad(options) { const { id, title } = options; // 实际项目里根据 id 请求详情接口 const newsList = wx.getStorageSync('toutiao_news') || []; const current = newsList.find(item => item.id === Number(id)); if (current) { this.setData({ id, title: current.title, content: current.content }); } else { this.setData({ title: decodeURIComponent(title) }); } wx.setNavigationBarTitle({ title: this.data.title.length > 10 ? this.data.title.slice(0, 10) + '...' : this.data.title }); } });

从列表跳转时,id是数字,但通过 URL 传递后变成字符串,所以用Number(id)做严格相等比较。title建议在列表页跳转时执行encodeURIComponent,在详情页decodeURIComponent还原,避免中文乱码。详情页样式不用太多,标题大号加粗,内容用white-space: pre-wrap保留换行结构。

5.2 微信开发者工具导出截图的标准流程

做 demo 必须配截图,很多博客里贴的图模糊不清,是因为直接用了模拟器窗口的缩小视图。正确做法是:工具右上角“模拟器”菜单,点“截图”按钮,或者快捷键Ctrl + Shift + S(macOS 是Cmd + Shift + S),会打开截图面板,拖动选取页面区域,选择存储位置。此时生成的是 PNG 原图,适合直接贴到项目文档。

想要多机型效果,在模拟器顶部选择“iPhone 14 Pro”“Android”等不同机型,再重复上述步骤。需要注意的是,模拟器截图只截当前可见区域,不包含下拉刷新的 loading 动画。想截下拉瞬间的效果,可以用录屏工具,或者在onPullDownRefresh里加一个setTimeout延时 2 秒再stopPullDownRefresh,这样有时间在模拟器里按截图。

5.3 源代码管理与其他开发者共享

demo 的源代码不建议压缩打包发群,而应托管到 git。项目根目录新建.gitignore,把miniprogram_npmnode_modulesproject.private.config.json忽略掉。project.private.config.json是开发者工具本地生成的个性化配置,每次打开项目都会改动,如果提交到仓库容易产生无意义 diff。.gitignore内容如下:

node_modules/ miniprogram_npm/ dist/ project.private.config.json *.local

提交代码后,其他同事通过git clone下载,再用微信开发者工具“导入项目”选择根目录即可。注意工具会要求填写 AppID,demo 阶段选“测试号”即可,不需要自己注册企业账号。测试号也有request合法域名限制,但本地 Mock 数据不走网络,完全不受影响。

5.4 真机预览与远程调试

模拟器跑通后,点“预览”按钮生成二维码,真机微信扫码即可查看。如果真机白屏,大概率是基础库版本问题。打开“详情 - 本地设置”看“调试基础库”是不是设了过高的版本。真机上还有一点和模拟器不同:模拟器能绕过request域名校验,真机不行。如果后续接入真实 API,需要在 mp 后台配置合法域名,或者开发阶段在工具里勾选“不校验合法域名”。这是微信小程序最常见的上线前后差距之一。

真机调试模式下,可以直接在代码里console.log,并在工具的“调试器 - Console”里看到真机日志。如果想抓网络请求,工具自带“Network”面板,能看每个请求的耗时、请求头和返回。不要用第三方抓包工具,微信官方工具足够用,而且不会遇到 HTTPS 证书解密的问题。

5.5 给 demo 增加一点“今日头条感”的配色细节

头条主色是#f73d3d#f23030,不同版本略有差异。把选中 Tab 颜色、轮播指示器、频道高亮统一成一个变量,在app.wxss里定义为:

page { --primary-color: #f73d3d; }

组件里使用color: var(--primary-color)。小程序支持 CSS 变量,基础库从 2.9.0 开始稳定,demo 里提前使用是一种好习惯,后面换主题不用全局替换色值。不过注意不要在wxss里滥用运行时类名控制,尤其是wx:if频繁切换样式时,性能低于hidden属性。真正的今日头条样式很克制,文字密度高、留白适中,我们的 demo 做到“看起来像那么回事”即可,后面接入真数据时再慢慢打磨。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询