「小程序开发」项目结构和页面组成

224 阅读9分钟

微信小程序目录

微信小程序的目录,每种文件都有特定用途,组合起来才能构建完整应用。

小程序最基本的目录结构通常包含这些部分:

my-miniprogram/
├── pages/          // 存放所有页面
│   ├── index/      // 存放index页面的逻辑文件
│   └── logs/       // 存放logs页面的逻辑文件
├── utils/          // 存放公用工具
├── app.js          // 控制整个小程序
├── app.json        // 全局配置
└── app.wxss        // 全局样式

核心文件与简单案例

app.js文件

app.js 是项目的全局逻辑配置文件,用于定义小程序的生命周期函数、全局状态管理以及基础配置。它与app.json和页面级别的page.js文件共同构成了小程序的运行框架。

全局生命周期函数 app.js中提供的全局生命周期函数,包括:

  • onLaunch:小程序初始化时触发,仅执行一次。
  • onShow:当小程序启动或从后台进入前台时触发。
  • onHide:当小程序从前台进入后台时触发。
  • onError:当小程序发生脚本错误或API调用失败时触发。

示例代码

App({
  onLaunch() {
    // 初始化全局变量或调用登录接口
    console.log('小程序初始化');
  },
  onShow() {
    console.log('小程序显示');
  },
  onHide() {
    console.log('小程序隐藏');
  },
  onError(err) {
    console.error('发生错误:', err);
  }
});

此示例展示了app.js的基本结构,其中App()函数是程序入口点,用于注册小程序并提供全局配置和生命周期处理。

app.js 还可以定义全局变量和工具函数,供各个页面组件访问和调用。通过将常用的数据或方法挂载到 globalData 或自定义属性上,可以实现跨页面的数据共享和功能复用。

示例代码

App({
  globalData: {
    userInfo: null,
    apiUrl: 'https://api.example.com'
  },
  fetchUserInfo() {
    // 模拟获取用户信息
    this.globalData.userInfo = { name: '张三', id: 123 };
  }
});

此示例,在页面中可以通过const app = getApp();获取全局实例,并访问app.globalData.userInfo或调用 app.fetchUserInfo() 方法。

app.json文件

app.json 是全局配置文件,用于定义小程序的页面路径、窗口样式、导航栏设置等核心属性。其中,pageswindow

文件的作用

  • 全局配置:app.json 可以定义小程序的窗口表现、导航栏样式、默认页面路径、网络超时时间等全局属性。
  • 页面路由:通过 pages 字段指定小程序的初始页面和页面路径列表,控制页面的加载顺序。
  • 设备适配:可以为不同类型的设备(如手机、平板、TV 等)提供特定的配置选项,确保应用在各种设备上都能正常运行。
  • 功能启用/禁用:某些平台可能允许通过 app.json 控制是否启用特定的功能或模块。

示例代码:app.json配置文件

{
  "pages": ["pages/index/index", "pages/logs/logs"],
  "window": {
    "navigationBarTitleText": "My App",
    "backgroundColor": "#ffffff",
    "backgroundTextStyle": "light",
    "enablePullDownRefresh": false
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json"
}
  • pages字段,指定了小程序的页面路径列表,第一个元素代表启动页。
  • window对象,用于设置小程序的窗口样式,包括导航栏标题、背景颜色等。
  • style字段,用于指定小程序的样式版本。
  • sitemapLocation,指定sitemap.json的位置,帮助搜索引擎更好地抓取小程序内容。

pages字段示例代码

"pages": [
  "pages/index/index",
  "pages/note/add",
  "pages/me/me",
  "pages/login/login",
  "pages/note/detail",
  "pages/note/myNote"
]

示例配置表明小程序包含六个页面,其中"pages/index/index"是启动页。页面路径的最大数量限制为10个。如果需要使用底部 tab 栏,则需确保tabBar中列出的页面也包含在pages列表中,并且必须放在最前面。

window属性解析 window 字段用于配置小程序的窗口样式,包括导航栏标题、背景颜色、下拉刷新样式等。它影响所有页面的默认外观,除非某个页面单独设置了不同的 window 样式(通过页面级 json 文件)。 常见配置项如下:

  • "navigationBarTitleText":设置导航栏标题文字。
  • "navigationStyle":设置导航栏样式,可选值为 "default"(默认样式)或 "custom"(自定义样式,隐藏默认导航栏)。
  • "backgroundColor":设置窗口的背景颜色。
  • "backgroundTextStyle":设置下拉刷新时的文字样式,如 "light""dark"
  • "enablePullDownRefresh":是否启用下拉刷新功能,布尔值。

示例代码

"window": {
  "navigationBarTitleText": "我的小程序",
  "navigationStyle": "custom",
  "backgroundColor": "#ffffff",
  "backgroundTextStyle": "light",
  "enablePullDownRefresh": true
}

示例配置将导航栏标题设为“我的小程序”,并采用自定义样式,使开发者可以自行设计顶部区域。窗口背景色为白色,下拉刷新文字样式为浅色,并启用了下拉刷新功能。

app.wxss文件

app.wxss文件是微信小程序中用于全局样式定义的文件。它类似于网页开发中的CSS文件,但其语法和特性针对微信小程序进行了优化和支持。 app.wxss 的作用

  • 全局样式定义:在app.wxss中定义的样式对整个小程序的所有页面生效,可以确保整体风格的一致性。
  • 支持rpx单位:rpx(responsive pixel)是微信小程序独有的单位,是根据屏幕宽度进行自适应缩放。例如,在不同设备上保持元素比例一致。
  • 模块化管理:可以通过@import引入其他wxss文件,从而实现样式的模块化管理,提升代码可维护性。

使用app.wxss文件

  • 直接编写样式规则: 在app.wxss文件中可以直接书写CSS样式规则,这些规则将应用到所有页面组件中。例如:
    .container {
      height: 100%;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: space-between;
      padding: 200rpx 0;
      box-sizing: border-box;
    }
    
  • 引入外部样式文件: 使用@import指令可以引入外部的wxss文件,以便于组织复杂的样式表。需要注意路径的正确性,特别是在使用npm包时,可能需要指定构建后的具体路径。例如:
    @import '/miniprogram_npm/weui-miniprogram/weui-wxss/dist/style/weui.wxss';
    
    这种方式常用于引入第三方 UI 库如 WeUI,通过调整导入路径来解决常见的“File not found”错误。
  • 使用全局变量或混合: 虽然目前wxss不支持像Sass或Less那样的变量功能,但通过合理的类命名和结构设计,仍能实现一定程度上的样式复用和统一管理。
  • 与页面级wxss协同工作: 页面级别的wxss文件仅对该页面有效,而app.wxss是全局的,两者结合能够灵活控制样式覆盖范围。通常建议将公共样式放在app.wxss中,特定页面的样式则放在各自页面的 wxss 文件内。

示例代码:创建一个简单的全局样式

/* app.wxss */
.global-header {
  background-color: #07c160;
  color: white;
  font-size: 36rpx;
  padding: 20rpx;
}

.text-center {
  text-align: center;
}

注意事项

  • 确保路径正确,尤其是在引入第三方库时,应参考构建工具生成的实际路径。
  • 避免过度依赖全局样式,以免影响页面之间的独立性和可调试性。
  • 利用 rpx 单位提高布局的响应能力,同时注意测试不同分辨率下的显示效果。

页面结构

每个页面由4种文件组成,即WXML、WXSS、JS和JOSN:

  • .wxml:小程序的标记语言,用于描述页面的结构和组件布局。支持数据绑定、条件渲染、列表渲染等特性,使得开发者可以动态地构建用户界面。
  • .wxss:小程序的样式表语言,类似于CSS,但支持更多的特性,如rpx单位和@import引入外部样式文件。它用于控制页面的外观和视觉表现。
  • .js:负责处理页面的交互逻辑和数据操作。其中包含了页面的生命周期函数(如onLoad,onShow, onHide等)以及事件处理函数。此外,还可以通过 Page() 函数来注册页面,并传递初始数据和方法。
  • .json - 房间的特殊配置(要不要吊顶)

案例:一个简单的计数器页面 counter.js文件代码

// pages/counter/counter.js
Page({
  data: { count: 0 }, // 房间里的计数器初始为0
  addCount() {
    this.setData({ count: this.data.count + 1 }) // 每次点击加1
  }
})

counter.wxml文件代码

<!-- pages/counter/counter.wxml -->
<view class="container">
  <text>当前计数:{{count}}</text>
  <button bindtap="addCount">点我增加</button>
</view>

counter.wxss文件代码

/* pages/counter/counter.wxss */
.container {
  padding: 50px;
  text-align: center;
}
button {
  margin-top: 20px;
  background-color: #07c160;
  color: white;
}

常见错误

  • 页面路径写错:系统会提示"Page not found"。检查app.json中的pages配置和实际文件路径是否一致。
  • 忘记绑定事件:在wxml中写bindtap="函数名",但在js中忘记写对应的函数,点击按钮就像按了坏掉的开关没反应。
  • 修改数据方式不对:直接this.data.count=1不会更新界面,必须用this.setData({count:1}),就像装修必须通过物业批准。
  • 样式不生效:检查选择器是否正确,wxss中写.view-class但wxml中用的是<view class="view-class">,少个点或多点都会出问题。

练习题

理论题

  1. 小程序的全局配置文件是哪个?它主要管理哪些内容? 答案:全局配置文件是app.json。它管理页面路径列表、窗口表现、网络超时时间、底部tab等全局配置,就像建筑的总体规划图。
  2. 为什么修改数据要用setData而不是直接赋值? 答案:setData不仅更新数据,还会通知视图层重新渲染。直接赋值只改变数据但界面不会更新,就像偷偷换了房间家具但没告诉管家。

实践题

  1. 创建一个新的页面"about",显示你的姓名和简短自我介绍。要求:
    • 在app.json中注册这个页面
    • 编写wxml展示信息
    • 使用wxss为文字添加样式

参考代码 添加about页面

// app.json中添加
"pages/about/about"

about.wxml文件

<!-- about.wxml -->
<view class="about-container">
  <text class="name">张三</text>
  <text class="bio">我是小程序开发者,热爱编程与分享</text>
</view>

about.wxss文件

/* about.wxss */
.about-container {
  padding: 30px;
}
.name {
  font-size: 24px;
  color: #333;
  display: block;
  margin-bottom: 15px;
}
.bio {
  font-size: 16px;
  color: #666;
}
  1. 改造计数器案例,增加一个"减少"按钮,点击后计数减1。注意处理计数不能小于0的情况。 参考代码 counter.js文件代码
// pages/counter/counter.js
Page({
  data: { count: 0 },
  addCount() {
    this.setData({ count: this.data.count + 1 })
  },
  reduceCount() {
    if(this.data.count > 0) {
      this.setData({ count: this.data.count - 1 })
    }
  }
})

counter.wxml文件代码

<!-- pages/counter/counter.wxml -->
<view class="container">
  <text>当前计数:{{count}}</text>
  <button bindtap="addCount">点我增加</button>
  <button bindtap="reduceCount">点我减少</button>
</view>

counter.wxss文件代码

/* pages/counter/counter.wxss */
.container {
  padding: 50px;
  text-align: center;
}
button {
  margin-top: 20px;
  background-color: #07c160;
  color: white;
}

点我减少