3、项目结构解剖:.axml、.acss、.js、.json 文件的作用与协同

说实话,很多新手刚接触支付宝小程序时,看到一堆 .axml、.acss、.js、.json 文件就懵了。我当年第一次打开项目目录,心里也在嘀咕:这跟普通的前端项目到底有啥区别?

今天我就带你把这四个文件彻底搞明白。它们就像一个小团队的四个角色,各司其职,又紧密配合。

3.1 四个文件,四个角色

先给你一个直观的印象。每个页面通常由这四个文件组成,它们名字相同,但后缀不同:

pages/
  └── index/
      ├── index.axml    // 页面结构
      ├── index.acss    // 页面样式
      ├── index.js      // 页面逻辑
      └── index.json    // 页面配置

嗯,你可以把 .axml 想象成房子的骨架,.acss 是装修风格,.js 是水电线路和智能家居系统,.json 则是房子的户型图说明书。缺一个,房子就住不了人。

3.2 .axml 文件:页面的骨架

.axml 是支付宝小程序的模板文件,说白了就是用来描述页面长什么样。它跟 HTML 很像,但又不完全一样。

核心特点:

  • 使用小程序自定义的标签,比如 <view><text><image>
  • 支持数据绑定,用 {{ }} 把 JS 里的数据渲染到页面上
  • 支持条件渲染和循环渲染

举个例子,一个简单的列表页面:

<view class="container">
  <text class="title">{{pageTitle}}</text>
  <view a:for="{{itemList}}" a:key="id" class="item">
    <text>{{item.name}}</text>
    <text>价格:{{item.price}}元</text>
  </view>
</view>

这里 {{pageTitle}}{{itemList}} 都是从 .js 文件里拿过来的数据。我个人习惯把这种数据绑定叫做「桥梁」——.axml 搭好桥,.js 把数据送过来。

小技巧: .axml 里不要写复杂的逻辑表达式。我曾经见过有人直接在模板里写三元运算符嵌套三层,调试的时候差点崩溃。记住,模板只负责展示,复杂逻辑交给 .js。

3.3 .acss 文件:页面的皮肤

.acss 就是小程序的样式文件,相当于 CSS 的「小程序定制版」。它支持大部分 CSS 属性,但也有一些自己的特性。

跟普通 CSS 的区别:

  • 尺寸单位用 rpx,自适应不同屏幕宽度。我建议你把它当成「响应式像素」来理解
  • 支持 @import 引入外部样式文件
  • 不支持通配符 * 选择器

来看个例子:

.container {
  display: flex;
  flex-direction: column;
  padding: 20rpx;
  background-color: #f5f5f5;
}

.title {
  font-size: 36rpx;
  color: #333;
  margin-bottom: 16rpx;
}

.item {
  background-color: #fff;
  padding: 24rpx;
  border-radius: 12rpx;
  margin-bottom: 12rpx;
}

你想想看,为什么支付宝小程序要用 rpx 而不是 px?因为手机屏幕千差万别,iPhone 和安卓的宽度不一样。rpx 会根据屏幕宽度自动缩放,省去了你写媒体查询的麻烦。

注意: .acss 文件的作用域默认是全局的。如果你只想让样式影响当前页面,记得在 .json 文件里设置 "styleIsolation": "apply-shared"。我曾经因为忘记这个设置,导致一个页面的样式污染了其他页面,排查了半天。

3.4 .js 文件:页面的大脑

.js 文件是四个文件里最核心的。它负责处理数据、响应事件、调用 API。说白了,用户点了个按钮,数据怎么变、要不要请求服务器,全在 .js 里控制。

标准结构:

Page({
  data: {
    pageTitle: '商品列表',
    itemList: [
      { id: 1, name: '商品A', price: 99 },
      { id: 2, name: '商品B', price: 199 }
    ]
  },

  onLoad() {
    // 页面加载时触发
    console.log('页面加载了');
    this.fetchData();
  },

  fetchData() {
    // 自定义方法,请求数据
    my.request({
      url: 'https://api.example.com/items',
      success: (res) => {
        this.setData({
          itemList: res.data
        });
      }
    });
  },

  handleTap(e) {
    // 点击事件处理
    const id = e.currentTarget.dataset.id;
    my.navigateTo({ url: `/pages/detail/detail?id=${id}` });
  }
});

这里有几个关键点:

  • data 对象:所有页面需要的数据都放在这里。修改数据必须用 this.setData(),直接赋值不会触发页面更新
  • 生命周期函数:onLoadonShowonReady 等,控制页面在不同阶段的行为
  • 事件处理:通过 data-* 属性传递参数
核心原则: .js 是数据的中枢。.axml 只负责展示,.acss 只负责样式,所有数据变化和业务逻辑都集中在 .js 里。这叫「单向数据流」,能让你少踩很多坑。

3.5 .json 文件:页面的配置清单

.json 文件看起来最简单,就几行配置,但它的作用不可小觑。它告诉小程序:这个页面用什么导航栏、要不要下拉刷新、窗口背景色是什么。

典型配置:

{
  "navigationBarTitleText": "商品详情",
  "navigationBarBackgroundColor": "#1677ff",
  "enablePullDownRefresh": true,
  "usingComponents": {
    "custom-header": "/components/header/header"
  }
}

嗯,这里要注意:

  • navigationBarTitleText:导航栏标题,比在 .axml 里写死要灵活得多
  • usingComponents:引入自定义组件。我建议你把复用的 UI 都抽成组件,然后在 .json 里注册
  • 全局配置在 app.json 里,页面配置会覆盖全局配置
我的习惯: 每个页面的 .json 文件我都会先写好。因为配置决定了页面的「外壳」,比如导航栏颜色、是否允许分享。先把外壳定好,再写内部逻辑,思路会更清晰。

3.6 四个文件如何协同工作?

现在我们把四个文件串起来,看看它们是怎么配合的。

一个完整的交互流程:

  1. 用户打开页面,小程序读取 .json 配置,确定导航栏样式和组件依赖
  2. .jsonLoad 被触发,请求数据并调用 setData 更新数据
  3. .axml 检测到数据变化,重新渲染页面,展示最新的内容
  4. .acss 为渲染出来的标签应用样式,让页面看起来美观
  5. 用户点击按钮,事件冒泡到 .js 中定义的处理函数,触发新一轮的数据更新

你看,这就像一条流水线:配置 → 数据 → 结构 → 样式 → 交互。每个文件只负责自己那一环,互不干扰。

文件 职责 类比
.axml 页面结构 + 数据绑定 房子的骨架
.acss 样式与布局 房子的装修
.js 数据 + 逻辑 + 事件 水电 + 智能系统
.json 页面配置 户型图说明书
避坑指南: 我曾经在项目里遇到一个 bug——页面数据更新了,但视图没变。查了半天,发现是 .js 里直接修改了 data 对象的属性,没有用 setData。记住,setData 是连接 .js 和 .axml 的唯一通道,绕过去就会出问题。

3.7 小结

四个文件各司其职,缺一不可。.json 定配置,.js 管数据,.axml 搭结构,.acss 做美化。它们通过数据绑定和事件系统紧密配合,构成了支付宝小程序的页面单元。

下一章我们会深入 .js 的生命周期函数,看看页面从加载到销毁到底经历了什么。到时候我会分享一些我在实际项目中踩过的坑,保证让你少走弯路。