从 H5 到 uni-app:一篇写给前端小白的"翻译指南"

📌 本文适合谁? 你会写 HTML/CSS/JS,但第一次接触 uni-app,对 Vue、小程序、跨端开发一无所知。本文基于 uni-app 官方文档「白话 uni-app」 深度梳理,用大白话帮你完成从"传统网页开发者"到"跨端开发者"的认知升级。

📌 阅读收获: 搞清楚 uni-app 和传统 H5 到底哪里不一样、为什么不一样、怎么写才对。所有知识点均严格依据官方文档整理,确保权威、无坑。


一、先搞清楚:uni-app 到底是什么?

一句话:uni-app 是一个让你"写一次代码,跑遍所有平台"的跨端开发框架。

你写一套代码,它能帮你编译出:

  • ✅ iOS App
  • ✅ Android App
  • ✅ 鸿蒙 App
  • ✅ H5 网页
  • ✅ 微信/支付宝/百度/抖音/QQ/快手/飞书/钉钉等各家小程序
  • ✅ 快应用

💡 类比理解: 你可以把 uni-app 想象成一个"万能翻译官"。你用"中文"(Vue 语法)写好一篇稿子,它帮你翻译成英文、日文、法文......每个平台都能读懂。

但注意------翻译官不是万能的 。你写的"中文"必须符合它的语法规则,否则翻译出来的东西就会出错。所以,如果你之前写的是传统网页(H5),你会发现 uni-app 的写法和以前有很大不同

这篇文章,就是帮你把"旧知识"平滑迁移到"新世界"。


二、网络模型变了:从"服务端渲染"到"前后端分离"

2.1 传统 H5 是怎么工作的?

早期的网页开发,后端(服务器)把数据直接塞进 HTML 里,然后整体返回给浏览器。用户看到的就是一个"已经填好内容的网页"。

这种模式叫做 B/S 模式(Browser/Server,浏览器/服务器模式)。

📖 什么是 B/S 模式?

B/S 即 Browser/Server(浏览器/服务器)架构。用户只需要一个浏览器,所有业务逻辑和数据都在服务器端处理,浏览器只负责"展示"。与之对应的是 C/S 模式(Client/Server,客户端/服务器),比如你电脑上的 QQ、微信桌面版,需要安装专门的客户端软件。

简单说:B/S = 打开浏览器就能用;C/S = 必须装个软件才能用。

在传统 B/S 模式下,后端使用 JSP、PHP、ASP.NET 等技术,把数据"渲染"到 HTML 中再返回。前端和后端代码是混在一起的。

2.2 现在 uni-app 是怎么工作的?

uni-app 采用的是前后端分离架构:

  • 前端(你写的代码): 负责画界面、处理交互
  • 后端(服务器): 只提供数据接口(通常返回 JSON 格式的数据)
  • 两者通过 HTTP 请求通信

页面加载的流程变成了:

markdown 复制代码
1. 前端先渲染一个"空壳子"页面
2. 页面加载后,JS 发起网络请求(uni.request)
3. 后端返回 JSON 数据
4. 前端拿到数据,填充到页面上

📖 什么是 JSON?

JSON(JavaScript Object Notation)是一种轻量级的数据格式,长这样:{"name": "张三", "age": 25}。它是目前前后端数据交换的"通用语言"。
📖 什么是 HTTP 请求?

就是浏览器/客户端向服务器"要数据"的动作。你在浏览器地址栏输入网址回车,本质就是发了一次 HTTP 请求。在代码中,我们用 uni.request() 来手动发起请求。
🍔 打个比方:

以前是餐厅把菜直接端到你桌上(服务端渲染好再给你);现在是餐厅给你一份空盘子和菜单,你自己去吧台取菜(前端主动请求数据,再自己填到页面上)。

2.3 代码层面怎么用?

javascript 复制代码
// 在 uni-app 中发起网络请求
uni.request({
  url: 'https://api.example.com/user/list',  // 后端接口地址
  method: 'GET',
  success: (res) => {
    // res.data 就是后端返回的 JSON 数据
    this.userList = res.data;
  }
});

⚠️ 注意: 这里用的是 uni.request(),不是以前你熟悉的 $.ajax()(jQuery)或 fetch()。在 uni-app 中,所有 API 都以 uni. 开头,这是为了跨平台兼容。后面会详细讲。


三、文件类型变了:从 .html.vue

3.1 你写的文件不再是 HTML 了

对比项 传统 H5 uni-app
文件后缀 .html .vue
开发时写的 HTML 标签 Vue 模板语法
运行时实际是什么 HTML 直接运行 经过编译器转换成各平台代码

3.2 什么是"编译器"和"运行时"?

这是理解 uni-app 的核心概念:

📖 什么是编译器?

把你写的 .vue 源代码,"翻译"成各个平台能识别的代码。比如编译到微信小程序,就生成 wxml + wxss + js;编译到 H5,就生成 html + css + js。你写一次,它翻译多次。
📖 什么是运行时(Runtime)?

编译后的代码在设备上实际执行时,需要一套"运行环境"来支撑。比如 Vue 的响应式系统、组件生命周期管理等,都属于运行时的范畴。
🍔 类比: 编译器像"翻译官",把你的中文稿翻译成各国语言;运行时像"同声传译设备",确保翻译出来的内容能被正确"播放"。


四、文件内部结构变了:从"一栋楼"到"三个房间"

4.1 以前的 HTML 文件

xml 复制代码
<!DOCTYPE html>
<html>
  <head>
    <script src="js/jquery.js"></script>
    <style>
      body { background: #fff; }
    </style>
  </head>
  <body>
    <div id="app">页面内容</div>
    <script>
      // JS 逻辑
    </script>
  </body>
</html>

所有东西------结构、样式、逻辑------都塞在一个 <html> 大壳子里,混在一起。

4.2 现在的 Vue 单文件组件(SFC)

📖 什么是 SFC?

SFC 是 Single File Component 的缩写,即"单文件组件"。它是 Vue 的核心概念:一个 .vue 文件 = 一个组件 = 一个功能模块 。每个 .vue 文件包含三个顶级代码块:<template><script><style>

xml 复制代码
<template>
  <!-- ⚠️ 必须有一个根元素(如 view),且只能有一个! -->
  <view class="container">
    <text>{{ message }}</text>
    <button @click="changeText">点我修改文字</button>
  </view>
</template>

<script>
export default {
  data() {
    return {
      message: '你好,uni-app!'
    };
  },
  methods: {
    changeText() {
      this.message = '文字被修改了!';
    }
  }
}
</script>

<style scoped>
/* scoped 表示样式只作用于当前组件,不会污染其他页面 */
.container {
  padding: 20rpx;
}
</style>

🏠 类比:

以前是"大开间"------客厅、卧室、厨房全在一个空间里,互相干扰。

现在是"三室一厅"------<template> 是客厅(放界面结构)、<script> 是书房(放业务逻辑)、<style> 是衣帽间(放样式),各司其职,互不干扰

4.3 三个块的职责(必须记牢)

代码块 作用 类比
<template> 定义页面长什么样(结构) 房子的户型图
<script> 定义页面怎么动(逻辑) 房子里的电路系统
<style> 定义页面好不好看(样式) 房子的装修

4.4 几个关键规则

  1. <template> 内必须有一个根元素 ,且只能有一个。通常用 <view> 包裹。
  2. <script> 中必须 export default {} ,这是 ES6 模块语法,表示"导出这个组件"。
  3. <style> 中建议加 scoped,防止样式泄漏到其他组件。

📖 什么是 ES6 模块和 export default

ES6(ECMAScript 2015)是 JavaScript 的一次重大升级,引入了模块化语法。export default 的意思是"把这个对象作为默认导出",别的文件通过 import 引入后就能使用。你可以理解为"这个文件对外提供的产品"。


五、外部文件的引用方式变了

5.1 引入 JS 文件

以前:

xml 复制代码
<script src="js/jquery.js"></script>
<script src="js/bootstrap.js"></script>

现在:

javascript 复制代码
// 方式一:CommonJS 规范(require)
const util = require('@/common/util.js');
const result = util.formatTime(new Date());

// 方式二:ES6 模块规范(import)------ 推荐
import { formatTime } from '@/common/util.js';
const result = formatTime(new Date());

📖 @ 符号是什么?

在 uni-app 中,@ 代表项目的根目录@/common/util.js 就等于"项目根目录下的 common 文件夹里的 util.js"。这样写路径,无论文件被嵌套多深,都不会出错。
📖 requireimport 的区别?

两者都是"引入外部模块"的语法。require 是 CommonJS 规范(Node.js 风格),import 是 ES6 模块规范。在 uni-app 中推荐使用 import,因为编译器对 ES6 模块的支持更好,且支持 Tree Shaking(自动去除未使用的代码,减小包体积)。

5.2 引入 CSS 文件

以前:

ini 复制代码
<link href="css/bootstrap.css" rel="stylesheet" />

现在:

xml 复制代码
<style>
@import "@/common/uni.css";
</style>

⚠️ 注意: @import 语句必须写在 <style> 标签内的最顶部 ,后面要加分号 ;

5.3 全局样式写在哪?

项目根目录有一个 App.vue 文件,它是整个应用的"入口组件"。

xml 复制代码
<!-- App.vue -->
<script>
export default {
  onLaunch() {
    console.log('App 启动了');
  }
}
</script>

<style>
/* 这里写的样式是全局的,所有页面都会生效 */
page {
  background-color: #f5f5f5;
}
</style>

⚠️ 重要: App.vue没有 <template> !它不定义任何界面,只负责全局逻辑和全局样式。页面的 UI 由 pages/ 目录下的各个 .vue 文件定义。

5.4 组件引入(重点!)------easycom 机制详解

📖 什么是"组件"?

组件就是把一段"界面 + 逻辑 + 样式"打包成一个可复用的模块。比如你做了一个"评分星星"的 UI,封装成组件后,任何页面都能直接使用,不用重复写代码。

uni-app 提供了 easycom 机制,极大简化了组件引入。

传统方式(需要手动 import + 注册):

xml 复制代码
<script>
import MyComponent from '@/components/my-component.vue';

export default {
  components: {
    MyComponent  // 注册组件
  }
}
</script>

<template>
  <my-component />
</template>

easycom 方式(零配置,直接用):

📖 什么是 easycom?

easycom 是 uni-app 提供的组件自动导入机制 。它让你无需手动 import,无需手动注册,只要在模板中写组件标签名,编译器就会自动找到并加载组件。翻译过来就是"轻松使用组件"。

核心路径规则(必须严格遵守):

复制代码
components/组件名称/组件名称.vue

也就是说:文件夹名和文件名必须完全一致,且都是小写加连字符(kebab-case)风格。

正确示例:

bash 复制代码
components/my-button/my-button.vue     →  模板中用 <my-button />
components/user-card/user-card.vue     →  模板中用 <user-card />
components/uni-list/uni-list.vue       →  模板中用 <uni-list />

错误示例(不会生效):

css 复制代码
components/MyButton.vue                 ← 缺少同名文件夹,❌
components/my-button/index.vue          ← 文件名不是 my-button.vue,❌
components/my-button/MyButton.vue       ← 大小写不匹配,❌

📖 补充规则: 如果组件安装在 uni_modules 目录下,easycom 同样支持自动识别,路径格式为:

bash 复制代码
uni_modules/插件id/components/组件名称/组件名称.vue

例如你通过插件市场安装了 uni-ui,它会自动注册 uni-badgeuni-card 等组件,你直接在模板中写标签名就能用。

为什么传统 Vue 开发者会困惑?

如果你之前用 Vue 开发过 Web 项目,你一定习惯了 import + components 注册。第一次用 uni-app 时,看到别人模板里直接写 <uni-list> 而没有任何 import,会本能地觉得"这不可能生效"。

答案就是 easycom。 编译器在编译阶段会扫描 components/uni_modules/ 目录,自动完成 import 和注册。你只需要保证路径符合规范即可。

💡 记忆口诀: "同名文件夹 + 同名文件 = 直接用"。


六、标签大换血:HTML 标签 → uni-app 组件

这是最直观、最影响日常编码的变化。你熟悉的 HTML 标签,在 uni-app 中要换成对应的组件

6.1 为什么不能直接用 HTML 标签?

因为 uni-app 要跨平台。<div><span> 这些标签只有浏览器认识,微信小程序不认识、原生 App 也不认识。所以 uni-app 定义了一套跨平台通用的组件标签,由编译器负责翻译成各平台的原生写法。

📖 标签 vs 组件,有什么区别?

  • 标签(Tag): 浏览器"出厂自带"的,数量有限且固定,如 <div><p><img>
  • 组件(Component): 开发者可以自由封装和扩展的 UI 模块,就像函数一样,把一段 UI + 逻辑打包起来反复使用。组件的标签名是自定义的,如 <my-button><user-card>

6.2 核心标签对照表(必背)

传统 HTML 标签 uni-app 组件 说明
<div> <view> 最基础的容器组件,相当于一个"盒子"
<span> / <p> / <font> <text> 文本展示
<a href="..."> <navigator url="..."> 页面跳转
<img src="..."> <image src="..."> 图片展示
<select> <picker> 下拉选择器
<iframe> <web-view> 嵌入外部网页
<ul> / <li> / <ol> ❌ 不存在 <view> 嵌套实现列表
<input type="radio"> <radio> / <radio-group> 单选
<input type="checkbox"> <checkbox> / <checkbox-group> 多选
<input type="date"> <picker mode="date"> 日期选择
<audio> 不推荐用标签 改用 uni.createInnerAudioContext() API

6.3 uni-app 独有的"移动端"组件

这些是传统网页没有的,专为移动端场景设计:

组件 用途 使用场景
<scroll-view> 可滚动区域 列表、长内容区域
<swiper> + <swiper-item> 轮播图 首页 Banner
<switch> 开关 设置页"开启通知"
<slider> 滑块 音量调节、亮度调节
<progress> 进度条 下载进度、加载进度
<camera> 相机 拍照、扫码
<map> 地图 位置展示、导航
<video> 视频播放器 视频播放
<cover-view> / <cover-image> 覆盖层 覆盖在 <video><map> 等原生组件上方

⚠️ 关于 <cover-view> 在小程序端,<video><map><camera>原生组件 ,层级最高,普通的 <view> 盖不住它们。如果你需要在视频上方显示按钮或文字,必须用 <cover-view><cover-image>

6.4 一个完整的对比例子

以前写一个图片列表(HTML):

ini 复制代码
<div class="list">
  <img src="pic1.jpg" alt="图片1" />
  <img src="pic2.jpg" alt="图片2" />
</div>

现在在 uni-app 中写:

xml 复制代码
<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>

💡 注意 mode="widthFix" 这是 <image> 组件的属性,表示"宽度固定,高度按比例自适应"。传统 <img> 标签没有这个属性,需要写 CSS 实现。


七、JS 的三大变化(核心重点!)

7.1 运行环境变了------浏览器专属 API 不能用了

对比项 传统 H5(浏览器中) uni-app(App/小程序端)
JS 运行在哪 浏览器的 JS 引擎 V8 引擎(App端)/ 各小程序引擎
window 对象 ✅ 可用 ❌ 不可用
document 对象 ✅ 可用 ❌ 不可用
navigator 对象 ✅ 可用 ❌ 不可用
location 对象 ✅ 可用 ❌ 不可用
localStorage ✅ 可用 ❌ 不可用(用 uni.setStorage
Cookie ✅ 可用 ❌ 不可用
jQuery / DOM 操作库 ✅ 可用 ❌ 不可用

📖 什么是 windowdocument

  • window:浏览器提供的"全局对象",代表当前浏览器窗口。alert()setTimeout()location 都挂在它上面。
  • document:代表当前网页的 DOM 树(文档对象模型),通过它可以查找和操作页面上的任何元素。

在 App 和小程序端,没有浏览器,自然就没有 windowdocument
⚠️ 唯一例外: 当你把 uni-app 编译为 H5 时,运行环境就是浏览器,此时 windowdocument 是可用的。但为了跨端兼容,建议永远不要直接使用它们

7.2 不再操作 DOM,改用"数据绑定"(MVVM)

这是最核心的思维转变,请务必理解透。

📖 什么是 DOM?

DOM(Document Object Model,文档对象模型)是浏览器把 HTML 解析后生成的一棵"树"。每个 HTML 标签都是树上的一个节点。通过 document.getElementById()document.querySelector() 等方法可以"找到"某个节点,然后修改它的内容、样式、属性。
📖 什么是 MVVM?

MVVM 是 Model-View-ViewModel 的缩写:

  • Model(模型): 数据(如 message: "你好"
  • View(视图): 用户看到的界面
  • ViewModel(视图模型): 连接数据和界面的"桥梁"(在 Vue 中就是 data() 和模板的绑定关系)

核心思想:你只需要修改数据,界面会自动更新。你不需要手动去"找到某个元素然后改它"。

❌ 以前的写法(操作 DOM):

xml 复制代码
<span id="myText">123</span>
<button onclick="changeText()">修改</button>

<script>
function changeText() {
  // 第一步:通过 id 找到元素
  // 第二步:修改元素的文本内容
  document.getElementById("myText").innerText = "789";
}
</script>

你需要手动找到元素 → 手动修改它

✅ 现在的写法(数据绑定):

xml 复制代码
<template>
  <view>
    <text>{{ message }}</text>
    <button @click="changeText">修改</button>
  </view>
</template>

<script>
export default {
  data() {
    return {
      message: '123'  // ← 这就是"数据"
    };
  },
  methods: {
    changeText() {
      this.message = '789';  // ← 只改数据,界面自动变!
    }
  }
}
</script>

你只需要修改 data 中的变量 ,界面上所有引用了这个变量的地方会自动更新。不需要找元素,不需要操作 DOM。

🍔 类比:

以前你是"手动挡"------每次换挡都要自己踩离合、拨挡杆(找元素、改属性)。

现在你是"自动挡"------你只管踩油门(改数据),变速箱自动帮你换挡(更新界面)。

关键规则:

规则 说明
需要绑定到界面的数据,必须 写在 data()return {} 否则模板中无法识别
修改数据直接赋值:this.xxx = 新值 不需要微信小程序的 setData()
事件绑定用 @事件名="方法名" @click@input@longpress
方法定义在 methods: {} 通过 this.方法名() 调用

📖 什么是 this

在 Vue 组件中,this 指向当前组件实例。通过 this 你可以访问 data 中的数据、调用 methods 中的方法。比如 this.message 就是访问 data 里的 message 变量。

7.3 API 全换了

以前你用的浏览器 API,在 uni-app 中全部替换为 uni.xxx() 形式:

你想做的事 传统 H5 写法 uni-app 写法
弹窗提示 alert('提示') uni.showToast({ title: '提示' })
确认弹窗 confirm('确定吗?') uni.showModal({ title: '提示', content: '确定吗?' })
网络请求 $.ajax()fetch() uni.request()
本地存储(存) localStorage.setItem(k, v) uni.setStorageSync(k, v)
本地存储(取) localStorage.getItem(k) uni.getStorageSync(k)
页面跳转 location.href = 'xxx' uni.navigateTo({ url: 'xxx' })
返回上一页 history.back() uni.navigateBack()
获取屏幕宽度 window.innerWidth uni.getSystemInfoSync().windowWidth

📖 命名规律: uni-app 的 API 基本是把微信小程序的 wx.xxx 改成了 uni.xxx。如果你看过微信小程序文档,会发现非常亲切。

实际代码示例:

javascript 复制代码
// 发起网络请求
uni.request({
  url: 'https://api.example.com/data',
  method: 'GET',
  success: (res) => {
    console.log('请求成功:', res.data);
  },
  fail: (err) => {
    console.log('请求失败:', err);
  }
});

// 本地存储
uni.setStorageSync('username', '张三');
const name = uni.getStorageSync('username'); // '张三'

// 弹窗
uni.showModal({
  title: '提示',
  content: '确定要删除吗?',
  success: (res) => {
    if (res.confirm) {
      // 用户点了"确定"
    }
  }
});

八、页面跳转详解:五种 API 各有分工(重要!)

在 uni-app 中,页面跳转不再是简单的 location.href,而是有 5 种专用 API,各有不同的使用场景。搞混了就会出现"页面回不去"、"跳转无反应"等问题。

8.1 五种跳转方式对比表

API 作用 页面栈变化 能否传参 适用场景
uni.navigateTo 保留当前页,打开新页面 栈 +1 层 从列表进详情页、从首页进设置页
uni.redirectTo 关闭当前页,打开新页面 栈不变(替换) 登录成功后跳到首页(不想让用户返回登录页)
uni.switchTab 关闭所有非 Tab 页,切到 Tab 页 清空非 Tab 栈 底部导航栏切换(首页/我的/消息)
uni.reLaunch 关闭所有页面,打开指定页面 清空所有栈 退出登录后回到登录页、重置整个应用状态
uni.navigateBack 返回上一页(或上 N 页) 栈 -1(或 -N)层 用户点返回、提交后返回

📖 什么是"页面栈"?

页面栈是一个"后进先出"的结构。每打开一个新页面,就压入栈顶;每返回一次,就弹出栈顶。就像一摞盘子------你只能从最上面拿。uni.navigateTo 就是往这摞盘子上"加一个",uni.navigateBack 就是"拿走最上面那个"。

⚠️ 注意: 微信小程序端页面栈最多 10 层,超过就无法再 navigateTo 了。

8.2 逐个详解

uni.navigateTo------最常用,"前进"

php 复制代码
// 从首页跳转到详情页(保留首页,用户可以返回)
uni.navigateTo({
  url: '/pages/detail/detail?id=123&title=hello'
});

规则:

  • ✅ 可以传参(URL 拼接 ?key=value
  • 不能跳转到 tabBar 页面(会报错或无反应)
  • 新页面被压入页面栈,用户点返回可回到原页面

uni.redirectTo------"替换",不保留当前页

php 复制代码
// 登录成功后跳到首页(用户不能返回登录页)
uni.redirectTo({
  url: '/pages/home/home'
});

规则:

  • ✅ 可以传参
  • 不能跳转到 tabBar 页面
  • 当前页面被关闭销毁,无法返回

🍔 类比: navigateTo 像"打开新标签页"(旧页面还在);redirectTo 像"在当前标签页输入新网址"(旧页面没了)。

uni.switchTab------专门切 Tab 页

php 复制代码
// 切换到底部导航栏的"我的"页面
uni.switchTab({
  url: '/pages/user/user'
});

规则:

  • 不能传参! 这是官方限制。如果需要传数据,用 uni.setStorageSync 或全局变量中转
  • 只能跳转到 pages.jsontabBar.list 里声明过的页面
  • 会关闭所有非 tabBar 页面

⚠️ 常见坑: 如果你用 uni.navigateTo 去跳一个 tabBar 页面,会直接报错 page is not found。必须用 uni.switchTab

uni.reLaunch------"核弹级"重置

php 复制代码
// 退出登录,回到登录页(关闭所有页面)
uni.reLaunch({
  url: '/pages/login/login'
});

规则:

  • ✅ 可以传参
  • ✅ 可以跳转到任何页面(包括 tabBar 页面)
  • 关闭所有已打开的页面,从零开始

uni.navigateBack------"后退"

ini 复制代码
// 返回上一页(默认 delta=1)
uni.navigateBack();

// 返回上两层(如果栈里够两层的话)
uni.navigateBack({ delta: 2 });

规则:

  • 如果页面栈只剩一个页面,调用无效(不会关闭最后一个页面)
  • delta 参数表示回退几层,默认 1

8.3 实战场景决策树

markdown 复制代码
我要跳转到一个新页面?
│
├── 目标页面是 tabBar 页面吗?
│   ├── 是 → 用 uni.switchTab(不能传参)
│   └── 否 ↓
│
├── 用户需要返回当前页面吗?
│   ├── 需要 → 用 uni.navigateTo
│   └── 不需要(当前页可以关掉)→ 用 uni.redirectTo
│
├── 需要关闭所有页面重新开始?
│   └── 是 → 用 uni.reLaunch
│
└── 用户点了返回按钮?
    └── 用 uni.navigateBack

💡 一句话记忆: 日常开发 90% 的场景用 navigateTo,切底部 Tab 用 switchTab,登录/退出场景用 redirectToreLaunch


九、CSS 的变化

好消息:标准 CSS 语法基本都能用。 但有几个重要差异:

9.1 选择器限制

选择器 是否支持 说明
.class-name 类选择器,最常用
#id ID 选择器
tag 标签选择器,如 view {}
*(通配符) 不支持
body 改为 page
后代选择器 .a .b 支持
子选择器 .a > .b ⚠️ 部分端支持

⚠️ 重点: 以前你写 body { margin: 0; },现在要写成 page { margin: 0; }。因为在非 H5 端没有 body 这个概念,page 代表整个页面。

9.2 单位:用 rpx 替代 px

📖 什么是 rpx?

rpx(responsive pixel,响应式像素)是 uni-app 引入的自适应单位。

换算规则: 无论什么屏幕,都规定屏幕宽度 = 750rpx。

  • 如果设计稿是 750px 宽,那 1px = 1rpx,直接换算。
  • 如果设计稿是 375px 宽(iPhone 6/7/8),那 1px = 2rpx。

好处: 你不需要写任何媒体查询(@media),rpx 会自动适配所有屏幕宽度。

css 复制代码
/* 以前的写法 */
.box {
  width: 100px;
  font-size: 14px;
  padding: 10px 20px;
}

/* 现在推荐写法(假设设计稿 750px 宽) */
.box {
  width: 200rpx;
  font-size: 28rpx;
  padding: 20rpx 40rpx;
}

💡 实际使用建议: 如果你的 UI 设计稿是 750px 宽,直接把 px 换成 rpx 即可。如果是 375px 宽,把数值 ×2 再写 rpx。

9.3 布局:强烈推荐 Flex

📖 什么是 Flex 布局?

Flex(Flexible Box,弹性盒子)是 CSS3 引入的一维布局方式。通过给父元素设置 display: flex,子元素会自动排列,支持对齐、分布、换行等。它是目前移动端最主流、兼容性最好的布局方案。

css 复制代码
/* 水平排列,两端对齐,垂直居中 */
.row {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
}

/* 垂直排列 */
.column {
  display: flex;
  flex-direction: column;
}

✅ Flex 布局在 uni-app 的所有端(H5、App、各家小程序)都完美支持,放心使用。

9.4 其他注意事项

注意点 说明
背景图 / 字体文件 建议不超过 40KB,否则影响编译性能。大图建议用网络地址或 base64
position: fixed 在部分小程序端表现有差异,谨慎使用
百分比高度 需要父元素有明确高度才生效

十、工程结构和页面管理

10.1 项目目录结构(必须了解)

sql 复制代码
├── pages/                  ← 所有页面放这里
│   ├── index/
│   │   └── index.vue       ← 首页
│   └── user/
│       └── user.vue        ← 用户页
├── components/             ← 自定义组件(easycom 扫描目录)
├── static/                 ← 静态资源(图片、字体等,不会被编译)
├── uni_modules/            ← 插件/组件库(easycom 也扫描这里)
├── App.vue                 ← 应用入口(全局逻辑+全局样式)
├── main.js                 ← 应用初始化文件
├── pages.json              ← 页面路由和窗口配置(重要!)
├── manifest.json           ← 应用配置(appid、版本、权限等)
└── uni.scss                ← 全局 SCSS 变量

10.2 pages.json------你的"页面调度中心"

📖 在传统网页中,页面之间的跳转靠 <a href="xxx.html"> 链接。在 uni-app 中,每个页面都必须在 pages.json 中注册,否则无法访问。

json 复制代码
{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "navigationBarTitleText": "首页"
      }
    },
    {
      "path": "pages/user/user",
      "style": {
        "navigationBarTitleText": "个人中心"
      }
    }
  ],
  "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "我的应用",
    "navigationBarBackgroundColor": "#ffffff"
  },
  "tabBar": {
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "static/home.png",
        "selectedIconPath": "static/home-active.png"
      },
      {
        "pagePath": "pages/user/user",
        "text": "我的",
        "iconPath": "static/user.png",
        "selectedIconPath": "static/user-active.png"
      }
    ]
  }
}

关键规则:

规则 说明
pages 数组的第一项就是首页 不需要额外配置
新建页面必须在这里注册 否则路由找不到
navigationBarTitleText 页面顶部导航栏标题
tabBar 底部选项卡(类似微信底部的"首页/通讯录/发现/我")
tabBar.list 中的页面只能用 switchTab 跳转 navigateTo 会报错

10.3 与小程序的对应关系

如果你看过微信小程序文档,这个对应关系能帮你快速理解:

微信小程序 uni-app 说明
app.json(页面配置部分) pages.json 管页面路由和窗口样式
app.json(应用配置部分) manifest.json 管 appid、版本号、权限
app.js + app.wxss App.vue 全局逻辑 + 全局样式
.wxml .vue 中的 <template> 页面结构
.wxss .vue 中的 <style> 页面样式
.js .vue 中的 <script> 页面逻辑

十一、生命周期------页面从生到死的过程

📖 什么是生命周期?

每个页面/组件从"创建 → 显示 → 隐藏 → 销毁"会经历一系列阶段,每个阶段 uni-app 都会自动调用对应的函数(钩子),你可以在这些函数里写特定逻辑。

页面生命周期(写在 .vue<script> 中):

钩子函数 触发时机 典型用途
onLoad(options) 页面加载时(只执行一次) 接收参数、发起初始请求
onShow() 页面每次显示时 刷新数据(从其他页面返回时)
onReady() 页面初次渲染完成 操作 canvas、初始化地图
onHide() 页面隐藏时(跳到其他页面) 暂停定时器、保存临时数据
onUnload() 页面卸载时(彻底关闭) 清理定时器、释放资源
xml 复制代码
<script>
export default {
  onLoad(options) {
    // options 中是前一个页面传过来的参数
    // 如:uni.navigateTo({ url: '/pages/detail/detail?id=123' })
    // 这里 options.id === '123'
    console.log('页面加载了,参数:', options);
    this.loadData();
  },
  onShow() {
    console.log('页面显示了');
  },
  methods: {
    loadData() {
      // 发起请求获取数据
    }
  }
}
</script>

⚠️ 注意: 这些生命周期钩子(onLoadonShow 等)是 uni-app 扩展的,直接写在 export default {} 里面 ,和 datamethods 平级,不是写在 methods 里面!


十二、一张总结表:从 H5 到 uni-app 的完整迁移清单

序号 传统 H5 uni-app 备注
1 .html 文件 .vue 文件 单文件组件
2 <div> <view> 容器
3 <span> / <p> <text> 文本
4 <img> <image> 图片
5 <a> <navigator> 跳转
6 document.getElementById() 数据绑定(MVVM) 不再操作 DOM
7 onclick="fn()" @click="fn" 事件绑定
8 alert() / confirm() uni.showToast() / uni.showModal() 弹窗
9 $.ajax() / fetch() uni.request() 网络请求
10 localStorage uni.setStorageSync() / uni.getStorageSync() 本地存储
11 location.href uni.navigateTo() 页面跳转
12 history.back() uni.navigateBack() 返回
13 px / rem rpx 尺寸单位
14 <script src="..."> import / require 引入 JS
15 <link rel="stylesheet"> @import 引入 CSS
16 body 选择器 page 选择器 全局样式
17 URL 路由 / 链接 pages.json 配置 页面管理
18 手动 import + 注册组件 easycom 自动识别 组件引入

十三、给小白的学习建议

如果你是一个熟悉 H5 但没接触过 Vue 和小程序的新手,记住三句话就够了:

  1. 别操作 DOM,改数据就行。 这是最核心的思维转变,一旦理解,后面一切豁然开朗。
  2. 标签换一套,API 换一套。 但编程思想不变,只是"语法"不同。就像你从写中文作文改写成英文作文,思路一样,单词和语法不同。
  3. 一切页面配置看 pages.json 它就是你的"页面调度中心",新建页面、配置导航栏、设置 TabBar 都在这里。

推荐学习路线:

arduino 复制代码
第 1 步:跑通一个 uni-app 项目(用 HBuilderX 创建)
    ↓
第 2 步:理解 .vue 文件的三段式结构(template / script / style)
    ↓
第 3 步:掌握数据绑定(data → template 的 {{}} 语法)
    ↓
第 4 步:学会常用组件(view、text、image、button、input)
    ↓
第 5 步:学会页面跳转和传参(navigateTo + onLoad)
    ↓
第 6 步:学会网络请求(uni.request)
    ↓
第 7 步:学会列表渲染(v-for)和条件渲染(v-if)
    ↓
第 8 步:上手一个完整小项目(如 Todo List、资讯列表)

写在最后

uni-app 的学习曲线并不陡峭,尤其对于有 HTML/CSS/JS 基础的同学。它本质上就是 Vue 语法 + 一套跨平台组件和 API。把 Vue 的数据绑定、组件化思想搞明白,剩下的就是熟悉各平台的差异和 uni-app 特有的 API 而已。

不要怕"不一样",要拥抱"不一样"。 正是这些差异,让 uni-app 能做到一套代码跑遍所有平台,极大提升开发效率。

祝你在跨端开发的路上,一路畅通!🚀


📚 参考资料:

📝 本文为原创技术总结,基于官方文档深度梳理和个人理解重新组织。所有技术点均严格依据 uni-app 官方文档,确保准确权威。转载请注明出处。


如果这篇文章对你有帮助,欢迎点赞、收藏、关注!有问题欢迎评论区交流~ 👋

相关推荐
陈随易3 小时前
moon,apt和yum之外linux系统命令安装新选择
前端·后端·程序员
IT小盘4 小时前
13-企业Prompt模板-角色任务约束与输出格式
java·前端·prompt
徐小夕4 小时前
开源!我用SQLite + DuckDB打造了一款可视化AI问数平台
前端·算法·github
leslie1185 小时前
babel笔记
前端
用户059540174465 小时前
Redis 记忆存储踩坑实录:一个并发写入 Bug 让我排查了 4 小时
前端·css
小徐_23336 小时前
Wot UI 2.3.0 发布:二维码组件来了,Open Wot 与 wot-starter 同步更新
前端·微信小程序·uni-app
kyriewen6 小时前
Claude自己跑出去hack了3家公司——我为什么还在用它写代码
前端·ai编程·claude
IT_陈寒6 小时前
SpringBoot自动配置的坑,这次真踩疼我了
前端·人工智能·后端
子兮曰6 小时前
AI 浏览器 Agent 的安全困局:当自动化工具可以偷走你的登录态
前端·人工智能·后端