移动端
一、小程序基础
1. 小程序概述与特点
问题:小程序的作用是什么?小程序的特点是什么?小程序与 H5 的区别是什么?小程序与 App 的区别是什么?小程序的应用场景有哪些?
答案:
小程序定义:小程序是一种运行在特定平台(如微信、支付宝、百度等)内部的轻量级应用程序,无需下载安装即可使用,实现了"触手可及、用完即走"的理念。
小程序的作用:
- 轻量化服务:提供核心功能,无需完整App的复杂功能
- 降低获取成本:用户无需下载安装,扫码或搜索即可使用
- 提升转化率:缩短用户路径,提高业务转化效率
- 平台生态整合:与平台能力深度整合(支付、分享、社交等)
- 跨平台一致性:在不同设备上提供一致体验
小程序的特点:
- 无需安装:直接在平台内运行,不占用设备存储
- 即用即走:使用后不留痕迹,可随时再次访问
- 开发成本低:相比原生App,开发和维护成本更低
- 跨平台:一次开发,多平台运行(理论上)
- 体验接近原生:使用平台提供的组件和API,体验流畅
- 获客门槛低:可通过扫码、搜索、分享等快速获客
- 审核快速:相比App Store,审核周期更短
小程序 vs H5 对比表:
| 对比项 | 小程序 | H5网页 |
|---|---|---|
| 运行环境 | 平台提供的沙箱环境 | 浏览器环境 |
| 技术栈 | WXML、WXSS、JS(平台特定) | HTML、CSS、JavaScript(标准) |
| 性能体验 | 接近原生,加载快 | 依赖网络,性能较差 |
| 系统权限 | 可调用部分系统能力(需授权) | 能力受限,依赖浏览器API |
| 发布方式 | 平台审核后发布 | 直接部署到服务器 |
| 更新机制 | 版本更新需审核 | 实时更新,无需审核 |
| 存储能力 | 本地存储(平台提供) | Cookie、LocalStorage等 |
| 分享能力 | 深度整合平台分享 | 依赖浏览器的分享能力 |
| 入口场景 | 扫码、搜索、分享、历史列表等 | URL链接、二维码等 |
| 网络请求 | 平台封装的安全请求 | 标准HTTP/HTTPS请求 |
小程序 vs App 对比表:
| 对比项 | 小程序 | 原生App |
|---|---|---|
| 安装方式 | 无需安装,即用即走 | 需要下载安装包 |
| 占用空间 | 无需下载,缓存小 | 下载安装,占用存储空间 |
| 开发成本 | 较低(一套代码多平台) | 较高(需多平台开发) |
| 开发周期 | 较短 | 较长 |
| 性能体验 | 接近原生,但有限制 | 最优,可充分调用系统能力 |
| 功能完整性 | 受限(平台限制) | 完整,可调用所有系统API |
| 用户粘性 | 较低(用完即走) | 较高(占桌面入口) |
| 推送能力 | 受限(模板消息) | 完整推送(可实时推送) |
| 审核机制 | 平台审核(较快) | 应用商店审核(较严) |
| 更新方式 | 后台更新,用户无感知 | 需要用户主动更新 |
小程序应用场景:
- 工具类:计算器、翻译、天气查询等轻量工具
- 电商类:商品展示、购物车、订单管理
- 服务类:预约、点餐、票务预订
- 资讯类:新闻阅读、内容聚合
- 社交类:社区、论坛、小游戏
- 企业服务:CRM、内部办公、数据展示
- 生活服务:缴费、出行、政务办理
微信小程序特点补充:
- 微信生态整合:与微信支付、微信登录、微信分享深度整合
- 社交传播能力强:可通过微信群、朋友圈快速传播
- 用户基数大:依托微信10亿+用户
- 开发工具完善:官方提供完整的开发工具链
- 文档和社区成熟:官方文档齐全,社区活跃
二、微信小程序架构
2. 小程序框架与目录结构
问题:什么是微信小程序?微信小程序的目录结构是什么?微信小程序的配置文件有哪些?app.json、app.js、app.wxss 的配置是什么?小程序的框架是什么?小程序的 MVVM 模式是什么?
答案:
微信小程序定义:微信小程序是运行在微信内部的应用,基于微信提供的框架和API进行开发,具有独立的运行环境和沙盒机制。
微信小程序目录结构:
project-name/
├── pages/ # 页面目录
│ ├── index/ # 首页
│ │ ├── index.js # 页面逻辑
│ │ ├── index.json # 页面配置
│ │ ├── index.wxml # 页面结构
│ │ └── index.wxss # 页面样式
│ └── logs/ # 日志页
├── utils/ # 工具类目录
│ └── util.js # 工具函数
├── app.js # 应用逻辑
├── app.json # 应用配置
├── app.wxss # 应用全局样式
├── project.config.json # 项目配置
└── sitemap.json # 站点地图配置
配置文件详解:
1. app.json(应用配置):
{
"pages": [
"pages/index/index",
"pages/logs/logs",
"pages/user/user"
],
"window": {
"navigationBarTitleText": "我的小程序",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f8f8f8",
"backgroundTextStyle": "light",
"enablePullDownRefresh": true
},
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "images/home.png",
"selectedIconPath": "images/home-active.png"
},
{
"pagePath": "pages/user/user",
"text": "我的",
"iconPath": "images/user.png",
"selectedIconPath": "images/user-active.png"
}
],
"color": "#999999",
"selectedColor": "#FF0000",
"backgroundColor": "#ffffff",
"borderStyle": "black"
},
"networkTimeout": {
"request": 10000,
"connectSocket": 10000,
"uploadFile": 10000,
"downloadFile": 10000
},
"debug": true,
"functionalPages": true,
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/cat/cat",
"pages/dog/dog"
]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["packageA"]
}
}
}
app.json 配置字段说明:
- pages:页面路径列表,第一个页面为小程序的首页
- window:全局窗口配置(导航栏、背景色等)
- tabBar:底部/顶部tab栏配置
- networkTimeout:网络请求超时时间
- debug:是否开启调试模式
- functionalPages:是否启用功能页
- subpackages:分包配置,用于代码分包加载
- preloadRule:分包预下载规则
2. app.js(应用逻辑):
// app.js
App({
// 小程序初始化时执行,全局只触发一次
onLaunch(options) {
console.log('小程序初始化', options);
// 获取用户信息
wx.getUserInfo({
success: res => {
this.globalData.userInfo = res.userInfo;
}
});
// 检查更新
if (wx.canIUse('getUpdateManager')) {
const updateManager = wx.getUpdateManager();
updateManager.onCheckForUpdate(res => {
if (res.hasUpdate) {
console.log('检测到新版本');
}
});
}
},
// 小程序显示时执行(从后台进入前台)
onShow(options) {
console.log('小程序显示', options);
},
// 小程序隐藏时执行(从前台进入后台)
onHide() {
console.log('小程序隐藏');
},
// 小程序发生脚本错误时执行
onError(error) {
console.error('小程序错误', error);
},
// 全局数据
globalData: {
userInfo: null,
token: '',
appVersion: '1.0.0'
},
// 自定义全局方法
login() {
return new Promise((resolve, reject) => {
wx.login({
success: res => {
if (res.code) {
// 发送code到服务器换取openid和session_key
resolve(res.code);
} else {
reject(res.errMsg);
}
},
fail: reject
});
});
}
});
3. app.wxss(全局样式):
/* app.wxss - 全局样式 */
page {
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
font-size: 32rpx;
color: #333;
background-color: #f8f8f8;
}
/* 文本样式 */
.text-primary {
color: #576b95;
}
.text-success {
color: #09bb07;
}
.text-warning {
color: #e64340;
}
/* 布局样式 */
.flex-row {
display: flex;
flex-direction: row;
}
.flex-column {
display: flex;
flex-direction: column;
}
.flex-center {
display: flex;
justify-content: center;
align-items: center;
}
/* 边距样式 */
.mt-10 {
margin-top: 10rpx;
}
.mb-10 {
margin-bottom: 10rpx;
}
.ml-10 {
margin-left: 10rpx;
}
.mr-10 {
margin-right: 10rpx;
}
/* 按钮样式 */
.btn {
padding: 20rpx 40rpx;
border-radius: 8rpx;
text-align: center;
font-size: 32rpx;
}
.btn-primary {
background-color: #07c160;
color: #fff;
}
.btn-disabled {
background-color: #cccccc;
color: #ffffff;
}
小程序框架: 微信小程序采用 MVVM(Model-View-ViewModel) 架构模式:
MVVM 组件关系:
- Model(模型):数据层,对应小程序中的data对象和服务器数据
- View(视图):界面层,对应WXML模板,负责UI展示
- ViewModel(视图模型):逻辑层,对应小程序Page对象,负责数据绑定和事件处理
MVVM 数据流:
- 数据绑定:View通过数据绑定显示Model中的数据
- DOM监听:View中的用户操作触发事件,通知ViewModel
- 数据更新:ViewModel更新Model,Model的变化自动同步到View
小程序 MVVM 实现:
// page.js - ViewModel
Page({
// Model数据
data: {
message: 'Hello World',
items: ['Apple', 'Banana', 'Orange'],
user: {
name: '张三',
age: 25
},
count: 0
},
// 事件处理函数
onTapButton() {
// 更新Model数据
this.setData({
count: this.data.count + 1
});
},
onInputChange(e) {
this.setData({
message: e.detail.value
});
}
});
<!-- page.wxml - View -->
<view class="container">
<!-- 数据绑定 -->
<text>{{message}}</text>
<!-- 列表渲染 -->
<view wx:for="{{items}}" wx:key="index">
{{index + 1}}. {{item}}
</view>
<!-- 条件渲染 -->
<view wx:if="{{count > 0}}">
点击次数:{{count}}
</view>
<!-- 事件绑定 -->
<button bindtap="onTapButton">点击我</button>
<!-- 双向绑定(基础库2.9.3+) -->
<input model:value="{{message}}" />
</view>
小程序框架核心特性:
- 数据驱动:数据变化自动更新视图
- 组件化:内置丰富组件和自定义组件支持
- 模块化:支持CommonJS模块规范
- 事件系统:tap、input、scroll等事件处理
- 生命周期:页面和应用级别的生命周期管理
- 路由系统:页面栈管理和导航控制
三、小程序组件
3. 小程序组件与使用
问题:小程序的组件有哪些?视图容器组件有哪些?view、scroll-view、swiper组件的使用?基础内容组件有哪些?text、rich-text组件的使用?表单组件有哪些?button、input组件的使用?媒体组件有哪些?image、video组件的使用?如何创建自定义组件?组件的通信方法有哪些?
答案:
小程序组件分类:
- 视图容器组件:view、scroll-view、swiper、movable-view等
- 基础内容组件:text、rich-text、icon、progress等
- 表单组件:button、checkbox、radio、input、textarea等
- 媒体组件:image、video、audio、camera等
- 地图组件:map
- 画布组件:canvas
- 导航组件:navigator
- 开放能力组件:open-data、web-view等
1. 视图容器组件:
view(视图容器):
- 基本布局容器,类似于HTML中的div
- 支持flex布局、hover效果、点击事件等
<!-- 基础使用 -->
<view class="container">
<view class="item" hover-class="hover-style" bindtap="onItemTap">
点击我有hover效果
</view>
</view>
/* wxss */
.container {
display: flex;
flex-direction: column;
}
.item {
padding: 20rpx;
margin: 10rpx;
background-color: #f0f0f0;
}
.hover-style {
background-color: #e0e0e0;
}
scroll-view(可滚动视图):
- 可滚动的视图区域,支持横向或纵向滚动
- 常用属性:scroll-x、scroll-y、scroll-top、bindscroll等
<!-- 纵向滚动 -->
<scroll-view
scroll-y
style="height: 500rpx;"
bindscroll="onScroll"
scroll-top="{{scrollTop}}">
<view wx:for="{{100}}" wx:key="index" style="height: 100rpx;">
第{{index + 1}}项
</view>
</scroll-view>
<!-- 横向滚动 -->
<scroll-view scroll-x style="white-space: nowrap;">
<view wx:for="{{10}}" wx:key="index" style="display: inline-block; width: 200rpx;">
横向项{{index + 1}}
</view>
</scroll-view>
swiper(滑块视图容器):
- 轮播图组件,支持自动播放、无限循环、指示点等
- 常用属性:autoplay、interval、duration、indicator-dots等
<swiper
autoplay="{{true}}"
interval="{{3000}}"
duration="{{500}}"
indicator-dots="{{true}}"
indicator-color="rgba(0,0,0,.3)"
indicator-active-color="#000">
<swiper-item wx:for="{{banners}}" wx:key="index">
<image
src="{{item.imageUrl}}"
mode="aspectFill"
bindtap="onBannerTap"
data-id="{{item.id}}"
style="width: 100%; height: 100%;" />
</swiper-item>
</swiper>
2. 基础内容组件:
text(文本):
- 文本组件,支持长按选择、复制、空格处理等
- 常用属性:selectable、space、decode、user-select等
<view>
<!-- 基础文本 -->
<text>普通文本</text>
<!-- 可选中文本 -->
<text selectable="{{true}}">可选中文本</text>
<!-- 处理空格 -->
<text space="ensp">文本 空格</text>
<!-- HTML实体解码 -->
<text decode="{{true}}"><div>HTML实体</div></text>
<!-- 内嵌样式 -->
<text class="text-class" style="color: red;">样式文本</text>
<!-- 嵌套文本 -->
<text>
嵌套
<text style="font-weight: bold;">加粗</text>
文本
</text>
</view>
rich-text(富文本):
- 支持HTML节点和属性的富文本组件
- 通过nodes属性传入节点数组或HTML字符串
<rich-text nodes="{{htmlNodes}}" />
Page({
data: {
// 节点数组格式
htmlNodes: [
{
name: 'div',
attrs: { class: 'wrapper' },
children: [
{
name: 'h1',
attrs: { style: 'color: red;' },
children: [{ type: 'text', text: '标题' }]
},
{
name: 'p',
children: [
{ type: 'text', text: '段落内容' },
{
name: 'span',
attrs: { style: 'font-weight: bold;' },
children: [{ type: 'text', text: '加粗文本' }]
}
]
},
{
name: 'img',
attrs: {
src: 'https://example.com/image.jpg',
style: 'width: 100px; height: 100px;'
}
}
]
}
],
// HTML字符串格式(基础库2.4.4+)
htmlString: '<div class="wrapper"><h1 style="color: red;">标题</h1><p>段落内容<span style="font-weight: bold;">加粗文本</span></p><img src="https://example.com/image.jpg" style="width: 100px; height: 100px;" /></div>'
}
});
3. 表单组件:
button(按钮):
- 按钮组件,支持多种类型和开放能力
- 常用属性:type、size、plain、loading、form-type等
<view>
<!-- 主要按钮 -->
<button type="primary" bindtap="onPrimaryTap">主要按钮</button>
<!-- 次要按钮 -->
<button type="default" bindtap="onDefaultTap">默认按钮</button>
<!-- 警告按钮 -->
<button type="warn" bindtap="onWarnTap">警告按钮</button>
<!-- 禁用状态 -->
<button disabled="{{true}}">禁用按钮</button>
<!-- 加载状态 -->
<button loading="{{isLoading}}" bindtap="onLoadingTap">加载按钮</button>
<!-- 镂空按钮 -->
<button plain="{{true}}" type="primary">镂空按钮</button>
<!-- 表单提交按钮 -->
<form bindsubmit="onFormSubmit">
<input name="username" placeholder="请输入用户名" />
<button form-type="submit">提交</button>
<button form-type="reset">重置</button>
</form>
<!-- 开放能力(获取用户信息) -->
<button open-type="getUserInfo" bindgetuserinfo="onGetUserInfo">
获取用户信息
</button>
<!-- 分享 -->
<button open-type="share" bindtap="onShare">分享</button>
</view>
input(输入框):
- 单行输入框组件,支持多种输入类型
- 常用属性:value、type、password、placeholder、focus、bindinput等
<view>
<!-- 文本输入 -->
<input
value="{{username}}"
placeholder="请输入用户名"
bindinput="onUsernameInput"
maxlength="20" />
<!-- 数字输入 -->
<input
type="number"
value="{{age}}"
placeholder="请输入年龄"
bindinput="onAgeInput" />
<!-- 密码输入 -->
<input
type="password"
value="{{password}}"
placeholder="请输入密码"
password="{{true}}"
bindinput="onPasswordInput" />
<!-- 身份证输入 -->
<input
type="idcard"
placeholder="请输入身份证号"
bindinput="onIdCardInput" />
<!-- 数字键盘输入 -->
<input
type="digit"
placeholder="请输入金额"
bindinput="onDigitInput" />
<!-- 获取焦点 -->
<input
focus="{{isFocus}}"
placeholder="自动获取焦点"
bindfocus="onFocus"
bindblur="onBlur" />
<!-- 带清除按钮 -->
<input
value="{{searchText}}"
placeholder="搜索..."
confirm-type="search"
bindconfirm="onSearch"
bindinput="onSearchInput" />
</view>
Page({
data: {
username: '',
age: '',
password: '',
searchText: '',
isFocus: false
},
onUsernameInput(e) {
this.setData({ username: e.detail.value });
},
onAgeInput(e) {
this.setData({ age: e.detail.value });
},
onPasswordInput(e) {
this.setData({ password: e.detail.value });
},
onSearchInput(e) {
this.setData({ searchText: e.detail.value });
},
onSearch(e) {
console.log('搜索:', this.data.searchText);
// 执行搜索操作
},
onFocus() {
console.log('输入框获取焦点');
},
onBlur() {
console.log('输入框失去焦点');
}
});
4. 媒体组件:
image(图片):
- 图片组件,支持懒加载、错误处理、多种展示模式
- 常用属性:src、mode、lazy-load、bindload、binderror等
<view>
<!-- 基础图片 -->
<image src="{{imageUrl}}" />
<!-- 指定展示模式 -->
<image
src="{{avatarUrl}}"
mode="aspectFill"
style="width: 200rpx; height: 200rpx; border-radius: 50%;" />
<!-- 懒加载 -->
<image
src="{{bannerUrl}}"
mode="widthFix"
lazy-load="{{true}}"
bindload="onImageLoad"
binderror="onImageError" />
<!-- 占位图 -->
<image
class="product-image"
src="{{product.imageUrl || '/images/placeholder.png'}}"
mode="aspectFit" />
<!-- 图片预览 -->
<image
src="{{previewImage}}"
mode="aspectFit"
bindtap="previewImage"
data-src="{{previewImage}}" />
</view>
图片 mode 属性详解:
| 模式值 | 说明 | 特点 |
|---|---|---|
| scaleToFill | 缩放模式,不保持纵横比 | 填充整个image元素 |
| aspectFit | 缩放模式,保持纵横比 | 完整显示图片,可能留白 |
| aspectFill | 缩放模式,保持纵横比 | 填充整个元素,可能裁剪 |
| widthFix | 宽度不变,高度自适应 | 高度按原图比例计算 |
| top | 不缩放,顶部对齐 | |
| bottom | 不缩放,底部对齐 | |
| center | 不缩放,居中 | |
| left | 不缩放,左对齐 | |
| right | 不缩放,右对齐 | |
| top left | 不缩放,左上角对齐 | |
| top right | 不缩放,右上角对齐 | |
| bottom left | 不缩放,左下角对齐 | |
| bottom right | 不缩放,右下角对齐 |
video(视频):
- 视频播放组件,支持弹幕、控制栏、全屏等
- 常用属性:src、controls、autoplay、loop、bindplay、bindpause等
<view>
<!-- 基础视频播放 -->
<video
src="{{videoUrl}}"
controls="{{true}}"
autoplay="{{false}}"
loop="{{false}}"
muted="{{false}}"
bindplay="onVideoPlay"
bindpause="onVideoPause"
bindended="onVideoEnded"
style="width: 100%; height: 400rpx;" />
<!-- 自定义视频控制 -->
<video
id="myVideo"
src="{{videoUrl}}"
controls="{{false}}"
bindtimeupdate="onTimeUpdate"
style="width: 100%; height: 400rpx;" />
<view class="video-controls">
<button bindtap="playVideo">播放</button>
<button bindtap="pauseVideo">暂停</button>
<button bindtap="seekVideo">跳转到30秒</button>
<button bindtap="requestFullScreen">全屏</button>
</view>
</view>
Page({
onReady() {
this.videoContext = wx.createVideoContext('myVideo');
},
playVideo() {
this.videoContext.play();
},
pauseVideo() {
this.videoContext.pause();
},
seekVideo() {
this.videoContext.seek(30); // 跳转到30秒
},
requestFullScreen() {
this.videoContext.requestFullScreen();
},
onTimeUpdate(e) {
const currentTime = e.detail.currentTime;
const duration = e.detail.duration;
const progress = (currentTime / duration * 100).toFixed(2);
console.log(`播放进度: ${progress}%`);
}
});
5. 自定义组件:
创建自定义组件:
- 在项目根目录创建
components文件夹 - 在
components下创建组件文件夹(如my-component) - 在组件文件夹中创建4个文件:
.js、.json、.wxml、.wxss
// components/my-component/my-component.js
Component({
// 组件属性定义
properties: {
title: {
type: String,
value: '默认标题',
observer: function(newVal, oldVal) {
console.log('title改变:', oldVal, '→', newVal);
}
},
count: {
type: Number,
value: 0
},
show: {
type: Boolean,
value: true
},
list: {
type: Array,
value: []
},
config: {
type: Object,
value: {}
}
},
// 组件内部数据
data: {
internalData: '内部数据'
},
// 组件生命周期
lifetimes: {
attached() {
console.log('组件被添加到页面');
},
detached() {
console.log('组件从页面移除');
}
},
// 组件方法
methods: {
onTap() {
// 触发自定义事件
this.triggerEvent('customevent', {
detail: {
value: '触发事件的数据'
}
});
// 更新properties
this.setData({
count: this.data.count + 1
});
},
// 对外暴露的方法
publicMethod() {
return '这是对外暴露的方法';
}
},
// 外部样式类
externalClasses: ['external-class']
});
// components/my-component/my-component.json
{
"component": true,
"usingComponents": {
"other-component": "../other-component/other-component"
}
}
<!-- components/my-component/my-component.wxml -->
<view class="my-component {{externalClass}}">
<text>{{title}}</text>
<text>计数: {{count}}</text>
<view wx:if="{{show}}">
<text>显示内容</text>
</view>
<view wx:for="{{list}}" wx:key="index">
{{index}}: {{item}}
</view>
<button bindtap="onTap">点击触发事件</button>
<!-- 使用其他组件 -->
<other-component />
<!-- 插槽 -->
<slot name="header"></slot>
<view>
<slot></slot> <!-- 默认插槽 -->
</view>
<slot name="footer"></slot>
</view>
/* components/my-component/my-component.wxss */
.my-component {
padding: 20rpx;
border: 1rpx solid #e0e0e0;
border-radius: 8rpx;
}
.my-component text {
display: block;
margin-bottom: 10rpx;
}
使用自定义组件:
// 页面的json文件
{
"usingComponents": {
"my-component": "/components/my-component/my-component"
}
}
<!-- 页面wxml -->
<view>
<my-component
title="自定义标题"
count="{{count}}"
show="{{true}}"
list="{{['A', 'B', 'C']}}"
external-class="custom-style"
bind:customevent="onCustomEvent">
<!-- 插槽内容 -->
<view slot="header">头部插槽</view>
<view>默认插槽内容</view>
<view slot="footer">底部插槽</view>
</my-component>
</view>
组件通信方式:
- 父传子:通过properties传递数据
- 子传父:通过triggerEvent触发自定义事件
- 获取组件实例:通过
this.selectComponent('#id')获取子组件实例 - 全局数据:通过getApp().globalData共享数据
- 事件总线:通过全局事件管理器实现组件间通信
组件实例获取与调用:
Page({
onReady() {
// 获取组件实例
const myComponent = this.selectComponent('#my-component');
if (myComponent) {
// 调用组件方法
const result = myComponent.publicMethod();
console.log('调用组件方法结果:', result);
// 更新组件数据
myComponent.setData({
title: '通过父组件修改'
});
}
},
onCustomEvent(e) {
console.log('收到子组件事件:', e.detail);
}
});
组件样式隔离:
- apply-shared:组件接受组件外部的样式
- shared:组件接受组件外部的样式,且组件的样式也影响其他组件
- isolated:组件样式隔离(默认)
- page-isolated:页面样式隔离
{
"component": true,
"styleIsolation": "apply-shared"
}
补充说明:
- 自定义组件可以嵌套使用,形成组件树
- 组件应尽量保持低耦合、高内聚
- 复杂的组件应拆分为多个简单组件
- 合理使用slot提高组件复用性
- 注意组件性能,避免不必要的渲染
由于篇幅限制,这里先提供移动端答案的前三部分(小程序基础、微信小程序架构、小程序组件)。后续部分(小程序API、小程序样式、小程序路由、小程序性能优化、小程序调试与发布、小程序常见问题)将根据相同模式继续编写,每部分包含问题概述、详细答案、代码示例和对比表格。