JavaScript基础课程三十、微信小程序实战

本课聚焦微信小程序实战开发,覆盖从环境搭建到项目上线前的全流程知识点。微信小程序作为主流轻应用,语法贴合前端基础,上手难度低,传播和使用场景广泛。课程从项目结构、配置文件、页面语法,到网络请求、缓存、路由传参,用单词小程序案例贯穿全程,拆解开发细节与避坑要点。学习本课不仅能掌握小程序独立开发能力,更能理解平台规则与用户体验优化逻辑,适配企业轻量化产品开发需求。小程序项目体量小、开发周期短,是前端开发者必备的实战技能,掌握本课内容,可独立完成各类轻量化小程序开发,拓宽就业与实战方向。

一、课程学习目的

  1. 掌握微信小程序的开发流程、环境搭建,熟悉小程序官方开发工具。

  2. 理解小程序的项目结构、配置文件、页面组成,分清页面与全局逻辑。

  3. 熟练运用小程序基础语法、数据绑定、事件处理、列表渲染。

  4. 学会小程序网络请求、本地缓存、页面跳转与参数传递。

  5. 规避小程序开发常见坑,适配小程序平台规范。

  6. 独立开发完整小程序项目,实现从搭建到运行的全流程,贴合上线标准。

二、核心知识点讲解

1. 微信小程序基础认知

微信小程序是依附于微信平台的轻应用,无需下载安装,扫码即可打开,占用资源少、传播便捷,是移动端常用的产品形态。

开发门槛低,语法贴近前端三件套,配合官方开发者工具,上手速度快,适合快速落地业务、搭建轻量化工具。小程序有严格的权限管控、域名限制,开发前需完成账号注册与配置。

2. 开发环境与工具

开发必备工具:微信开发者工具(官方专属编辑器,集编写、调试、预览、发布于一体)。

前期准备:注册微信小程序账号、获取AppID、配置服务器域名、下载安装开发者工具,无AppID可使用测试号进行本地开发。

3. 小程序项目结构

小程序项目由全局配置、页面文件、静态资源组成,每个页面独立成文件夹,遵循固定命名规范。

  • app.json:全局配置文件,配置页面路由、导航栏、底部TabBar、网络域名等。

  • app.js:全局入口文件,存放全局生命周期、全局数据。

  • app.wxss:全局样式文件,作用于所有页面。

  • pages:页面文件夹,每个页面包含wxml、wxss、js、json四个文件。

  • utils:工具函数文件夹,存放封装的请求、工具方法。

4. 页面文件组成

每个小程序页面由四个文件构成,分工明确,缺一不可。

  • .wxml:结构文件,类似HTML,专用小程序组件,禁止使用HTML原生标签。

  • .wxss:样式文件,类似CSS,支持rpx响应式单位,适配移动端屏幕。

  • .js:逻辑文件,处理数据、事件、请求、生命周期、路由。

  • .json:页面配置文件,单独配置当前页面导航栏、标题。

5. 小程序核心语法

数据绑定:使用双大括号{{}}包裹变量,实现数据与视图联动。

列表渲染:使用wx:for指令循环渲染列表,必须搭配wx:key保证渲染稳定。

事件绑定:使用bind+事件名绑定点击、输入等交互,如bindtap、bindinput。

页面生命周期:onLoad(页面加载)、onShow(页面显示)、onReady(渲染完成)、onUnload(页面卸载)。

6. 小程序网络与缓存

网络请求:使用wx.request发起请求,必须配置合法域名,不支持本地localhost请求(测试可关闭域名校验)。

本地缓存:使用wx.setStorageSync、wx.getStorageSync实现数据持久化存储,用法与uni-app一致。

7. 小程序路由跳转

wx.navigateTo:保留当前页面,跳转到新页面,支持返回。

wx.switchTab:跳转到TabBar页面,关闭其他非TabBar页面。

wx.navigateBack:返回上一级或多级页面。

三、示例程序

示例1:app.json全局配置

json 复制代码
{
  "pages": [
    "pages/index/index",
    "pages/list/list",
    "pages/detail/detail"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#42b983",
    "navigationBarTitleText": "单词小程序",
    "navigationBarTextStyle": "white"
  },
  "tabBar": {
    "color": "#666",
    "selectedColor": "#42b983",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页"
      },
      {
        "pagePath": "pages/list/list",
        "text": "单词列表"
      }
    ]
  },
  "sitemapLocation": "sitemap.json"
}

示例2:列表页面wxml结构

xml 复制代码
<!-- pages/list/list.wxml -->
<view class="container">
  <!-- 加载提示 -->
  <view wx:if="{{loading}}" class="tip">加载中...</view>
  
  <!-- 单词列表 -->
  <view 
    wx:for="{{wordList}}" 
    wx:key="id" 
    class="item"
    bindtap="goDetail"
    data-id="{{item.id}}"
    data-en="{{item.en}}"
    data-cn="{{item.cn}}"
  >
    <text>{{item.en}} - {{item.cn}}</text>
  </view>
  
  <!-- 空数据提示 -->
  <view wx:elif="{{wordList.length === 0}}" class="tip">暂无单词数据</view>
</view>

示例3:列表页面js逻辑

javascript 复制代码
// pages/list/list.js
Page({
  // 页面数据
  data: {
    wordList: [],
    loading: false
  },

  // 页面加载时触发
  onLoad() {
    this.getWordList()
  },

  // 获取单词列表
  getWordList() {
    this.setData({ loading: true })
    // 发起网络请求
    wx.request({
      url: 'https://xxx/api/word/list',
      method: 'GET',
      success: (res) => {
        if (res.statusCode === 200) {
          this.setData({
            wordList: res.data.data
          })
          // 缓存数据
          wx.setStorageSync('wordList', res.data.data)
        }
      },
      fail: () => {
        // 读取缓存
        const cache = wx.getStorageSync('wordList')
        if (cache) this.setData({ wordList: cache })
        wx.showToast({ title: '网络异常', icon: 'none' })
      },
      complete: () => {
        this.setData({ loading: false })
      }
    })
  },

  // 跳转到详情页
  goDetail(e) {
    const { id, en, cn } = e.currentTarget.dataset
    wx.navigateTo({
      url: `/pages/detail/detail?id=${id}&en=${en}&cn=${cn}`
    })
  }
})

示例4:详情页面接收参数

javascript 复制代码
// pages/detail/detail.js
Page({
  data: {
    word: {}
  },

  // 接收路由参数
  onLoad(options) {
    this.setData({
      word: options
    })
  },

  // 返回上一页
  goBack() {
    wx.navigateBack()
  }
})

四、掌握技巧与方法

  1. 开发前配置好合法域名,测试阶段可在开发者工具中关闭域名校验。

  2. 数据更新必须使用setData,直接修改data数据无法触发视图刷新。

  3. 列表渲染必须配置wx:key,推荐用唯一id,不建议使用index。

  4. 样式优先使用rpx单位,实现移动端自适应,适配不同机型。

  5. 网络请求失败时,读取本地缓存,提升用户体验,避免空白页面。

  6. 页面跳转传参,通过data-*属性传递数据,在事件对象中获取。

  7. 全局配置app.json中,pages数组第一项为默认首页。

  8. 调试使用开发者工具控制台,查看请求、缓存、报错信息。

五、课后作业

基础作业

  1. 安装微信开发者工具,使用测试号创建空白小程序项目。

  2. 配置app.json,注册首页、列表页、详情页,设置导航栏样式。

  3. 编写页面结构,完成数据绑定、列表渲染基础效果。

进阶作业

  1. 使用wx.request请求单词数据,渲染到页面,处理加载与异常状态。

  2. 实现页面跳转与参数传递,详情页接收并展示数据。

  3. 配合本地缓存,实现离线展示数据功能。

实战作业

  1. 开发完整单词学习小程序,包含首页、单词列表页、单词详情页,配置底部TabBar,实现网络请求数据、缓存存储、页面跳转、参数接收功能,处理加载、空数据、异常状态,符合微信小程序开发规范,可正常预览运行。

上一课 实战作业代码 答案:uni-app 网络请求与数据缓存

完整实战代码

项目结构

Plain 复制代码
uni-app-request-word/
├── pages/
│   └── index/
│       └── index.vue
├── utils/
│   └── request.js
├── App.vue
├── main.js
└── pages.json

pages.json配置

json 复制代码
{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "navigationBarTitleText": "单词列表"
      }
    }
  ],
  "globalStyle": {
    "navigationBarTextStyle": "white",
    "navigationBarBackgroundColor": "#42b983",
    "backgroundColor": "#f5f5f5"
  }
}

utils/request.js(封装请求)

javascript 复制代码
// 基础请求地址(替换为自己的后端接口)
const baseUrl = 'http://localhost:3000'

// 封装统一请求
const request = (options) => {
  // 开启加载提示
  uni.showLoading({
    title: '加载中...',
    mask: true
  })

  return new Promise((resolve, reject) => {
    uni.request({
      url: baseUrl + options.url,
      method: options.method || 'GET',
      data: options.data || {},
      header: {
        'Content-Type': 'application/json'
      },
      success: (res) => {
        if (res.statusCode === 200) {
          resolve(res.data)
        } else {
          uni.showToast({
            title: '请求失败',
            icon: 'none'
          })
          reject(res)
        }
      },
      fail: (err) => {
        uni.showToast({
          title: '网络异常',
          icon: 'none'
        })
        reject(err)
      },
      complete: () => {
        // 关闭加载提示
        uni.hideLoading()
      }
    })
  })
}

// 导出GET方法
export const get = (url, data) => {
  return request({ url, method: 'GET', data })
}

// 导出POST方法
export const post = (url, data) => {
  return request({ url, method: 'POST', data })
}

pages/index/index.vue(主页面)

vue 复制代码
<template>
  <view class="container">
    <!-- 加载状态 -->
    <view class="tip" v-if="loading">正在加载单词数据...</view>
    
    <!-- 单词列表 -->
    <view class="list" v-else>
      <view class="item" v-for="item in wordList" :key="item.id">
        <text class="en">{{ item.en }}</text>
        <text class="cn">{{ item.cn }}</text>
      </view>
      <view class="tip" v-if="wordList.length === 0">暂无单词数据</view>
    </view>
    
    <!-- 刷新按钮 -->
    <button class="refresh-btn" @click="getWordList" :disabled="loading">刷新数据</button>
  </view>
</template>

<script setup>
import { ref, onLoad } from 'vue'
import { get } from '../../utils/request'

// 响应式数据
const wordList = ref([])
const loading = ref(false)

// 页面加载触发
onLoad(() => {
  initPage()
})

// 初始化:先读缓存,再请求
const initPage = () => {
  // 读取本地缓存
  const cacheData = uni.getStorageSync('wordList')
  if (cacheData) {
    wordList.value = cacheData
  }
  // 请求最新数据
  getWordList()
}

// 获取单词列表
const getWordList = async () => {
  loading.value = true
  try {
    const res = await get('/api/word/list')
    wordList.value = res.data || []
    // 缓存最新数据
    uni.setStorageSync('wordList', wordList.value)
  } catch (err) {
    console.log('获取数据失败', err)
  } finally {
    loading.value = false
  }
}
</script>

<style scoped>
.container {
  padding: 30rpx;
}
.tip {
  text-align: center;
  color: #666;
  padding: 40rpx 0;
  font-size: 28rpx;
}
.list {
  margin-bottom: 30rpx;
}
.item {
  background-color: #fff;
  padding: 30rpx;
  border-radius: 12rpx;
  margin-bottom: 20rpx;
  display: flex;
  justify-content: space-between;
}
.en {
  font-size: 32rpx;
  color: #333;
  font-weight: 500;
}
.cn {
  font-size: 28rpx;
  color: #666;
}
.refresh-btn {
  margin-top: 20rpx;
}
</style>

App.vue(全局配置)

vue 复制代码
<script>
export default {
  onLaunch: function () {
    console.log('App启动')
  }
}
</script>

<style>
/* 全局样式 */
page {
  background-color: #f5f5f5;
}
</style>

main.js(入口文件)

javascript 复制代码
import { createSSRApp } from 'vue'
export function createApp() {
  const app = createSSRApp(App)
  return { app }
}

运行方式

  1. 使用HBuilderX打开项目,安装所需依赖。

  2. 启动后端接口服务,修改request.js中的baseUrl为正确地址。

  3. 点击运行,选择运行到浏览器或微信小程序。

  4. 测试加载、缓存、刷新、异常处理功能。

代码功能说明

本实战作业基于uni-app Vue3语法开发单词列表页面,主打网络请求与缓存两大核心功能。项目封装了统一请求工具,统一配置基础域名、请求头、加载提示和异常处理,支持GET请求;页面加载时先读取本地缓存数据,快速展示内容,再发起网络请求更新数据和缓存,提升加载体验。页面包含加载状态、空数据提示、异常提示,适配H5和微信小程序端,数据渲染流畅。代码实现了接口对接、缓存读写、状态管理全套逻辑,完整贴合课程知识点,巩固uni-app网络交互与本地存储技能。

注意事项

  • H5端运行需开启后端跨域,小程序端需配置request合法域名。

  • 网络请求为异步操作,推荐使用async/await简化代码逻辑。

  • 数据更新需用响应式赋值,保证视图正常刷新。

  • 缓存键名保持语义化,避免和其他项目缓存冲突。

  • 调试时关闭浏览器缓存,防止接口数据不更新。

  • 请求加载期间,禁止重复点击、重复发起请求。

  • 项目路径禁止出现中文、空格和特殊字符,防止编译报错。

  • 修改工具文件后,需重新编译项目,确保配置生效。

作业验收标准

  1. 项目正常编译运行,无控制台报错。

  2. 请求接口成功,正常渲染单词列表,加载提示流畅。

  3. 网络异常时,能正常读取缓存数据展示。

  4. 刷新按钮可重新请求并更新缓存。

  5. 适配H5和微信小程序,无兼容性问题。

  6. 代码规范,注释清晰,请求封装合理。