The H5 Developer's Field Manual for uni-app
📌 Who is this for? You can write HTML/CSS/JS, but you are touching uni-app for the first time and know nothing about Vue, mini programs, or cross-platform development. This article is based on a deep reorganization of the uni-app official documentation 'Vernacular uni-app', using plain language to help you complete the cognitive upgrade from a "traditional web developer" to a "cross-platform developer."
📌 Reading gains: Figure out exactly how uni-app differs from traditional H5, why it differs, and how to write code correctly. All knowledge points are strictly organized according to the official documentation to ensure authority and no pitfalls.
1. First, figure out: What exactly is uni-app?
In one sentence: uni-app is a cross-platform development framework that lets you "write code once, run on all platforms."
You write one set of code, and it can compile out:
- ✅ iOS App
- ✅ Android App
- ✅ HarmonyOS App
- ✅ H5 Webpage
- ✅ WeChat/Alipay/Baidu/Douyin/QQ/Kuaishou/Feishu/DingTalk and other mini programs
- ✅ Quick App
💡 Analogy: You can think of uni-app as a "universal translator." You write a manuscript in "Chinese" (Vue syntax), and it translates it into English, Japanese, French... every platform can understand it.
But note—the translator is not omnipotent. The "Chinese" you write must conform to its grammatical rules, otherwise the translated output will be wrong. So, if you previously wrote traditional web pages (H5), you will find that uni-app's writing style is very different from before.
This article is to help you smoothly migrate your "old knowledge" to the "new world."
2. The network model has changed: From "Server-Side Rendering" to "Front-End/Back-End Separation"
2.1 How does traditional H5 work?
In early web development, the backend (server) directly stuffed data into the HTML and then returned the whole thing to the browser. What the user saw was a "webpage already filled with content."
This model is called B/S mode (Browser/Server).
📖 What is B/S mode? B/S stands for Browser/Server architecture. The user only needs a browser; all business logic and data are processed on the server side, and the browser is only responsible for "display." The counterpart is C/S mode (Client/Server), like QQ or WeChat desktop apps on your computer, which require installing dedicated client software.
Simply put: B/S = open a browser to use; C/S = must install software to use.
In the traditional B/S mode, the backend uses technologies like JSP, PHP, ASP.NET to "render" data into HTML and then return it. Front-end and back-end code are mixed together.
2.2 How does uni-app work now?
uni-app adopts a front-end/back-end separation architecture:
- Front-end (the code you write): Responsible for drawing the interface and handling interactions
- Backend (the server): Only provides data interfaces (usually returning data in JSON format)
- The two communicate via HTTP requests
The page loading process becomes:
1. The front-end first renders an "empty shell" page
2. After the page loads, JS initiates a network request (uni.request)
3. The backend returns JSON data
4. The front-end receives the data and fills it into the page
📖 What is JSON? JSON (JavaScript Object Notation) is a lightweight data format that looks like this:
{"name": "Zhang San", "age": 25}. It is the current "universal language" for front-end/back-end data exchange.
📖 What is an HTTP request? It is the action of the browser/client "asking for data" from the server. Typing a URL into the browser address bar and hitting enter is essentially sending an HTTP request. In code, we use
uni.request()to manually initiate requests.
🍔 An analogy: Before, the restaurant brought the dish directly to your table (server-side rendered and then given to you); now, the restaurant gives you an empty plate and a menu, and you go to the counter to get the food yourself (the front-end actively requests data and fills it onto the page itself).
2.3 How to use it in code?
// Initiating a network request in uni-app
uni.request({
url: 'https://api.example.com/user/list', // Backend API address
method: 'GET',
success: (res) => {
// res.data is the JSON data returned by the backend
this.userList = res.data;
}
});
⚠️ Note: This uses
uni.request(), not the$.ajax()(jQuery) orfetch()you were familiar with before. In uni-app, all APIs start withuni., which is for cross-platform compatibility. This will be detailed later.
3. File types have changed: From .html to .vue
3.1 The files you write are no longer HTML
| Comparison Item | Traditional H5 | uni-app |
|---|---|---|
| File extension | .html |
.vue |
| What you write during development | HTML tags | Vue template syntax |
| What it actually is at runtime | HTML runs directly | Converted by a compiler into code for each platform |
3.2 What are "compiler" and "runtime"?
These are core concepts for understanding uni-app:
📖 What is a compiler? It "translates" the
.vuesource code you write into code that each platform can recognize. For example, compiling to WeChat Mini Program generateswxml + wxss + js; compiling to H5 generateshtml + css + js. You write once, it translates multiple times.
📖 What is a Runtime? When the compiled code actually executes on a device, it needs a set of "runtime environments" to support it. For example, Vue's reactivity system, component lifecycle management, etc., all belong to the runtime category.
🍔 Analogy: The compiler is like a "translator," translating your Chinese manuscript into various languages; the runtime is like "simultaneous interpretation equipment," ensuring the translated content can be "played back" correctly.
4. The internal file structure has changed: From "one building" to "three rooms"
4.1 The old HTML file
<!DOCTYPE html>
<html>
<head>
<script src="js/jquery.js"></script>
<style>
body { background: #fff; }
</style>
</head>
<body>
<div id="app">Page Content</div>
<script>
// JS Logic
</script>
</body>
</html>
Everything—structure, style, logic—is crammed into one big <html> shell, mixed together.
4.2 The current Vue Single File Component (SFC)
📖 What is SFC? SFC stands for Single File Component. It is a core concept of Vue: one
.vuefile = one component = one functional module. Each.vuefile contains three top-level code blocks:<template>,<script>,<style>.
<template>
<!-- ⚠️ Must have one root element (like view), and only one! -->
<view class="container">
<text>{{ message }}</text>
<button @click="changeText">Click me to change text</button>
</view>
</template>
<script>
export default {
data() {
return {
message: 'Hello, uni-app!'
};
},
methods: {
changeText() {
this.message = 'Text has been changed!';
}
}
}
</script>
<style scoped>
/* scoped means the style only applies to the current component, won't pollute other pages */
.container {
padding: 20rpx;
}
</style>
🏠 Analogy: Before, it was a "studio apartment"—living room, bedroom, kitchen all in one space, interfering with each other. Now, it's a "three-bedroom apartment"—
<template>is the living room (holds the interface structure),<script>is the study (holds business logic),<style>is the walk-in closet (holds styles), each with its own role, not interfering with each other.
4.3 The responsibilities of the three blocks (must remember)
| Code Block | Function | Analogy |
|---|---|---|
<template> |
Defines what the page looks like (structure) | The floor plan of a house |
<script> |
Defines how the page moves (logic) | The electrical system in the house |
<style> |
Defines whether the page looks good (style) | The decoration of the house |
4.4 A few key rules
<template>must have one root element, and only one. Usually wrap with<view>.<script>mustexport default {}, this is ES6 module syntax, meaning "export this component."- It is recommended to add
scopedin<style>to prevent styles from leaking to other components.
📖 What are ES6 modules and
export default? ES6 (ECMAScript 2015) was a major upgrade to JavaScript, introducing modular syntax.export defaultmeans "export this object as the default export," which other files can use after importing viaimport. You can understand it as "the product this file provides to the outside world."
5. The way external files are referenced has changed
5.1 Importing JS files
Before:
<script src="js/jquery.js"></script>
<script src="js/bootstrap.js"></script>
Now:
// Method 1: CommonJS specification (require)
const util = require('@/common/util.js');
const result = util.formatTime(new Date());
// Method 2: ES6 module specification (import) — Recommended
import { formatTime } from '@/common/util.js';
const result = formatTime(new Date());
📖 What is the
@symbol? In uni-app,@represents the root directory of the project.@/common/util.jsequals "util.js inside the common folder under the project root directory." Writing paths this way ensures no errors no matter how deeply nested the file is.
📖 What is the difference between
requireandimport? Both are syntax for "importing external modules."requireis the CommonJS specification (Node.js style),importis the ES6 module specification. In uni-app, usingimportis recommended because the compiler has better support for ES6 modules and supports Tree Shaking (automatically removing unused code to reduce bundle size).
5.2 Importing CSS files
Before:
<link href="css/bootstrap.css" rel="stylesheet" />
Now:
<style>
@import "@/common/uni.css";
</style>
⚠️ Note: The
@importstatement must be written at the very top inside the<style>tag, followed by a semicolon;.
5.3 Where to write global styles?
There is an App.vue file in the project root directory, which is the "entry component" of the entire application.
<!-- App.vue -->
<script>
export default {
onLaunch() {
console.log('App launched');
}
}
</script>
<style>
/* Styles written here are global and will take effect on all pages */
page {
background-color: #f5f5f5;
}
</style>
⚠️ Important: There is no
<template>inApp.vue! It does not define any UI, only responsible for global logic and global styles. The UI of pages is defined by the various.vuefiles in thepages/directory.
5.4 Component import (Key point!) — easycom mechanism explained
📖 What is a "component"? A component is packaging a section of "UI + logic + style" into a reusable module. For example, if you make a "star rating" UI, after encapsulating it into a component, any page can use it directly without writing repetitive code.
uni-app provides the easycom mechanism, which greatly simplifies component importing.
Traditional way (requires manual import + registration):
<script>
import MyComponent from '@/components/my-component.vue';
export default {
components: {
MyComponent // Register component
}
}
</script>
<template>
<my-component />
</template>
easycom way (zero configuration, use directly):
📖 What is easycom? easycom is an automatic component import mechanism provided by uni-app. It allows you to skip manual import and manual registration; just write the component tag name in the template, and the compiler will automatically find and load the component. It translates to "easy component usage."
Core path rule (must be strictly followed):
components/component-name/component-name.vue
That is to say: the folder name and file name must be exactly the same, and both are in lowercase with hyphens (kebab-case) style.
✅ Correct examples:
components/my-button/my-button.vue → Use <my-button /> in template
components/user-card/user-card.vue → Use <user-card /> in template
components/uni-list/uni-list.vue → Use <uni-list /> in template
❌ Incorrect examples (will not take effect):
components/MyButton.vue ← Missing folder with the same name, ❌
components/my-button/index.vue ← File name is not my-button.vue, ❌
components/my-button/MyButton.vue ← Case mismatch, ❌
📖 Supplementary rule: If a component is installed under the
uni_modulesdirectory, easycom also supports automatic recognition, with the path format:uni_modules/plugin-id/components/component-name/component-name.vueFor example, if you installed
uni-uithrough the plugin marketplace, it will automatically register components likeuni-badge,uni-card, and you can use them directly by writing the tag name in the template.
Why would traditional Vue developers be confused?
If you have developed Web projects with Vue before, you are definitely used to import + components registration. When first using uni-app, seeing others write <uni-list> directly in the template without any import will instinctively make you think "this can't possibly work."
The answer is easycom. During the compilation phase, the compiler scans the components/ and uni_modules/ directories and automatically completes the import and registration. You just need to ensure the path conforms to the specification.
💡 Memory tip: "Same-name folder + same-name file = use directly."
6. A major tag overhaul: HTML tags → uni-app components
This is the most intuitive change that most affects daily coding. The HTML tags you are familiar with need to be replaced with corresponding components in uni-app.
6.1 Why can't HTML tags be used directly?
Because uni-app needs to be cross-platform. Tags like <div>, <span> are only recognized by browsers, not by WeChat Mini Programs or native Apps. So uni-app defines a set of cross-platform universal component tags, and the compiler is responsible for translating them into the native writing style of each platform.
📖 Tags vs Components, what's the difference?
- Tag: "Factory built-in" to the browser, limited in number and fixed, like
<div>,<p>,<img>.- Component: A UI module that developers can freely encapsulate and extend, like a function, packaging a piece of UI + logic for repeated use. Component tag names are custom, like
<my-button>,<user-card>.
6.2 Core tag comparison table (must memorize)
| Traditional HTML Tag | uni-app Component | Description |
|---|---|---|
<div> |
<view> |
The most basic container component, equivalent to a "box" |
<span> / <p> / <font> |
<text> |
Text display |
<a href="..."> |
<navigator url="..."> |
Page navigation |
<img src="..."> |
<image src="..."> |
Image display |
<select> |
<picker> |
Dropdown selector |
<iframe> |
<web-view> |
Embed external webpage |
<ul> / <li> / <ol> |
❌ Does not exist | Use <view> nesting to implement lists |
<input type="radio"> |
<radio> / <radio-group> |
Single selection |
<input type="checkbox"> |
<checkbox> / <checkbox-group> |
Multiple selection |
<input type="date"> |
<picker mode="date"> |
Date picker |
<audio> |
Not recommended to use tag | Use uni.createInnerAudioContext() API instead |
6.3 uni-app's unique "mobile" components
These are not found in traditional web pages, designed specifically for mobile scenarios:
| Component | Use | Use Case |
|---|---|---|
<scroll-view> |
Scrollable area | Lists, long content areas |
<swiper> + <swiper-item> |
Carousel | Homepage Banner |
<switch> |
Switch | "Enable notifications" on settings page |
<slider> |
Slider | Volume adjustment, brightness adjustment |
<progress> |
Progress bar | Download progress, loading progress |
<camera> |
Camera | Taking photos, scanning codes |
<map> |
Map | Location display, navigation |
<video> |
Video player | Video playback |
<cover-view> / <cover-image> |
Overlay layer | Overlay on top of native components like <video>, <map> |
⚠️ About
<cover-view>: On the mini-program side,<video>,<map>,<camera>are native components with the highest level, ordinary<view>cannot cover them. If you need to display buttons or text on top of a video, you must use<cover-view>and<cover-image>.
6.4 A complete comparison example
Previously writing an image list (HTML):
<div class="list">
<img src="pic1.jpg" alt="Image 1" />
<img src="pic2.jpg" alt="Image 2" />
</div>
Now writing in uni-app:
<template>
<view class="list">
<image src="/static/pic1.jpg" mode="widthFix" />
<image src="/static/pic2.jpg" mode="widthFix" />
</view>
</template>
<style>
.list {
display: flex;
flex-direction: column;
padding: 20rpx;
}
image {
width: 100%;
margin-bottom: 20rpx;
}
</style>
💡 Note
mode="widthFix": This is an attribute of the<image>component, meaning "fixed width, height adapts proportionally." The traditional<img>tag does not have this attribute and requires CSS to achieve.
7. Three major changes in JS (Core focus!)
7.1 The runtime environment has changed—Browser-specific APIs can no longer be used
| Comparison Item | Traditional H5 (in Browser) | uni-app (App/Mini Program side) |
|---|---|---|
| Where JS runs | Browser's JS engine | V8 engine (App side) / Each mini program engine |
window object |
✅ Available | ❌ Not available |
document object |
✅ Available | ❌ Not available |
navigator object |
✅ Available | ❌ Not available |
location object |
✅ Available | ❌ Not available |
localStorage |
✅ Available | ❌ Not available (use uni.setStorage) |
| Cookie | ✅ Available | ❌ Not available |
| jQuery / DOM manipulation libraries | ✅ Available | ❌ Not available |
📖 What are
window,document?
window: The "global object" provided by the browser, representing the current browser window.alert(),setTimeout(),locationall hang off it.document: Represents the DOM tree (Document Object Model) of the current webpage, through which you can find and manipulate any element on the page.On the App and Mini Program side, there is no browser, so naturally there is no
windowordocument.
⚠️ The only exception: When you compile uni-app to H5, the runtime environment is the browser, and
window,documentare available. But for cross-platform compatibility, it is recommended to never use them directly.
7.2 No more DOM manipulation, switch to "data binding" (MVVM)
This is the most core mental shift, please make sure to understand it thoroughly.
📖 What is DOM? DOM (Document Object Model) is a "tree" generated by the browser after parsing HTML. Each HTML tag is a node on the tree. Through methods like
document.getElementById(),document.querySelector(), you can "find" a certain node and then modify its content, style, attributes.
📖 What is MVVM? MVVM stands for Model-View-ViewModel:
- Model: Data (e.g.,
message: "Hello")- View: The interface the user sees
- ViewModel: The "bridge" connecting data and the interface (in Vue, it's the binding relationship between
data()and the template)Core idea: You only need to modify the data, and the interface will update automatically. You don't need to manually "find an element and then change it."
❌ The old way (DOM manipulation):
<span id="myText">123</span>
<button onclick="changeText()">Modify</button>
<script>
function changeText() {
// Step 1: Find the element by id
// Step 2: Modify the element's text content
document.getElementById("myText").innerText = "789";
}
</script>
You need to manually find the element → manually modify it.
✅ The new way (data binding):
<template>
<view>
<text>{{ message }}</text>
<button @click="changeText">Modify</button>
</view>
</template>
<script>
export default {
data() {
return {
message: '123' // ← This is "data"
};
},
methods: {
changeText() {
this.message = '789'; // ← Just change the data, the interface updates automatically!
}
}
}
</script>
You just need to modify the variable in data, and all places in the interface referencing this variable will automatically update. No need to find elements, no need to manipulate DOM.
🍔 Analogy: Before, you were driving a "manual transmission"—every gear shift required you to press the clutch and move the gear stick yourself (find element, change attribute). Now, you are driving an "automatic transmission"—you just press the accelerator (change data), and the gearbox automatically shifts for you (updates the interface).
Key rules:
| Rule | Description |
|---|---|
Data that needs to be bound to the interface must be written in the return {} of data() |
Otherwise, it cannot be recognized in the template |
Modify data by direct assignment: this.xxx = newValue |
No need for WeChat Mini Program's setData() |
Event binding uses @eventName="methodName" |
Like @click, @input, @longpress |
Methods are defined in methods: {} |
Called via this.methodName() |
📖 What is
this? In a Vue component,thispoints to the current component instance. Throughthis, you can access data indataand call methods inmethods. For example,this.messageaccesses the message variable in data.
7.3 All APIs have been replaced
The browser APIs you used before are all replaced with the uni.xxx() form in uni-app:
| What you want to do | Traditional H5 way | uni-app way |
|---|---|---|
| Popup alert | alert('Notice') |
uni.showToast({ title: 'Notice' }) |
| Confirmation dialog | confirm('Are you sure?') |
uni.showModal({ title: 'Notice', content: 'Are you sure?' }) |
| Network request | $.ajax() or fetch() |
uni.request() |
| Local storage (save) | localStorage.setItem(k, v) |
uni.setStorageSync(k, v) |
| Local storage (get) | localStorage.getItem(k) |
uni.getStorageSync(k) |
| Page navigation | location.href = 'xxx' |
uni.navigateTo({ url: 'xxx' }) |
| Go back to previous page | history.back() |
uni.navigateBack() |
| Get screen width | window.innerWidth |
uni.getSystemInfoSync().windowWidth |
📖 Naming convention: uni-app's APIs basically changed WeChat Mini Program's
wx.xxxtouni.xxx. If you have read WeChat Mini Program documentation, you will find it very familiar.
Actual code example:
// Initiate a network request
uni.request({
url: 'https://api.example.com/data',
method: 'GET',
success: (res) => {
console.log('Request successful:', res.data);
},
fail: (err) => {
console.log('Request failed:', err);
}
});
// Local storage
uni.setStorageSync('username', 'Zhang San');
const name = uni.getStorageSync('username'); // 'Zhang San'
// Popup dialog
uni.showModal({
title: 'Notice',
content: 'Are you sure you want to delete?',
success: (res) => {
if (res.confirm) {
// User clicked "Confirm"
}
}
});
8. Page navigation explained: Five APIs each have their own role (Important!)
In uni-app, page navigation is no longer a simple location.href, but has 5 dedicated APIs, each with different use cases. Mixing them up will cause problems like "can't go back to the page" or "navigation has no response."
8.1 Comparison table of five navigation methods
| API | Function | Page stack change | Can pass params? | Use case |
|---|---|---|---|---|
uni.navigateTo |
Keep current page, open a new page | Stack +1 layer | ✅ | Enter detail page from list, enter settings page from homepage |
uni.redirectTo |
Close current page, open a new page | Stack unchanged (replaced) | ✅ | Jump to homepage after login success (don't want user to return to login page) |
uni.switchTab |
Close all non-Tab pages, switch to a Tab page | Clear non-Tab stack | ❌ | Bottom navigation bar switch (Home/Mine/Messages) |
uni.reLaunch |
Close all pages, open specified page | Clear all stacks | ✅ | Return to login page after logout, reset entire app state |
uni.navigateBack |
Go back to previous page (or N pages back) | Stack -1 (or -N) layers | ❌ | User clicks back, return after submission |
📖 What is a "page stack"? A page stack is a "Last In, First Out" structure. Every time a new page is opened, it is pushed onto the top of the stack; every time you go back, the top is popped off. Like a stack of plates—you can only take from the top.
uni.navigateTois "adding one" to this stack of plates,uni.navigateBackis "taking the top one away."⚠️ Note: On the WeChat Mini Program side, the page stack has a maximum of 10 layers, beyond which you can no longer navigateTo.
8.2 Detailed explanation of each
① uni.navigateTo—Most commonly used, "forward"
// Navigate from homepage to detail page (keep homepage, user can return)
uni.navigateTo({
url: '/pages/detail/detail?id=123&title=hello'
});
Rules:
- ✅ Can pass parameters (URL concatenation
?key=value) - ❌ Cannot navigate to a tabBar page (will error or have no response)
- The new page is pushed onto the page stack, user can click back to return to the original page
② uni.redirectTo—"Replace", does not keep current page
// Jump to homepage after login success (user cannot return to login page)
uni.redirectTo({
url: '/pages/home/home'
});
Rules:
- ✅ Can pass parameters
- ❌ Cannot navigate to a tabBar page
- The current page is closed and destroyed, cannot go back
🍔 Analogy:
navigateTois like "opening a new tab" (the old page is still there);redirectTois like "typing a new URL in the current tab" (the old page is gone).
③ uni.switchTab—Specifically for switching Tab pages
// Switch to the "Mine" page on the bottom navigation bar
uni.switchTab({
url: '/pages/user/user'
});
Rules:
- ❌ Cannot pass parameters! This is an official limitation. If you need to transfer data, use
uni.setStorageSyncor a global variable as a relay. - Can only navigate to pages declared in the
tabBar.listwithinpages.json - Will close all non-tabBar pages
⚠️ Common pitfall: If you use
uni.navigateToto jump to a tabBar page, it will directly errorpage is not found. You must useuni.switchTab.
④ uni.reLaunch—"Nuclear option" reset
// Log out, return to login page (close all pages)
uni.reLaunch({
url: '/pages/login/login'
});
Rules:
- ✅ Can pass parameters
- ✅ Can navigate to any page (including tabBar pages)
- Closes all opened pages, starting from scratch
⑤ uni.navigateBack—"Go back"
// Go back to the previous page (default delta=1)
uni.navigateBack();
// Go back two layers (if there are at least two layers in the stack)
uni.navigateBack({ delta: 2 });
Rules:
- If the page stack only has one page left, calling it is ineffective (won't close the last page)
- The
deltaparameter indicates how many layers to go back, default is 1
8.3 Practical scenario decision tree
I want to navigate to a new page?
│
├── Is the target page a tabBar page?
│ ├── Yes → Use uni.switchTab (cannot pass params)
│ └── No ↓
│
├── Does the user need to return to the current page?
│ ├── Yes → Use uni.navigateTo
│ └── No (current page can be closed) → Use uni.redirectTo
│
├── Need to close all pages and start over?
│ └── Yes → Use uni.reLaunch
│
└── User clicked the back button?
└── Use uni.navigateBack
💡 One-sentence memory: 90% of daily development uses
navigateTo, switch bottom Tab usesswitchTab, login/logout scenarios useredirectToorreLaunch.
9. Changes in CSS
Good news: Standard CSS syntax can basically all be used. But there are a few important differences:
9.1 Selector limitations
| Selector | Supported? | Description |
|---|---|---|
.class-name |
✅ | Class selector, most commonly used |
#id |
✅ | ID selector |
tag |
✅ | Tag selector, like view {} |
* (wildcard) |
❌ | Not supported |
body |
❌ | Changed to page |
Descendant selector .a .b |
✅ | Supported |
Child selector .a > .b |
⚠️ | Supported on some platforms |
⚠️ Key point: Previously you wrote
body { margin: 0; }, now you need to writepage { margin: 0; }. Because on non-H5 platforms, there is no concept ofbody,pagerepresents the entire page.
9.2 Units: Use rpx instead of px
📖 What is rpx? rpx (responsive pixel) is an adaptive unit introduced by uni-app.
Conversion rule: Regardless of the screen, the screen width is defined as = 750rpx.
- If the design draft is 750px wide, then 1px = 1rpx, direct conversion.
- If the design draft is 375px wide (iPhone 6/7/8), then 1px = 2rpx.
Benefit: You don't need to write any media queries (
@media), rpx will automatically adapt to all screen widths.
/* Old way */
.box {
width: 100px;
font-size: 14px;
padding: 10px 20px;
}
/* New recommended way (assuming design draft is 750px wide) */
.box {
width: 200rpx;
font-size: 28rpx;
padding: 20rpx 40rpx;
}
💡 Practical usage suggestion: If your UI design draft is 750px wide, directly replace px with rpx. If it's 375px wide, multiply the value by 2 and write rpx.
9.3 Layout: Flex is strongly recommended
📖 What is Flex layout? Flex (Flexible Box) is a one-dimensional layout method introduced in CSS3. By setting
display: flexon the parent element, child elements will automatically arrange, supporting alignment, distribution, wrapping, etc. It is currently the most mainstream and best-compatible layout scheme for mobile.
/* Horizontal arrangement, justified to ends, vertically centered */
.row {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
/* Vertical arrangement */
.column {
display: flex;
flex-direction: column;
}
✅ Flex layout is perfectly supported on all uni-app platforms (H5, App, various mini programs), use with confidence.
9.4 Other notes
| Note | Description |
|---|---|
| Background images / Font files | Recommended not to exceed 40KB, otherwise it affects compilation performance. For large images, recommend using network URLs or base64 |
position: fixed |
Behaves differently on some mini-program platforms, use with caution |
| Percentage height | Requires the parent element to have an explicit height to take effect |
10. Project structure and page management
10.1 Project directory structure (must understand)
├── pages/ ← All pages go here
│ ├── index/
│ │ └── index.vue ← Homepage
│ └── user/
│ └── user.vue ← User page
├── components/ ← Custom components (easycom scan directory)
├── static/ ← Static assets (images, fonts, etc., not compiled)
├── uni_modules/ ← Plugins/component libraries (easycom also scans here)
├── App.vue ← App entry (global logic + global styles)
├── main.js ← App initialization file
├── pages.json ← Page routing and window configuration (Important!)
├── manifest.json ← App configuration (appid, version, permissions, etc.)
└── uni.scss ← Global SCSS variables
10.2 pages.json—Your "page dispatch center"
📖 In traditional web pages, navigation between pages relies on
<a href="xxx.html">links. In uni-app, every page must be registered inpages.json, otherwise it cannot be accessed.
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "Home"
}
},
{
"path": "pages/user/user",
"style": {
"navigationBarTitleText": "Profile"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "My App",
"navigationBarBackgroundColor": "#ffffff"
},
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "Home",
"iconPath": "static/home.png",
"selectedIconPath": "static/home-active.png"
},
{
"pagePath": "pages/user/user",
"text": "Mine",
"iconPath": "static/user.png",
"selectedIconPath": "static/user-active.png"
}
]
}
}
Key rules:
| Rule | Description |
|---|---|
The first item in the pages array is the homepage |
No extra configuration needed |
| Newly created pages must be registered here | Otherwise, the route cannot be found |
navigationBarTitleText |
Title of the top navigation bar of the page |
tabBar |
Bottom tab bar (similar to WeChat's bottom "Chats/Contacts/Discover/Me") |
Pages in tabBar.list can only be navigated to using switchTab |
Using navigateTo will cause an error |
10.3 Correspondence with Mini Programs
If you have read WeChat Mini Program documentation, this correspondence can help you understand quickly:
| WeChat Mini Program | uni-app | Description |
|---|---|---|
app.json (page config part) |
pages.json |
Manages page routing and window styles |
app.json (app config part) |
manifest.json |
Manages appid, version number, permissions |
app.js + app.wxss |
App.vue |
Global logic + Global styles |
.wxml |
<template> in .vue |
Page structure |
.wxss |
<style> in .vue |
Page styles |
.js |
<script> in .vue |
Page logic |
11. Lifecycle—The process of a page from birth to death
📖 What is a lifecycle? Every page/component goes through a series of stages from "creation → display → hide → destruction". At each stage, uni-app automatically calls the corresponding function (hook), and you can write specific logic inside these functions.
Page lifecycle (written in the <script> of .vue):
| Hook Function | Trigger Timing | Typical Use |
|---|---|---|
onLoad(options) |
When the page loads (executes only once) | Receive parameters, initiate initial requests |
onShow() |
Every time the page is displayed | Refresh data (when returning from another page) |
onReady() |
When the page's initial rendering is complete | Operate canvas, initialize map |
onHide() |
When the page is hidden (navigated to another page) | Pause timers, save temporary data |
onUnload() |
When the page is unloaded (completely closed) | Clear timers, release resources |
<script>
export default {
onLoad(options) {
// options contains the parameters passed from the previous page
// e.g.: uni.navigateTo({ url: '/pages/detail/detail?id=123' })
// Here options.id === '123'
console.log('Page loaded, parameters:', options);
this.loadData();
},
onShow() {
console.log('Page displayed');
},
methods: {
loadData() {
// Initiate request to get data
}
}
}
</script>
⚠️ Note: These lifecycle hooks (
onLoad,onShow, etc.) are uni-app extensions, written directly insideexport default {}, at the same level asdata,methods, not insidemethods!
12. A summary table: Complete migration checklist from H5 to uni-app
| No. | Traditional H5 | uni-app | Note |
|---|---|---|---|
| 1 | .html file |
.vue file |
Single File Component |
| 2 | <div> |
<view> |
Container |
| 3 | <span> / <p> |
<text> |
Text |
| 4 | <img> |
<image> |
Image |
| 5 | <a> |
<navigator> |
Navigation |
| 6 | document.getElementById() |
Data binding (MVVM) | No more DOM manipulation |
| 7 | onclick="fn()" |
@click="fn" |
Event binding |
| 8 | alert() / confirm() |
uni.showToast() / uni.showModal() |
Popups |
| 9 | $.ajax() / fetch() |
uni.request() |
Network request |
| 10 | localStorage |
uni.setStorageSync() / uni.getStorageSync() |
Local storage |
| 11 | location.href |
uni.navigateTo() |
Page navigation |
| 12 | history.back() |
uni.navigateBack() |
Go back |
| 13 | px / rem |
rpx |
Size unit |
| 14 | <script src="..."> |
import / require |
Import JS |
| 15 | <link rel="stylesheet"> |
@import |
Import CSS |
| 16 | body selector |
page selector |
Global style |
| 17 | URL routing / Links | pages.json config |
Page management |
| 18 | Manual import + register components | easycom auto-recognition | Component import |
13. Study advice for beginners
If you are a newcomer familiar with H5 but haven't touched Vue and mini programs, just remember three sentences:
- Don't manipulate DOM, just change the data. This is the most core mental shift. Once understood, everything else becomes clear.
- Swap one set of tags, swap one set of APIs. But the programming mindset remains the same, only the "syntax" differs. It's like switching from writing a Chinese essay to an English essay—the ideas are the same, the words and grammar are different.
- Look at
pages.jsonfor all page configuration. It is your "page dispatch center"; creating new pages, configuring the navigation bar, setting up the TabBar all happen here.
Recommended learning path:
Step 1: Get a uni-app project running (create with HBuilderX)
↓
Step 2: Understand the three-part structure of a .vue file (template / script / style)
↓
Step 3: Master data binding (data → template's {{}} syntax)
↓
Step 4: Learn common components (view, text, image, button, input)
↓
Step 5: Learn page navigation and parameter passing (navigateTo + onLoad)
↓
Step 6: Learn network requests (uni.request)
↓
Step 7: Learn list rendering (v-for) and conditional rendering (v-if)
↓
Step 8: Start a complete small project (like a Todo List, news list)
Final words
The learning curve for uni-app is not steep, especially for those with an HTML/CSS/JS foundation. It is essentially Vue syntax + a set of cross-platform components and APIs. Once you understand Vue's data binding and componentization concepts, the rest is just getting familiar with the differences across platforms and uni-app's specific APIs.
Don't be afraid of "differences," embrace "differences." It is precisely these differences that allow uni-app to achieve writing one set of code that runs on all platforms, greatly improving development efficiency.
Wishing you a smooth journey on the road of cross-platform development! 🚀
📚 References:
- uni-app Official Documentation - Vernacular uni-app
- uni-app Official Documentation - Component Usage Introduction
- uni-app Official Documentation - API Overview
- uni-app Official Documentation - Page Routing
- uni-app Official Documentation - easycom Components
- uni-app Official Documentation - Project Introduction
📝 This article is an original technical summary, deeply reorganized based on official documentation and personal understanding. All technical points are strictly based on the uni-app official documentation to ensure accuracy and authority. Please indicate the source when reprinting.
If this article was helpful to you, welcome to like, bookmark, and follow! Feel free to communicate in the comments if you have questions~ 👋