# 微信小程序入门与基础语法

# 今日学习目标

1、熟悉APPID与微信开发者工具使用

2、熟练配置项目与沉浸式导航栏

3、掌握数据绑定并能实现双向数据绑定

4、掌握列表渲染与条件渲染

5、了解模板使用

6、掌握WXS的使用

7、掌握组件化开发、组件传值方法

8、掌握路由跳转与tabbar页面跳转

9、掌握生命周期

10、掌握数据请求及封装

# 预:微信小程序账号注册与APPID获取【了解】

访问 http://mp.weixin.qq.com/ ,并点击 立即注册 :

点击:

然后填写邮箱和密码(记住:如果你的邮箱注册过微信公众号,请重新注册一个邮箱):

点击注册,并且登录邮箱去激活:

到邮箱中点击激活链接:

跳转到小程序官网后:

选择“个人”,然后按照要求填写:

扫码确认后,点击继续:

点击确定,就会跳转到小程序后台,这时候,点击左侧“开发”,再点击Tab栏“开发设置”,就可以获取到APPID了:

这个APPID只有自己能用,其他人是无法使用的。

# 一、微信小程序官网【了解】

https://mp.weixin.qq.com/

# 二、APPID注册【了解】

从官网这里进去:

选择小程序进行注册:

然后按照流程,填写好账号密码等信息即可。

若在填写过程中,需要你选择企业类型,请选择个人。

如果依然不知道要怎么操作,请查看《微信小程序账号注册与APPID

# 三、获取APPID【掌握】

注册后,回到登录界面,登录刚刚注册的账号,进入系统后台,找到左侧的 开发

虽然我们的小程序在学习阶段,可以用测试号进行开发,但我们后期需要用到云开发,云开发要求必须有appid,因此,请尽快注册。

# 四、创建项目【掌握】

打开 微信开发者工具(下载地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html),扫码后进入到这个界面:

点击此处,新建项目,按照以下图示填选:

点击 新建,创建成功,进入到以下界面:

若未能进入此页面,请按快捷键 ctrl+R 重新编译一次即可。

# 五、工具与目录介绍【了解】

# 1、开发工具介绍

工具使用方法听讲师讲述即可。

# 2、目录介绍

我们先学习静态页面开发,再深入学习云开发。因此,我们目前只需要关注 miniprogram 目录下的内容即可。

# 六、项目总配置文件【重点】

打开 app.json 后,我们可以看到,所有的页面的创建,都在 pages 这个数组中填写:

其中,哪个页面地址写在数组的第一项,编译/刷新整个浏览器时,哪个页面就会优先显示。

# 1、创建页面

这里我们把pages下,所有页面都删掉,把这个 pages 字段也清空,我们自己来书写一个页面:

# 2、沉浸式导航栏

pages 同级的 window 对象,可用于控制整个小程序的沉浸式导航栏,但每个 页面也可单独配置。我们先配置整个小程序试试:

# 3、tabBar配置【重点】

这里提供tabbar配置所需要的图片:

链接: https://pan.baidu.com/s/1ZtYFpuE2HoacIKikyMeUnw (opens new window) 提取码: dm3i

app.json 中,windows 同级的位置,写入:

{
  "windows": {
    ...
  },
  "tabBar": {
    "color": "#909192",
    "selectedColor": "#0600B8",
    "list": [{
      "pagePath": "pages/home/home",
      "text": "首页",
      "iconPath": "images/bar/bar1_1.png",
      "selectedIconPath": "images/bar/bar1.png"
    },{
      "pagePath": "pages/menu/menu",
      "text": "菜单",
      "iconPath": "images/bar/bar2_2.png",
      "selectedIconPath": "images/bar/bar2.png"
    },{
      "pagePath": "pages/new/new",
      "text": "新品",
      "iconPath": "images/bar/bar3_3.png",
      "selectedIconPath": "images/bar/bar3.png"
    },{
      "pagePath": "pages/kefu/kefu",
      "text": "小二",
      "iconPath": "images/bar/bar4_4.png",
      "selectedIconPath": "images/bar/bar4.png"
    }]
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

这里路径不允许使用 ./ 开头。来看看效果:

# 七、配置Home页面【重点】

打开 home.json 文件,我们尝试隐藏导航栏:

# 八、页面文件介绍【掌握】

pages 目录下,每个页面就是一个文件夹,一个页面包含wxml、wxss、js和json文件,其中:

  • wxml:相当于html文件
  • wxss:相当于css文件

# 1、标签

标签分单双标签,书写格式与html完全一样,但在微信小程序里,没有div、span、p、h1-h6这些标签,它只有非常简单的两个最基本的标签:view(即:div) 与 text(即:span)。当然,还有其他经过封装的组件,我们后面会再做介绍。

# 2、JavaScript

微信小程序与vue.js框架用法大致相同,同属MVVM框架,都是由数据驱动视图更新。因此,js事件和变量的书写,也会与原生JS稍有差异。

# 九、数据绑定【重点】

home.wxml 页面写入:

<view>{{msg}}</view>
1

home.js 写入:

Page({
  data: {
    msg: '你好,世界'
  }
})
1
2
3
4
5

如此,便完成了数据绑定。

可以看到,动态变化的数据,我们统一放在data里面。这里跟vue做个区别,vue中规定组件内data必须是函数,而小程序不用,使用一个对象表示即可。

小程序中,我们要记住,凡是调用data中的数据,在wxml文件使用时,就需要加 {{}},这语法便是著名的:mustache语法,也称胡子语法。

# 十、双向数据绑定【重点】

# 1、修改data中的数据

小程序中,使用 this.setData() 来修改data中的数据。

# 2、方法绑定

一个标签需要调用一个函数(或称:方法),需要在标签上绑定事件,如绑定触摸事件(即:pc上的点击事件):

<button bindtap="tapFn">按钮</button>
1

然后在js中:

Page({
  data: {
    ...
  },
  tapFn(){
    // do something...
  }
})
1
2
3
4
5
6
7
8

# 3、实现双向数据绑定

我们来实现双向数据绑定:

home.wxml 中:

<input value="{{msg}}" bindinput="iptFn"></input>
<view>{{msg}}</view>
1
2

在js中:

Page({
  data: {
    msg: '你好,世界'
  },
  // input值被修改时触发的函数
  iptFn(e){
    this.setData({
      msg: e.detail.value
    })
  }
})
1
2
3
4
5
6
7
8
9
10
11

# 十一、列表循环【重点】

微信小程序实现for循环有好几种方式,一种是使用block标签来循环一段代码,当然,也可以直接在要循环的那段代码的外层,直接进行 wx:for ,看个人喜好。

<!-- 方法1 -->
<view class="box">
    <view wx:for="{{arr}}" wx:key="*this">{{item}}</view>
</view>

<!-- 方法2 -->
<view class="box">
    <block wx:for="{{arr}}" wx:key="*this">
      <view>{{item}}</view>
    </block>
</view>
1
2
3
4
5
6
7
8
9
10
11

js中:

Page({
  data: {
    arr: ['张三', '李四', '王五']
  }
})
1
2
3
4
5

可以复制以上代码,到模拟器看看效果,会发现原来效果一样。

这里要注意几点:

  1. wx:key可以不写,但不写会报黄色警告;
  2. 保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字;
  3. 每个循环都会自带 itemindex ,不需要像vue一样写:v-for="(item, index) in arr"
  4. 如果出现多层数组的循环,那就会出现item指向不明确,虽然小程序可以帮我们自动识别,但代码可维护性降低,因此,我们可以使用 wx:for-item="items" 来改变item的名称。

# 十二、条件渲染【重点】

# 1、wx:if

在框架中,使用 wx:if="" 来判断是否需要渲染该代码块:

<view wx:if="{{condition}}"> True </view>
1

也可以用 wx:elifwx:else 来添加一个 else 块:

<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
1
2
3

# 2、block wx:if

因为 wx:if 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。

<block wx:if="{{true}}">
  <view> view1 </view>
  <view> view2 </view>
</block>
1
2
3
4

注意: block 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。

# 3、wx:if vs hidden 【了解】

因为 wx:if 之中的模板也可能包含数据绑定,所以当 wx:if 的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。

同时 wx:if 也是惰性的,如果在初始渲染条件为 false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染

相比之下,hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。

一般来说,wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。

# 4、总结

hidden 属性用于频繁切换,切换较少时,建议使用 wx:if。用法:

wxml中:

<view hidden="{{ifShow}}">显示或隐藏</view>
1

js中:

Page({
  data: {
    ifShow: false	// 由于hidden代表一种否定(或称:取反),所以这里为false,上面的view标签才能显示
  }
})
1
2
3
4
5

# 十三、模板与引用【熟悉】

vue中有插槽的概念,小程序中有模板与引用,这两者还是比较像的。我们先来看看怎么玩。

# 1、模板创建

pages/home/ 目录下创建 templates 文件夹,里面用于存放模板文件。我们新建 item.wxml 文:

<template name="box1">
  <text bindtap="txtFn">box1: {{content}}</text>
</template>

<template name="box2">
  <text bindtap="txtFn">box2: {{content}}</text>
</template>
1
2
3
4
5
6
7

# 2、模板引用

home.wxml 中:

<import src="./templates/item.wxml" />
<template is="box1" data="{{content: txt}}"></template>
1
2

这里通过import标签引入模板,通过template标签使用模板,使用is属性来指定调用 item.wxml 中哪个模板,使用data属性来传值。

这里大家要注意,创建模板时,我们写的 bindtap="txtFn" ,实现txtFn的方法,需要写在 调用方 的js文件中,而非模板的js文件。

// home.js
Page({
  data: {
    txt: '叩丁狼H5大前端'
  },
  // 可供模板调用的方法
  txtFn(){
    console.log('打印...')
  }
})
1
2
3
4
5
6
7
8
9
10

# 十四、WXS模块【掌握】

WXS 代码可以编写在 wxml 文件中的 <wxs> 标签内,或以 .wxs 为后缀名的文件内。

WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。

wxs可以说就是为了满足能在页面中使用js存在的,在wxml页面中,只能在插值中写简单的js表达式,而不能调用方法,例如想取出一个字符串的最后一位,就不能调用slice()方法。

通常的解决办法是在page的data对象中先把这个字符串截取好赋给某个变量,然后在页面中使用这个变量,但是问题又来了,如果变量多了呢,是不是要定义很多次?wxs就是弥补了这样的短处。

相对来说wxml中使用js语法就比较薄弱了,wxs就是弥补了这样的短处。

# 1、使用方法

  • 写好wxs文件 然后使用 module.exports 导出要使用的方法或变量
  • 在待使用页面 使用 <wxs src="/path" module="tools" /> 引入
  • 在插值{{}}中使用 tools.method_name(para)

# 2、实用教程

# * wxs写法1

home 页面下,新建 test.wxs ,并写一段截取字符串的方法:

function my_slice(str,a,b){
  return str.slice(a,b);
}
module.exports = {
  my_slice: my_slice
}
1
2
3
4
5
6

在wxml文件:

<wxs src="./test.wxs" module="tools" />
<view>
  {{tools.my_slice("123456789",0,5)}}
</view>
1
2
3
4

# * wxs写法2

在wxml文件:

<wxs module="tools">
  function add(a, b){
    var sum = a + b;
    return sum;
  }
  module.exports = {
    add: add
  };
</wxs>

<view>
  {{tools.add(3, 4)}}
</view>
1
2
3
4
5
6
7
8
9
10
11
12
13

# 十五、组件化开发【重点】

接下来的首页“新品展示”区块,我们采用组件化开发的操作:

# 1、创建组件

组件相当于页面,创建的方法与创建页面相同,可以在 app.json 中的 pages 进行创建:

{
  "pages": [
    ...,
    "components/product/product"
  ],
}
1
2
3
4
5
6

我们看到,在项目根目录中,增加了一个 components/product/product 目录。

# 2、结构、样式与数据渲染

product.wxml 中:

<view class="product_list">
  <view wx:for="{{showArr}}" wx:key="*this" class="product_list_box">
    <image src="{{item.imgSrc}}" mode="widthFix"></image>
    <view>{{item.imgTxt}}</view>
  </view>
</view>
1
2
3
4
5
6

product.wxss 中:

/* components/product/product.wxss */
.product_list{
  display: flex;
  padding: 20rpx 2%;
  justify-content: space-between;
  flex-wrap: wrap;
}

.product_list_box{
  width: 49%;
  box-shadow: 0 0 6rpx #666;
  border-radius: 10rpx;
  overflow: hidden;
  margin-bottom: 20rpx;
}

.product_list_box image{
  width: 100%;
  display: block;
}

.product_list_box view{
  height: 50rpx;
  line-height: 50rpx;
  text-align: center;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

product.js 中:

// 注意注意:这里的Page()方法改成了Component()方法
Component({
  data: {
    showArr: [
      {imgSrc: "/images/home/newPro1.jpg", imgTxt: "卡布奇诺"},
      {imgSrc: "/images/home/newPro2.jpg", imgTxt: "白咖啡"},
      {imgSrc: "/images/home/newPro3.jpg", imgTxt: "摩卡咖啡"},
      {imgSrc: "/images/home/newPro4.jpg", imgTxt: "爱尔兰咖啡"},
      {imgSrc: "/images/home/newPro5.jpg", imgTxt: "甜品咖啡"},
      {imgSrc: "/images/home/newPro6.jpg", imgTxt: "意大利咖啡"},
      {imgSrc: "/images/home/newPro7.jpg", imgTxt: "拿铁咖啡"},
      {imgSrc: "/images/home/newPro8.jpg", imgTxt: "中式咖啡"}
    ]
  },
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 3、声明为组件

product.json 中:

{
  "usingComponents": {},
  "component": true
}
1
2
3
4

# 4、调用组件

home.json 中:

{
  "usingComponents": {
    "product-block": "/components/product/product"
  },
  "navigationStyle": "custom"
}
1
2
3
4
5
6

home.wxml 中:

<product-block />
或:
<product-block></product-block>
1
2
3

# 十六、组件传值【重点】

虽然此时我们已经完成了组件化开发并引入成功,但我们要考虑数据是否放在子组件中,很明显这个子组件可能将来会被复用,因此数据应该由父级获取后传给子级,这样更加稳妥些。

# 1、父传子

我们将该组件的数据迁移到父组件 Home.js 中,然后通过父传子传过来:

Home.wxml 中:

<product-block showArr="{{showArr}}" />
1

product.js 中:

Component({
  // properties用于接收传值,类似于vue中的props
  properties: {
    showArr: {
      // 设置数据类型
      type: Array,
 			// 设定初始值(即默认值)
      value: [{imgSrc: "/images/home/newPro1.jpg", imgTxt: "卡布奇诺"}]
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11

# 2、子传父

我们尝试点击 product 组件中的任意一项,来触发父级的事件。

<!-- 子组件wxml -->
<view class="product_list">
  <view wx:for="{{showArr}}" wx:key="*this" class="product_list_box" bindtap="productTap">
    ...
  </view>
</view>
1
2
3
4
5
6
// components/product/product.js
Component({
  ...,
  // 如果是组件,不是页面,就必须写methods
  methods: {
    productTap(){
  		// 小程序中子传父通过triggerEvent来实现
      this.triggerEvent('fatherEvent', 100);
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11

父组件:

<!-- 标签上使用bind来接收子组件传过来的事件 -->
<product-block showArr="{{showArr}}" bind:fatherEvent="fatherEventFn" />
1
2
Page({
  ...,
  // 页面无需写methods
  fatherEventFn(data){
    console.log(data.detail); // 100
  }
})
1
2
3
4
5
6
7

如此,我们实现了父子传值。

# 3、全局变量globalData

微信小程序全局变量globalData在app.js中,调用的方法有:

【方法一(推荐)】通过app获取,需要在第一行声明app的实例 const app = getApp()

const app = getApp()
Page({
  onLoad: function () {
    console.log(app.globalData.name);
  },
})
1
2
3
4
5
6

【方法二】直接通过getApp().globalData获取,不需要写const app = getApp()实例

onLoad: function () {
    console.log(getApp().globalData.name);
},
1
2
3

【方法三】在app.js文件内使用

onLoad: function () {
    console.log(this.globalData.name);
},
1
2
3

修改global的方法【借助方法一】:

app.globalData.name = "xxxx";
1

# 十七、路由跳转【掌握】

# 1、跳转到非tabbar页面(js)

wx.navigateTo({
    url: '/pages/logs/logs'
})

// url携带参数的形式:
wx.navigateTo({
    url: '/pages/logs/logs?id=123',
})

// 如何获取参数?
onLoad: function (options) {
    console.log(options.id)		// 123
},
    
// 携带复杂参数的形式
wx.navigateTo({
    url: '/pages/logs/logs?id=123',
    success: function(res) {
        // 通过eventChannel向被打开页面传送数据
        res.eventChannel.emit('someData', { arr: [1,2,3] })
    }
})

// 接收复杂参数的形式
onLoad: function (options) {
    console.log(options.id)		// 123
    const eventChannel = this.getOpenerEventChannel()	// 通过eventChannel来获取参数
    eventChannel.on('someData', function(data) {
        console.log(data.arr)	// [1,2,3]
    })
},
    
// 当前页反向发射数据到上一页
onLoad: function (options) {
    const eventChannel = this.getOpenerEventChannel()
    // 反向发射数据
    eventChannel.emit('fanxiang', {username: '张三'});
},
    
// 上一页接收反向发射的数据
wx.navigateTo({
    url: '/pages/list/list?id=123',
    // events中写反向发射的函数
    events: {
        fanxiang(data){
            console.log(data)
        }
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 2、跳转到非tabbar页面(wxml)

<navigator url="/pages/logs/logs"></navigator>
1

# 3、跳转到tabbar页面

wx.switchTab({
    url: '/pages/user/user'
})
1
2
3

# 十八、生命周期【重点】

微信小程序有两类生命周期,一类是组件的生命周期 (opens new window),另一类是页面的生命周期 (opens new window)

# 1、页面的生命周期:

img

总的来说,小程序页面的生命周期为:

onLoad > onShow > onReady > onHide > onShow > onUnload

# 2、组件生命周期

组件的生命周期:

Component({
  lifetimes: {
    attached: function() {
      // 在组件实例进入页面节点树时执行
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
    },
  }
})
1
2
3
4
5
6
7
8
9
10

这里提供组件的生命周期表:

生命周期 参数 描述 最低版本
created 在组件实例刚刚被创建时执行 1.6.3 (opens new window)
attached 在组件实例进入页面节点树时执行 1.6.3 (opens new window)
ready 在组件在视图层布局完成后执行 1.6.3 (opens new window)
moved 在组件实例被移动到节点树另一个位置时执行 1.6.3 (opens new window)
detached 在组件实例被从页面节点树移除时执行 1.6.3 (opens new window)
error Object Error 每当组件方法抛出错误时执行 2.4.1 (opens new window)

这里有个要注意的点:

官方文档:

组件实例刚刚被创建好时, created 生命周期被触发。此时,组件数据 this.data 就是在 Component 构造器中定义的数据 data此时还不能调用 setData 通常情况下,这个生命周期只应该用于给组件 this 添加一些自定义属性字段。

可以看出,在created中无法使用this,因此,建议不在created中做请求

再提供组件所在页面的生命周期:

生命周期 参数 描述 最低版本
show 组件所在的页面被展示时执行 2.2.3 (opens new window)
hide 组件所在的页面被隐藏时执行 2.2.3 (opens new window)
resize Object Size 组件所在的页面尺寸变化时执行 2.4.0 (opens new window)

代码示例:

Component({
  pageLifetimes: {
    show: function() {
      // 页面被展示
    },
    hide: function() {
      // 页面被隐藏
    },
    resize: function(size) {
      // 页面尺寸变化
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13

# 十九、数据请求【重点】

# 1、原生API调用

在微信小程序中,我们使用 wx.request() 方法做数据请求,如:

wx.request({
  url: 'http://kumanxuan1.f3322.net:8001',
  success(res){
    console.log(res);
  }
})
1
2
3
4
5
6

接口地址:

叩丁严选项目接口文档 http://www.docway.net/project/1Ve70KqViGf/share/1Wi8PNyUmTA (opens new window) 阅读密码:zhaowenxian

# 2、合法域名配置

正常来讲,按照以上操作会碰到合法域名的报错,如:

1618026295311

这是因为小程序对接口地址有严格要求,所有的baseUrl必须在小程序后台配置合法域名。

mp.weixin.qq.com 登录,找到 开发 - 开发管理 - 开发设置 - 服务器域名 。只需要将后端给你的接口地址填写进去即可。这里注意:合法域名必须是https开头,否则无法配置,只能作为开发阶段的测试。

开发阶段想要测试,可以点击开发工具右上角的 详情

1618026491334

不校验合法域名 勾选上即可。

# 3、request封装

使用资料中封装好的request,其中有三个文件:

这里提供资料获取链接:

链接: https://pan.baidu.com/s/1BYzvpIbTlid_MLrh1RFA1g (opens new window) 提取码: 7gsl

  • request.js 是用来封装请求的,一般我们不动它
  • api.js 是用来统一管理Restful风格的接口地址与baseUrl的
  • fetch.js 是用来导出请求函数,供页面调用的,其中有3套模板,大家可以直接copy使用

# 二十、作业

参考 【硬核干货】小程序+Weapp自定义TabBar (opens new window) 做出tabbar。

支付宝打赏 微信打赏
Last Updated: 12/16/2021, 5:56:10 PM