uniapp 第6章 6.1 H5 端开发:让你的页面能被全世界看到

上章回顾:上一章我们一起动手做了一个仿美团外卖的小程序,从页面布局到数据渲染,算是把 uniapp 的核心能力都过了一遍。做完了你肯定有个疑问:我写的东西别人怎么访问?总不能让人家也装个小程序吧?

好问题!这一章我们就来解决这个「让别人也能访问」的问题——学会 H5 端开发,把你的页面发布到网上,任何人用浏览器扫个码就能用。

学完这章,你的小程序不仅能在微信里跑,还能变成一个独立的网页,分享给任何人。


🎯 开场 3 分钟:为什么要学 H5 端开发?

先讲个真实的坑。

我有个学员做了个内部工具小程序,功能挺实用,就想让部门同事都用上。结果:

  • 有人不是微信小程序用户,用不了
  • 有人嫌安装小程序麻烦,懒得装
  • 公司限制了小程序安装,压根装不上

最后怎么办?改成 H5 网页,一键分享链接,浏览器打开就能用,所有问题瞬间解决。

H5 端开发解决的就是这个问题:一次开发,让你的应用既能跑在小程序里,也能发布成网页,任何设备、任何浏览器都能访问\n\nSimple tech illustration expla\n\nAI comic creation scene, creat\n\n。

这章我们就来学这个技能。


🧱 基础 25 分钟:H5 端开发核心概念

什么是 H5?

说白了,H5 就是网页技术的统称——HTML5 + CSS3 + JavaScript。

你可以理解成:

  • HTML:网页的骨架(有哪些按钮、输入框、文字)
  • CSS:网页的化妆师(好不好看、什么颜色、多大字号)
  • JavaScript:网页的大脑(点击按钮干什么、数据怎么传)

uniapp 写一套代码,能同时编译成:
- 微信小程序
- iOS 原生 App
- Android 原生 App
- H5 网页 ← 今天学这个

关键概念 1:路由模式(vue-router)

网页有个东西叫「URL 地址」,比如 https://example.com/user/123,这个地址告诉浏览器现在要看哪个页面。

uniapp 在 H5 端用的是 vue-router 来管理页面跳转,有两种模式:

1. hash 模式(默认)

https://example.com/#/user/123

# 后面的内容叫 hash,优点是兼容性极好,缺点是 URL 不好看

2. history 模式

https://example.com/user/123

正常的 URL 好看,但需要服务器配置支持

生活类比:hash 模式像是用房间号找人(#后面是房间号),history 模式像是用精确地址找地点(直接是门牌号)。

代码怎么配?在 manifest.json 里改:

// manifest.json
{
"h5": {
"router": {
  "mode": "hash",  // 改成 "history" 就是好看的那种
  "base": "/myapp/"  // 部署到子目录时用
}
}
}

关键概念 2:跨域问题(为什么请求会失败)

假设你的 H5 网页部署在 https://a.com,但你的 API 后端在 https://b.com,这时候浏览器会报错:

Access-Control-Allow-Origin' header is present on the requested resource

这就是跨域问题——浏览器出于安全考虑,不允许网页从 A 网站请求 B 网站的数据。

解决方案有 3 种:

方案 1:CORS(后端配置,推荐)
让后端在响应头里加一行:

Access-Control-Allow-Origin: *

方案 2:JSONP(老技术,了解就行)
通过 <script> 标签绕过限制,现在基本不用了

方案 3:代理(开发时常用)
配置 uniapp 的开发服务器做中转,生产环境还是得靠 CORS

开发时配置代理,在 vue.config.js 里写:

// vue.config.js
module.exports = {
devServer: {
proxy: {
  '/api': {
    target: 'https://your-backend.com',  // 真实后端地址
    changeOrigin: true,
    pathRewrite: {
      '^/api': ''  // 把 /api 前缀去掉再转发
    }
  }
}
}
}

关键概念 3:SEO 优化(让搜索引擎找到你)

小程序和 App 天然是闭环,搜索引擎搜不到。但 H5 网页能被百度、Google 收录,这就涉及 SEO(搜索引擎优化)

核心就 3 点:

  1. 页面标题 <title> 要包含关键词
  2. 页面描述 <meta name="description"> 要写清楚这页干什么
  3. 语义化标签:用 <header><main><nav> 而不是一堆 <div>

uniapp 里配置 SEO,在 pages.json 对应页面配置:

// pages.json
{
"pages": [
{
  "path": "pages/index/index",
  "style": {
    "navigationBarTitleText": "首页 - 好物推荐",
    "metaDescription": "精选好物推荐,品质生活从这里开始"
  }
}
]
}

🔥 实战 35 分钟:3 个递进的小项目

项目 1(5 分钟):配置第一个 H5 项目

目标:把现有项目配置成能编译成 H5 网页。

步骤

  1. 在 HBuilderX 里打开项目
  2. 点击 运行 → 运行到浏览器 → Chrome
  3. 等待编译,浏览器自动打开

就这么简单!uniapp 会自动打开一个本地服务器,你看到的就是 H5 版本的页面。

完整操作流程

项目右键 → 选择"运行到浏览器" → Chrome
↓ 等待 5-10 秒编译
↓ 浏览器自动打开 http://localhost:8080
↓ 你看到 H5 页面了!

项目 2(15 分钟):读取 JSON 数据并渲染

目标:做一个「书籍列表」页面,从本地 JSON 文件读取数据并展示。

数据文件 books.json

[
{"title": "Python编程:从入门到实践", "author": "埃里克·马瑟斯", "price": 89},
{"title": "JavaScript高级程序设计", "author": "Nicholas Zakas", "price": 119},
{"title": "Vue.js实战", "author": "梁灏", "price": 79}
]

页面代码 pages/books/books.vue

<template>
<view class="container">
<view class="header">
  <text class="title">我的书架</text>
</view>

<view class="book-list">
  <view 
    class="book-item" 
    v-for="(book, index) in books" 
    :key="index"
  >
    <text class="book-title">{{ book.title }}</text>
    <text class="book-author">{{ book.author }}</text>
    <text class="book-price">¥{{ book.price }}</text>
  </view>
</view>
</view>
</template>

<script>
export default {
data() {
return {
  books: []
}
},
onLoad() {
// 模拟从服务器加载数据
uni.request({
  url: '/api/books',  // 假设这是你的接口地址
  success: (res) => {
    if (res.statusCode === 200) {
      this.books = res.data
    }
  }
})

// 开发时先用本地数据演示
this.books = [
  {"title": "Python编程:从入门到实践", "author": "埃里克·马瑟斯", "price": 89},
  {"title": "JavaScript高级程序设计", "author": "Nicholas Zakas", "price": 119},
  {"title": "Vue.js实战", "author": "梁灏", "price": 79}
]
}
}
</script>

<style>
.container { padding: 20px; }
.header { margin-bottom: 20px; }
.title { font-size: 24px; font-weight: bold; }
.book-list { display: flex; flex-direction: column; gap: 15px; }
.book-item { 
padding: 15px; 
background: #f5f5f5; 
border-radius: 8px; 
}
.book-title { display: block; font-size: 16px; font-weight: bold; }
.book-author { display: block; color: #666; font-size: 14px; margin-top: 5px; }
.book-price { display: block; color: #e74c3c; font-size: 18px; margin-top: 5px; }
</style>

预期输出

我的书架
━━━━━━━━━━━━━━━
Python编程:从入门到实践
埃里克·马瑟斯
¥89
━━━━━━━━━━━━━━━
JavaScript高级程序设计
Nicholas Zakas
¥119
━━━━━━━━━━━━━━━
Vue.js实战
梁灏
¥79

这代码做的事:定义一个空的书单数组,页面加载时往里面填数据,Vue 自动循环渲染出列表。

项目 3(15 分钟):做一个「待办清单」H5 小工具

目标:把项目 1 和 2 的能力组合起来,做一个有点真实用的小工具——能添加任务、标记完成、删除任务。

完整代码 pages/todo/todo.vue

<template>
<view class="container">
<view class="header">
  <text class="title">我的待办</text>
  <text class="count">共 {{ todos.length }} 项,已完成 {{ doneCount }} 项</text>
</view>

<!-- 输入区域 -->
<view class="input-area">
  <input 
    class="input" 

    v-model="newTask" 
    placeholder="输入新任务,回车添加"
    @confirm="addTask"
  />
  <button class="add-btn" @click="addTask">添加</button>
</view>

<!-- 任务列表 -->
<view class="todo-list">
  <view 
    class="todo-item"
    :class="{ done: todo.done }"
    v-for="(todo, index) in todos" 
    :key="index"
  >
    <checkbox 
      :checked="todo.done" 
      @click="toggleDone(index)"
    />
    <text class="todo-text">{{ todo.text }}</text>
    <text class="delete-btn" @click="deleteTask(index)">×</text>
  </view>
</view>

<!-- 空状态提示 -->
<view class="empty" v-if="todos.length === 0">
  <text>还没有任务,添加一个吧~</text>
</view>
</view>
</template>

<script>
export default {
data() {
return {
  newTask: '',
  todos: [
    { text: '学习 H5 端开发', done: false },
    { text: '配置跨域代理', done: true },
    { text: '发布第一个 H5 页面', done: false }
  ]
}
},
computed: {
doneCount() {
  return this.todos.filter(t => t.done).length
}
},
methods: {
addTask() {
  if (!this.newTask.trim()) {
    uni.showToast({ title: '任务不能为空', icon: 'none' })
    return
  }
  this.todos.push({
    text: this.newTask.trim(),
    done: false
  })
  this.newTask = ''
},
toggleDone(index) {
  this.todos[index].done = !this.todos[index].done
},
deleteTask(index) {
  this.todos.splice(index, 1)
}
}
}
</script>

<style>
.container { padding: 20px; max-width: 600px; margin: 0 auto; }
.header { margin-bottom: 20px; }
.title { font-size: 24px; font-weight: bold; display: block; }
.count { font-size: 14px; color: #666; }
.input-area { display: flex; gap: 10px; margin-bottom: 20px; }
.input { 
flex: 1; 
padding: 10px; 
border: 1px solid #ddd; 
border-radius: 5px;
font-size: 16px;
}
.add-btn { 
padding: 10px 20px; 
background: #007aff; 
color: white; 
border: none; 
border-radius: 5px;
}
.todo-list { display: flex; flex-direction: column; gap: 10px; }
.todo-item { 
display: flex; 
align-items: center; 
padding: 15px; 
background: #f9f9f9;
border-radius: 8px;
gap: 10px;
}
.todo-item.done .todo-text { 
text-decoration: line-through; 
color: #999;
}
.todo-text { flex: 1; font-size: 16px; }
.delete-btn { 
font-size: 24px; 
color: #999; 
cursor: pointer;
}
.delete-btn:hover { color: #e74c3c; }
.empty { text-align: center; color: #999; padding: 40px; }
</style>

预期输出

我的待办
共 3 项,已完成 1 项
━━━━━━━━━━━━━━━━━━━━━━━
[ ] 学习 H5 端开发    ×
[✓] 配置跨域代理      ×
[ ] 发布第一个 H5 页面 ×
━━━━━━━━━━━━━━━━━━━━━━━
[输入框] [添加]

这代码做的事:用一个数组存任务列表,每项有文字和完成状态,提供添加、勾选、删除三个操作,数据变化后 Vue 自动更新界面。


💪 进阶 20 分钟:常见坑 + 性能小贴士

坑 1:路径大小写

错误

// Windows 不报错,Linux 服务器上报 404
import MyComponent from './MyComponent'  // 文件实际叫 mycomponent.vue

正确:保持路径大小写一致,或者养成习惯全用小写


坑 2:H5 特有的 API 限制

错误

// 小程序里正常,H5 里可能报错
uni.scanCode({
success: (res) => { console.log(res) }
})

正确:H5 端扫码要引入专门的扫码库(如 quagga.js),或者判断平台:

// #ifdef H5
console.log('H5 端不支持扫码')
// #endif

坑 3:本地存储 key 冲突

错误

// 小程序和 H5 用同一个 key,可能串数据
uni.setStorageSync('userInfo', data)

正确:H5 端加个前缀区分:

const storageKey = 'h5_userInfo'  // H5 专用
const storageKey = 'mp_userInfo'  // 小程序专用

坑 4:history 模式需要服务器配置

错误:以为改个配置就好了,直接上线发现刷新 404

正确:服务器配置 nginx 转发规则:

location / {
try_files $uri $uri/ /index.html;
}

坑 5:CSS 单位混用

错误

/* H5 端 rpx 可能不生效 */
width: 750rpx;

正确:H5 端用常规单位,或者配合媒体查询:

/* H5 端用 rem 或百分比 */
width: 100%;
max-width: 750px;

调试技巧:console 大法

H5 端调试超方便,直接按 F12 打开浏览器开发者工具:

// 打印普通信息
console.log('当前数据:', this.todos)

// 打印对象(可展开看详情)
console.log('用户信息:', userInfo)

// 打印警告(黄色)
console.warn('这个 API H5 不支持')

// 打印错误(红色)
console.error('请求失败了:', err)

另一个好用的是 Vue DevTools 插件,装上后能可视化看到组件数据和状态,跟调试小程序一样方便。


✏️ 练习题 + 作业题

练习题(10 分钟)

练习 1(2 分钟):改配置
- 输入:把 manifest.json 的路由模式从 hash 改成 history
- 预期输出:编译后 URL 从 #/pages/index/index 变成 /pages/index/index
- 提示:改 h5.router.mode 的值

练习 2(2 分钟):加判断
- 输入:在项目 2 的基础上,加一个判断,当书价大于 100 时显示"有点贵"
- 预期输出:价格 > 100 的书后面多个"有点贵"标签
- 提示:用 v-if 或三元表达式

练习 3(3 分钟):新数据处理
- 输入:用项目 2 的方法读取以下数据,显示"成绩单":

scores = [
{name: "张小明", chinese: 92, math: 88, english: 95},
{name: "李小红", chinese: 85, math: 92, english: 78}
]
  • 预期输出:显示每个人三科成绩和平均分
  • 提示:可以用计算属性算平均分

练习 4(3 分钟):任务组合
- 输入:把项目 2(读取数据)+ 项目 3(待办清单)组合,实现从接口加载待办任务列表
- 预期输出:页面加载时从本地数据渲染,支持添加和删除
- 提示:把 onLoad 里的本地数组替换成接口返回的数据

练习 5(挑战题,5 分钟):分析报错
- 输入:下面这段代码运行时报错 Cannot read property 'push' of undefined
- 代码:

addTask() {
this.newTask.trim();  // 注意这里没赋值
this.tasks.push({ text: this.newTask, done: false });
}
  • 预期输出:说出错误原因并修复
  • 提示:检查 trim() 的返回值有没有被使用

作业题(30 分钟-2 小时)

作业:做一个「个人信息卡片」H5 工具

  • 需求描述:做一个展示和编辑个人信息的 H5 页面,功能类似的名片小程序
  • 功能点
    1. 展示姓名、职位、联系方式(手机、邮箱)
    2. 点击编辑按钮进入编辑模式
    3. 修改后点击保存,数据存储到本地(uni.setStorage
    4. 页面加载时自动读取本地存储恢复数据
  • 加分项
    1. 添加头像显示(用 emoji 代替)
    2. 增加「一键复制」功能,点击手机号/邮箱自动复制
  • 验收标准
  • 页面能正常渲染姓名、职位、联系方式
  • 编辑后刷新页面数据不丢失
  • H5 端运行正常(浏览器 F12 无报错)
  • 提交方式:评论区贴代码或 GitHub 链接

📚 总结 + 资源

本文学了 3 个核心点
1. H5 端是 uniapp 跨平台的重要出口,让你的应用能被所有人通过浏览器访问
2. 路由模式(hash/history)、跨域、SEO 是 H5 端开发的三个关键技术
3. uniapp 开发 H5 和开发小程序体验几乎一样,但要注意平台差异

延伸学习资源

  1. uniapp 官方 H5 端文档 — 官方出品,最权威的配置说明
  2. Vue Router 中文文档 — 想深入理解路由模式就看这个
  3. 《Vue.js 实战》— 梁灏著,配合本系列学习效果更好

互动钩子:你在做 H5 页面时遇到过跨域问题吗?当时是怎么解决的?评论区聊聊,老粉优先回复!


下章剧透:做好了 H5 页面,下一章我们要把它装到手机里——iOS 和 Android 打包,让你的应用变成真正的 App,不用联网也能用!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。