Fork me on GitHub

微信小程序篇

view 容器

1
2
< view ></view>
// 相当于 div ,起到承载作用,小程序内没div, 故用view 代替

image 图片

1
2
<image src='/xxx/xxx.png'></image>
// 注意请尽量使用相对路径

text 文本

1
<text>我是文本内容</text>

swiper 轮播组件

1
2
3
4
5
6
7
8
9
10
11
<swiper>
<swiper-item>
<image src='/images/vr.png'></image>
</swiper-item>
<swiper-item>
<image src='/images/iqiyi.png'></image>
</swiper-item>
<swiper-item>
<image src='/images/wx.png'></image>
</swiper-item>
</swiper>

数据绑定概念和基础

简单– 不适用, 数据必须是在 data中才能渲染到页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 请在当前页面的js 文件中👇函数中编写数据 

// 页面的初始数据
data: {
date: "Hu 18 2020",
title: "大通湖大闸蟹",
}
// 在当前页面的的wxml 页面中编写如下代码就能渲染出 js中的数据

<text >{{ date }} </text>
<text >{{ title }} </text>

// 页面会渲染出
Hu 18 2020
大通湖大闸蟹

setData方法绑定数据

获取服务器数据方式(模拟–不适用,不是动态的,不是服务器上的)

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
// 页面的初始数据
// 👉⚠data

data: {
date: "Hu 18 2020",
title: "大通湖大闸蟹",
},

// 生命周期函数-----监听页面加载
onLoad: function (options){
var post = {
date: "Hu feifei",
title: "18岁少年",
post_img: "/xxx/xxx/xxx.png",
content: "xxxxxxxxxxxxxxxxxxxxxxxxx",
view_num: "112"
}
// 注释:所有的数据必须在 data 中才能被渲染,上面的数据必须 传入到 data 中。
// 👉 ⚠数据 --->> ⚠data --->> ⚠渲染页面
this.setData( post ) // post = 数据的变量名称
}

// 👉⚠渲染页面
<text >{{ date }} </text>
<text >{{ title }} </text>
<image scr="{{post_img}}"></image>

setData方法绑定数据

数据嵌套— 如何获取??? 如何调用数据???

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 生命周期函数-----监听页面加载
onLoad: function (options){
var post = {
// 👇 数据嵌套
img:{
post_img: "/xxx/xxx/xxx.png",
content: "xxxxxxxxxxxxxxxxxxxxxxxxx",
view_num: "112"
}
}
// 👉 数据 ---->> data 获取数据 ---->> WXML 调用数据
this.setData( post )
}

// 👉⚠渲染页面
<text >{{ img.content }} </text>
<text >{{ img.view_num }} </text>
<image scr="{{ img.post_img }}"></image>

wx:if 条件渲染

某个元素的隐藏显示的控制通过 wx:if 来判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 👇⚠渲染页面
<text wx:if="wxif">{{ img.content }} </text>


// 生命周期函数-----监听页面加载
onLoad: function (options){
var post = {
data: '我是数据data',
img:{
post_img: "/xxx/xxx/xxx.png",
content: "xxxxxxxxxxxxxxxxxxxxxxxxx",
view_num: "112",
wxif: true // 👈 显示,false 隐藏
}
}
this.setData( post )
}

wx:for 列表渲染

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
//   👇block 列表渲染--- wx:for="xx" 数据对象  wx:for-item ="item"  =  第几个子元素  wx:for-index = "index"  =  数组索引值 = 数组序号

<block wx:for="{{ post_key }}" wx:for-item="item" >
<view class='post-box'>
<text >{{ item.date }} </text>
<text >{{ item.title }} </text>
<image scr="{{ item.post_img }}"></image>
</view>
</block>



// 生命周期函数-----监听页面加载
onLoad: function (options){
var post = [{
date: "Hu feifei",
title: "18岁少年",
post_img: "/xxx/xxx/xxx.png",
},{
date: "zhou bangbang",
title: "16岁菇娘",
post_img: "/xxx/xxx/xxx.png",
}]
// 👉 数据(传送必须是对象) ---->> data 获取数据 ---->> WXML 调用数据
// 这里需要注意的是当前变量,必须是对象,而现在是数组。需要把对象赋值给变量。
// 该变量值,必须跟wx:for="post" 相同的,不然无法获取到数据
this.setData({ post_key :post })

}
// 注释,列表循环是根据数据 的组数来决定生成的,列子是2组数据,页面会自动生成俩组数据
// item : 估计是指"每组数据", 1 2 3 4 5 6 ... 跟 循环中i 值,相等。

事件机制——捕捉与回调1

1
2
3
4
5
6
7
8
9
10
11
12
13
// 事件监听
<view bind:tap="onTap"></view>

// js
Page({
// 回调函数
noTap:funciton(){
// 内置 跳转 API,值必须是一个对象
wx:navigateTo({
url:"../xxx/xxx"
})
}
})

事件机制——捕捉与回调2

1
2
3
4
5
6
7
8
9
10
11
12
13
// 事件监听
<view bind:tap="onTap"></view>

// js
Page({
// 回调函数
noTap:funciton(){
// 该内置跳转API,没有返回按钮
wx:redirectTo({
url:"../xxx/xxx"
})
}
})

冒泡与非冒泡

1
2
3
4
// 该情况下,点击子元素,父元素的事件监听也会被触发
<view bind:tap="noTap">
<view bind:tap= "caTch"></view>
</view>
1
2
3
4
// 该情况下,点击子元素,父元素的事件监听,不会被触发,被阻止冒泡了
<view bind:tap="noTap">
<view catch:tap= "caTch"></view>
</view>

把数据分离到一个新的文件中,数据需要给导出的出口

1.新建js文件(创建新的数据模块)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 定义变量,存储数组 ---->> 对象数据
var 自定义变量名 = [{
date: "Hu feifei",
title: "18岁少年",
post_img: "/xxx/xxx/xxx.png",
},{
date: "zhou bangbang",
title: "16岁菇娘",
post_img: "/xxx/xxx/xxx.png",
}]

// 数据导出
module.exports = {
postList: 引用👆自定义变量名
}

2. require 导入新的数据模块

1
2
3
4
// 当前js页面顶部-----导入数据,必须是相对路径
var 数据名称 = require('../../xxx.js')
// 检测数据是否获取到数据
console.log( 数据名称 )

3.载入数据模块

1
2
3
4
5
6
// 把数据载入到 data 
onLoad: function(options){
this.setData({
自定义变量名 : 数据名称.postList
})
}

4.页面渲染 数据

1
2
3
4
5
6
<!-- 循环渲染 -->
<block wx:key='1' wx:for="{{ 渲染数据 }}" wx:for-item="item" wx:for-index="index">
<text >{{ item.date }} </text>
<text >{{ item.title }} </text>
<image scr="{{item.post_img}}"></image>
</block>

template 使用模板 (别称 占位符)

template 组件化思维, 小程序中有— 自定义组件Component

用途: 代码的复用性,代码的更好的表现形式。

1.wxml 创建模块

1
2
3
4
5
6
// 👇 模块名字 postItem
<template name="postItem" >

// 模板内容

</template>

2.wxml 模块调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// wxml 页面顶部 引入模块内容 👇,必须有结束符合/
<import src="模块路径地址.wxml"/>


// 列表渲染
<block wx:for="{{ 循环数据名 }}" wx:for-item="item" wx:for-index="index" >
// 循环数据名= js中导入到数据,通过自定义变量名传入到data 中的这个变量

// template 调用模块内容,1.必须要传递数据到模块内进行数据绑定,2.必须有结束标签 /
<template is = "postItem" data="{{ item }}"/>
// ⚠️: data 必须传,不然获取不到数据
// ⚠️: 结束符 必须写,不然报错

</block>

3.wxss 模块创建与调用

1
1.CSS样式移到新的 wxml 下的wxss 文件中,直接粘贴即可
1
2
2.在当前WXSS文件 顶部引入 css模块路径
@import "../../...wxss";

数据填充

新闻列表

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
// 导入数据
var postsData = require('../../data/posts-data.js')

/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {

// 数据导入到data 进行数据初始化渲染
// this.data.postList = postsData.postList
this.setData({
post_key: postsData.postList
});
},

// 新闻列表点击当前这个,进入对应到详情
noPostTap: function(event) {
// 获取 postid
var postId = event.currentTarget.dataset.postid;
console.log("当前点击到是第" + postId + "页")
// 点击,跳转到子页面,并且有返回按钮
wx.navigateTo({
url: 'posts-datail/posts-datail?id=' + postId,
})
}

新闻详情页js

1
2
3
4
5
6
7
8
9
10
11
12
13
// 导入数据
var postsData = require('../../data/posts-data.js')


noPostTap: function(event) {
// 获取 postid
var postId = event.currentTarget.dataset.postid;
console.log("当前点击到是第" + postId + "页")
// 点击,跳转到子页面,并且有返回按钮
wx.navigateTo({
url: 'posts-datail/posts-datail?id=' + postId,
})
}

新闻详情页wxml

1
<image class='head-image' src='{{postData.headImgSrc}}'></image>

图解:

ES6扩展运算符的巧妙应用

ES6扩展运算符,… 把数据展开,每组数据都是一个对象,数据展开意思是把对象去掉,直接获取到 对应的对象名上,也就说添加了三个小点,就如同把数据 子项直接写在data 里面

不添加三个小点:

1
2
3
4
5
6
{	
title :"12345",
content:"6789"
}
// 必须这样获取数据
<text>{{ item.title }}</text>

添加三个小点如同数据写在data 里面

1
2
3
4
5
6
7
data{
title :"12345",
content:"6789"
}

// 这样获取数据
<text>{{ title }}</text>
1
2
3
4
5
6
7
<!-- 循环渲染 -->
<block wx:key='1' wx:for="{{post_key}}" wx:for-item="item" wx:for-index="index">
// item ,前面添加三个... 可以在每个页面调用不同的数据,模块内部,不需要添加 item.xxx
// 由外部的页面 ...item 去传入(ES6语法)
<template is="postItem" data="{{ ...item }}" />

</block>
1
2
// 这里由外部,去传入 item ,内部 src={{ item.imgSrc }},不需要去添加 item.imgSrc,直接写imgSrc值
<image class='post-image' src='{{imgSrc}}'></image>

组件的自定义属性及获取属性

原则:先静后动,先样式再数据

如果我们想把一个值或者一个属性,绑定到标签上面不能使用自定义属性名,在小程序中如果你想记录数据,必须使用:如下👇

1
2
3
<view bind:tap="noPostTap" data-s="{{item.postId}}">
// data-s
</view>

收藏、未收藏功能思路

  • 获取所有缓存状态

  • 判断所有缓存状态是否存在

    • 获取当前文章的缓存状态
    • (遇上报错一个巨坑mac:该位置需要对当前缓存值做判断 vs windows :不做判断,居然不报错,一切正常)
      • 修改data 的Collected 的值
  • 如果 缓存状态不存在

    • 则需要创建 缓存状态的对象
    • 如果没有缓存状态,证明当前的文章缓存值,默认为false:表示未收藏
    • 然后把该缓存值,存放到缓存状态中
    • 更新文章是否收藏的缓存值
    • 更新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
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      /**
      * 生命周期函数--监听页面加载
      */
      onLoad: function (options) {
      // 接收 post.js 传送来的 ID
      var postId = options.id;

      // 把Postid 放到 data 中去,作为参数共点击事件做调用
      this.data.currentPostId = postId;

      console.log(postId);

      // 取本地的数据: 本地数据名.postList[ 数据ID名 ]
      var postData = postsData.postList[postId]

      // 数据绑定,添加扩展运算符
      this.setData({...postData})


      // 获取所有缓存状态
      var postsCollected = wx.getStorageSync("posts_Collected");

      // 判断所有缓存状态是否存在
      if (postsCollected) {

      // 2.1 获取:当前缓存状态(
      var Collected = postsCollected[postId];

      // windows不做判断,不报错,Macos 不做判断,报错。
      // 2.2 巨坑---解决报错:Setting data field "collected" to undefined is invalid.
      // 2.2 判断当前缓存状态是否存在,如果存在,则更改data数据,否则不要做任何操作
      if (Collected) {
      // 2.2 更改:data中collected当前缓存值状态
      this.setData({collected: Collected})
      }


      } else {
      // 如果 缓存状态不存在,则需要创建 缓存状态的对象
      var postsCollected = {};

      // 如果没有缓存状态,证明当前的文章缓存值,默认为false:表示未收藏
      postsCollected[postId] = false;

      // 然后把该缓存值,存放到缓存状态中
      wx.setStorageSync("posts_Collected", postsCollected)

      }

      },


      // 当用户点击收藏按钮时,发生的事件
      onCollectedTap: function (event) {

      // 获取所有缓存状态
      var postsCollected = wx.getStorageSync("posts_Collected");

      // 获取当前,文章的缓存值。(currentPostId ,不存在当前函数中,需要借助变量来传递)
      var Collected = postsCollected[this.data.currentPostId];

      // 点击之后,收藏变成未收藏,未收藏变成收藏
      Collected = !Collected;

      // 把当前缓存值,赋值到 所有缓存状态中
      postsCollected[this.data.currentPostId] = Collected;

      // 更新文章是否收藏的缓存值
      wx.setStorageSync("posts_Collected", postsCollected)

      // 更新data数据绑定, 实现图片的切换
      this.setData({
      collected: Collected
      });

      // 提示收藏未收藏文字
      wx.showToast({
      title: Collected ? "收藏成功" : "取消收藏",
      duration: 1000,
      icon: "success"
      })
      },

分享功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 分享事件
noSharTap: function (event) {
var itemList = [
"分享到微信",
"分享到微博",
"分享到QQ空间",
"分享到朋友圈"
]
wx.showActionSheet({
itemList: itemList,
itemColor: "#405f80",
// 回调函数
success(res) {
// res.cancel 用户是不是点击了取消
// res.tapIndex 数组元素的序号,从0开始
wx.showModal({
title: "用户" + itemList[res.tapIndex],
content: "用户是否取消?" + res.cancel + "现在无法实现分享功能,什么时候能实现,官网没说"
})
}
})
}

同步异步方法对比

(1)同步的缺陷是如果在这里执行不了,整个UI会在此处卡住,后面的代码走不了,这段时间耗时会非常长.
(2)在小程序中,能用同步用同步,尽量少用异步.
(3)京东订单系统用的是异步操作。
(4)异步的缺陷是在下一个方法中要使用上一个方法执行后的数据,由于异步原因,上一个方法还未执行完就开始执行下一个方法,导致数据获取失败

音乐播放功能

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
// 音乐播放组件业务
noMusicTap: function (event) {
// 获取当前音乐
var isPlayingMusic = this.data.isPlayingMusic;

// 从数据对象中获取音乐数据
var currentPostId = this.data.currentPostId;
// 获取到数据对象,postList下面才是数据,请输入控制台查看获取数据情况
var postData = postsData.postList[currentPostId];
console.log(postData )

// 判断当前音乐是否 开启
if (isPlayingMusic) {
// 关闭音乐
wx.pauseBackgroundAudio();
// 关闭音乐后,把变量状态值,改变为false,更新Data值,必须用setData
this.setData({
isPlayingMusic: false
})


} else {
// 音乐启动API
wx.playBackgroundAudio({
dataUrl: postData.music.url ,
title: postData.music.title,
coverImg: postData.music.coverImg,
});
// 开启音乐后,把变量状态值,改变为 true
this.setData({
isPlayingMusic: true
})
}


}
1
2
3
// 图片切换通过三元表达式方法切换  
<image catchtap="noMusicTap" class="audio"
src="{{isPlayingMusic?'/images/music/music-stop.png':'/images/music/music-start.png'}}"></image>

音乐BUG 解决方法

问题1:总控开关和页面开关不同步
解决方案:监听函数

1
2
3
4
5
6
7
8
9
10
11
12
// 播放监听
wx.onBackgroundAudioPlay(()=>{
this.setData({
isPlayingMusic : true
})
});
// 暂停监听
wx.onBackgroundAudioPause(()=>{
this.setData({
isPlayingMusic : false
})
});
  1. 事件驱动思想, 使用事件驱动来实现模块之间传递参数与解耦.比如在A模块发射一个事件,在B模块监听这个事件,中间使用数据来进行传递即可,像这里就是在总模块里面监听子模块里面的音乐播放状态 ;
  2. 数据优先思想, 改变UI, 只需要改变该数据绑定的对应的数据就可以. 这点和angular,iOS中的RAC, 响应式编程思想类似.;
  3. 数据绑定优势还有,一个数据可以绑定多个事件,这样只需要在js文件里面写上对应的多个事件即可,不用像jQuery一样要获取多个dom元素才能进行多个事件描述;
  4. 可能利于做单元测试