# 开发 \| 小程序开发有哪些坑？这份笔记都整理出来了

- 作者：知晓程序
- 发布时间：2017-02-14 12:29
- 原文：https://www.ifanr.com/minapp/786415

![](https://s3.ifanr.com/wp-content/uploads/2017/02/Featured-7.jpg)

**知晓程序注：**

即使你认为小程序开发很简单，也无法否认小程序开发中，仍然有许多需要注意的地方。稍不注意，就会产生意料之外的问题。

知晓程序（微信号 zxcx0101）今天推荐的这篇文章，是**作者通过亲身开发，列出的小程序开发领域问题，并在文章给出了解决方案**。希望能够帮助开发小程序的你，避开这些坑。

---

文 \| 泡芙小姐 110

### 1. JSON 配置文件

小程序中，包含唯一的全局配置文件 `app.json`，以及每个页面的配置文件 `page.json`。每单页页面相应的 JSON 文件会覆盖与 `app.json` 相同的配置项。

如下，是一个包含了所有配置选项的简单配置 `app.json`。

```
"pages": [ //设置页面的路径
  "pages/index/index", //不需要写index.wxml,index.js,index,wxss,框架会自动寻找并整合
  "pages/logs/logs"
],
"window": { //设置默认窗口的表现形式
  "navigationBarBackgroundColor": "#ffffff", //顶部导航栏背景色
  "navigationBarTextStyle": "black", //顶部导航文字的颜色 black/white
  "navigationBarTitleText": "微信接口功能演示", //顶部导航的显示文字
  "backgroundColor": "#eeeeee", //窗口的背景色
  "backgroundTextStyle": "light", //下拉背景字体、loading 图的样式，仅支持 dark/light
  "enablePullDownRefresh": "false"， //是否支持下拉刷新 ，不支持的话就直接不写！
  "disableScroll": true, //  设置true不能上下滚动，true/false，注意！只能在 page.json 中有效，无法在 app.json 中设置该项。
},
"tabBar": { //底部tab或者顶部tab的表现，是个数组，最少配置2个，最多5个
  "list": [{ //设置tab的属性，最少2个，最多5个
    "pagePath": "pages/index/index", //点击底部 tab 跳转的路径
    "text": "首页", //tab 按钮上的文字
    "iconPath": "../img/a.png", //tab图片的路径
    "selectedIconPath": "../img/a.png" //tab 在当前页，也就是选中状态的路径
  }, {
    "pagePath": "pages/logs/logs",
    "text": "日志"
  }],
  "color": "red", //tab 的字体颜色
  "selectedColor": "#673ab7", //当前页 tab 的颜色，也就是选中页的
  "backgroundColor": "#2196f3", //tab 的背景色
  "borderStyle": "white", //边框的颜色 black/white
  "position": "bottom" //tab处于窗口的位置 top/bottom
  },
"networkTimeout": { //默认都是 60000 秒一分钟
    "request": 10000, //请求网络超时时间 10000 秒
    "downloadFile": 10000， //链接服务器超时时间 10000 秒
      "uploadFile": "10000", //上传图片 10000 秒
    "downloadFile": "10000" //下载图片超时时间 10000 秒
  },
"debug": true //项目上线后，建议关闭此项，或者不写此项

```

### 2. JS 逻辑层

小程序的逻辑层由 JavaScript 语言完成。但因为小程序不在浏览器中运行，所以 JS 在 web 浏览器中的一些函数不能用，如 `document`、`window` 等。

`app.js` 有全局的小程序生命周期，`page.js` 有自己本页面的生命周期。

#### 2.1 注册小程序 `app.js`

这一步骤，有这几个需要注意的地方：

1. 必须在 `app.js` 中，使用 `app()` 函数注册微信小程序。全局小程序中，只能注册一次；
2. 不能在 `app()` 内的函数中调用 `getApp()`（小程序实例），使用 `this` 就可以拿到小程序的实例；
3. 不要在 `onLaunch` 的时候 `getCurrentPage()`，因为此时 `page` 还没有生成；
4. 通过其他子页面调用 `getApp()` 获取实例后，不要私自调用小程序全局的生命周期方法；
5. 可以通过 `var app=getApp()` 获取小程序的实例。

```
app ( {
  // 小程序生命周期的各个阶段
  onLaunch: function(){},//当小程序初始化完成时，会触发 onLaunch（全局只触发一次）
  onShow: function(){},//当小程序启动，或从后台进入前台显示，会触发 onShow
  onHide: function(){},//当小程序从前台进入后台隐藏，会触发 onHide
  onError: function(){},//当小程序发生脚本错误，或者 api 调用失败时，会触发 onError 并带上错误信息
  // 自定义函数或者属性，用 this可以访问
  ...
})
```

#### 2.2 注册小程序的页面 `page.js`

`Page()` 用来注册一个页面，维护该页面的生命周期以及数据。

```
Page({
  data: { //页面的初始数据//调用：{{text}} {{array[0].msg}}
    text: 'init data',
    array: [{
      msg: '1'
    }, {
      msg: '2'
    }]
  },
  // 页面生命周期的各个阶段
  onLoad: function () {}, //生命周期函数--监听页面加载
  onShow: function () {}, //生命周期函数--监听页面初次渲染完成
  onReady: function () {}, //生命周期函数--监听页面显示
  onHide: function () {}, //生命周期函数--监听页面隐藏
  onUnload: function () {}, //生命周期函数--监听页面卸载
  onPullDownRefresh: function () {}, //页面相关事件处理函数。如果需要监听用户下拉动作，需要 在app.json中配置  "enablePullDownRefresh":"true" 允许上拉刷新
  onReachBottom: function () {}, //页面上拉触底事件的处理函数
  onShareAppMessage: function () { //用户点击右上角分享
    return {
      title: '自定义分享标题',
      desc: '自定义分享描述',
      path: '/page/user?id=123'
    }
  },
  // 自定义函数或者属性如：
  customData: {
    hi: 'MINA'
  }...
})
```

#### 2.3 公共模块 `util.js`

公共模块方法需要通过 `module.exports` 对外暴露接口，使用的时候需要利用 `require(path)`，将文件引入。如：

```
function sayHello(name) {//公共方法util类
  console.log(`Hello ${name} !`)
}
module.exports.sayHello = sayHello//用module.exports 对外暴露接口
```

```
//先引入文件，是新建的一个 utils 包，公共方法在 util.js 里面
var util = require('../../utils/util.js')
Page({//调用类
  onLoad: function () {//  使用时，用 util 引用名调用，如：util.sayHello()
    util.sayHello('我是传的值');
  }
})

```

#### 2.4 数据操作

`setData()` 不能直接操作数据，例如 `this.data.text="xxxxx"` 就是错误的。你需要在 `this.setData ()` 之中，进行数据的操作。

同时，这里有作用域的问题。比如，需要在局部函数中使用，就需要 `.bind(this)`。

如果你需要操作全局的数据，你需要在 app.js 中进行相应设置，例如：

```
App({// app.js
  globalData: 1
})
// 某 page.js
console.log(getApp().globalData)
```

### 3. 视图层 WXML

视图层的数据绑定均来自于 `Page` 中的 `data`，想要修改相应值，你需要用到 `this.setData`。数据绑定使用两对花括号，将变量名包起来。

#### 3.1 条件渲染

你可以利用 `if` 和 `else`，在视图层上编写在特定情况下，出现的不同的视图结果。

```
<view wx:if="{{zhenjiaa=='123'}}">123334</view>
<view wx:if="{{zhanjia}}">123334</view>
<view wx:if="{{len > 5}}">大于5我就显示了 </view>
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>

<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
```

很多人会将 CSS 中的 `display: hidden` 属性，将其做一个比较。

- 微信小程序中的 `wx:if` 是惰性的。如果不符合渲染条件，它不会渲染相应部分；
- 使用 `display: hidden` 时，元素始终渲染，只是视图层上没有显示，用户看不见。

如果你的小程序有元素显示频繁切换的需求，建议你使用 `display: hidden`，能够为用户提供能顺畅的使用体验。

#### 3.2 列表渲染

相当于让 WXML 处理一个循环。

在 WXML 中，你可以这样来建立一个 for 循环：

`<view wx:for="{{array}}"> {{index}}:{{item}} </view>`

然后在相应的 JS 中，新建一个数组：

```
page.jsPage({
  data: {
    array: [1, 2, 3, 4, 5] 
  }
}) 
```

需要注意的是，如果列表中的项需要动态添加到列表中，并希望项目保持原有的特征和状态，那么你应该使用 `wx:key`。

`wx:key` 有两种形式：

1. 字符串：`wx:key="unique"`
2. 保留关键字：`wx:key="*this"`

#### 3.3 运算

WXML 可以执行简单的运算任务。例如：

`<view> {{a + b}} + {{c}} + d </view>`

也可以做到字符串拼接：

`<view>{{"hello" + name}}</view>`

甚至，你可以使用 `...` 在 WXML 中展开对象。

#### 3.4 模板

`name` 定义组件模版的名称，引用模版的时候使用 `is` 属性指定模版的名字，`is` 可以进行简单的三目运算，需要传入模版需要的 `data` 数据。

因为模版拥有自己的作用域，所以只能使用 data 传入数据，而不接受双花括号的写法。

```
<template name="msgItem">
<view>
<text> {{index}}: {{msg}} </text>
<text> Time: {{time}} </text>
</view>
</template>

<!-- 其他代码 -->

<template is="msgItem" data="{{...item}}"/>
```

#### 3.5 公共模块的引用

WXML 提供 `import` 和 `include` 两种文件引用方式。

`import` 有作用域的概念，不能多重引用。

```
<!-- B.wxml -->
<import src="a.wxml"/>

<!-- A.wxml -->
<template name="A">
 <text> A template </text>
</template>
```

而 `include` 就可以多重引用了。

```
<!--引用 header、其中 header.wxml 中也引用了 footer.wxml-->
<include src="header.wxml"/>
<view> body </view>

<!-- header.wxml -->
<view> header </view>
<include src="footer.wxml"/>
```

#### 3.6 事件

名称以 `bind` 开头的事件不阻止冒泡，名称以 `catch` 开头的事件冒泡是阻止的。如 `bindTap` 和 `catchTab`。

在 WXML 中，可以使用 `dataset` 定义 `data` 中的数据，会通过事件传递。它的事件以 `data-` 开头，多个单词以 `-` 链接，如 `data-a-b`。

需要注意的是，使用这种方式定义的变量不能有大写。它会自动转成驼峰命名，调取的时候去驼峰命名的名字。

### 4. WXSS

WXSS 的用法类似于 CSS，并在 CSS 的基础上，扩展了 rpx 尺寸单位和样式导入功能。

WXSS 可以使用内联样式，但这样会影响渲染速度。

每个页面自己的 `page.wxss` 样式表，会覆盖全局样式表 `app.wxss`。

原文地址：http://www.jianshu.com/p/f8f85757e90d

#### 往期精选文章

- [开发 \| 一篇文章读懂微信小程序视图层](http://www.ifanr.com/minapp/784666)
- [如何在小程序中绘制图表？](http://www.ifanr.com/minapp/783579)
- [如何解决小程序的兼容性问题？](http://www.ifanr.com/minapp/782408)

**本文由知晓程序授权转载，关注微信号 zxcx0101，可获得以下内容和服务：**

- 在微信后台回复「1228」，获取全网首本《微信小程序入门指南》。
- 在微信后台回复「加群」，加入「一起发现小程序」微信交流群。
- 在微信后台回复任意关键词，还能获得相关小程序推荐，赶紧试试吧！

![zxcx&#95;0208](https://s3.ifanr.com/wp-content/uploads/2017/02/zxcx_0208.png)
