Step-by-Step Example for Building a Basic WeChat Mini Program
Initial Project Structure
After creating a new Mini Program project, the developer tool automatically generates a default directory structure:
pagesdirectory: Stores all page files for the Mini Program, each page gets its own dedicated subdirectory here (like the defaultindexpage)utilsdirectory: Holds shared utility JavaScript code. You can expose functions and objects viamodule.exports, then import them anywhere withrequire()for code reuseapp.js(required): The global entry JavaScript file. Missing this file will throw errors. Its used to listen to Mini Program lifecycle events and declare global variablesapp.json(required): Global configuration file, also required to avoid errors. It configures page routing, the default homepage, window behavior and other global settingsapp.wxss: Global stylesheet for the Mini Program, equivalent to standard global CSSproject.config.json: IDE-specific local configuration, can be ignored for core development work
Add Custom Pages
Beyond the default index and logs pages, we will add two new pages: home (our homepage) and item (our detail page for navigation testing):
- Right-click the
pagesdirectory, select New > Directory, name ithome - Right-click the new
homedirectory, select New > Page, name ithome. The IDE will automatically generate all four required files for the page:.js,.json,.wxml,.wxss
For context:
.wxmlis analogous to HTML for web,.wxssis equivalent to CSS,.jshandles page logic, and.jsonstores page-specific window configuration (like title bar text and background color).
Repeat the same process to create the item page.
Create A Static Asset Directory
WeChat Mini Program does not enforce a strict structure for static assets, but a common convention is to store them in a dedicated assets folder. Create a top-level assets directory in your project root, then add an images subdirectory inside assets to store image files. Reference these assets using relative or root-relative paths in your code.
Note: WeChat Mini Program enforces a total package size limit for production releases, so avoid storing large assets like high-resolution images directly in your project.
Configure Tab Bar Navigation
Open app.json (the global configuration file), and add a tabBar configuration after the existing window object. Don't forget to add a trailing comma after window to avoid JSON syntax errors.
The tabBar configuration accepts these core parameters:
backgroundColor: Background color of the tab barcolor: Default text color for unselected tabsselectedColor: Text color for the currently active tablist: An array of tab configuration objects, each object contains:pagePath: File path to the target pagetext: Display title of the tabiconPath: Path to the default tab iconselectedIconPath: Path to the icon for the selected state
Sample configuration:
"tabBar": {
"backgroundColor": "#ffffff",
"color": "#7f7f7f",
"selectedColor": "#e64a19",
"list": [
{
"pagePath": "pages/home/home",
"text": "Home",
"iconPath": "/assets/images/home.png",
"selectedIconPath": "/assets/images/home-active.png"
},
{
"pagePath": "pages/index/index",
"text": "Profile",
"iconPath": "/assets/images/user.png",
"selectedIconPath": "/assets/images/user-active.png"
}
]
}
Make sure you add the corresponding icon files to your assets/images directory for the tab bar to render correctly.
Build The Home Page Layout
We'll start with a static layout, then convert it to dynamic data rendering. Open pages/home/home.wxml and replace the default content with this markup:
<!--pages/home/home.wxml-->
<view class="card-group">
<view class="content-card">
<navigator url="../item/item">
<image class="card-cover" src="https://7n.w3cschool.cn/attachments/cover/cover_html.png?t=15547020"></image>
<view class="card-title">HTML Tutorial</view>
</navigator>
</view>
<view class="content-card">
<navigator url="../item/item">
<image class="card-cover" src="https://7n.w3cschool.cn/attachments/cover/cover_html5.png?t=1314520"></image>
<view class="card-title">HTML5 Tutorial</view>
</navigator>
</view>
</view>
Key notes for Mini Program markup:
viewis the primary layout container, equivalent todivin standard HTML- Use
imageinstead ofimgfor embedding images in Mini Programs navigatorhandles in-app page navigation, similar to theatag in HTML, and uses theurlattribute to set the target path. External domain navigation requires enterprise verification and domain whitelisting.
Next add styles. Open home.wxss and add the following flexbox layout styles:
/* pages/home/home.wxss */
.card-group{
display:flex;
flex-wrap:wrap;
padding:10rpx 12rpx;
}
.content-card{
width:339rpx;
margin:0rpx 12rpx 30rpx 12rpx;
flex-shrink:0;
}
.card-cover{
width:100%;
height:180rpx;
border-radius:8rpx;
}
.card-title{
font-size:26rpx;
line-height:1.5;
margin-top:10rpx;
color:#333333;
text-align:center;
}
Important: Mini Program
imageelements require an explicit height, they do not auto-size to content. If you don't set a height, the image will not render correctly.
Set The Default Homepage
By default, the first entry in the pages array in app.json is set as the Mini Program homepage. To set home as your homepage, simply move the pages/home/home entry to the first position in the pages array.
Note: Each page path in the
pagesarray maps to a JavaScript file with the same name. If the file is missing, the Mini Program will throw a runtime error.
Add Dynamic Data Rendering
Right now our content is hardcoded in the markup. Let's update it to pull data from the page's JavaScript data object. For this example, we use static local data instead of an external API response.
Note: To load external images or call external APIs, you must add the corresponding domain to your Mini Program's whitelist in the WeChat backend.
Open home.js and update the default data object to store our content list:
/**
* Page initial data
*/
data: {
contentList: [
{ 'cover': 'https://7n.w3cschool.cn/attachments/cover/cover_html.png?t=15547020', 'title': 'HTML' },
{ 'cover': 'https://7n.w3cschool.cn/attachments/cover/cover_html5.png?t=1314520', 'title': 'HTML5' },
{ 'cover': 'https://example.com/css-cover.png', 'title': 'CSS' },
{ 'cover': 'https://example.com/css3-cover.png', 'title': 'CSS3' },
]
},
Update home.wxml to use list rendering with dynamic data, and add event binding for navigation:
<!--pages/home/home.wxml-->
<view class="card-group">
<view class="content-card" wx:for="{{contentList}}" wx:key="title" >
<navigator data-title="{{item.title}}" bindtap="openDetailPage" >
<image class="card-cover" src="{{item.cover}}"></image>
<view class="card-title">{{item.title}}</view>
</navigator>
</view>
</view>
We use wx:for to loop over the contentList array and render one card per entry. To pass custom parameters from markup to event handlers in Mini Programs, use the data-* atribute syntax. Note that custom parameter names can not use camelCase.
Add Navigation Event Handler
Add the event handler to home.js after the default lifecycle methods (don't forget to add a trailing comma after the previous method):
/**
* Navigate to detail page with selected title parameter
*/
openDetailPage: function(e) {
const pageTitle = e.currentTarget.dataset.title;
wx.navigateTo({
url: `../item/item?title=${pageTitle}`
})
}
This handler extracts the custom title parameter from the event target, then calls wx.navigateTo to navigate to the detail page with the parameter appended to the URL.
Retrieve Parameter In Detail Page
Open item.wxml and add a text element to display the received title:
<!--pages/item/item.wxml-->
<text>{{title}}</text>
Open item.js and update the onLoad lifecycle method to retrieve the parameter from the navigation options:
/**
* Lifecycle function -- listen for page load
*/
onLoad: function (options) {
this.setData({
title: options.title
})
},
We get the title parameter from the options object passed to onLoad, then use setData to update the page's data, which automatically updates the displayed content on the page.