微信小程序04-常用API上

零、文章目录

微信小程序04-常用API上

1、案例:音乐播放器

(1)案例分析
  • 需求:"音乐播放器"微信小程序可以让用户随时随地享受音乐,给用户带来了便捷的音乐体验,且支持后台播放,用户可以在听音乐的同时进行其他操作。
  • "音乐播放器"微信小程序的页面由上、中、下共3个部分组成,这3个部分分别是标签栏区域、内容区域和播放器区域。
    • ①标签栏区域:该区域有音乐推荐、播放器和播放列表3个标签按钮,通过点击标签按钮可以进行标签页的切换。
    • ②内容区域:通过左右滑动可以实现音乐推荐、播放器和播放列表3个标签页的切换。这3个标签页的具体说明如下。
      • 音乐推荐:用于向用户推荐一些歌曲。
      • 播放器:用于显示当前播放音乐的信息、专辑封面、播放进度和时间。其中,音乐信息包括当前播放音乐的标题和歌手。
      • 播放列表:用于显示当前播放的曲目列表,用户可以进行曲目切换。
    • ③播放器区域:显示当前播放的音乐信息,并且提供了3个按钮,按钮的功能依次为"切换到播放列表""播放/暂停""下一曲"。
(2)知识储备-scroll-view组件
  • scroll-view组件

    • 当一个容器中的内容有很多时,如果容器无法完整显示内容,则可以通过滚动操作来查看完整内容。
    • 在微信小程序中,可以通过scroll-view组件来实现滚动效果,它支持横向滚动和纵向滚动,默认是不滚动的,需要通过scroll-x和scroll-y属性允许横向和纵向滚动。
    html 复制代码
    <scroll-view>实现可滚动视图区域</scroll-view>
    • scroll-view组件的常用属性如下
  • 代码演示:

    • 在pages/index/index.wxml文件中编写如下代码。
    html 复制代码
    <scroll-view scroll-x="{{ true }}" scroll-y="{{ true }}" style="height: 200px;"
    bindscroll="scroll">
       <view style="width: 200%; height: 400px; background-image: linear-gradient(to bottom
    right, red, yellow);"></view>
      </scroll-view> 
    • 在pages/index/index.js文件中添加scroll()事件处理函数并输出e.detail的值。
    js 复制代码
    scroll: function (e) {
      console.log(e.detail)
    }
    • 通过e.detail可以获取滚动时的位置信息。
      • scrollLeft:横向滚动条左侧到视图左边的距离。
      • scrollTop:纵向滚动条上端到视图顶部的距离。
      • scrollHeight:纵向滚动条在y轴上最大滚动距离。
      • scrollWidth:横向滚动条在x轴上最大的滚动距离。
      • deltaX:横向滚动条的滚动状态。
      • deltaY:纵向滚动条的滚动状态。
(2)知识储备-slider组件
  • slider组件

    • 在开发中,有时需要在一个固定区间内控制数值的变化,例如音乐的播放进度、音量的大小、亮度的高低等,这些需求可以利用滑动选择器来实现。
    • 在微信小程序中,通过slider组件可以定义一个滑动选择器。slider组件是微信小程序表单组件中的一种,用于滑动选择某一个值。用户可以通过拖曳滑块在一个固定区间内进行选择。
    • slider组件的常用属性如下
  • 代码演示

    • 在pages/index/index.wxml文件中编写页面结构。
    html 复制代码
    <slider bindchanging="sliderChanging" show-value="true" />
    • 在pages/index/index.js文件中编写事件处理函数sliderChanging()。
    js 复制代码
    sliderChanging: function (e){
      console.log(e.detail.value)
    }
(2)知识储备-<include>标签
  • **<include>标签:**用于引用其他文件的代码,相当于把引用的代码复制到<include>标签的位置。<include>标签的用途主要有以下两点

    • **方便地查找代码:**当一个WXML页面中的代码过多时,会给代码的维护带来麻烦,有时为了找到某一处代码可能需要翻阅几百行。这时可以利用<include>标签将代码拆分到多个文件中,从而可以更方便地查找代码。
    • **代码复用减少维护:**当多个WXML页面中有相同的部分时,可以将这些公共部分抽取出来,保存到一个单独的WXML文件中,然后在用到的地方通过<include>标签引入。这样可以减少重复的代码,并且修改时只需要修改一次。
  • 代码演示

    • ①在pages/index/index.wxml文件中编写页面结构。
    html 复制代码
    <!-- index.wxml -->
    <include src="header.wxml" />
    <view>body</view>
    <include src="footer.wxml" />
    • ②在pages/index/header.wxml文件中编写头部的页面结构。
    html 复制代码
    <view>header</view>
    • ③在pages/index/footer.wxml文件中编写尾部的页面结构。
    html 复制代码
    <view>footer</view>
    • 运行后,实际得到的pages/index/index.wxml文件如下
    html 复制代码
    <view>header</view>
    <view>body</view>
    <view>footer</view>
(2)知识储备-背景音频API
  • 背景音频API

    • 在微信小程序中,使用背景音频API可以实现音频的后台播放。
    • 在使用背景音频API前,需要在app.json文件中配置requiredBackgroundModes属性,开启微信小程序后台音频播放功能。
    json 复制代码
    "requiredBackgroundModes": ["audio"]
    • 背景音频API的使用方法是,先通过wx.getBackgroundAudioManager()方法获取到一个BackgroundAudioManager实例,然后通过该实例的相关属性和方法实现背景音频的播放。
    js 复制代码
    var audioGbam = wx.getBackgroundAudioManager()
    • BackgroundAudioManager实例常用的属性和方法如下
  • 代码演示:在pages/index/index.js文件的onReady()函数中编写如下代码。

js 复制代码
 onReady: function () {
   // 创建BackgroundAudioManager实例
   var audio = wx.getBackgroundAudioManager()
   // 当开始播放音乐时,输出调试信息
   audio.onPlay(function () {
     console.log('开始播放')
   })
   // 设置背景音频的标题
   audio.title = '音乐标题'
   // 设置背景音频的资源地址
   audio.src = 'http://127.0.0.1:3000/1.mp3'
 } 
(3)案例实现
  • 准备工作

    • ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为"音乐播放器",模板选择"不使用模板"。
    • ②配置页面。清单如下。
    • ③配置导航栏。在pages/index/index.json文件中配置页面导航栏。
    json 复制代码
    {
      "navigationBarTitleText": "音乐",
      "navigationBarBackgroundColor": "#17181a",
      "navigationBarTextStyle": "white"
    } 
    • ④配置页面样式和准备图片。在pages/index/index.wxss文件中配置页面样式。在images文件夹中准备图片。
    • ⑤启动服务器。切换工作目录到nodejs服务程序目录,打开命令提示符,然后在命令提示符中执行如下命令,启动服务器。
    bash 复制代码
    node index.js
  • 实现页面结构:

    • 在pages/index/index.wxml文件中编写"音乐播放器"微信小程序的页面结构。
    html 复制代码
    <!--index.wxml-->
    <!-- 标签栏区域的页面结构 -->
    <view class="tab">
      <view class="tab-item {{ tab == 0 ? 'active' : '' }}" bindtap="changeItem" data-item="0">音乐推荐</view>
      <view class="tab-item {{ tab == 1 ? 'active' : '' }}" bindtap="changeItem" data-item="1">播放器</view>
      <view class="tab-item {{ tab == 2 ? 'active' : '' }}" bindtap="changeItem" data-item="2">播放列表</view>
    </view>
    <!-- 内容区域的页面结构 -->
    <view class="content">
    <!-- 使用swiper组件实现标签页切换 -->
      <swiper current="{{ item }}" bindchange="changeTab">
        <swiper-item>
          <!-- 音乐推荐 -->
          <include src="info.wxml" />
        </swiper-item>
        <swiper-item>
          <!-- 播放器 -->
          <include src="play.wxml" />
        </swiper-item>
        <swiper-item>
          <!-- 播放列表 -->
          <include src="playlist.wxml" />
        </swiper-item>
      </swiper>
    </view>
    <!-- 底部播放器区域 -->
    <view class="player">
      <image class="player-cover" src="{{ play.coverImgUrl }}" data-item="1" bindtap="changeItem" />
      <view class="player-info">
        <view class="player-info-title" data-item="1" bindtap="changeItem">{{ play.title }}</view>
        <view class="player-info-singer" data-item="1" bindtap="changeItem">{{ play.singer }}</view>
      </view>
      <view class="player-controls">
        <!-- 切换到播放列表 -->
        <image src="/images/01.png" data-item="2" bindtap="changeItem" />
        <!-- 播放/暂停 -->
        <image wx:if="{{ state == 'paused' }}" src="/images/02.png" bindtap="play" />
        <image wx:else src="/images/02stop.png" bindtap="pause" />
        <!-- 下一曲 -->
        <image src="/images/03.png" bindtap="next" />
      </view>
    </view>
    • pages/index/info.wxml文件中的代码如下。
    html 复制代码
    <swiper class="content-info-slide" indicator-color="rgba(255,255,255,.5)" indicator-active-color="#fff" indicator-dots circular autoplay>
      <swiper-item>
        <image src="/images/banner.jpg" />
      </swiper-item>
      <swiper-item>
        <image src="/images/banner.jpg" />
      </swiper-item>
      <swiper-item>
        <image src="/images/banner.jpg" />
      </swiper-item>
    </swiper>
    <view class="content-info-portal">
      <view>
        <image src="/images/04.png" />
        <text>私人FM</text>
      </view>
      <view>
        <image src="/images/05.png" />
        <text>每日歌曲推荐</text>
      </view>
      <view>
        <image src="/images/06.png" />
        <text>云音乐新歌榜</text>
      </view>
    </view>
    <view class="content-info-list">
      <view class="list-title">推荐歌曲</view>
      <view class="list-inner">
        <view class="list-item">
          <image src="/images/cover.jpg" />
          <view>山水之间</view>
        </view>
        <view class="list-item">
          <image src="/images/cover.jpg" />
          <view>惊鸿一面</view>
        </view>
        <view class="list-item">
          <image src="/images/cover.jpg" />
          <view>稻香</view>
        </view>
        <view class="list-item">
          <image src="/images/cover.jpg" />
          <view>如果当时</view>
        </view>
        <view class="list-item">
          <image src="/images/cover.jpg" />
          <view>清明雨上</view>
        </view>
        <view class="list-item">
          <image src="/images/cover.jpg" />
          <view>有何不可</view>
        </view>
      </view>
    </view>
    • pages/index/play.wxml文件中的代码如下。
    html 复制代码
    <view class="content-play">
      <!-- 音乐信息 -->
      <view class="content-play-info">
        <text>{{ play.title }}</text>
        <view>------ {{ play.singer }} ------</view>
      </view>
      <!-- 专辑封面 -->
      <view class="content-play-cover">
        <image src="{{ play.coverImgUrl }}" style="animation-play-state:{{ state }}" />
      </view>
      <!-- 播放进度和时间 -->
      <view class="content-play-progress">
        <text>{{ play.currentTime }}</text>
        <view>
          <slider bindchanging="sliderChanging" bindchange="sliderChange" activeColor="#d33a31" block-size="12" backgroundColor="#dadada" value="{{ play.percent }}" />
        </view>
        <text>{{ play.duration }}</text>
      </view>
    </view>
    • pages/index/playlist.wxml文件中的代码如下。
    html 复制代码
    <scroll-view class="content-playlist" scroll-y>
      <view class="playlist-item" wx:for="{{ playlist }}" wx:key="id" bindtap="change" data-index="{{ index }}">
        <image class="playlist-cover" src="{{ item.coverImgUrl }}" />
        <view class="playlist-info">
          <view class="playlist-info-title">{{ item.title }}</view>
          <view class="playlist-info-singer">{{ item.singer }}</view>
        </view>
        <view class="playlist-controls">
          <text wx:if="{{ index == playIndex }}">正在播放</text>
        </view>
      </view>
    </scroll-view>
  • **获取页面数据:**在pages/index/index.js文件中获取页面所需的数据。

js 复制代码
// index.js

// 格式化时间
function formatTime(time) {
  var minute = Math.floor(time / 60) % 60;
  var second = Math.floor(time) % 60
  return (minute < 10 ? '0' + minute : minute) + ':' + (second < 10 ? '0' + second : second)
}

Page({
  data: {
    item: 0,
    tab: 0,
    // 播放列表数组playlist
    playlist: [{
      id: 1,
      title: '祝你生日快乐',
      singer: '小丽',
      src: 'http://127.0.0.1:3000/1.mp3',
      coverImgUrl: '/images/cover.jpg'
    }, {
      id: 2,
      title: '劳动最光荣',
      singer: '小朋',
      src: 'http://127.0.0.1:3000/2.mp3',
      coverImgUrl: '/images/cover.jpg'
    }, {
      id: 3,
      title: '龙的传人',
      singer: '小华',
      src: 'http://127.0.0.1:3000/3.mp3',
      coverImgUrl: '/images/cover.jpg'
    }, {
      id: 4,
      title: '小星星',
      singer: '小红',
      src: 'http://127.0.0.1:3000/4.mp3',
      coverImgUrl: '/images/cover.jpg'
    }],
    state: 'running',
    playIndex: 0,
    play: {
      currentTime: '00:00',
      duration: '00:00',
      percent: 0,
      title: '',
      singer: '',
      coverImgUrl: '/images/cover.jpg',
    }
  },
  // 在页面初次渲染时,自动选择播放列表中的第1个曲目
  audioBam: null,
  sliderChangeLock: false,
  onReady: function () {
    this.audioBam = wx.getBackgroundAudioManager()
    // 默认选择第1曲
    this.setMusic(0)
    // 播放失败检测
    this.audioBam.onError(() => {
      console.log('播放失败:' + this.audioBam.src)
    })
    // 播放完成自动换下一曲,监听音频自然播放结束的事件
    this.audioBam.onEnded(() => {
      this.next()
    })
    // 监听音频播放进度更新事件,获取音乐状态信息
    var updateTime = 0 // 上次更新的时间
    this.audioBam.onTimeUpdate(() => {
      var currentTime = parseInt(this.audioBam.currentTime)
      if (!this.sliderChangeLock && currentTime !== updateTime) { // // 将更新频率限制在1秒1次
        updateTime = currentTime
        this.setData({
          'play.duration': formatTime(this.audioBam.duration || 0),
          'play.currentTime': formatTime(currentTime),
          'play.percent': currentTime / this.audioBam.duration * 100
        })
      }
    })
  },
  sliderChange: function (e) {
    var second = e.detail.value * this.audioBam.duration / 100
    this.audioBam.seek(second)
    setTimeout(() => {
      this.sliderChangeLock = false
    }, 1000)
  },
  sliderChanging: function (e) {
    var second = e.detail.value * this.audioBam.duration / 100
    this.sliderChangeLock = true
    this.setData({
      'play.currentTime': formatTime(second),
    })
  },
  // 设置当前播放的曲目
  setMusic: function (index) {
    var music = this.data.playlist[index]
    this.audioBam.src = music.src
    this.audioBam.title = music.title
    this.setData({
      playIndex: index,
      'play.title': music.title,
      'play.singer': music.singer,
      'play.coverImgUrl': music.coverImgUrl,
      'play.currentTime': '00:00',
      'play.duration': '00:00',
      'play.percent': 0,
      state: 'running' // 新增
    })
  },
  changeItem: function (e) {
    this.setData({
      item: e.target.dataset.item
    })
  },
  changeTab: function (e) {
    this.setData({
      tab: e.detail.current
    })
  },
  play: function () {
    this.audioBam.play()
    this.setData({
      state: 'running'
    })
    console.log(this.data.state) // running
  },
  pause: function () {
    this.audioBam.pause()
    this.setData({
      state: 'paused'
    })
    console.log(this.data.state) // paused
  },
  // 点击播放下一曲的操作
  next: function () {
    var index = this.data.playIndex >= this.data.playlist.length - 1 ? 0 : this.data.playIndex + 1
    this.setMusic(index)
    console.log(this.data.state)
    // if (this.data.state === 'running') {
      // this.play()
    // }
  },
  // 点击播放列表中的某一项时进行该曲目的播放
  change: function (e) {
    this.setMusic(e.currentTarget.dataset.index)
    // this.play()
  }
})
  • 页面实现效果

2、案例:录音机

(1)案例分析
  • 需求:录音机是生活中的常用工具,它可以在开会的时候记录说话人的声音,也可以在生活中留下一段美妙歌声。录音机可以记录声音和播放声音,因此其成为新闻工作者工作的重要器材。
  • 录音机"微信小程序页面分为顶部区域和按钮控制区域。
    • 顶部区域展示录音时长
    • 按钮控制区域中从左到右的3个按钮
      • "播放录音"按钮
      • "开始/暂停录音"按钮
      • "停止录音"按钮
(2)知识储备-录音API
  • 录音API

    • 录音功能在日常生活中使用很广泛,使用该功能可以记录重要的工作内容、优美的歌声等。
    • 微信小程序为开发者提供了录音API,使用录音API首先需要通过wx.getRecorderManager()方法获取到一个RecorderManager实例,该实例是一个全局唯一的录音管理器,用于实现录音功能。
    js 复制代码
    var recorderManager = wx.getRecorderManager()
    • RecorderManager实例的常用方法如下。
  • 代码演示:在pages/index/index.js文件的onReady()函数中编写如下代码。

js 复制代码
 // 获取全局唯一的录音管理器RecorderManager
 var recorderManager = wx.getRecorderManager()
 // 监听录音开始事件
 recorderManager.onStart(() => {
   console.log('录音开始');
 })
 // 监听录音停止事件
 recorderManager.onStop(res => {
   console.log('录音停止')
   console.log(res.tempFilePath)
 })
 // 开始录音
 recorderManager.start()
 // 5秒后自动停止录音
 setTimeout(() => {
   recorderManager.stop()
 }, 5000) 
(2)知识储备-音频API
  • 音频API

    • 在微信小程序中,除了背景音频API可以实现播放音频的功能外,还可以通过音频API来播放音乐。
    • 背景音频API与音频API的区别在于背景音频API支持后台播放,而音频API不支持后台播放。
    • 在使用音频API时,需要通过以下代码创建一个InnerAudioContext实例。
    js 复制代码
    var audioCtx = wx.createInnerAudioContext()
    • InnerAudioContext实例特有的属性和方法如下。
  • 代码演示:在pages/index/index.js文件的onReady()函数中编写如下代码。

js 复制代码
 // 创建InnerAudioContext实例
 var audioCtx = wx.createInnerAudioContext()
 // 设置音频资源地址
 audioCtx.src = 'http://127.0.0.1:3000/1.mp3'
 // 当开始播放音频时,输出调试信息
 audioCtx.onPlay(() => {
   console.log('开始播放')
 })
 // 开始播放
 audioCtx.play() 
(3)案例实现
  • 准备工作

    • ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为"录音机",模板选择"不使用模板"。
    • ②配置导航栏。在pages/index/index.json文件中配置页面导航栏。
    • ③配置页面样式。在pages/index/index.wxss文件中配置页面样式。
  • **封装录音功能:**在pages/utils/timer.js文件中封装相关功能。

js 复制代码
var sec = 0
var timer = null
var pause = false
var callback = null

function formatTime(value) {
  var h = parseInt(value / 60 / 60 % 24)
  h = h < 10 ? '0' + h : h
  var m = parseInt(value / 60 % 60)
  m = m < 10 ? '0' + m : m
  var s = parseInt(value % 60)
  s = s < 10 ? '0' + s : s
  return h + ':' + m + ':' + s
}

function createTimer() {
  return setInterval(() => {
    if (!pause) {
      ++sec
    }
    callback && callback(formatTime(sec))
  }, 1000)
}

module.exports = {
  onTimeUpdate(cb) {
    callback = cb
  },
  start() {
    if (pause) {
      pause = false
    }
    if (!timer) {
      timer = createTimer()
    }
  },
  pause() {
    pause = true
  },
  reset() {
    sec = 0
    pause = false
    clearInterval(timer)
    timer = null
  }
}
  • **实现录音功能:**在pages/index/index.js文件中实现录音相关功能。
js 复制代码
// index.js
var timer = require('../../utils/timer.js')

var audioCtx = wx.createInnerAudioContext()
var rec = wx.getRecorderManager()

var tempFilePath = null
var onStopCallBack = null

rec.onStop(res => {
  tempFilePath = res.tempFilePath
  console.log('录音成功:' + tempFilePath)
  onStopCallBack && onStopCallBack(tempFilePath)
})

Page({
  data: {
    time: '00:00:00',	  // 录音时长
    state: 0,           // 录音状态,0表示停止,1表示开始,2表示暂停
  },
  rec: function () {
    switch (this.data.state) {
      case 0:
        rec.start()
        timer.onTimeUpdate(time => {
          this.setData({ time })
        })
        timer.start()
        this.setData({ time: '00:00:00', state: 1 })
        break
      case 1:
        rec.pause()
        timer.pause()
        this.setData({ state: 2 })
        break
      case 2:
        rec.resume()
        timer.start()
        this.setData({ state: 1 })
        break
    }
  },
  stop: function () {
    rec.stop()
    timer.reset()
    this.setData({ state: 0 })
  },
  play: function () {
    if (this.data.state > 0) {
      // 第1种情况,录音尚未完成
      onStopCallBack = tempFilePath => {
        onStopCallBack = null
        audioCtx.src = tempFilePath
        audioCtx.play()
        this.setData({ time: '播放录音' })
      }
      this.stop()
    } else if (tempFilePath) {
      // 第2种情况,录音已完成
      audioCtx.src = tempFilePath
      audioCtx.play()
      this.setData({ time: '播放录音' })
    } else {
      // 第3种情况,尚未录音
      this.setData({ time: '暂无录音' })
    }
  }
})
  • **实现页面结构:**在pages/index/index.wxml文件中编写页面结构。
html 复制代码
<!--index.wxml-->
<view class="top">
  <view class="top-title">录音机</view>
  <view class="top-time">{{ time }}</view>
</view>
<view class="control">
  <view class="btn btn-play" bindtap="play" hover-class="btn-hover" hover-stay-time="50"></view>
  <view class="btn btn-rec {{ state ===  1 ? 'btn-rec-pause' : 'btn-rec-normal' }}" bindtap="rec" hover-class="btn-hover" hover-stay-time="50"></view>
  <view class="btn btn-stop" bindtap="stop" hover-class="btn-hover" hover-stay-time="50"></view>
</view>
  • 页面实现效果

3、案例:头像上传下载

(1)案例分析
  • 需求:头像上传下载是微信小程序开发中常见的一个功能,一般会出现在用户中心模块中,用于设置用户的头像。
  • 头像上传下载"微信小程序展示了头像信息,并提供了3个按钮,依次为"更改头像""头像上传""头像下载"。
    • 点击"更改头像"按钮,可以重新选择头像图片;
    • 点击"头像上传"按钮,可以将头像上传到服务器;
    • 点击"头像下载"按钮,可以从服务器中下载头像图片并预览。
(2)知识储备-选择媒体API
  • 选择媒体API

    • 微信小程序提供了选择媒体API,其用于选择图片或视频,一般用于上传头像、上传照片和上传视频等功能中。
    • 通过调用wx.chooseMedia()方法即可使用选择媒体API,该方法执行后,会提示用户拍摄图片或视频,或从手机相册中选择图片或视频。
    • wx.chooseMedia()方法的常用选项如下。
      • mediaType选项的合法值有3个
        • image(只能拍摄图片或从相册选择图片)
        • video(只能拍摄视频或从相册选择视频)
        • mix(可同时选择图片和视频);
      • sourceType选项的合法值有2个
        • album(从相册选择)
        • camera(使用相机拍摄)。
  • 代码演示:

    • 在pages/index/index.wxml文件中编写如下代码。
    html 复制代码
    <button bindtap="test">选择图片</button>
    • 在pages/index/index.js实现test函数。
    js 复制代码
    test: function () {
      wx.chooseMedia({
        count: 9,                             // 最多可以选择9个文件
        mediaType: ['image'],                 // 文件类型为只能拍摄图片或从相册中选图片
        sourceType: ['album', 'camera'],      // 图片来源为从相册选择和使用相机拍摄
        success (res) {
          // 获取用户选择的文件
          const tempFilePath = res.tempFiles[0].tempFilePath
          console.log(tempFilePath)
        }
      })
    } 
(2)知识储备-图片预览API
  • 图片预览API

    • 微信小程序提供了图片预览API,通过图片预览API可以预览图片,且在预览过程中用户可以进行保存图片、发送给朋友等操作。
    • 通过调用wx.previewImage()方法即可使用图片预览API。
    • wx.previewImage()方法的常用选项如下。
    • urls选项支持http或者https协议的网络图片地址,如果使用本地图片进行预览,会出现黑屏加载不出图片的情况。
  • 代码演示:

    • 在pages/index/index.wxml文件中编写页面结构。
    html 复制代码
    <image src="{{ url }}" bindtap="previewImage" />
    • 在pages/index/index.js文件中实现预览功能。
    js 复制代码
    data: {
      url: 'http://127.0.0.1:3000/tree.jpg'
    },
    
    previewImage() {
      wx.previewImage({
        urls: [
          this.data.url        // 需要预览的图片链接列表
        ]
      })
    }  
(2)知识储备-文件上传API
  • 文件上传API

    • 在生活中,经常需要进行文件上传操作,例如更改头像需要将新的头像上传到服务器中。
    • 微信小程序提供了文件上传API,使用文件上传API可以在微信小程序中发起一个POST请求,将本地资源上传到服务器。通过调用wx.uploadFile()方法即可使用文件上传API。
    • wx.uploadFile()方法的常用选项如下
  • 代码演示

js 复制代码
wx.uploadFile({
  filePath: '文件路径',
  name: 'image',
  url: 'http://127.0.0.1:3000/upload',
  success: res => {
    console.log(res)
  }
}) 
(2)知识储备-文件下载API
  • 文件下载API

    • 在生活中,经常需要下载一些文件,例如将网络中某个参考资料下载到本地进行查看。
    • 微信小程序提供了文件下载API,使用文件下载API可以实现文件下载功能。通过调用wx.downloadFile()方法即可使用文件下载API。
    • wx.downloadFile()方法的常用选项如下。
  • 代码演示

js 复制代码
wx.downloadFile({
  url: 'http://127.0.0.1:3000/tree.jpg',
  success: res => {
    // 判断服务器响应的状态码
    if (res.statusCode === 200) {
      console.log(res.tempFilePath)
    }
  }
}) 
(3)案例实现
  • 准备工作

    • ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为"头像上传下载",模板选择"不使用模板"。
    • ②配置导航栏。在pages/index/index.json文件中配置页面导航栏。
    • ③配置页面样式和准备图片。在pages/index/index.wxss文件中配置页面样式。在images文件夹中准备图片。
    • ④启动服务器。切换工作目录到nodejs服务程序目录,打开命令提示符,然后在命令提示符中执行如下命令,启动服务器。
    bash 复制代码
    node index.js
  • **实现页面结构:**在pages/index/index.wxml文件中编写页面结构。

html 复制代码
<!--index.wxml-->
<view class="imgbox">
  <image src="{{ imgUrl }}" mode="aspectFit" />
  <button type="primary" size="mini" bindtap="changeImg">更改头像</button>
  <button type="primary" size="mini" bindtap="upload">头像上传</button>
  <button type="primary" size="mini" bindtap="download">头像下载</button>
</view>
  • **实现页面逻辑:**在pages/index/index.js文件的Page({})中编写逻辑代码。
js 复制代码
// index.js
Page({
  data: {
    imgUrl: '/images/guest.png',
    tempFilePath: null
  },
  uploadFileUrl: null,
  // 图片选择
  changeImg: function () {
    wx.chooseMedia({
      count: 1,
      mediaType: ['image'],
      sourceType: ['album', 'camera'],
      success: res => {
        var tempFilePath = res.tempFiles[0].tempFilePath
        this.setData({
          tempFilePath: tempFilePath,
          imgUrl: tempFilePath
        })
      }
    })
  },
  upload: function () {
    // 如果没有更改照片则提示更改后再上传
    if (!this.data.tempFilePath) {
      wx.showToast({
        title: '请您更改头像之后再进行上传操作',
        icon: 'none',
        duration: 2000
      })
      return
    }
    // 确认更改头像之后再上传
    wx.uploadFile({
      filePath: this.data.tempFilePath,
      name: 'image',
      url: 'http://localhost:3000/upload',
      success: res => {
        this.uploadFileUrl = JSON.parse(res.data).file
        console.log('上传成功')
      }
    })
  },
  // 图片的下载
  download: function () {
    if (!this.uploadFileUrl) {
      wx.showToast({
        title: '请您上传头像之后再进行下载操作',
        icon: 'none',
        duration: 2000
      })
      return
    }
    wx.showLoading({
      title: '图片下载中,请稍后......',
    })
    wx.downloadFile({
      url: this.uploadFileUrl,
      success: res => {
        wx.hideLoading()
        console.log('下载完成')
        wx.previewImage({
          urls: [res.tempFilePath]
        })
      }
    })
  }
})
  • 页面实现效果

4、案例:模拟时钟

(1)案例分析
  • 需求:"模拟时钟"微信小程序是一个简约风格的动态时钟,该时钟时间与系统时间一致,且时针、分针、秒针会与系统时间同步更新,用户可以很方便地查看时间。
  • "模拟时钟"微信小程序利用canvas组件绘制时钟,刻度为12个刻度,需要分别画出中心圆、外层大圆、时针、分针、秒针。
(2)知识储备-canvas组件
  • canvas组件

    • 在HTML中,<canvas>标签可用于图形的绘制,也可用于创建图片特效和动画。
    • 在微信小程序中,canvas组件也起着类似作用,可用于自定义绘制图形,该组件支持2D和WebGL的绘图。
    html 复制代码
    <canvas></canvas>
    • canvas组件的常用属性如下。
  • 代码演示:

    • 在pages/index/index.wxml文件中编写页面结构。
    html 复制代码
    <canvas id="myCanvas" type="2d"></canvas>
    • 在pages/index/index.wxss文件中编写canvas组件的页面样式。
    css 复制代码
    #myCanvas {
      display: block;
      width: 300px;
      height: 150px;
      position: relative;
      border: 1px solid red;
    } 
(2)知识储备-画布API
  • 画布API

    • 通过canvas组件创建画布后,要想在画布中绘制图案,需要通过画布API来完成。
    • 若要使用画布API,需要先获取Canvas实例,然后通过Canvas实例获取RenderingContext(渲染上下文)实例,最后通过RenderingContext实例的属性和方法完成绘图操作。
    js 复制代码
    wx.createSelectorQuery()
    .select('#myCanvas') // 页面中<canvas>标签的id
    .fields({ node: true, size: true })
    .exec(res => {
      // 获取Canvas实例
      const canvas = res[0].node
      // 调用getContext()方法获取RenderingContext实例
      const ctx = canvas.getContext('2d')
    }) 
    • RenderingContext实例的常用属性和方法如下
  • 代码实现

    • 在pages/index/index.wxml文件中编写页面结构。
    html 复制代码
    <!--index.wxml-->
    <canvas id="draw" type="2d"></canvas>
    • 在pages/index/index.js文件中编写代码绘制图形。
    js 复制代码
    // index.js
    Page({
      onReady: function () {
        wx.createSelectorQuery()
          .select('#myCanvas') // 页面中<canvas>标签的id
          .fields({
            node: true,
            size: true
          })
          .exec(res => {
            // 获取Canvas实例
            const canvas = res[0].node
            // 调用getContext()方法获取RenderingContext实例
            const ctx = canvas.getContext('2d')
          })
    
        wx.createSelectorQuery()
          .select('#draw')
          .fields({
            node: true,
            size: true
          })
          .exec(res => {
            const canvas = res[0].node
            const ctx = canvas.getContext('2d')
            this.drawRect(ctx)
            this.drawSmile(ctx)
          })
      },
      drawRect: function (ctx) {
        ctx.fillStyle = 'rgba(0, 0, 200, 0.5)'
        ctx.fillRect(10, 10, 150, 50)
      },
    
      drawSmile: function (ctx) {
        // 设置线条颜色为红色,线条宽度为2px
        ctx.strokeStyle = '#f00'
        ctx.lineWidth = '2'
        // 移动画笔坐标位置,绘制外部大圆
        ctx.moveTo(160, 80)
        ctx.arc(100, 80, 60, 0, 2 * Math.PI, true)
        // 移动画笔坐标位置,绘制外部嘴巴线条
        ctx.moveTo(140, 80)
        ctx.arc(100, 80, 40, 0, Math.PI, false)
        // 移动画笔坐标位置,绘制左眼圆圈
        ctx.moveTo(85, 60)
        ctx.arc(80, 60, 5, 0, 2 * Math.PI, true)
        // 移动画笔坐标位置,绘制右眼圆圈
        ctx.moveTo(125, 60)
        ctx.arc(120, 60, 5, 0, 2 * Math.PI, true)
        ctx.stroke()
      }
    })
(3)案例实现
  • 准备工作
    • ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为"模拟时钟",模板选择"不使用模板"。
    • ②配置导航栏。在pages/index/index.json文件中配置页面导航栏。
  • 初始化画布

    • ①在pages/index/index.wxml文件中定义canvas组件。
    html 复制代码
    <canvas id="myCanvas" type="2d"></canvas>
    • ②在pages/index/index.wxss文件中编写canvas组件的样式。
    css 复制代码
      #myCanvas {
        width: 100%;
        height: 100%;
        position: fixed;
      } 
  • **绘制代码封装:**在项目根目录下创建utils文件夹,将绘制功能封装到utils/drawClock.js文件中

    js 复制代码
    // 将角度转换为弧度
    const D6 = 6 * Math.PI / 180
    const D30 = 30 * Math.PI / 180
    const D90 = 90 * Math.PI / 180
    
    module.exports = canvas => {
      const ctx = canvas.getContext('2d')
      // 计算表盘半径,留出30px外边距
      var radius = canvas.width / 2 - 30
      return () => {
        // 在绘制时钟前先清除画布
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        // 设置坐标轴原点为画布的中心点
        ctx.translate(canvas.width / 2, canvas.height / 2)
        // 绘制表盘
        drawDial(ctx, radius)
        // 绘制指针
        drawHand(ctx, radius)
        // 绘制完成后将画布恢复成初始状态
        ctx.rotate(D90)
        ctx.translate(-canvas.width / 2, -canvas.height / 2)
        ctx.restore()
      }
    }
    // 表盘整体部分,包括外层大圆和中心圆部分
    function drawDial(ctx, radius) {
      // 绘制外层大圆
      ctx.lineWidth = '2' // 设置线条宽度为2px
      ctx.beginPath() // 开始一条路径
      ctx.arc(0, 0, radius, 0, 2 * Math.PI, true) // 画弧线
      ctx.stroke() // 绘制
      // 绘制中心圆
      ctx.lineWidth = '1'
      ctx.beginPath()
      ctx.arc(0, 0, 8, 0, 2 * Math.PI, true) // 中心圆半径为8px
      ctx.stroke()
      // 绘制大刻度盘
      ctx.lineWidth = '5'
      // 从三点钟开始,转圈进行绘制
      for (var i = 0; i < 12; ++i) {
        // 以原点为中心顺时针旋转,多次调用旋转的角度会叠加,从而画出倾斜的线
        ctx.rotate(D30) // 大刻度盘绘制12个线条
        ctx.beginPath()
        // 设置起始点,现在原点是在中心点,调用moveTo()方法将线条移动到外层大圆上
        ctx.moveTo(radius, 0)
        // 设置终点
        ctx.lineTo(radius - 15, 0) // 大刻度长度15px
        ctx.stroke()
      }
      // 绘制小刻度盘
      ctx.lineWidth = '1'
      for (var i = 0; i < 60; ++i) {
        ctx.rotate(D6)
        ctx.beginPath()
        ctx.moveTo(radius, 0)
        ctx.lineTo(radius - 10, 0) // 小刻度盘长度10px
        ctx.stroke()
      }
      // 绘制数字
      ctx.font = '22px sans-serif'
      ctx.textBaseline = 'middle' // 文本垂直居中
      // 文本距离时钟中心点半径,让文字与表盘线有距离
      var r = radius - 30
      // 文本位置是绕外圈圆的,所以要计算文本坐标
      for (var i = 1; i <= 12; ++i) {
        // 利用三角函数计算文本坐标
        var x = r * Math.cos(D30 * i - D90)
        var y = r * Math.sin(D30 * i - D90)
        // console.log(x, y)
        // 位置进行调整
        if (i > 10) {
          // 在画布上绘制文本,fillText(文本, 左上角x坐标, 左上角y坐标)
          ctx.fillText(i, x - 12, y) // 绘制11和12
        } else {
          ctx.fillText(i, x - 6, y) // 绘制1~10
        }
      }
    }
    // 绘制指针
    function drawHand(ctx, radius) {
      var t = new Date() // 获取当前时间
      var h = t.getHours() // 小时
      var m = t.getMinutes() // 分
      var s = t.getSeconds() // 秒
      h = h > 12 ? h - 12 : h // 将24小时制转化为12小时制
      // 时间从3点开始,逆时针旋转90°,指向12点
      ctx.rotate(-D90)
      // 绘制时针
      ctx.save() // 记录旋转状态
      ctx.rotate(D30 * (h + m / 60 + s / 3600))
      ctx.lineWidth = '6'
      ctx.beginPath()
      ctx.moveTo(-20, 0) // 线条起点(针尾留出20px)
      ctx.lineTo(radius / 2.6, 0) // 线条长度
      ctx.stroke()
      ctx.restore() // 恢复旋转状态,避免旋转叠加
      // 绘制分针
      ctx.save()
      ctx.rotate(D6 * (m + s / 60))
      ctx.lineWidth = '4'
      ctx.beginPath()
      ctx.moveTo(-20, 0)
      ctx.lineTo(radius / 1.8, 0)
      ctx.stroke()
      ctx.restore()
      // 绘制秒针
      ctx.save()
      ctx.rotate(D6 * s)
      ctx.lineWidth = '2'
      ctx.beginPath()
      ctx.moveTo(-20, 0)
      ctx.lineTo(radius / 1.6, 0)
      ctx.stroke()
      ctx.restore()
    }
  • **绘制代码实现:**在pages/index/index.js实现绘制代码。

    js 复制代码
    // index.js
    const drawClock = require('../../utils/drawClock.js')
    
    Page({
      timer: null, // 定时器
    
      onReady: function () {
        wx.createSelectorQuery()
        .select('#myCanvas')
        .fields({ node: true, size: true })
        .exec(res => {
          const canvas = res[0].node
          canvas.width = res[0].width
          canvas.height = res[0].height
          const draw = drawClock(canvas)
          draw()
          this.timer = setInterval(draw, 1000)
        })
      },
      // 在页面卸载时清除定时器
      onUnload: function () {
        clearInterval(this.timer)
      }
    })
    • 页面实现效果
相关推荐
V+zmm101341 小时前
基于微信小程序的乡村政务服务系统springboot+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
还这么多错误?!1 小时前
uniapp微信小程序,使用fastadmin完成一个一键获取微信手机号的功能
微信小程序·小程序·uni-app
_院长大人_1 小时前
微信小程序用户信息解密 AES/CBC/NoPadding 解密失败问题
微信小程序·小程序
web135085886352 小时前
uniapp小程序使用webview 嵌套 vue 项目
vue.js·小程序·uni-app
guanpinkeji2 小时前
废品回收小程序:助力企业转型发展
小程序·小程序开发·小程序制作·回收·废品回收小程序·废品回收
407指导员3 小时前
uniapp 微信小程序 页面部分截图实现
微信小程序·小程序·uni-app
三木吧5 小时前
开发微信小程序的过程与心得
人工智能·微信小程序·小程序
Kika写代码5 小时前
【微信小程序】3|首页搜索框 | 我的咖啡店-综合实训
微信小程序·小程序
金金金__5 小时前
微信小程序:解决顶部被遮挡的问题
微信小程序·小程序
zhulangfly16 小时前
Wux weapp 组件库的 bug—— wux-picker选择器组件无法正确初始化到选定的value
小程序·wux weapp