微信小程序初识

一、从0构建项目

打开微信公众平台 -> 注册账号 -> 下载开发工具 -> 创建项目

1. 创建项目

微信小程序初识_第1张图片

2. 开通云开发

项目创建完成之后,在调试器里会报一个错误:云开发初始化错误

微信小程序初识_第2张图片

  1. 点击云开发按钮,不断下一步

  1. 输入环境信息,点击确定(当我们创建环境的时候,每个环境会对应一套云开发资源,每个环境是独立的)

微信小程序初识_第3张图片

  1. 等待 10 - 30min 之后,重启开发工具

微信小程序初识_第4张图片

3. 代码结构初始化

  1. 基础结构
    微信小程序初识_第5张图片

  2. app.js 文件配置云开发环境,填写环境 id

  wx.cloud.init({
    // env 参数说明:
    // env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源
    // 此处请填入环境 ID, 环境 ID 可打开云控制台查看
    // 如不填则使用默认环境(第一个创建的环境)
    env: 'dev-f2y9s',
    // 是否在云开发控制台中记录访问过我们小程序的用户
    traceUser: true,
  })
  1. 配置页面 & 配置tabBar
"pages": [
    "pages/playlist/playlist",
    "pages/blog/blog",
    "pages/profile/profile"
],
"tabBar": {
    "color": "#8a8a8a",
    "selectedColor": "#d43c43",
    "list": [
        {
          "pagePath": "pages/playlist/playlist",
          "text": "音乐",
          "iconPath": "./images/playlist.png",
          "selectedIconPath": "./images/playlist_active.png"
        },
        {
          "pagePath": "pages/blog/blog",
          "text": "发现",
          "iconPath": "./images/blog.png",
          "selectedIconPath": "./images/blog_active.png"
        },
        {
          "pagePath": "pages/profile/profile",
          "text": "我的",
          "iconPath": "./images/profile.png",
          "selectedIconPath": "./images/profile_active.png"
        }
    ]
},
  

4. 代码规范

借鉴的规范:https://github.com/airbnb/javascript

5. 调用云函数

  1. 首先看一下当前拥有的云函数

微信小程序初识_第6张图片

  1. 由于当前云函数还未上传,直接使用的话会报如下错误:

  1. 上传云函数

右键云函数 -> 创建并部署:云端安装依赖(不上传 node_modules)

  1. 使用云函数
  onLoad: function (options) {
    wx.cloud.callFunction({
      name: 'login'
    }).then((res) => {
      console.log(res)
    })
  },

二、 播放列表功能实现

1. 轮播图组件 Swiper

资源地址:
https://github.com/xiecheng328/miniprogram/tree/master/assets

1)数据

资源地址:https://github.com/xiecheng328/miniprogram/tree/master/assets

  data: {
    swiperImages: [{
        url: 'http://p1.music.126.net/oeH9rlBAj3UNkhOmfog8Hw==/109951164169407335.jpg',
      },
      {
        url: 'http://p1.music.126.net/xhWAaHI-SIYP8ZMzL9NOqg==/109951164167032995.jpg',
      },
      {
        url: 'http://p1.music.126.net/Yo-FjrJTQ9clkDkuUCTtUg==/109951164169441928.jpg',
      }
    ]
  },

2)结构

在这里,循环写到了标签内;在DOM中不会渲染出来


<swiper class="swiper" indicator-dots="{{ true }}" autoplay="{{ true }}" interval="{{ 2000 }}" circular="{{ true }}">
  <block wx:for="{{swiperImages}}" wx:key="{{ index }}">
    <swiper-item>
      <image class="bannerImg" src="{{item.url}}" mode="widthFix">image>
    swiper-item>
  block>
swiper>

2. 组件化开发

新建组件

组件位置:miniprogram/components

新建组件:新建目录 -> 新建component

使用组件

注册组件

<!--
"usingComponents": {
  "组件名": "组件路径"
}
-->
{
  "usingComponents": {
    "gx-playlist": "/components/playlist/playlist"
  }
}

使用组件

<gx-playlist>gx-playlist>

3. 自定义歌单组件 playlist

1)使用组件的流程

初始化组件

新建组件 - 注册组件 - 初始化数据

给组件传值


组件中 - 接收父级传入的数据

  /**
   * 组件的属性列表
   */
  properties: {
    playItem: {
      type: Object
    }
  },

使用父级传入的数据

<view class="playlist-container">
  <image class="playlist-image" src="{{ playItem.picUrl }}">image>
  <text class="playlist-count">{{ playItem.playCount }}text>
  <view class="playlist-name">{{ playItem.name }}view>
view>

2)组件化开发中的数据监听器

组件化开发中的数据监听器(格式化播放数量)

observers

  1. 数据监听器支持监听属性或内部数据的变化,可以同时监听多个。一次 setData 最多触发每个监听器一次。
    同时,监听器可以监听子数据字段
Component({
  observers: {
    'some.subfield': function(subfield) {
      // 使用 setData 设置 this.data.some.subfield 时触发
      // (除此以外,使用 setData 设置 this.data.some 也会触发)
      subfield === this.data.some.subfield
    },
    'arr[12]': function(arr12) {
      // 使用 setData 设置 this.data.arr[12] 时触发
      // (除此以外,使用 setData 设置 this.data.arr 也会触发)
      arr12 === this.data.arr[12]
    },
  }
})
  1. 如果需要监听所有子数据字段的变化,可以使用通配符 ** 。
Component({
  observers: {
    'some.field.**': function(field) {
      // 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
      // (除此以外,使用 setData 设置 this.data.some 也会触发)
      field === this.data.some.field
    },
  },
})
  1. 特别地,仅使用通配符 ** 可以监听全部 setData 。
Component({
  observers: {
    '**': function() {
      // 每次 setData 都触发
    },
  },
})
  1. 好了,基础说完了,接下来看一下怎样格式化播放数量
  // 数据监听器
  observers: {
    ['playItem.playCount'](count) {
      this.setData({
        _count: this._filterCount(count, 2)
      })
    }
  },
  // 组件的初始数据
  data: {
    _count: ''
  },
  methods: {
    /**
     * 格式化逻辑部分
     * num: 待转化的数字
     * point:保留几位小数
     */
    _filterCount(num, point) {
      let numStr = num.toString().split('.')[0] // 舍弃小数点,并转成String
      if (numStr.length < 6) {
        return numStr
      } else if (numStr.length >= 6 && numStr.length <= 8) {
        return (num/10000).toFixed(point) + '万'
      } else if(numStr.length > 8) {
        return (num/100000000).toFixed(point) + '亿'
      }
    },
  },

3)小程序的列表渲染

在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item

<view wx:for="{{array}}">
  {{index}}: {{item.message}}
view>
Page({
  data: {
    array: [{
      message: 'foo',
    }, {
      message: 'bar'
    }]
  }
})

使用 wx:for-item 可以指定数组当前元素的变量名,
使用 wx:for-index 可以指定数组当前下标的变量名:

<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
  {{idx}}: {{itemName.message}}
view>

注意

  1. 在小程序中的背景图片是不能使用网络图片的,可以使用本地图片或者是 base64格式
  2. 如果当前文字是白色,背景颜色不确定,可以添加上适当的阴影,来保证不管背景颜色是淡是深,都尽可能的有一个比较好的展示效果
    微信小程序初识_第7张图片
  3. 传入组件的值,在组件内不能改变,同vue;

4. 通过 base64 的方式,使用 svg 图片

  1. 搜索:在线制作base64

  2. 随便找一个,打开,上传svg图片,生成 base64 字符串

  3. 使用 将生成的字符串放到background: url()

  background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMiAyMCI+PGcgb3BhY2l0eT0iLjE1Ij48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiMwNDAwMDAiIGQ9Im0yMiAxNi43NzdjMCAxLjIzMy0xLjEyMSAyLjIzMy0yLjUwNiAyLjIzMy0xLjM4NCAwLTIuNTA2LTEtMi41MDYtMi4yMzN2LTIuNTUzYzAtMS4yMzQgMS4xMjItMi4yMzMgMi41MDYtMi4yMzMuMTc0IDAgLjM0My4wMTcuNTA2LjA0NnYtMS4zN2gtLjAzM2MuMDE3LS4yMi4wMzMtLjQ0MS4wMzMtLjY2NiAwLTQuNDE4LTMuNTgyLTgtOC04LTQuNDE4IDAtOCAzLjU4Mi04IDggMCAuMjI1LjAxNi40NDYuMDM0LjY2NmgtLjAzNHYxLjM3Yy4xNjMtLjAyOS4zMzMtLjA0Ni41MDUtLjA0NiAxLjM4NCAwIDIuNTA2Ljk5OSAyLjUwNiAyLjIzM3YyLjU1M2MwIDEuMjMzLTEuMTIyIDIuMjMzLTIuNTA2IDIuMjMzcy0yLjUwNS0uOTk5LTIuNTA1LTIuMjMzdi0yLjU1M2MwLS4yNTguMDU5LS41MDEuMTQ4LS43My0uMDg1LS4xNDgtLjE0OC0uMzEtLjE0OC0uNDkzdi0yLjY2N2MwLS4wMjMuMDEyLS4wNDMuMDEzLS4wNjctLjAwNC0uMDg4LS4wMTMtLjE3Ni0uMDEzLS4yNjYgMC01LjUyMyA0LjQ3Ny0xMCAxMC0xMCA1LjUyMyAwIDEwIDQuNDc3IDEwIDEwIDAgLjA5LS4wMDkuMTc4LS4wMTQuMjY2LjAwMi4wMjQuMDE0LjA0NC4wMTQuMDY3djJjMCAuMzA2LS4xNDUuNTY5LS4zNi43NTMuMjI0LjMzNC4zNi43Mi4zNiAxLjEzOHYyLjU1MiIvPjwvZz48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiNmZmYiIGQ9Im0yMCAxNi43NzdjMCAxLjIzMy0xLjEyMSAyLjIzMy0yLjUwNiAyLjIzMy0xLjM4NCAwLTIuNTA2LTEtMi41MDYtMi4yMzN2LTIuNTUzYzAtMS4yMzQgMS4xMjItMi4yMzMgMi41MDYtMi4yMzMuMTc0IDAgLjM0My4wMTcuNTA2LjA0NnYtMS4zN2gtLjAzM2MuMDE3LS4yMi4wMzMtLjQ0MS4wMzMtLjY2NiAwLTQuNDE4LTMuNTgyLTgtOC04LTQuNDE4IDAtOCAzLjU4Mi04IDggMCAuMjI1LjAxNi40NDYuMDM0LjY2NmgtLjAzNHYxLjM3Yy4xNjMtLjAyOS4zMzMtLjA0Ni41MDUtLjA0NiAxLjM4NCAwIDIuNTA2Ljk5OSAyLjUwNiAyLjIzM3YyLjU1M2MwIDEuMjMzLTEuMTIyIDIuMjMzLTIuNTA2IDIuMjMzcy0yLjUwNS0uOTk5LTIuNTA1LTIuMjMzdi0yLjU1M2MwLS4yNTguMDU5LS41MDEuMTQ4LS43My0uMDg1LS4xNDgtLjE0OC0uMzEtLjE0OC0uNDkzdi0yLjY2N2MwLS4wMjMuMDEyLS4wNDMuMDEzLS4wNjctLjAwNC0uMDg4LS4wMTMtLjE3Ni0uMDEzLS4yNjYgMC01LjUyMyA0LjQ3Ny0xMCAxMC0xMCA1LjUyMyAwIDEwIDQuNDc3IDEwIDEwIDAgLjA5LS4wMDkuMTc4LS4wMTQuMjY2LjAwMi4wMjQuMDE0LjA0NC4wMTQuMDY3djJjMCAuMzA2LS4xNDUuNTY5LS4zNi43NTMuMjI0LjMzNC4zNi43Mi4zNiAxLjEzOHYyLjU1MiIvPjwvc3ZnPg==);

5. wx:key

  1. 如果数组是单纯的字符串数组,如:arr: ['wxml', 'js', 'wxss', 'json'] ; 则wx:key建议使用wx:key="*this"
  2. 如果是数组对象,直接使用对象每一项的id就好;使用每一项的id的时候,如果字段也是id,不用写成wx:key="item.id",直接写成wx:key="id" 就好;
  3. 注意:不要用 index

6. async / await

说明:async / await 是 Es7 的语法,如果在云函数中使用,云函数默认是支持的,因为云函数要求,node版本最低是 8.9,所以在云函数端async / await是默认支持的;但是在小程序端,默认是不支持async / await,所以需要引入额外的文件,才能使小程序端支持;

说明:当我写这篇博客的时候,小程序已经支持 async / await语法了

下面还是记录一下,如果不支持,我们该怎么处理;

1. 下载文件

地址:https://github.com/xiecheng328/miniprogram/tree/master/regenerator
tuntime.js 文件,放到/miniprogram/utils

2. 引入文件

// 注意 regeneratorRuntime 不要变
import regeneratorRuntime from '../../utils/runtime.js'

然后就可以使用 async / await 语法了;

7. 读取歌单数据并插入云数据库

音乐数据是从第三方获取到的,每天都会有新的推荐的歌单,如果我只是一次获取的话,那我的歌单就只是那些数据,所以说,我们要给函数设置一个定时触发器,每天会有固定的时间去服务器上取数据,这样就能保证我每天取到的都是最新的数据;
取数据的时候,要和旧数据做一下比较,把数据库中没有的数据才插入到数据库中;

1. 创建云函数

右键 cloudfunctions
->
新建 Node.js 云函数
->
getPlayList

2. 发送网络请求

微信小程序初识_第8张图片
微信小程序初识_第9张图片
工具
借助第三方工具,使用的是axios

yarn add axios

地址

http://musicapi.leanapp.cn/

推荐歌单 (get)

	说明 : 调用此接口 , 可获取推荐歌单
	
	可选参数 : limit: 取出数量 , 默认为 30 (不支持 offset)
	
	接口地址 : /personalized
	
	调用例子 : /personalized?limit=1

请求到数据

// 云函数入口文件
const cloud = require('wx-server-sdk')
// axios
const axios = require('axios')
const url = 'http://musicapi.leanapp.cn/personalized?limit=20'

cloud.init()

// 云函数入口函数
exports.main = async (event, context) => {
  const res = await axios.get(url)
  console.log(res.data.result)
}

3. 将请求到的数据插入数据库

1)创建数据库集合
微信小程序初识_第10张图片
2)插入数据
https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/database/init.html

云数据库插入的时候只能单条插入,所以要循环遍历当前数组

// 云函数入口文件
const cloud = require('wx-server-sdk')
// axios
const axios = require('axios')
const url = 'http://musicapi.leanapp.cn/personalized?limit=20'

cloud.init()

// 数据库 - 要在初始化后面,因为有cloud,所以就不用wx.cloud了
const db = cloud.database()

// 云函数入口函数
exports.main = async (event, context) => {
  const res = await axios.get(url)
  if (res.data.result.length > 0) {
    for (let i = 0; i < res.data.result.length; i++) {
      await db.collection('playlist').add({
        data: {
          ...res.data.result[i],
          createTime: db.serverDate()
        }
      }).then((res) => {
        console.log('Success', res)
      }).catch((err) => {
        console.log('Error', err);
      })
    }
  }
}

注意:

  1. 获取数据库的引用,要在cloud.init()之后,因为能直接拿到cloud,所以就不用wx.cloud.database()引用了;
  2. const db = cloud.database()db.serverDate() 能获取到当前服务器的时间,在写入数据库数据的时候,添加上时间,方便做按时间排序操作
  3. 因为把数据插入数据库也是异步操作,需要插入一条后再插入下一条数据,所以要加上await

8. 歌单数据去重

当我再次调用 请求歌单数据并插入数据库 这个函数的时候,假设我读取到的还是这些数据,同样插入到数据库中,这样我对应的歌单信息就会有重复的数据,所以需要去重;
微信小程序初识_第11张图片

// 云函数入口函数
exports.main = async (event, context) => {
  // 读取数据库中的歌单数据
  const list = await db.collection('playlist').get();

  // 读取服务器的歌单数据
  const res = await axios.get(url)
  const playList = res.data.result;

  // 数组去重
  const newData = []
  for (let i = 0; i < playList.length; i++) {
    let flag = true;
    for (let j = 0; j < list.data.length; j++) {
      if (playList[i].id === list.data[j].id) {
        flag = false
        break
      }
    }
    if (flag) {
      newData.push(playList[i])
    }
  }

  // 循环数据并插入数据库
  if (newData.length > 0) {
    for (let i = 0; i < newData.length; i++) {
      await db.collection('playlist').add({
        data: {
          ...newData[i],
          createTime: db.serverDate()
        }
      }).then((res) => {
        console.log('Success', res)
      }).catch((err) => {
        console.log('Error', err);
      })
    }
  }
}

9. 突破获取条数的限制

当我们去获取云数据库中某一个集合的所有数据的时候,其实是有对应的条数限制的,如果我们在云函数中获取,那么每次最多获取100条,如果是在小程序端获取,每次最多获取20条数据;
随着时间推移,歌单的数量会不断增多,所以100条数据很明显不会满足需求;这里就说一下如何突破100条的条数限制;

需要优化的,就是这一行代码

// 读取数据库中的歌单数据
const list = await db.collection('playlist').get();

思路:假设当前我的数据库中有210条数据,如果每次只能取100条的话,我取三次就能把这210条数据取完,然后把这三次的数据拼装成一个数组,这个数组的数据就是全部的数据;

skip: https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/database/collection/Collection.skip.html

  // 每次能获取的最大数量
  const MAX_COUNT = 10;
  // 获取歌单条数
  const countResult = await db.collection('playlist').count();
  const total = countResult.total
  // 要获取的次数(向上取整)
  const batchTimes = Math.ceil(total / MAX_COUNT)

  // 所有的歌单数据数组
  const list = []
  for (let i = 0; i < batchTimes; i++) {
    const arr = await db.collection('playlist').skip(i * MAX_COUNT).limit(MAX_COUNT).get()
    list.push(...arr.data);
  }

你可能感兴趣的:(前端开发)