微信小程序开发实战
第一部分——入门篇
注册小程序(注册账号,完善信息,管理成员)
需要前往微信公众平台官网,选择小程序类型进行注册。注册时需提供有效的邮箱地址(未绑定过微信公众平台)、手机号等信息,并通过邮箱和短信验证。注册成功后,该邮箱将成为小程序的管理账号,用于后续所有管理操作。
注册完成后,需填写小程序的基本信息,包括名称(需符合微信命名规范)、头像(需清晰体现品牌特征)、服务类目(需选择与小程序功能匹配的类目)等。名称一旦确定,修改需通过微信审核。此外,还需补充小程序简介、服务范围等详细信息,这些内容将直接影响小程序的搜索排名和用户信任度。
微信支持多人协作开发,管理员可在后台添加项目成员并分配权限(开发者、体验者、数据分析者等)。不同角色拥有不同操作权限,例如开发者可上传代码但无法提交审核。通过精细化的权限管理,既能保障开发效率,又能避免误操作风险。
小程序开发工具
开发者需根据操作系统(Windows/macOS)从官网下载对应版本的稳定版或预览版。安装过程简单,但需注意关闭杀毒软件以避免误拦截。安装完成后,工具内置模拟器、调试器和代码编辑器,支持实时预览效果,大幅提升开发效率。
首次启动需使用管理员或开发者账号扫码登录。登录后需在工具中绑定小程序AppID(从公众平台获取),否则部分高级功能将受限。工具提供夜间模式、自定义编辑区布局等个性化设置,支持插件扩展以满足特定开发需求。
生成小程序
自动生成小程序
微信小程序开发工具提供了快速生成基础项目的功能,极大降低了初学者的入门门槛。
1. 项目创建 ,代码预览与调试,完整代码结构
通过开发者工具选择"新建项目",填写小程序AppID、项目名称和目录(路径)后,工具会自动生成包含基础目录结构(如pages、utils、app.js/json/wxss[配置文件],JS(utils/util.js)[公共文件],[页面文件.......WXML(HTML),WXSS(CSS),JS,JSON])的模板。此模板已实现简单的页面路由和样式框架,开发者可直接在此基础上进行扩展。
手动生成小程序
对于需要深度定制的项目,手动创建能提供更大灵活性
1. 项目初始化
与自动生成不同,手动创建需从零开始配置项目设置文件和基础目录。建议先规划好页面结构,再通过`app.json`的`pages`字段逐项注册页面。
2. 页面开发全流程
- 页面配置:可通过`app.json`文件中的window属性可设置导航栏颜色等属性
- 视图设计:使用WXML(html)语言编写组件结构,结合WXSS(css)实现Flex布局
- 逻辑实现:在Page()函数中定义数据绑定、生命周期函数和事件处理
新点:
### **代码解释:**
html
<button
open-type="getUserInfo"
bindgetuserinfo="getMyInfo"
>
点击获取头像和昵称
</button>
```
1. **`open-type="getUserInfo"`**
- 这是微信小程序按钮组件的特殊属性,声明按钮的功能为**获取微信用户信息**。
- 只有添加此属性后,按钮才能触发微信官方的用户授权弹窗(需用户主动点击同意)。
- 类似的其他 `open-type` 还有 `contact`(客服会话)、`share`(分享)等,对应不同的微信开放能力。
2. **`bindgetuserinfo="getMyInfo"`**
- 这是一个事件绑定属性,表示当用户点击按钮并授权后,微信会将用户数据(如头像、昵称等)通过事件对象 `e` 传递给开发者自定义的函数 `getMyInfo`。
- `bindgetuserinfo` 是微信规定的固定事件名,不可修改,但右侧的 `getMyInfo` 是开发者可自定义的函数名。
---
### **逻辑实现(JS部分):**
```javascript
getMyInfo: function(e) {
console.log(e.detail.userInfo)
}
```
- **`e.detail.userInfo`** 是微信返回的用户数据对象,包含以下关键字段:
```json
{
nickName: "用户昵称",
avatarUrl: "头像图片URL",
gender: 1, // 性别(1男,2女)
province: "省份",
city: "城市"
}
```
- 开发者可通过 `this.setData()` 将这些数据绑定到页面的 `data` 中,用于动态显示用户信息。
---
### **注意事项:**
1. **用户授权限制**:微信要求用户必须主动点击按钮才能触发授权,直接调用 API(如 `wx.getUserInfo`)将无法获取数据。
2. **兼容性**:2021年后,微信调整了用户信息获取策略,可能需要结合 `wx.getUserProfile` API 使用(具体需参考最新文档)。
3. **数据安全**:用户头像和昵称属于敏感信息,需在隐私政策中声明用途。
通过这种方式,开发者可以合法、安全地获取用户公开信息,并实现个性化功能(如显示用户昵称和头像)。
典型案例展示了如何通过`this.setData()`实现数据驱动视图更新。
3. 完整开发案例
- WXML中`{{}}`插值表达式的使用
完整代码突出了"数据变更→自动渲染"的核心机制。
关键技术与注意事项
- 目录规范:页面文件必须放在`pages`目录下,且每个页面需包含同名四类文件
- 调试技巧:善用`console.log`和"远程调试"功能真机测试
本章通过对比自动生成与手动开发两种模式,帮助开发者理解小程序的基础架构和开发范式,为后续复杂功能开发奠定基础。建议初学者先通过模板熟悉流程,再逐步过渡到自定义开发。
第二部分——基础篇
本章通过列表布局案例,系统讲解了小程序框架的核心开发流程,帮助开发者掌握从项目搭建到功能实现的完整链路。
小程序框架(列表布局,九宫格布局)
仿微信发现页
1 项目创建
- 使用开发者工具新建项目,选择空白模板
- 强调项目目录规范:`pages` 存放页面文件,`utils` 放置工具模块,`images` 存储静态资源。
2 页面配置
- 通过页面对应的 .json
文件设置导航栏标题、背景色等属性,覆盖全局配置(`app.json`)。
- 示例代码演示了如何动态修改页面标题:
index.json
{
"navigationBarTitleText": "商品列表"
}
```
3 视图设计
- 使用 WXML 构建列表结构,结合 wx:for
(v-for)指令循环渲染数据:
html
<view wx:for="{{list}}" wx:key="id">{{item.name}}</view>
```
- 通过 WXSS(css) 实现 Flex 布局,优化列表项的间距和对齐方式。
.container{
height:100;
background-color:silver;
display:flex:
flex-direction:column;
}
4 逻辑实现
使用动态数据展示列表,减少html页面的代码量
5 完整代码展示
p40-42
仿微信钱包页
1 项目创建
- 复用已有项目结构,新增九宫格页面,强调模块化开发思想。
2 页面配置
- 配置页面背景色和导航栏透明效果,增强视觉体验。
3 视图设计
- 使用 flex布局(`display: flex`)实现九宫格,结合 WXML 动态生成格子:
.container{
height:100;
background-color:silver;
display:flex:
flex-direction:row;
flex-wrap:wrap;//允许换行
}
4 逻辑实现
使用动态数据展示列表,减少html页面的代码量
5 完整代码展示
p51-54
本章核心要点
1. 框架思维:理解“配置→视图→逻辑”的分层开发模式。
2. 布局能力:掌握列表循环(`wx:for`)和 flex布局等关键技术。
本章通过两个典型案例,不仅巩固了基础开发技能,还为后续学习组件化开发(如第4章的猜数字游戏)奠定了基础。建议开发者动手实现案例,并尝试扩展功能(如列表筛选、九宫格数据动态加载)。
小程序组件(猜数字游戏)
1 项目创建与配置
本章通过开发"猜数字游戏"小程序,系统讲解了组件化开发的全流程。项目采用多页面架构,包含游戏主界面、规则说明页和关于页面。
1. 项目初始化:
- 使用开发者工具创建新项目,选择"不使用云服务"
- 通过`app.json`配置全局窗口样式和页面路由,设置默认导航栏标题为"数字猜猜看"
- 特别强调删除无用模板文件,保持项目结构清晰
2. 页面文件管理:
- 规范创建`pages/game`(游戏页)、`pages/rule`(规则页)、`pages/about`(关于页)三个目录
- 每个目录严格包含`.js`、`.json`、`.wxml`、`.wxss`四类同名文件
- 演示了如何批量修改页面配置,提高开发效率
2 视图设计
游戏界面采用模块化设计思想,突出组件的复用性。
1. 导航系统设计:
以上文index.json为例
2. 公共页面设计:
在app.wxss中中设置小程序页面的公共样式
.container{
height:100vh;//100视图
background-color:silver;
display:flex:
flex-direction:column;//垂直布局
align-item:center://水平方向居中
justify-content:space-around;//内容调整
}
3. 响应式布局:
- 使用rpx单位适配不同屏幕尺寸
- 通过Flex布局实现元素居中和对齐
- 定义CSS变量统一管理主题色(如`--primary-color`)
4.页面设计:
(1) 首页(index)
首页采用垂直布局设计,包含三个主要按钮:
- 开始游戏按钮:跳转到游戏页面
- 游戏规则按钮:跳转到规则说明页面
- 关于我们按钮:跳转到开发者信息页面
```html
<view class="container">
<button bindtap="goToGame" type="primary">开始游戏</button>
<button bindtap="goToRules" type="primary">游戏规则</button>
<button bindtap="goToAbout" type="primary">关于我们</button>
</view>
```
按钮样式通过WXSS设置为固定宽度350rpx,确保在不同设备上显示一致。
#### (2) 游戏规则页面(rules)
规则页面使用`<text>`组件展示游戏规则文本,支持自动换行:
```html
<view class="container">
<text>
1. 系统会随机生成一个0~100的数字让玩家猜。
2. 玩家共有8次机会。
3. 在8次之内猜中则游戏成功。
4. 点击"开始游戏"进入游戏画面。
</text>
</view>
```
#### (3) 关于我们页面(about)
关于页面同样使用`<text>`组件,简洁展示开发者信息:
```html
<view class="container">
<text>xxx工作室荣誉出品。</text>
</view>
```
#### (4) 游戏主页面(game)
游戏页面结构最为复杂,包含三个主要部分:
- 顶部欢迎语(`<text>`)
- 中间表单区域(`<form>`),包含输入框和提交按钮
- 底部提示区域(`<text id="tip">`),显示游戏过程反馈
```html
<view class="container">
<text>欢迎来到猜数字小游戏</text>
<form>
<block wx:if="{{isGameStart}}">
<input bindblur="getNumber" type="number" placeholder="请输入0~100的数字"/>
<button type="primary" form-type="reset" bindtap="guess">提交</button>
</block>
<block wx:else>
<button type="primary" bindtap="restartGame">重新开始</button>
</block>
</form>
<text id="tip">{{tip}}</text>
</view>
```
1. 基础容器样式
- 使用了名为`container`的类作为各页面的底层容器
- 示例CSS代码片段包含了一些样式声明(虽然部分语法看起来有问题)
2. 首页设计
- 包含3个垂直排列且水平居中的按钮:
- 开始游戏(跳转到游戏页面)
- 游戏规则(跳转到规则页面)
- 关于我们(跳转到关于页面)
- 使用`<view>`作为容器,`<button>`作为按钮组件
- 按钮样式设置了固定宽度(350rpx)
3. 游戏规则页面
- 简单使用`<text>`组件显示游戏规则文本
- 规则内容包括:
1. 系统生成0-100的随机数
2. 玩家有8次猜测机会
3. 8次内猜中则成功
4. 点击开始游戏进入游戏画面
4. 关于我们页面
- 同样使用`<text>`组件显示开发者/工作室信息
- 示例文本为"xxx工作室荣誉出品"
5. 开始游戏页面设计
- 包含三部分:
- 顶部欢迎语句(`<text>`)
- 表单(`<form>`),包含数字输入框和提交按钮
- 提示语句区域(`<text id="tip">`)
- 样式设置:
- 输入框有绿色边框、圆角、外边距
- 提示区域固定高度(800rpx)
- 设计图中显示游戏过程提示示例(如"第1回合,大了")
6. 开发特点
- 使用WXML进行页面结构编写
- 使用WXSS进行样式设计
- 采用rpx作为响应式单位
- 强调组件化开发(`<view>`, <button>
, <text>
等)
这些内容展示了微信小程序开发的基本流程和常见组件使用方式,从简单页面布局到表单交互界面的实现。
3 游戏逻辑实现
1. 游戏逻辑实现
游戏页面的JavaScript逻辑是整个应用的核心,主要包括以下几个关键部分:
(1) 游戏初始化
通过`initial`函数初始化游戏数据:
```javascript
initial: function() {
this.setData({
answer: Math.round(Math.random() * 100), // 随机答案(0-100)
count: 0, // 回合计数器
tip: '', // 提示信息
x: -1, // 用户输入值
isGameStart: true // 游戏状态
});
}
```
初始化在页面加载时通过`onLoad`生命周期函数调用:
```javascript
onLoad: function(options) {
this.initial();
}
```
(2) 获取用户输入
通过`bindinput`事件绑定输入框,获取用户输入的数字:
```javascript
getNumber: function(e) {
this.setData({x: e.detail.value});
}
```
(3) 游戏猜测逻辑
guess
函数处理用户提交的猜测,包含以下功能:
- 输入验证(0-100范围)
- 回合计数
- 比较用户输入与正确答案
- 生成并显示提示信息
- 游戏结束判断(猜中或达到8次限制)
```javascript
guess: function() {
let x = this.data.x;
this.setData({x: -1}); // 重置输入状态
if(x < 0) {
wx.showToast({title: '不能小于0'});
} else if(x > 100) {
wx.showToast({title: '不能大于100'});
} else {
let count = this.data.count + 1;
let tip = this.data.tip;
let answer = this.data.answer;
if(x == answer) {
tip += '\n第'+ count + '回合:' + x + ',猜对了';
this.setData({isGameStart: false});
} else if(x > answer) {
tip += '\n第'+ count + '回合:' + x + ',大了';
} else {
tip += '\n第'+ count + '回合:' + x + ',小了';
}
if(count == 8) {
tip += '\n游戏结束';
this.setData({isGameStart: false});
}
this.setData({
tip: tip,
count: count
});
}
}
```
(4) 游戏重新开始
通过`restartGame`函数重置游戏状态:
```javascript
restartGame: function() {
this.initial();
}
```
2. 页面导航实现
首页按钮通过`bindtap`事件绑定导航函数,使用微信小程序的`wx.navigateTo`API实现页面跳转:
```javascript
goToGame(){
wx.navigateTo({
url: '../game/game',
});
},
goToAbout(){
wx.navigateTo({
url: './about/about',
});
},
goToRules(){
wx.navigateTo({
url: './rules/rules',
});
}
3. 条件渲染优化
游戏页面使用`wx:if`条件渲染,根据游戏状态显示不同的UI:
```html
<block wx:if="{{isGameStart}}">
<!-- 游戏进行中显示输入框和提交按钮 -->
<input bindblur="getNumber" type="number" placeholder="请输入0~100的数字"/>
<button type="primary" form-type="reset" bindtap="guess">提交</button>
</block>
<block wx:else>
<!-- 游戏结束显示重新开始按钮 -->
<button type="primary" bindtap="restartGame">重新开始</button>
</block>
```
项目总结与经验
1. 技术要点总结
通过本项目实践,我们掌握了以下微信小程序开发核心技术:
1. 页面布局与样式:熟练使用WXML和WXSS构建页面结构并设置样式
2. 数据驱动视图:理解小程序的数据绑定机制,实现数据与视图的同步
3. 事件处理:掌握bindtap、bindinput等事件绑定方法
4. 条件渲染:使用wx:if实现根据状态显示不同UI
5. 页面导航:使用wx.navigateTo实现页面跳转
6. 生命周期管理:合理使用onLoad等生命周期函数
2. 最佳实践
从项目中可以总结出以下最佳实践:
1. 组件化设计:将重复使用的样式和结构抽象为组件或模板
2. 状态集中管理:将相关状态集中管理,便于维护和更新
3. 输入验证:对用户输入进行严格验证,提供友好提示
4. 响应式设计:使用rpx单位确保在不同设备上良好显示
5. 代码组织:合理组织代码结构,保持可维护性
3. 扩展思考
基于当前项目,可以考虑以下扩展方向:
1. 增加难度选择:允许用户选择不同难度级别(如数字范围、猜测次数)
2. 添加音效:为游戏操作添加适当的音效反馈
3. 积分系统:根据猜测次数计算得分,增加竞争性
4. 多语言支持:实现国际化,支持多种语言
5. 云开发集成:使用微信云开发实现用户数据存储和排行榜功能
本章核心价值
通过完整项目实践,开发者可以掌握:
1. 组件化开发思维
2. 数据驱动视图的开发模式
本微信小程序开发实战项目是一个完整的"猜数字"游戏应用,包含了首页导航、游戏规则说明、关于我们信息以及核心的游戏功能模块。项目采用微信小程序原生开发框架,通过WXML、WXSS和JavaScript实现了页面布局、样式设计和业务逻辑。整个开发过程展示了微信小程序的基础架构和核心开发技术,包括页面路由、数据绑定、事件处理、条件渲染等关键功能。
为后续学习网络API(如第五章天气查询等应用)奠定了坚实基础,可以发散思维扩展实现"难度选择"、"排行榜"等功能以巩固知识。
第三部分——应用篇
天气查询
一、API密钥申请与配置
选择和风天气API作为小程序天气数据源是本章的第一个关键步骤。和风天气(HeWeather)是国内知名的气象数据服务提供商,提供全球范围内的气象数据接口服务。其免费版本足以满足学习开发需求,提供三天内的实时天气数据,调用频率限制为每天1000次,每分钟200次,这对于学习开发完全足够。
申请API密钥的过程从访问和风天气官网(https://www.heweather.com/)开始。开发者需要选择"免费用户"类型,通过邮箱完成注册和激活流程。成功注册后,登录控制台(https://console.heweather.com/my/service)即可查看个人认证key,这个key是调用API时的身份凭证,必须妥善保管。
API密钥的安全使用有几个注意事项:首先,key不应该直接暴露在前端代码中,理想情况下应该通过后端服务中转请求;其次,免费key有调用限制,开发时应注意不要频繁调用导致配额耗尽;最后,如果项目商业化,需要考虑升级到付费套餐以获得更稳定的服务。
在实际开发中,我们还需要了解和风天气API的数据更新机制。实时天气数据通常有15-30分钟的更新间隔,不同地区的更新频率可能有所不同。API返回的数据包含丰富的天气信息,从基本温度到风向风速、湿度气压等,为天气应用开发提供了充分的数据支持。
此外,和风天气API还支持多种查询方式,包括城市名称(中英文)、城市ID、IP地址和经纬度等,这为不同场景下的天气查询提供了灵活性。例如,可以结合微信小程序的定位API获取用户当前位置的经纬度,再查询当地天气,实现更智能的服务。
二,API调用方法与参数理解
和风天气API的调用方法是本章的核心技术点。免费用户调用的基础URL为"https://free-api.heweather.com/s6",通过追加不同的关键词可以获取不同类型的气象数据。本章示例使用的是实况天气接口,关键词为"weather"。
API调用需要两个必填参数:city和key。city参数支持多种格式,为开发者提供了极大的灵活性:
1. 城市名称:支持中文(如"北京")和拼音(如"beijing")
2. 城市ID:如"CN101010100"(北京的城市ID)
3. IP地址:如"60.194.130.0"
4. 经纬度:如"116.40,39.9"(经度在前,纬度在后)
key参数则是开发者申请的个人认证key,用于身份验证和访问控制。没有有效key的请求会被拒绝。
此外,API还提供两个可选参数:
- lang:指定返回数据的语言,默认为简体中文(zh),可设置为英文(en)等
- unit:选择公制(m)或英制(i)单位,主要影响温度、风速等数据的显示方式
API返回的数据是结构化的JSON格式,包含三个主要部分:
1. basic:基础信息,包括地区名称、ID、经纬度、所属行政区等
2. update:数据更新时间,包括本地时间和UTC时间
3. now:实况天气数据,包含温度、天气状况、风力、湿度、气压等详细信息
返回数据中还包含status字段,表示请求状态。常见的状态码有:
- "ok":请求成功
- "invalid key":无效的key
- "unknown location":未知地区
- "no more requests":超过调用限制
理解这些状态码对于错误处理非常重要。例如,当收到"invalid key"响应时,需要检查key是否正确配置;"no more requests"则表示当天配额已用完。
在实际调用时,建议先在浏览器地址栏直接输入API URL进行测试,确认能获取正确数据后再集成到小程序代码中。这可以快速验证参数是否正确,避免在小程序开发工具中反复调试。
API的响应时间也是需要考虑的因素。正常情况下,API响应应该在几百毫秒内完成,但在网络状况不佳时可能需要更长时间。因此,小程序中应该添加适当的加载状态提示,改善用户体验。
三、服务器域名配置
微信小程序的网络安全策略要求所有网络请求必须指向预先配置的合法域名,这是本章的一个重要知识点。每个小程序在与指定域名通信前,必须将该域名添加到管理员后台的白名单中。
配置服务器域名的步骤如下:
1. 登录微信公众平台(mp.weixin.qq.com)
2. 进入"开发"-"开发设置"
3. 在"服务器域名"中找到"request合法域名"
4. 添加和风天气API域名"https://free-api.heweather.com"
5. 保存配置
这一配置有几个重要限制需要注意:首先,每个月最多只能修改5次服务器域名配置,因此需要谨慎规划;其次,配置的域名必须使用HTTPS协议,不支持HTTP;最后,域名不能包含端口号和路径,只能是基础域名。
域名配置完成后,在小程序开发工具中需要重新编译项目才能使配置生效。如果遇到网络请求失败的情况,首先应该检查域名配置是否正确,是否已经生效。
在实际开发中,可能会遇到需要请求多个域名的情况。例如,除了和风天气API,可能还需要请求自己的后端服务。微信小程序允许配置多个request合法域名,但总数不能超过20个。
域名验证是另一个重要环节。微信小程序在首次向新域名发起请求时,会进行域名验证,包括:
1. 检查域名是否已备案
2. 验证SSL证书是否有效
3. 检查服务器是否支持小程序的校验文件
验证通过后,后续请求才能正常进行。如果验证失败,需要根据错误提示进行排查,常见问题包括SSL证书配置错误、校验文件放置位置不正确等。
值得注意的是,开发阶段可以在开发者工具中临时开启"不校验合法域名"选项,方便调试。但正式发布的小程序必须配置合法的服务器域名,否则网络请求将无法成功。
对于需要频繁更换域名的开发场景,可以考虑使用微信云开发或搭建自己的API网关作为代理,减少小程序端域名配置的变更频率。这种架构也更有利于保护API密钥等敏感信息。
四、项目创建与页面配置
项目创建与初始化是天气查询小程序的起点。本章选择从空白项目开始,命名为weatherDemo,这种干净的起点有利于理解和控制项目的每个部分。
创建项目后的第一步是清理工作:
1. 删除utils文件夹及其内容
2. 删除pages/logs目录及其内容
3. 清空index.wxml和index.wxss文件内容
4. 清空并重新初始化index.js和app.js
5. 清空app.wxss样式文件
这种彻底的清理确保了项目从最简状态开始,避免了默认模板带来的干扰。在index.js和app.js中,使用IDE的代码补全功能快速生成基本的Page和App结构,这比手动输入更高效准确。
项目结构配置的关键点包括:
1. 在app.json中配置页面路径,本章只需要index页面
2. 创建专门的images文件夹存放天气图标素材
3. 在images下建立weather_icon子目录分类存放图标
天气图标是和风天气提供的配套视觉资源,每个图标对应特定的天气状况代码。例如"100.png"表示晴,"101.png"表示多云等。这些图标文件需要按照规范命名并放置在正确目录下,以便程序动态加载。
页面配置还包括导航栏的自定义。在app.json中设置全局导航栏样式:
```json
"window": {
"navigationBarBackgroundColor": "#3883FA",
"navigationBarTitleText": "今日天气"
}
```
这种集中配置的方式确保了整个小程序导航栏风格一致。
项目结构优化方面,良好的目录结构对后续开发和维护至关重要。建议的目录结构如下:
- /pages/index/:主页面文件
- /images/weather_icon/:天气图标
- /utils/:后期可添加的工具函数
- /config/:可添加配置文件存放API key等
在准备图标素材时,需要注意不同分辨率的适配问题。和风天气提供的图标通常是清晰的PNG格式,但开发者可能需要准备不同尺寸的版本以适应各种设备。此外,夜间模式图标(如"100n.png")也需要考虑在内,以提供更完整的用户体验。
这种从零开始的配置过程虽然初期工作量较大,但为后续开发奠定了清晰的基础,避免了冗余代码和混乱的结构。在更复杂的项目中,这种规范化的初始化过程尤为重要。
五、页面视图设计
页面视图设计是天气查询小程序的门面,直接影响用户体验。本章采用清晰的区域划分和合理的布局方式,打造直观易用的天气展示界面。
整体布局使用flexbox模型,主要特点包括:
1. 容器设置为display:flex和flex-direction:column,实现垂直排列
2. 使用align-items:center使内容水平居中
3. justify-content:space-around均匀分布各个区域
4. 高度设置为100vh,确保填满整个视窗
页面划分为四个逻辑区域:
1. 地区选择器:使用<picker mode="region">组件,提供省市区三级选择
2. 温度与天气状态:大字号显示当前温度和天气状况文字描述
3. 天气图标:直观展示当前天气状况的图形表示
4. 详细信息区:表格形式展示湿度、气压、能见度、风向等附加信息
地区选择器的实现有几个技术要点:
- 绑定bindchange事件处理地区变更
- 初始值通过data中的region数组设置
- 选择结果是一个包含省、市、区三级的数组
- 实际天气查询通常使用市级数据,因为区级数据可能不可用
六,逻辑实现
1. 页面数据初始化
```javascript
data: {
region: ['安徽省','芜湖市','镜湖区'],
now: {
tmp: 0,
cond_txt: '未知',
cond_code: '999',
hum: 0,
pres: 0,
vis: 0,
wind_dir: '无',
wind_spd: 0,
wind_sc: 0
},
isGameStart: true
}
```
- 使用`region`数组存储省市区三级信息
- now
对象预置所有天气字段的默认值
- 特殊天气代码`999`对应"未知"状态图标
2. 网络请求封装
```javascript
getWeather: function() {
const that = this;
wx.request({
url: 'https://free-api.heweather.com/s6/weather/now',
data: {
location: that.data.region[1], // 使用市级单位查询
key: 'your-api-key'
},
success: function(res) {
if(res.data.HeWeather6[0].status === 'ok'){
that.setData({
now: res.data.HeWeather6[0].now
});
}
},
fail: function(error) {
wx.showToast({ title: '网络请求失败' });
}
});
}
```
3. 关键交互逻辑
#### 地区选择器事件处理
```javascript
regionChange: function(e) {
this.setData({
region: e.detail.value // 更新选择的省市区
});
this.getWeather(); // 立即获取新地区天气
wx.showLoading({ title: '加载中...' });
}
```
- picker
组件的`bindchange`事件返回包含省市区三级信息的数组
- 典型问题处理:直辖市可能返回空字符串的区级数据
#### 生命周期函数集成
```javascript
onLoad: function() {
this.getWeather(); // 页面加载时首次获取
},
onShow: function() {
if(!this.data.isGameStart){
this.initial(); // 返回页面时重置游戏状态
}
}
```
4. 数据绑定与渲染优化
#### 动态数据绑定示例
```xml
<!-- 温度与天气状态 -->
<text>{{now.tmp}}℃ {{now.cond_txt}}</text>
<!-- 动态图标加载 -->
<image src="/images/weather_icon/{{now.cond_code}}.png"/>
<!-- 风力信息展示 -->
<view class="box">{{now.wind_dir}} {{now.wind_sc}}级</view>
```
5.条件渲染实现
```xml
<block wx:if="{{now.cond_code !== '999'}}">
<!-- 正常天气信息展示 -->
</block>
<block wx:else>
<text>数据加载中...</text>
</block>
```
6. 错误处理与用户体验
#### 网络异常处理
```javascript
// 在getWeather函数中添加
fail: function(error) {
wx.hideLoading();
wx.showToast({
title: '获取数据失败',
icon: 'none'
});
console.error('API请求失败:', error);
}
```
#### 数据有效性校验
```javascript
success: function(res) {
if(!res.data || !res.data.HeWeather6){
throw new Error('无效的响应格式');
}
const weatherData = res.data.HeWeather6[0];
if(weatherData.status !== 'ok'){
this.handleAPIError(weatherData.status);
return;
}
// ...正常处理逻辑
}
本章通过完整的逻辑实现,将静态页面与动态数据相结合,构建出功能完备的天气查询小程序。
口诉校史
1 项目创建
1. 工程初始化
- 使用空白模板创建`videoDemo`项目
- 标准化目录结构:
```
/pages/index/ # 主页面
/images/ # 播放图标资源
```
- 关键配置:
- 删除冗余日志页面
- 清空默认样式文件
- 禁用非必要组件
2 页面配置
1. 导航栏定制
```json
{
"navigationBarBackgroundColor": "#987938",
"navigationBarTitleText": "口述校史",
"navigationBarTextStyle": "white"
}
```
- 设计要点:历史感配色(金棕+白字)
- 适配方案:动态计算标题宽度避免截断
2. 资源管理
- 图标规范:
- 播放按钮尺寸:`70×70rpx`
- 格式:PNG透明底
- 视频预加载:
```javascript
wx.preloadVideo({ src: url })
```
---
3 视图设计
1. 三区域布局
```xml
<!-- 区域1:视频播放器 -->
<video id="myVideo" controls/>
<!-- 区域2:弹幕控制 -->
<view class="danmu-area">
<input bindinput="updateDanmuText"/>
<button bindtap="sendDanmu">发送</button>
</view>
<!-- 区域3:视频列表 -->
<view wx:for="{{list}}" wx:key="id">
<image src="/images/play.png"/>
<text>{{item.title}}</text>
</view>
```
2. 样式优化
- Flex布局实现响应式适配
- 动态单位`rpx`保证多端显示一致
- 视频列表项`border-bottom`分割线
---
4 逻辑实现
1. 视频播放控制
```javascript
// 创建上下文
this.videoCtx = wx.createVideoContext('myVideo')
// 播放切换
playVideo(url) {
//停止之前正在播放的视频
this.videoCtx.stop()
//更新视频地址
this.setData({ src: url })
//播放新的视频
this.videoCtx.play()
}
2. 弹幕系统
```javascript
// 随机颜色生成
function getRandomColor() {
return #${Math.floor(Math.random()*16777215).toString(16)}
}
// 发送弹幕
sendDanmu() {
this.videoCtx.sendDanmu({
text: this.data.danmuText,
color: getRandomColor(),
time: this.videoCtx.currentTime
})
}
3. 数据绑定
- 视频列表动态渲染:
```javascript
data: {
list: [
{
id: '001',
title: '杨国宜先生访谈',
videoUrl: 'http://example.com/v1.mp4'
}
]
}
本总结完整覆盖教材第六章所有技术要点,包含基础实现、优化策略和扩展方向,可作为开发参考手册使用。
电子书橱
1 准备工作
本章的核心目标是实现一个电子书橱小程序,通过文件API完成电子书的下载、保存、打开等功能。在开始项目前,需要完成以下准备工作:
1. 服务器部署:
电子书文件需要存放在服务器端的`books`文件夹中。由于版权问题,开发者需自行准备PDF格式的电子书。服务器部署可参考附录A的说明,确保本地或远程服务器能够通过URL访问这些文件。例如,`http://localhost/books/book001.pdf`是一个典型的本地测试路径。
2. 文件命名规范:
建议为每本电子书分配唯一的ID(如`book001`、`book002`),并在代码中通过数组维护图书信息,包括标题、封面图URL和文件下载地址。封面图可以从豆瓣读书等平台获取。
3. 开发环境检查:
确保微信开发者工具已安装,并创建一个空白项目`bookDemo`。后续步骤将在此项目基础上进行页面配置和功能开发。
---
2 项目创建与初始化
1. 创建项目:
在微信开发者工具中选择“新建项目”,填写项目名称`bookDemo`,目录指向空白文件夹,AppID可使用测试号。项目模板选择“空白”,确保初始结构简洁。
2. 清理默认文件:
删除不必要的文件和代码:
- 移除`app.json`中`pages/logs/logs`的配置项,并删除多余的逗号。
- 删除`utils`文件夹及`pages/logs`目录。
- 清空`index.wxml`、`index.wxss`、`index.js`和`app.wxss`的内容。
- 在`index.js`中输入`Page`生成页面框架,在`app.js`中输入`App`生成应用实例。
3. 项目结构优化:
仅保留首页`index`,其他页面暂不需要。最终目录结构如下:
```
bookDemo/
├── app.js
├── app.json
├── app.wxss
└── pages/
└── index/
├── index.wxml
├── index.wxss
└── index.js
```
---
3 页面配置
1. 导航栏定制:
在`app.json`中自定义导航栏样式:
```json
{
"pages": ["pages/index/index"],
"window": {
"navigationBarBackgroundColor": "#663366",
"navigationBarTitleText": "我的书橱"
}
}
```
效果为紫红色背景(`#663366`)和白色标题文本。
2. 页面布局设计:
- 图书展示容器:使用`<view class="book-container">`和Flex布局实现九宫格效果,允许换行(`flex-wrap: wrap`)。
- 图书单元:每个单元包含`<image>`(封面)和`<text>`(标题),垂直居中排列(`flex-direction: column`)。
- 下载蒙层:通过`wx:if`控制显示,包含进度条(`<progress>`)和提示文本。
3. WXSS样式:
- 图书单元宽度设为`50%`,图片尺寸固定为`200rpx × 300rpx`。
- 文本居中显示,蒙层背景半透明以覆盖原内容。
4 视图设计与交互逻辑
1. 动态渲染图书列表:
在`index.js`的`data`中定义`bookList`数组,包含每本书的`id`、`title`、`poster`和`fileUrl`。通过`wx:for`循环渲染:
```xml
<view class="box" wx:for="{{bookList}}" wx:key="id">
<image src="{{item.poster}}"></image>
<text>{{item.title}}</text>
</view>
```
2. 下载与打开逻辑:
- 点击事件:绑定`readBook`函数,通过`dataset`获取图书ID和下载地址。
- 缓存检查:使用`wx.getStorageSync`判断是否已下载。若未下载,显示蒙层并调用`wx.downloadFile`。
- 进度监听:通过`downloadTask.onProgressUpdate`更新进度条。
- 文件保存:下载完成后调用`wx.saveFile`保存至本地,路径存入缓存。
3. 错误处理:
- 封装`showTips`函数统一显示错误模态框,覆盖网络请求失败、文件保存失败等场景。
---
5 功能实现与优化
1. 代码封装:
- `openBook`:封装`wx.openDocument`,直接打开本地文件。
- `saveBook`:保存临时文件并更新缓存,避免重复下载。
- `readBook`:整合下载、保存、打开流程,通过`that`解决`this`作用域问题。
2. 性能优化:
- 限制同时下载任务数量,避免占用过多内存。
- 检查本地文件大小(上限10MB),防止保存失败。
3. 测试与调试:
- 模拟服务器无响应、文件损坏等异常情况,确保提示友好。
- 使用真机预览,验证下载速度和文件打开兼容性。
---
总结:本章通过文件API实现了电子书橱的核心功能,涵盖了从页面设计到逻辑封装的完整流程。重点在于灵活运用`wx.downloadFile`、`wx.saveFile`和`wx.openDocument`,以及通过缓存机制提升用户体验。后续可扩展图书分类、搜索等功能。
医疗急救卡
1 项目概述与核心功能设计
医疗急救卡小程序是一个典型的个人健康信息管理应用,其核心功能设计围绕"紧急情况下的快速信息获取"展开。在医疗急救场景中,时间就是生命,因此小程序需要实现三大核心功能模块:
1. 关键医疗信息存储系统:
- 采用本地缓存技术存储包括血型、过敏史、用药记录等15类关键医疗数据
- 设计分层数据结构:基础信息(姓名、出生日期)、身体状况(身高体重)、医疗记录(病史、用药)、紧急联系等
- 实现数据加密存储,保护用户隐私安全
2. 智能表单交互体系:
- 开发动态表单系统,根据用户输入自动调整必填字段
- 集成7种表单控件:日期选择器、多行文本框、单选框、开关等
- 设计实时校验机制,确保电话号码等关键信息的有效性
2 项目架构与技术选型
1. 整体架构设计:
采用经典的双页面架构:
- 首页(index):信息展示与功能入口
(是否创建医疗卡,否创建按钮页面,是展示医疗卡,创建和编辑医疗卡点击都可以跳转form表单)
- 表单页(form):数据录入与编辑
2. 技术栈选择:
- 存储方案:优先选择同步API(wx.setStorageSync)确保数据一致性
- 界面框架:Flex布局实现响应式设计
- 交互方案:事件驱动模型绑定用户操作
3. 关键技术决策:
- 放弃使用云开发,采用纯本地存储满足隐私保护需求
- 选择JSON作为数据存储格式,便于扩展和维护
- 使用小程序原生组件保持最佳性能
4. 目录结构优化:
```
project/
├── app.js # 应用逻辑
├── app.json # 全局配置
├── app.wxss # 全局样式
└── pages/
├── index/ # 首页
└── form/ # 表单页
3 详细实现过程
1. 数据层实现:
- 设计医疗数据模型:
```javascript
{
date: '2000-01-01', // 出生日期
blood: 'A', // 血型
ylzk: '无', // 医疗状况
tel: '13800138000' // 紧急电话
// 其他15个字段...
}
```
- 实现CRUD操作:
```javascript
// 保存数据
wx.setStorageSync('myCard', data)
// 读取数据
const data = wx.getStorageSync('myCard')
// 删除数据
wx.removeStorageSync('myCard')
```
2. 视图层开发:
- 首页双状态设计:
```xml
<view wx:if="{{!myCard}}">
<!-- 未创建状态 -->
</view>
<view wx:else>
<!-- 已创建状态 -->
</view>
```
- 表单页动态渲染:
```xml
<picker name="blood" range="{{bloodItems}}">
<view>{{blood}}型</view>
</picker>
```
3. 交互逻辑实现:
- 表单提交处理:
```javascript
submitForm: function(e) {
const formData = e.detail.value
// 数据清洗
formData.height = parseInt(formData.height)
// 持久化存储
wx.setStorageSync('myCard', formData)
}
```
- 紧急呼叫功能:
```javascript
makeCall: function() {
wx.makePhoneCall({
phoneNumber: this.data.myCard.tel
})
}
```
4. 样式系统构建:
- 基础样式规范:
```css
/* 颜色系统 */
:root {
--primary-color: #FF2D55;
--secondary-color: #666;
}
```
- 响应式布局方案:
```css
.box {
display: flex;
flex-direction: row;
padding: 10rpx;
}
```
4 优化策略与难点攻克
1. 性能优化实践:
- 实现数据缓存策略:首次加载后缓存医疗数据
- 采用虚拟列表技术优化长表单渲染
- 减少不必要的setData调用
2. 用户体验提升:
- 添加表单自动保存功能
- 实现输入历史记忆
- 增加关键操作的二次确认
3. 技术难点解决:
- 日期选择器兼容性问题:通过自定义组件解决
- 表单数据验证:开发通用验证工具函数
- 多设备适配:采用rpx单位实现完美适配
4. 安全加固措施:
- 敏感数据本地加密
- 增加操作日志记录
- 实现防暴力破解机制
5 项目总结与扩展思考
1. 项目成果:
- 完整实现了医疗急救卡所有功能需求
2. 经验总结:
- 本地缓存API适合中小规模数据存储
- 表单开发要提前设计数据模型
- 紧急功能需要最高优先级保证
3. 扩展方向:
- 集成健康数据API获取实时身体指标
- 增加紧急定位功能
- 开发家属共享模式
4. 行业价值:
- 为医疗类小程序开发提供参考样板
- 探索了个人健康数据管理新模式
- 验证了小程序在应急场景的实用性
这个项目完整展示了如何利用小程序技术栈开发一个实用的医疗健康应用,从架构设计到具体实现,从性能优化到安全考量,为开发者提供了全面的参考方案。随着小程序能力的不断增强,这类应用将会在移动医疗领域发挥更大价值。
会议邀请函
1 项目创建
本章通过开发一个会议邀请函小程序,重点介绍了微信小程序中位置API的使用方法。项目创建是整个开发过程的第一步,也是基础性工作。
在项目创建环节,开发者需要注意以下几点:
1. 选择空白文件夹作为项目目录,命名为invitationDemo,确保项目结构清晰
2. 使用微信开发者工具创建项目时,需要正确填写AppID(如果有)和项目名称
3. 项目创建完成后会自动生成一些默认文件和目录结构,这些可能需要根据实际需求进行调整
4. 创建项目时要考虑后续的可扩展性和维护性,合理规划目录结构
项目创建完成后,开发者需要手动创建和配置页面文件,为后续开发做好准备。
2 页面配置
2.1 创建页面文件
页面配置是小程序开发的重要环节,合理的页面配置可以提高开发效率和代码可维护性。
在创建页面文件时,需要注意:
1. 小程序根目录下的pages文件夹用于存放所有页面文件
2. 首页通常命名为index,这是小程序运行的第一个页面
3. 其他页面可以根据功能命名,保持命名规范和一致性
4. 在app.json文件中配置页面路径时,需要删除不需要的默认页面(如logs页面)
实际操作步骤包括:
1. 修改app.json文件,删除不必要的页面配置
2. 保存修改,确保配置生效
3. 检查目录结构,确保页面文件组织合理
2.2 删除和修改文件
为了使项目更加简洁高效,需要删除和修改一些默认生成的文件:
1. 删除不必要的文件夹和文件:
- 删除utils工具文件夹(如果不需要)
- 删除默认生成的logs页面目录
- 清理不需要的样式文件和脚本文件
2. 修改关键文件:
- 清空index.wxml和index.wxss文件内容
- 在index.js中使用快捷方式生成Page函数
- 清空app.wxss文件内容
- 在app.js中使用快捷方式生成App函数
这些操作可以通过开发者工具的快捷键和自动补全功能高效完成,如图9-2和图9-3所示。通过精简项目文件,可以使项目结构更加清晰,便于后续开发和维护。
2.3 创建其他文件
除了基本的页面文件外,项目通常还需要其他资源文件:
1. 创建资源文件夹:
- 新建Images文件夹用于存放图片资源
- 在Images下创建子目录(如avatar)分类存放不同类型的图片
2. 添加项目素材:
- 背景图片(如图9-4所示)
- 头像图标(如图9-5所示)
3. 目录结构管理:
- 通过"硬盘打开"方式直接操作文件系统
- 确保图片资源放置在正确目录
- 完成后的目录结构应如图9-6所示清晰有序
合理的资源文件管理对于项目的可维护性和性能优化都很重要,特别是在小程序有包大小限制的情况下。
3 视图设计
3.1 导航栏设计
小程序的导航栏是用户首先看到的界面元素,良好的导航栏设计可以提升用户体验。
导航栏设计要点:
1. 默认导航栏是黑底白字,通常需要自定义样式
2. 在app.json中配置导航栏标题和背景颜色
3. 自定义导航栏效果应如图9-7所示美观协调
配置示例代码:
```json
{
"pages": [
"pages/index/index"
],
"window": {
"navigationBarTitleText": "会议邀请函",
"navigationBarBackgroundColor": "#00B26A"
}
}
```
3.2 页面设计
会议邀请函的页面设计采用垂直滚动布局,分为四个主要区域:
1. 整体布局规划:
- 使用多个`<view>`组件作为容器
- 每个区域定义统一的class='box'样式
- 区域标题使用class='title'样式
- 内容区域使用class='content'样式
2. 组件选择:
- 文本内容使用`<text>`组件
- 图片展示使用`<image>`组件
- 嘉宾列表使用flex布局的`<view>`组件
- 地图展示使用`<map>`组件
- 交互按钮使用`<button>`组件
3. 样式设计:
- 使用rpx单位确保多设备适配
- 定义统一的边框、颜色和间距
- 标题区域使用加粗字体和下划线
- 内容区域设置合适的行高和边距
初始效果如图9-9所示,展示了基本的布局框架和样式效果。
4 逻辑实现
4.1 更新嘉宾列表
动态展示嘉宾列表是提高代码复用性和可维护性的重要实践。
实现步骤:
1. 在JS文件的data中定义嘉宾数组,包含头像路径和姓名
2. 在WXML中使用wx:for循环渲染列表项
3. 为每个列表项设置唯一的wx:key标识
4. 使用flex布局排列头像和姓名
5. 设置头像图片的固定尺寸和间距
关键代码:
```html
<view class="bar" wx:for="{{guest}}" wx:key="guest{{index}}">
<image class="avatar" src="{{item.avatar}}"></image>
<text>{{item.name}}</text>
</view>
```
样式设置:
```css
.bar {
display: flex;
flex-direction: row;
align-items: center;
font-size: 16pt;
}
.avatar {
width: 200rpx;
height: 200rpx;
margin-right: 20rpx;
}
```
更新后的效果如图9-14所示,展示了完整的嘉宾列表。
4.2 更新地图位置
地图功能是本章的核心内容,展示了小程序位置API的基本用法。
实现步骤:
1. 确定会议地点的经纬度坐标(如集美大学)
2. 在JS的data中定义经纬度变量
3. 在WXML中为`<map>`组件绑定经纬度属性
4. 设置地图容器的固定高度
关键代码:
```html
<map latitude="{{lat}}" longitude="{{lon}}"></map>
```
JS数据定义:
```javascript
Page({
data: {
lat: 24.579805,
lon: 118.095086
}
})
```
地图显示效果如图9-15所示,准确定位到指定坐标位置。
### 9.4.3 查看地图详情
通过按钮交互打开全屏地图,展示了小程序与原生地图应用的集成能力。
实现步骤:
1. 为"查看详情"按钮绑定点击事件
2. 在JS中实现事件处理函数
3. 使用wx.openLocation API打开系统地图
4. 传入经纬度参数实现精确定位
关键代码:
```javascript
showGuide: function() {
var that = this
wx.openLocation({
latitude: that.data.lat,
longitude: that.data.lon,
})
}
```
本章总结
本章通过开发会议邀请函小程序,全面介绍了微信小程序位置API的使用方法。主要内容包括:
1. 项目创建和基本配置
2. 页面布局和样式设计
3. 地图组件的集成和使用
4. 位置API的调用和交互实现
关键知识点总结:
- 掌握获取位置、查看位置的接口使用方法
- 熟悉地图组件控制的相关API
- 了解小程序与系统地图应用的交互方式
- 掌握列表渲染和条件渲染等WXML特性
通过本章学习,开发者可以掌握小程序中位置相关功能的开发方法,为开发各类LBS(基于位置服务)应用打下基础。实际开发中,还可以根据需求扩展更多功能,如定位打卡、周边搜索、路线导航等。
指南针
1 项目创建
本章通过开发一个指南针小程序,重点介绍了微信小程序中设备API的使用方法,特别是指南针和位置相关API的应用。项目创建是开发过程的起点,需要做好基础配置工作。
在项目创建环节,开发者需要注意以下要点:
1. 选择空白文件夹作为项目目录,命名为compassDemo,保持项目结构清晰
2. 在微信开发者工具中正确填写项目信息,包括:
- 项目名称:compassDemo
- 项目目录路径
- AppID(可使用测试号)
- 开发模式选择"小程序"
- 后端服务选择"不使用云服务"
3. 了解各种开发模式的区别:
- 小程序云开发提供数据库、存储和云函数等功能
- 腾讯云服务适合更复杂的企业级应用
- 本章项目选择基础的小程序开发模式即可
图10-1展示了小程序项目填写的完整效果示意图,包括所有必填字段和选项。项目创建完成后,需要手动配置页面文件和相关资源,为后续开发做好准备。
2 页面配置
创建页面文件
合理的页面配置是小程序开发的重要基础工作,需要注意以下方面:
1. 页面文件组织:
- 使用pages文件夹存放所有页面文件
- 首页命名为index,作为小程序入口页面
- 单页面应用只需保留首页即可
2. 配置文件修改:
- 在app.json中删除默认生成的logs页面配置
- 确保pages数组中只保留index页面路径
- 注意删除多余的逗号,保持JSON格式正确
3. 操作步骤:
- 修改app.json文件内容
- 使用快捷键保存修改(Ctrl+S)
- 检查目录结构是否符合预期
正确的页面配置可以提高开发效率,减少不必要的文件冗余,使项目结构更加清晰。
2. 删除和修改文件
为了使项目更加精简高效,需要进行以下文件操作:
1. 删除不必要的文件和目录:
- 删除utils工具文件夹(如不需要工具函数)
- 删除默认生成的logs页面目录
- 清理不需要的示例代码和资源
2. 重置关键文件内容:
- 清空index页面的WXML和WXSS文件
- 清空index.js并重新生成Page函数
- 清空app.wxss全局样式文件
- 清空app.js并重新生成App函数
3. 使用开发者工具快捷操作:
- 通过输入关键词快速生成Page和App函数框架
- 如图10-2和图10-3所示使用自动补全功能
- 利用快捷键提高操作效率
通过这些清理和重置操作,可以得到一个干净的项目基础,避免默认生成的代码对开发造成干扰。
3 创建其他文件
除了基本的页面文件外,指南针项目还需要特定的资源文件:
1. 创建资源目录:
- 新建images文件夹存放图片资源
- 通过开发者工具界面或直接操作文件系统创建
2. 添加指南针素材:
- 准备指南针图片(compass.jpg)
- 将图片复制到images目录中
- 确保图片路径和名称正确
3 视图设计
1 导航栏设计
导航栏是小程序的重要视觉元素,良好的设计可以提升用户体验。
导航栏设计要点:
1. 默认样式修改:
- 默认黑底白字通常需要自定义
- 在app.json中统一配置导航栏样式
2. 配置参数:
- navigationBarBackgroundColor:设置背景色(如棕色#A46248)
- navigationBarTitleText:设置标题文本(如"我的指南针")
3. 示例代码:
```json
{
"pages": ["pages/index/index"],
"window": {
"navigationBarBackgroundColor": "#A46248",
"navigationBarTitleText": "我的指南针"
}
}
```
2 页面设计
指南针小程序的页面设计注重简洁和功能性,主要分为图片和文字两个区域。
1. 整体布局设计:
- 使用flex布局实现垂直居中
- 设置容器高度为100vh占满全屏
- 定义主色调与导航栏协调
2. 关键样式:
```css
.container {
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
color: #A46248;
}
```
3. 图片区域设计:
- 使用`<image>`组件显示指南针
- 设置宽度为80%保持适当大小
- 使用mode='widthFix'保持宽高比
4. 文字区域设计:
- 使用flex垂直布局排列文本
- 设置不同字号区分信息层级
- 添加适当外边距保证可读性
初始效果如图10-8和图10-9所示,展示了基本的布局和样式效果。这种简洁的设计使核心功能更加突出,提升用户体验。
4 逻辑实现
1 指南针旋转动画
指南针的核心功能是通过设备方向实现图片旋转效果,关键技术点包括:
1. 旋转实现原理:
- 使用CSS3的transform:rotate()属性
- 通过JS动态计算旋转角度
- 绑定数据到style属性实现动态更新
2. WXML代码:
```html
<image src="/images/compass.jpg"
mode="widthFix"
style="transform:rotate({{rotate}}deg)">
</image>
```
3. JS数据定义:
```javascript
Page({
data: {
rotate: 0 // 初始旋转角度
}
})
```
4. 指南针API使用:
- 使用wx.onCompassChange监听设备方向变化
- 计算旋转角度(360度减去设备方向角度)
- 通过setData更新视图
5. 效果验证:
- 在真机预览旋转效果(如图10-10所示)
- 确保旋转方向与设备实际方向一致
- 检查旋转动画是否流畅
这一功能展示了小程序设备API的强大能力,通过简单的代码即可实现复杂的传感器交互效果。
2 更新角度和方向信息
除了视觉旋转效果,还需要实时显示精确的角度和方向信息。
1. 数据绑定:
- 在WXML中使用双花括号绑定动态数据
- 显示角度值和方向文字
2. 方向判断逻辑:
- 实现getDirection函数处理角度到方向的转换
- 划分8个基本方向区间(北、东北、东等)
- 处理边界条件和默认值
3. 关键代码:
```javascript
getDirection: function(deg) {
let dir = '未知';
if (deg >= 340 || deg <= 20) {
dir = '北';
} else if (deg > 20 && deg < 70) {
dir = '东北';
}
// 其他方向判断...
this.setData({
degree: deg,
direction: dir
});
}
```
3 更新地理位置信息
完整的指南针应用还应该显示当前位置的地理信息。
1. 位置API使用:
- 调用wx.getLocation获取经纬度和海拔
- 设置altitude:true获取海拔高度
- 处理成功和失败回调
2. 数据绑定:
- 在WXML中绑定经纬度和海拔数据
- 格式化显示数值(保留2位小数)
3. 权限配置:
- 在app.json中声明位置权限
- 处理用户授权逻辑
- 提供友好的未授权提示
4. 关键代码:
```javascript
wx.getLocation({
altitude: true,
success: function(res) {
that.setData({
lat: res.latitude.toFixed(2),
lon: res.longitude.toFixed(2),
alt: res.altitude.toFixed(2)
});
}
});
```
本章通过开发指南针小程序,全面介绍了微信小程序设备API的使用方法,特别是方向传感器和位置服务的集成。
关键知识点总结:
1. 设备API的使用:
- 掌握wx.onCompassChange监听设备方向
- 了解wx.getLocation获取位置信息
- 熟悉相关权限配置和注意事项
2. 动画实现技术:
- 使用CSS3变换实现旋转效果
- 通过数据绑定实现动态更新
- 优化性能确保动画流畅
3. 方向判断逻辑:
- 理解角度与方向的对应关系
- 实现精确的方向区间划分
- 处理边界条件和异常情况
4. 位置信息展示:
- 获取并格式化经纬度数据
- 显示海拔高度信息
- 处理位置服务授权流程
通过本章学习,开发者可以掌握小程序中设备相关功能的开发方法,为开发各类传感器交互应用打下基础。这些技术可以扩展到增强现实(AR)、室内导航等更复杂的应用场景中。
手绘时钟
1 项目创建
本章通过开发一个手绘时钟小程序,系统性地介绍了小程序界面API中绘图相关的知识。项目创建从空白文件夹clockDemo开始,通过微信开发者工具新建项目,并准备手动修改页面配置文件。这一步骤是小程序开发的起点,强调了项目结构的初始化和配置的重要性。
2 页面配置
1 创建页面文件
页面配置是小程序开发的基础环节。首先需要在pages文件夹下创建index页面作为程序运行的第一个页面。操作步骤包括:
1. 修改app.json文件,删除默认生成的logs页面配置
2. 保存修改,确保页面路由配置正确
2 删除和修改文件
为了保持项目简洁,需要进行以下清理工作:
1. 删除无用的utils文件夹和logs目录
2. 清空index页面的WXML、WXSS和JS文件内容
3. 使用关键词快速生成Page和App函数框架
4. 清空app.wxss样式文件
这一过程体现了小程序开发中保持项目结构清晰的重要性,为后续开发打下良好基础。
3 视图设计
1 导航栏设计
通过修改app.json文件可以自定义导航栏:
```json
{
"pages": ["pages/index/index"],
"window": {
"navigationBarTitleText": "我的时钟"
}
}
```
这一配置将所有页面的导航栏标题统一设置为"我的时钟",展示了小程序全局配置的便捷性。
2 页面设计
页面采用flex布局实现垂直居中效果,主要包含三个区域:
1. 标题区域:使用`<text>`组件显示"My Clock"
2. 画布区域:使用`<canvas>`组件实现手绘时钟
3. 数字时钟区域:使用`<text>`组件显示数字时间
WXSS样式代码:
```css
.container {
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
}
```
这种布局方式充分利用了flex布局的特性,实现了元素的完美居中和对齐。
4 逻辑实现
1 创建画布上下文
在JS文件的onLoad生命周期函数中创建画布上下文:
```javascript
onLoad: function(options) {
this.ctx = wx.createCanvasContext('clockCanvas')
// 测试代码
this.ctx.fillStyle = 'red'
this.ctx.fillRect(0, 0, 300, 300)
this.ctx.draw()
}
```
这段代码演示了如何获取画布上下文并进行基本绘图操作,为后续复杂绘图奠定基础。
2 绘制时钟刻度
时钟刻度绘制分为小时刻度和分钟刻度:
1. 小时刻度:12个,每个间隔30度(π/6弧度)
2. 分钟刻度:60个,每个间隔6度(π/30弧度)
关键代码:
```javascript
// 设置画布原点为中心点
ctx.translate(width/2, height/2)
// 旋转90度使12点方向朝上
ctx.rotate(-Math.PI/2)
// 绘制小时刻度
ctx.lineWidth = 6
for(let i=0; i<12; i++) {
ctx.beginPath()
ctx.moveTo(100, 0)
ctx.lineTo(120, 0)
ctx.stroke()
ctx.rotate(Math.PI/6)
}
```
这种极坐标系的绘图方式极大地简化了时钟刻度的绘制逻辑。
3 绘制时钟指针
时钟指针绘制需要考虑时针、分针和秒针的不同特性:
1. 时针计算:
```javascript
// 时针角度 = 30°×小时 + 0.5°×分钟 + 0.0083°×秒
ctx.rotate(h Math.PI/6 + m Math.PI/360 + s * Math.PI/21600)
ctx.lineWidth = 12
ctx.beginPath()
ctx.moveTo(-20, 0)
ctx.lineTo(80, 0)
ctx.stroke()
```
2. 分针计算:
```javascript
// 分针角度 = 6°×分钟 + 0.1°×秒
ctx.rotate(m Math.PI/30 + s Math.PI/1800)
ctx.lineWidth = 8
ctx.beginPath()
ctx.moveTo(-15, 0)
ctx.lineTo(105, 0)
ctx.stroke()
```
3. 秒针计算:
```javascript
// 秒针角度 = 6°×秒
ctx.rotate(s * Math.PI/30)
ctx.lineWidth = 4
ctx.beginPath()
ctx.moveTo(-10, 0)
ctx.lineTo(110, 0)
ctx.stroke()
```
这些计算展示了如何将时间转换为角度,并通过旋转画布实现指针指向的正确位置。
4 显示数字电子时钟
在WXML中添加数字时钟显示:
```xml
<text>{{h}}:{{m}}:{{s}}</text>
```
在JS中更新时间数据:
```javascript
getTime: function() {
let now = new Date()
this.setData({
h: now.getHours(),
m: now.getMinutes(),
s: now.getSeconds()
})
}
```
这种数据绑定机制展示了小程序响应式编程的特点。
5 每秒实时更新
使用setInterval实现时钟动画效果:
```javascript
onLoad: function(options) {
// 初始化代码...
this.interval = setInterval(() => {
this.drawClock()
}, 1000)
}
onUnload: function() {
clearInterval(this.interval)
}
```
这种定时器机制确保了时钟的实时更新,同时在页面卸载时清理资源,避免了内存泄漏。
## 总结
本章通过手绘时钟项目的开发,系统性地讲解了小程序绘图API的使用方法,包括:
1. 画布上下文的创建和管理
2. 基本图形和路径的绘制
3. 坐标变换和旋转的应用
4. 定时动画的实现
5. 数据绑定和界面更新
这个项目不仅教授了具体的技术实现,更展示了如何将数学计算与绘图API结合,创造出复杂的动态效果。通过本章的学习,读者可以掌握小程序绘图的核心技术,为开发更复杂的图形应用打下坚实基础。
第四部分——游戏篇
拼图游戏
1 需求分析
本章通过开发拼图游戏小程序,综合运用小程序组件与API,重点实现以下核心功能:
1 首页功能需求
1. 页面结构:包含标题和关卡列表,展示6个关卡选项。
2. 交互设计:点击关卡跳转至对应游戏页面。
3. 视觉呈现:每个关卡显示预览图片和关卡序号(如"第1关")。
2 游戏页功能需求
1. 核心组件:
- 提示图:显示当前关卡原图。
- 游戏画布:使用`<canvas>`组件实现3×3拼图。
- 操作按钮:提供"重新开始"功能。
2. 游戏逻辑:
- 随机打乱拼图方块。
- 支持用户移动方块。
- 实时检测拼图完成状态。
---
2 项目创建
1 项目初始化
- 项目配置:
- 选择空白文件夹`jigsawGame`作为项目目录。
- 填写AppID(测试号或正式号)。
- 开发模式选择"小程序",后端服务选择"不使用云服务"。
- 目录结构:
- 保留`pages/index`(首页)和`pages/game`(游戏页)。
- 删除默认生成的`logs`页面及`utils`工具目录。
---
3 页面配置
1 创建页面文件
1. 修改`app.json`:
```json
{
"pages": ["pages/index/index", "pages/game/game"],
"window": {
"navigationBarBackgroundColor": "#E64340",
"navigationBarTitleText": "拼图游戏"
}
}
```
- 删除`logs`页面路径,添加`game`页面配置。
- 自定义导航栏背景色为珊瑚红(`#E64340`),标题为"拼图游戏"。
2. 清理冗余文件:
- 删除`utils`文件夹及`logs`目录。
- 清空`index`和`game`页面的WXML、WXSS、JS文件内容,并重新生成`Page`和`App`函数框架。
### 12.3.2 创建资源文件夹
- 资源管理:
- 创建`images`文件夹存放关卡图片(如`pic01.jpg`至`pic06.jpg`)。
- 通过"硬盘打开"直接操作文件系统复制素材。
---
4 视图设计
1 导航栏设计
- 自定义导航栏:
- 在`app.json`中配置导航栏背景色与标题。
- 预览效果确保颜色协调(如图12-6)。
2 页面设计
1. 首页设计
- 布局实现:
- 使用`<view class="container">`作为整体容器。
- 标题区域:`<view class="title">游戏选关</view>`。
- 关卡列表:通过`wx:for`循环渲染图片和文本。
- WXML代码片段:
```html
<view class="container">
<view class="title">游戏选关</view>
<view class="levelBox">
<view class="box" wx:for="{{levels}}" wx:key="levels{{index}}" bindtap="chooseLevel" data-level="{{item}}">
<image src="/images/{{item}}"></image>
<text>第{{index + 1}}关</text>
</view>
</view>
</view>
```
- 关键样式:
```css
.container {
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
color: #E64340;
}
.levelBox {
width: 100%;
display: flex;
flex-wrap: wrap;
}
.box {
width: 50%;
margin: 25rpx 0;
text-align: center;
}
```
2. 游戏页设计
- 组件布局:
- 提示图区域:`<image src="{{url}}">`动态绑定图片路径。
- 游戏画布:`<canvas canvas-id="myCanvas" bindtouchstart="touchBox">`支持触摸事件。
- 操作按钮:`<button type="warn" bindtap="restartGame">重新开始</button>`。
- WXSS样式:
```css
canvas {
border: 1rpx solid #E64340;
width: 300px;
height: 300px;
margin: 20rpx auto;
}
```
---
5 逻辑实现
1 首页逻辑
1. 数据绑定:
- 在`index.js`中定义关卡数据:
```javascript
Page({
data: {
levels: ['pic01.jpg', 'pic02.jpg', ..., 'pic06.jpg']
}
})
```
2. 页面跳转:
- 为关卡列表项绑定`chooseLevel`事件,携带图片参数跳转:
```javascript
chooseLevel: function(e) {
const level = e.currentTarget.dataset.level;
wx.navigateTo({ url: ../game/game?level=${level}
});
}
```
2 游戏页逻辑
1. 初始化拼图
- 数据定义:
```javascript
let num = [['00', '01', '02'], ['10', '11', '12'], ['20', '21', '22']];
let w = 100; // 方块宽度
let url = '/images/pic01.jpg'; // 初始图片路径
```
- 随机打乱算法:
- 通过移动空白方块(初始位置为`num[2][2]`)实现可解的打乱逻辑:
```javascript
shuffle: function() {
let row = 2, col = 2;
for (let i = 0; i < 100; i++) {
const direction = Math.floor(Math.random() * 4);
// 根据方向交换空白方块与相邻方块
}
}
```
2. 绘制画布
- 使用`<canvas>`绘制拼图:
```javascript
drawCanvas: function() {
const ctx = this.ctx;
ctx.clearRect(0, 0, 300, 300);
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (num[i][j] !== '22') {
const row = parseInt(num[i][j] / 10);
const col = num[i][j] % 10;
ctx.drawImage(url, col w, row w, w, w, j w, i w, w, w);
}
}
}
ctx.draw();
}
```
3. 用户交互
- 触摸事件处理:
```javascript
touchBox: function(e) {
if (this.data.isWin) return;
const x = e.touches[0].x, y = e.touches[0].y;
const row = Math.floor(y / w), col = Math.floor(x / w);
if (num[row][col] === '22') return;
this.moveBox(row, col); // 移动方块
this.drawCanvas();
if (this.isWin()) {
// 绘制"游戏成功"提示
}
}
```
4. 游戏状态检测
- 判断胜利条件:
```javascript
isWin: function() {
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (num[i][j] !== ${i}${j}
) return false;
}
}
this.setData({ isWin: true });
return true;
}
```
5. 重新开始功能
- 重置游戏状态:
```javascript
restartGame: function() {
this.setData({ isWin: false });
this.shuffle();
this.drawCanvas();
}
```
推箱子游戏
1 需求分析
1 首页功能需求
1. 页面结构:
- 显示标题和4个及以上关卡列表。
- 每个关卡包含预览图片和序号(如“第1关”)。
2. 交互设计:
- 点击关卡跳转至对应游戏页面。
2 游戏页功能需求
1. 核心组件:
- 游戏画布(`<canvas>`组件):显示8×6的网格地图,包含围墙、地板、箱子、角色和目的地。
- 方向键:控制角色移动。
- 状态显示:当前关卡标题。
- 操作按钮:“重新开始”按钮。
2. 核心逻辑:
- 角色通过方向键移动并推动箱子。
- 所有箱子到达目的地时判定胜利。
- 点击“重新开始”按钮重置游戏。
---
2 项目创建
1 项目初始化
- 项目配置:
- 创建空白文件夹`boxGame`。
- 填写AppID(测试号或正式号)。
- 开发模式选择“小程序”,后端服务选择“不使用云服务”。
- 目录结构:
- 保留`pages/index`(首页)和`pages/game`(游戏页)。
- 删除默认生成的`logs`页面及`utils`工具目录。
---
3 页面配置
1 创建页面文件
1. 修改`app.json`:
```json
{
"pages": ["pages/index/index", "pages/game/game"],
"window": {
"navigationBarBackgroundColor": "#E64340",
"navigationBarTitleText": "推箱子游戏"
}
}
```
- 删除`logs`页面路径,添加`game`页面配置。
- 自定义导航栏背景色为珊瑚红(`#E64340`),标题为“推箱子游戏”。
2. 清理冗余文件:
- 删除`utils`文件夹及`logs`目录。
- 清空`index`和`game`页面的WXML、WXSS、JS文件内容,并重新生成`Page`和`App`函数框架。
### 13.3.2 创建资源文件夹
- 资源管理:
- 创建`images`文件夹存放关卡图片(如`level01.png`)和游戏图标(围墙、箱子等)。
- 创建`utils/data.js`存放公共地图数据。
---
4 视图设计
1 导航栏设计
- 自定义导航栏:
- 在`app.json`中配置导航栏背景色与标题。
- 预览效果确保颜色协调(如图13-8)。
2 页面设计
1. 首页设计
- 布局实现:
- 使用`<view class="container">`作为整体容器。
- 标题区域:`<view class="title">游戏选关</view>`。
- 关卡列表:通过`wx:for`循环渲染图片和文本。
- WXML代码片段:
```html
<view class="container">
<view class="title">游戏选关</view>
<view class="levelBox">
<view class="box" wx:for="{{levels}}" wx:key="levels{{index}}" bindtap="chooseLevel" data-level="{{index}}">
<image src="/images/{{item.image}}"></image>
<text>第{{index + 1}}关</text>
</view>
</view>
</view>
```
- 关键样式:
```css
.container {
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
color: #E64340;
}
.levelBox {
width: 100%;
display: flex;
flex-wrap: wrap;
}
.box {
width: 50%;
margin: 20rpx 0;
text-align: center;
}
```
2. 游戏页设计
- 组件布局:
- 关卡标题:`<view class="title">第{{currentLevel + 1}}关</view>`。
- 游戏画布:`<canvas canvas-id="myCanvas"></canvas>`。
- 方向键:使用`<button>`组件模拟上下左右操作。
- 操作按钮:`<button type="warn" bindtap="restartGame">重新开始</button>`。
- WXSS样式:
```css
canvas {
border: 1rpx solid #E64340;
width: 320px;
height: 320px;
margin: 20rpx auto;
}
.btnBox {
display: flex;
flex-direction: column;
align-items: center;
}
.btnBox button {
width: 90rpx;
height: 90rpx;
margin: 10rpx;
}
```
---
5 逻辑实现
1 公共逻辑
1. 地图数据定义(`utils/data.js`):
```javascript
// 地图编码规则:0-围墙外围,1-围墙,2-地板,3-终点,4-箱子,5-角色
const mapData = [
// 第1关
[
[1,1,1,1,1,1,1,1],
[1,2,2,2,2,2,2,1],
[1,2,3,4,2,5,2,1],
[1,2,2,2,2,2,2,1],
[1,1,1,1,1,1,1,1]
],
// 第2关及其他关卡...
];
export { mapData };
```
2 首页逻辑
1. 数据绑定:
- 在`index.js`中定义关卡数据:
```javascript
Page({
data: {
levels: [
{ image: "level01.png" },
{ image: "level02.png" },
// 其他关卡...
]
}
});
```
2. 页面跳转:
- 为关卡列表项绑定`chooseLevel`事件,传递关卡索引:
```javascript
chooseLevel: function(e) {
const level = e.currentTarget.dataset.level;
wx.navigateTo({ url: ../game/game?level=${level}
});
}
```
3 游戏页逻辑
1. 初始化游戏
- 加载地图数据:
```javascript
const { mapData } = require('../../utils/data.js');
let currentMap = [];
let playerPos = { x: 0, y: 0 }; // 角色初始位置
let boxes = []; // 箱子位置数组
Page({
onLoad: function(options) {
const level = parseInt(options.level);
currentMap = mapData[level];
this.initGame(currentMap);
this.drawCanvas();
}
});
```
- 初始化角色和箱子:
```javascript
initGame: function(map) {
for (let i = 0; i < map.length; i++) {
for (let j = 0; j < map[i].length; j++) {
if (map[i][j] === 5) {
playerPos = { x: j, y: i };
} else if (map[i][j] === 4) {
boxes.push({ x: j, y: i });
}
}
}
}
```
2. 绘制画布
- 使用`<canvas>`渲染地图:
```javascript
drawCanvas: function() {
const ctx = wx.createCanvasContext('myCanvas');
const tileSize = 40; // 每个方块的尺寸
for (let i = 0; i < currentMap.length; i++) {
for (let j = 0; j < currentMap[i].length; j++) {
switch (currentMap[i][j]) {
case 1: // 围墙
ctx.drawImage('/images/wall.png', j tileSize, i tileSize, tileSize, tileSize);
break;
case 3: // 终点
ctx.drawImage('/images/target.png', j tileSize, i tileSize, tileSize, tileSize);
break;
// 其他类型...
}
}
}
// 绘制角色和箱子
ctx.drawImage('/images/player.png', playerPos.x tileSize, playerPos.y tileSize, tileSize, tileSize);
boxes.forEach(box => {
ctx.drawImage('/images/box.png', box.x tileSize, box.y tileSize, tileSize, tileSize);
});
ctx.draw();
}
```
3. 角色移动逻辑
- 方向键事件处理:
```javascript
handleMove: function(direction) {
let dx = 0, dy = 0;
switch (direction) {
case 'up': dy = -1; break;
case 'down': dy = 1; break;
case 'left': dx = -1; break;
case 'right': dx = 1; break;
}
const newX = playerPos.x + dx;
const newY = playerPos.y + dy;
// 检测碰撞逻辑
if (this.canMove(newX, newY)) {
playerPos.x = newX;
playerPos.y = newY;
this.drawCanvas();
this.checkWin();
}
}
```
- 碰撞检测:
```javascript
canMove: function(x, y) {
if (currentMap[y][x] === 1) return false; // 撞墙
const boxIndex = boxes.findIndex(b => b.x === x && b.y === y);
if (boxIndex !== -1) {
const nextBoxX = x + (x - playerPos.x);
const nextBoxY = y + (y - playerPos.y);
if (currentMap[nextBoxY][nextBoxX] !== 1 && !boxes.some(b => b.x === nextBoxX && b.y === nextBoxY)) {
boxes[boxIndex] = { x: nextBoxX, y: nextBoxY };
return true;
}
return false;
}
return true;
}
```
4. 胜利条件检测
- 判断所有箱子是否到达终点:
```javascript
checkWin: function() {
const isWin = boxes.every(box => currentMap[box.y][box.x] === 3);
if (isWin) {
wx.showToast({ title: '通关成功!' });
}
}
```
5. 重新开始功能
贪吃蛇游戏
1 需求分析
1. 页面结构:
- 显示标题和4个及以上关卡列表。
- 每个关卡包含预览图片和序号(如“第1关”)。
2. 交互设计:
- 点击关卡跳转至对应游戏页面。
### 13.1.2 游戏页功能需求
1. 核心组件:
- 游戏画布(`<canvas>`组件):显示8×6的网格地图,包含围墙、地板、箱子、角色和目的地。
- 方向键:控制角色移动。
- 状态显示:当前关卡标题。
- 操作按钮:“重新开始”按钮。
2. 核心逻辑:
- 角色通过方向键移动并推动箱子。
- 所有箱子到达目的地时判定胜利。
- 点击“重新开始”按钮重置游戏。
---
2 项目创建
- 项目配置:
- 创建空白文件夹`boxGame`。
- 填写AppID(测试号或正式号)。
- 开发模式选择“小程序”,后端服务选择“不使用云服务”。
- 目录结构:
- 保留`pages/index`(首页)和`pages/game`(游戏页)。
- 删除默认生成的`logs`页面及`utils`工具目录。
---
3 页面配置
1. 修改`app.json`:
```json
{
"pages": ["pages/index/index", "pages/game/game"],
"window": {
"navigationBarBackgroundColor": "#E64340",
"navigationBarTitleText": "推箱子游戏"
}
}
```
- 删除`logs`页面路径,添加`game`页面配置。
- 自定义导航栏背景色为珊瑚红(`#E64340`),标题为“推箱子游戏”。
2. 清理冗余文件:
- 删除`utils`文件夹及`logs`目录。
- 清空`index`和`game`页面的WXML、WXSS、JS文件内容,并重新生成`Page`和`App`函数框架。
- 资源管理:
- 创建`images`文件夹存放关卡图片(如`level01.png`)和游戏图标(围墙、箱子等)。
- 创建`utils/data.js`存放公共地图数据。
---
4 视图设计
- 自定义导航栏:
- 在`app.json`中配置导航栏背景色与标题。
- 预览效果确保颜色协调(如图13-8)。
首页设计
- 布局实现:
- 使用`<view class="container">`作为整体容器。
- 标题区域:`<view class="title">游戏选关</view>`。
- 关卡列表:通过`wx:for`循环渲染图片和文本。
- WXML代码片段:
```html
<view class="container">
<view class="title">游戏选关</view>
<view class="levelBox">
<view class="box" wx:for="{{levels}}" wx:key="levels{{index}}" bindtap="chooseLevel" data-level="{{index}}">
<image src="/images/{{item.image}}"></image>
<text>第{{index + 1}}关</text>
</view>
</view>
</view>
```
- 关键样式:
```css
.container {
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
color: #E64340;
}
.levelBox {
width: 100%;
display: flex;
flex-wrap: wrap;
}
.box {
width: 50%;
margin: 20rpx 0;
text-align: center;
}
```
游戏页设计
- 组件布局:
- 关卡标题:`<view class="title">第{{currentLevel + 1}}关</view>`。
- 游戏画布:`<canvas canvas-id="myCanvas"></canvas>`。
- 方向键:使用`<button>`组件模拟上下左右操作。
- 操作按钮:`<button type="warn" bindtap="restartGame">重新开始</button>`。
- WXSS样式:
```css
canvas {
border: 1rpx solid #E64340;
width: 320px;
height: 320px;
margin: 20rpx auto;
}
.btnBox {
display: flex;
flex-direction: column;
align-items: center;
}
.btnBox button {
width: 90rpx;
height: 90rpx;
margin: 10rpx;
}
```
---
5 逻辑实现
1. 地图数据定义(`utils/data.js`):
```javascript
// 地图编码规则:0-围墙外围,1-围墙,2-地板,3-终点,4-箱子,5-角色
const mapData = [
// 第1关
[
[1,1,1,1,1,1,1,1],
[1,2,2,2,2,2,2,1],
[1,2,3,4,2,5,2,1],
[1,2,2,2,2,2,2,1],
[1,1,1,1,1,1,1,1]
],
// 第2关及其他关卡...
];
export { mapData };
```
2 首页逻辑
1. 数据绑定:
- 在`index.js`中定义关卡数据:
```javascript
Page({
data: {
levels: [
{ image: "level01.png" },
{ image: "level02.png" },
// 其他关卡...
]
}
});
```
2. 页面跳转:
- 为关卡列表项绑定`chooseLevel`事件,传递关卡索引:
```javascript
chooseLevel: function(e) {
const level = e.currentTarget.dataset.level;
wx.navigateTo({ url: ../game/game?level=${level}
});
}
```
3 游戏页逻辑
1. 初始化游戏
- 加载地图数据:
```javascript
const { mapData } = require('../../utils/data.js');
let currentMap = [];
let playerPos = { x: 0, y: 0 }; // 角色初始位置
let boxes = []; // 箱子位置数组
Page({
onLoad: function(options) {
const level = parseInt(options.level);
currentMap = mapData[level];
this.initGame(currentMap);
this.drawCanvas();
}
});
```
- 初始化角色和箱子:
```javascript
initGame: function(map) {
for (let i = 0; i < map.length; i++) {
for (let j = 0; j < map[i].length; j++) {
if (map[i][j] === 5) {
playerPos = { x: j, y: i };
} else if (map[i][j] === 4) {
boxes.push({ x: j, y: i });
}
}
}
}
```
2. 绘制画布
- 使用`<canvas>`渲染地图:
```javascript
drawCanvas: function() {
const ctx = wx.createCanvasContext('myCanvas');
const tileSize = 40; // 每个方块的尺寸
for (let i = 0; i < currentMap.length; i++) {
for (let j = 0; j < currentMap[i].length; j++) {
switch (currentMap[i][j]) {
case 1: // 围墙
ctx.drawImage('/images/wall.png', j tileSize, i tileSize, tileSize, tileSize);
break;
case 3: // 终点
ctx.drawImage('/images/target.png', j tileSize, i tileSize, tileSize, tileSize);
break;
// 其他类型...
}
}
}
// 绘制角色和箱子
ctx.drawImage('/images/player.png', playerPos.x tileSize, playerPos.y tileSize, tileSize, tileSize);
boxes.forEach(box => {
ctx.drawImage('/images/box.png', box.x tileSize, box.y tileSize, tileSize, tileSize);
});
ctx.draw();
}
```
3. 角色移动逻辑
- 方向键事件处理:
```javascript
handleMove: function(direction) {
let dx = 0, dy = 0;
switch (direction) {
case 'up': dy = -1; break;
case 'down': dy = 1; break;
case 'left': dx = -1; break;
case 'right': dx = 1; break;
}
const newX = playerPos.x + dx;
const newY = playerPos.y + dy;
// 检测碰撞逻辑
if (this.canMove(newX, newY)) {
playerPos.x = newX;
playerPos.y = newY;
this.drawCanvas();
this.checkWin();
}
}
```
- 碰撞检测:
```javascript
canMove: function(x, y) {
if (currentMap[y][x] === 1) return false; // 撞墙
const boxIndex = boxes.findIndex(b => b.x === x && b.y === y);
if (boxIndex !== -1) {
const nextBoxX = x + (x - playerPos.x);
const nextBoxY = y + (y - playerPos.y);
if (currentMap[nextBoxY][nextBoxX] !== 1 && !boxes.some(b => b.x === nextBoxX && b.y === nextBoxY)) {
boxes[boxIndex] = { x: nextBoxX, y: nextBoxY };
return true;
}
return false;
}
return true;
}
```
4. 胜利条件检测
- 判断所有箱子是否到达终点:
```javascript
checkWin: function() {
const isWin = boxes.every(box => currentMap[box.y][box.x] === 3);
if (isWin) {
wx.showToast({ title: '通关成功!' });
}
}
```
5. 重新开始功能
第五部分——提高篇
基于模拟数据的高效新闻稿
15.1 需求分析
1. 首页功能需求:
- 展示新闻分类导航栏和新闻列表。
- 支持下拉刷新和上拉加载更多。
- 点击新闻项跳转至详情页。
2. 新闻页功能需求:
- 显示新闻标题、发布时间、正文内容和相关图片。
- 提供返回首页和分享功能。
3. 个人中心页功能需求:
- 显示用户基本信息。
- 提供浏览历史记录和收藏功能。
15.2 项目创建与配置
1. 项目初始化:
- 创建空白项目`universityNews`。
- 配置`app.json`设置导航栏和tabBar样式。
2. 页面结构:
- 首页:`pages/index/index`
- 新闻页:`pages/news/news`
- 个人中心:`pages/user/user`
3. 数据模拟:
- 在`utils/data.js`中定义模拟新闻数据。
15.3 视图设计
1. 导航栏设计:
- 首页导航栏显示"高校新闻网"。
- 新闻页显示新闻标题。
2. tabBar设计:
- 底部tabBar包含首页、发现和个人中心三个选项。
3. 页面布局:
- 首页使用`scroll-view`展示新闻列表。
- 新闻页使用富文本组件`rich-text`显示内容。
15.4 逻辑实现
1. 数据加载:
- 首页通过`onLoad`和`onReachBottom`实现分页加载。
- 新闻页通过URL参数获取新闻ID并显示对应内容。
2. 交互功能:
- 实现新闻收藏和历史记录功能。
- 添加分享按钮配置。
15.5 项目总结
1. 技术要点:
- 掌握模拟数据的使用方法。
- 熟悉页面间传参和组件通信。
基于WAMP的高校新闻网
16.1 项目初始化
1. 后端环境搭建:
- 配置WAMP服务器(Windows+Apache+MySQL+PHP)。
- 创建新闻数据库表结构。
2. API接口设计:
- 新闻列表接口:`/api/news/list`
- 新闻详情接口:`/api/news/detail`
16.2 前端改造
1. 网络请求封装:
- 使用`wx.request`封装HTTP请求方法。
- 添加请求拦截器处理错误。
2. 首页优化:
- 实现真实的网络数据加载。
- 添加加载状态提示。
3. 新闻页改造:
- 从服务器获取新闻详情内容。
- 实现图片懒加载。
16.3 前后端联调
1. 跨域问题解决:
- 配置Apache允许跨域请求。
- 使用JSONP或代理解决开发环境问题。
2. 性能优化:
- 添加数据缓存机制。
- 实现图片压缩和CDN加速。
16.4 项目总结
1. 全栈开发流程:
- 掌握前后端分离开发模式。
- 学习RESTful API设计规范。
2. 部署要点:
- 服务器环境配置注意事项。
- 数据库备份与恢复方法。
基于云数据库的高校新闻网
17.1 云开发基础
1. 云开发能力:
- 云数据库:JSON文档型数据库。
- 云存储:文件存储服务。
- 云函数:服务器端逻辑。
2. 项目迁移:
- 将本地项目转为云开发模板。
- 初始化云开发环境。
17.2 数据库设计
1. 集合设计:
- news
集合:存储新闻数据。
- users
集合:存储用户信息。
2. 安全规则:
- 配置读写权限控制。
- 设置字段级权限。
17.3 功能实现
1. 首页改造:
- 使用云数据库查询新闻列表。
- 实现触底自动加载。
2. 新闻页优化:
- 通过云函数获取新闻详情。
- 添加阅读量统计功能。
17.4 项目总结
1. 云开发优势:
- 无需管理服务器基础设施。
- 快速实现前后端一体化开发。
2. 注意事项:
- 云数据库查询性能优化。
- 云函数冷启动问题解决。
基于云存储的电子书橱
18.1 项目初始化
1. 云资源部署:
- 创建云存储bucket存放电子书文件。
- 设计书籍数据库结构。
2. 权限配置:
- 设置云存储下载权限。
- 配置数据库安全规则。
18.2 核心功能实现
1. 图书列表:
- 分页加载图书数据。
- 实现搜索和筛选功能。
2. 阅读功能:
- 使用云存储文件ID获取临时链接。
- 集成PDF阅读器组件。
18.3 性能优化
1. 缓存策略:
- 实现书籍封面图缓存。
- 使用本地缓存记录阅读进度。
2. 安全防护:
- 添加用户权限验证。
- 防止恶意刷量下载。
18.4 项目总结
1. 技术亮点:
- 云存储大文件处理方案。
- 在线阅读体验优化。
2. 扩展方向:
- 添加书签和笔记功能。
- 实现社交分享能力。
第六部分——综合篇
基于Vant Weapp的生日管家
19.1 项目架构与初始化
1. 云开发环境搭建:
- 创建云开发模板项目,开通云开发服务
- 初始化云数据库,设计`users`、`photos`、`comments`集合
- 配置云存储权限,设置图片上传规则
2. 页面结构规划:
- 首页:图片瀑布流展示
- 上传页:多图选择与上传功能
- 个人中心:用户信息管理
- 详情页:图片评论与互动
3. 技术选型:
- 使用云数据库实现实时数据同步
- 云存储管理用户上传的图片资源
- 云函数处理敏感操作(如删除校验)
19.2 核心功能实现
1. 图片上传流程:
```javascript
wx.chooseImage({
success: (res) => {
const filePath = res.tempFilePaths[0]
const cloudPath = photos/${Date.now()}-${Math.random()}.jpg
wx.cloud.uploadFile({
cloudPath,
filePath,
success: (res) => {
// 写入数据库记录
}
})
}
})
```
2. 实时数据同步:
- 使用数据库watch实现新图片自动加载
- 云函数触发器处理点赞数统计
3. 安全防护:
- 配置数据库安全规则限制非授权访问
- 使用云函数进行内容安全检测
19.3 性能优化实践
1. 图片处理方案:
- 前端压缩:使用`quality`参数控制上传质量
- 云端处理:通过云函数生成缩略图
- CDN加速:配置自定义域名提升加载速度
2. 数据分页策略:
- 基于游标的分页查询
- 虚拟列表优化长列表渲染
3. 异常处理机制:
- 网络重试策略
- 失败图片上传队列管理
19.4 项目总结与扩展
1. 云开发最佳实践:
- 掌握云数据库的索引优化技巧
- 学习云函数冷启动优化方案
2. 社交功能扩展:
- 实现关注/粉丝系统
- 添加私信功能
- 开发热门推荐算法
基于全套云能力的图片分享社区
20.1 技术准备
1. 组件库引入:
- 通过npm安装Vant Weapp
- 配置app.json启用自定义组件
```json
{
"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
}
```
2. 核心组件应用:
- 表单组件:van-field、van-picker
- 展示组件:van-card、van-tag
- 交互组件:van-dialog、van-toast
3. 主题定制:
- 修改CSS变量实现品牌色适配
- 配置组件默认props减少重复代码
20.2 功能模块实现
1. 好友信息管理:
- 日期选择器实现生日提醒
```html
<van-field
label="生日"
readonly
clickable
value="{{ birthday }}"
placeholder="选择生日"
bind:click="showCalendar"
/>
<van-calendar
show="{{ show }}"
bind:close="onClose"
bind:confirm="onConfirm"
/>
```
2. 首页交互设计:
- 滑动单元格实现快捷操作
- 徽标数字显示即将过生日好友
3. 数据同步策略:
- 本地缓存+云数据库双写
- 冲突解决策略设计
### 20.3 性能与体验优化
1. 渲染性能:
- 使用虚拟列表优化长列表
- 按需加载非可视区域组件
2. 交互体验:
- 添加骨架屏减少等待焦虑
- 表单提交防抖处理
3. 多端适配:
- 响应式布局方案
- 设备API差异处理
20.4 项目总结
1. 组件化开发心得:
- 业务组件与基础组件划分原则
- 组件通信方案对比(properties vs 事件总线)
2. 扩展方向:
- 接入微信运动数据推算年龄
- 礼物推荐电商功能整合
- 纪念日倒数提醒功能
综合技术对比分析
1. 云开发与传统开发对比:
| 维度 | 云开发方案 | 传统开发方案 |
|-----------|-----------------|----------------|
| 部署成本 | 无需服务器运维 | 需要自建服务器 |
| 开发效率 | 快速集成云服务 | 需要前后端协作开发 |
| 扩展性 | 受限于云平台能力 | 可自由扩展架构 |
| 适合场景 | 快速验证型项目 | 复杂企业级应用 |
2. UI组件库选型建议:
- Vant Weapp:适合电商类项目,组件丰富
- WeUI:官方风格,适合工具类小程序
- MinUI:轻量级,适合性能敏感场景
3. 性能优化体系:
```mermaid
graph TD
A[启动优化] --> B[分包加载]
A --> C[按需注入]
D[渲染优化] --> E[虚拟列表]
D --> F[骨架屏]
G[网络优化] --> H[数据预取]
G --> I[智能缓存]
```
4. 进阶学习路径:
- 深入理解小程序底层原理(双线程模型)
- 学习跨平台解决方案(Taro、Uniapp)
- 掌握TypeScript增强开发体验
- 研究小程序自动化测试方案