微信小程序开发(二)

10k words

知识点


如何呈现动态数据

JavaScript首先从服务器拿到数据,然后通过数据绑定,如 setData 将数据给到View。

小程序最开始是没有双向数据绑定的,但是现在提供了简易的双向的数据绑定,双向数据绑定其实不是必需的。

关于数据绑定的微信小程序官方文档:数据绑定 | 微信开放文档 (qq.com)

理解DOM优先和数据优先的区别

关于JavaScript

生命周期函数由小程序调用,不需要开发者调用,在很多框架里生命周期函数被称为 hook function

我们在js文件下 Page({data:}) 函数里定义的所有变量都可以直接在wxml里面使用,在wxml时加 {{}}

预先在 data 中定义绑定数据的初始值是值得推荐的做法,即先在 data 中定义后再在 onLoadthis.setData({})

setData 键和值相同可以简写。

条件渲染

条件渲染的表达式 wx:if="" ,当满足这个条件的时候,这个标签才会被显示。

if else也是可以实现的!

<view>
    <text wx:if="{{flag}}">{{text}}</text>
    <text wx:else>{{text}}</text>
</view>

列表渲染

用来展示一组js对象的数据。

// 拿到一个数组,用setData包装成js对象
onLoad(options): {
    // 这里的content内的数据其实一般是服务端直接传来的
    var content = [{
        title: "text",
        // ......
    },{
        title: "text",
        // ......
    }]
})
    this.setData({
        posts:content
    })
}
<block wx:for="{{posts}}" wx:key="index" wx:for-item="item">
    <view>
        <text src="{{item.title}}"></text>
    </view>
</block>

如果要取到序号的话用 {{index}} 即可。

示例:

onLoad(options) {
    var content = [{
       avater: "/images/avater/2.png",
       title: "texttextexttext",
       content: "texttextexttexttexttextexttexttexttextexttext",
       reading: 102,
       detail: "texttextexttexttexttextexttexttexttextexttext",
       collection: 92,
       headImg: "/images/banner/banner1.jpg",
       author: "猫猫不是猫",
       date: "Nov 13 2022",
    }, {
       avater: "/images/avater/2.png",
       title: "texttextexttext",
       content: "texttextexttexttexttextexttexttexttextexttext",
       reading: 102,
       detail: "texttextexttexttexttextexttexttexttextexttext",
       collection: 92,
       headImg: "/images/banner/banner1.jpg",
       author: "猫猫不是猫",
       date: "Nov 13 2022",
    }]
    this.setData({
       posts: content
    })
},
<block wx:for="{{posts}}">
   <view class="post-container">
      <view class="post-author-date">
         <image class="post-author" src="{{item.avater}}"></image>
         <text class="post-date">{{item.date}}</text>
      </view>
      <text class="post-title">{{item.title}}</text>
      <image class="post-image" src="{{item.headImg}}"></image>
      <text class="post-content">{{item.content}}</text>
      <view class="post-like">
         <l-icon class="post-like-image" color="#666" size="26" name="favor" />
         <text class="post-like-font">{{item.collection}}</text>
         <l-icon class="post-like-image" color="#666" size="32" name="eye" />
         <text class="post-like-font">{{item.reading}}</text>
      </view>
   </view>
</block>

事件

事件 | 微信开放文档 (qq.com)

首页跳转按钮示例:

  1. 捕捉事件 bindtap=""
  2. 在js文件中定义函数。
  <view bind:tap="onTap" class="journey-container">
    <text class="journey">开启小程序之旅</text>
  </view>
Page({   
    onTap: function (params) {
      wx.navigateTo({
        url: '/pages/posts/posts',
      })
   }
})

最多只能有10个子页面。

wx.redirectTO 也是跳转,但是会卸载页面。

捕捉事件 catchbind 的区别: catch 会阻止事件继续冒泡,bind 不会阻止事件冒泡。

js模块的导入导出

js模块的导出:

module.exports = {
   postList:local_database
}
// 最新方式
export {
   local_database
}

js模块的导入:

// 在Page({})之外
var postData = require("../../data/data")
// 更推荐的另一种导入方式,这种导入方式要和导出数据同名
import {local_database} from '../../data/data'

导入只能使用相对路径。

用View模拟出分割线

<view class="horizon"></view>
.horizon {
   width: 660rpx;
   height: 1px;
   background-color: #e5e5e5;
}

如何设置元素浮动

align-items 设置子元素在交叉轴上的排布方式。

justify-content 设置子元素在主轴上的排布方式。

实现效果:image-20230416173526635

用flex方式实现:

   <view class="tool">
      <view class="circle">
         <image src="/images/icon/collection.png"></image>
         <image class="share-img" src="/images/icon/share.png"></image>
      </view>
      <view class="horizon"></view>
   </view>
.circle {
   display: flex;
   /* 容器要有宽度后面的排布方式才生效 */
   width: 660rpx;
   flex-direction: row;
   justify-content: flex-end;
}

.horizon {
   width: 660rpx;
   height: 1px;
   background-color: #e5e5e5;
   position: absolute;
   /* 降低层级 */
   z-index: -1;
}

.circle image {
   width: 90rpx;
   height: 90rpx;
}

.share-img {
   margin-left: 30rpx;
}

自定义属性

<view data-<name>=""> ,返回的键只有 <name>

如何通过自定义属性定位到相关页面(页面之间数据通信)

<!-- post.wxml -->
<view data-id="{{item.postId}}" bind:tap="onGoToDetail" class="post-container">
// posts.js
onGoToDetail(event) {
   const pid = event.currentTarget.dataset.id
   wx.navigateTo({
      url: '/pages/post-detail/post-detail?pid=' + pid
   })
}

// post-detail.js
onLoad(options) {
   const postData = postList[options.pid]
   console.log(postData)
   this.setData({
      postData
   })
   console.log(postData)
},

如何响应用户操作

关于同步和异步的区别:同步与异步的区别

app.js的一些作用

设置全局变量:

App({
   onLaunch(){
      console.log("小程序启动~")
   }
})

缓存

      // 设置缓存
      wx.setStorageSync('flag', true)
      wx.setStorageSync('flag2', true)
      // 清除缓存
      wx.removeStorageSync('flag')
      // 清除所有缓存
      wx.clearStorageSync() 
      // 获取同步缓存
      wx.setStorageSync('flag', true)
      // const flag = wx.getStorageSync('flag')
      // 获取异步缓存
      const flag = wx.getStorage({
         key: 'flag',
         // success(value){
         //    console.log(value.data)
         // }
      })
      // 获取Promise的方法(传统)
      flag.then((value)=>{
         console.log(value)
      })
      // ES7获取异步缓存的方法:
      // 在onLoad()前加上async
      wx.setStorageSync('flag2', true)
      const flag2 = await wx.getStorage({
         key: 'flag2',
      })

缓存就像是前端的数据库。

完善文章详情页收藏按钮

   /**
    * 页面的初始数据
    */
   data: {
      postData: {},
      collected: false,
      // 不做数据绑定的变量名开头加_
      _pid: null,
      _postsCollected: {},
   },

   /**
    * 生命周期函数--监听页面加载
    */
   onLoad(options) {
      const postData = postList[options.pid]
      // 获取pid
      this.data._pid = options.pid
      const postCollected = wx.getStorageSync('posts_collected')
      this.data._postsCollected = postCollected
      let collected = postCollected[this.data._pid]
      if (collected == undefined) {
         collected = false
      }
      this.setData({
         postData,
         collected
      })
   },

   /**
    * 收藏按钮
    */
   onCollection(event) {
      // 需要解决:
      // 1.哪篇文章被收藏
      // 2.多篇文章被收藏的情况
      const postsCollected = this.data._postsCollected
      postsCollected[this.data._pid] = !this.data.collected
      this.setData({
         collected: !this.data.collected
      })
      wx.setStorageSync('posts_collected', postsCollected)
   },
<image wx:if="{{!collected}}" bind:tap="onCollection" src="/images/icon/collection-anti.png"></image>

交互组件

showToast组件:轻提示

      wx.showToast({
         title: this.data.collected ? '收藏成功' : '取消收藏',
         // 停留时间
         duration: 3000,
      })

showModal组件:模态对话框

      wx.showModal({
         title: '这是一个提示框',
         content: '',
         complete: (res) => {
            if (res.cancel) {

            }

            if (res.confirm) {

            }
         }
      })

音乐组件

BackgroundAudioManager | 微信开放文档 (qq.com)

实现播放

   <image bind:tap="onMusic" class="audio" src="/images/music/music-start.png"></image>
   onMusic(event) {
      const mgr = wx.getBackgroundAudioManager()
      mgr.src = postList[this.data.pid].music.url
      mgr.title = postList[this.data.pid].music.title
   },

继续完善:状态切换

   data: {
      postData: {},
      collected: false,
      // 音乐播放标识(新增)
      isPlaying: false,
      // 不做数据绑定的变量名开头加_
      _pid: null,
      _postsCollected: {},
   },
   /**
    * 音乐播放
    * @param {onMusicStart} event 
    */
   onMusicStart(event) {
      const mgr = wx.getBackgroundAudioManager()
      mgr.src = postList[this.data._pid].music.url
      mgr.title = postList[this.data._pid].music.title
      // 设置音乐封面
      mgr.coverImgUrl = postList[this.data._pid].music.coverImgUrl
      this.setData({
         isPlaying: true,
      })
   },

   /**
    * 音乐停止
    * @param {onMusicStop} event 
    */
   onMusicStop(event) {
      const mgr = wx.getBackgroundAudioManager()
      mgr.stop()
      this.setData({
         isPlaying: false
      })
   },
   <image wx:if="{{!isPlaying}}" bind:tap="onMusicStart" class="audio" src="/images/music/music-start.png"></image>
   <image wx:else bind:tap="onMusicStop" class="audio" src="/images/music/music-stop.png"></image>

存在问题:音乐控制面板切换状态与页面没有同步(使用监听机制)

背景音频播放事件的监听函数:BackgroundAudioManager.onPlay(function listener) | 微信开放文档 (qq.com)

   data: {
      _mgr: null,
   },
   onLoad(options) {
      const mgr = wx.getBackgroundAudioManager()
      this.data._mgr = mgr
      mgr.onPlay(this.onMusicStart)
      mgr.onPause(this.onMusicPause)
   },
   onMusicStart(event) {
      const mgr = this.data._mgr
   },
   onMusicPause(event) {
      const mgr = this.data._mgr
      mgr.pause()
      this.setData({
         isPlaying: false
      })
   },

存在问题:音乐后台播放时返回上一页后再回来状态为初始状态(用全局变量解决)

在app.js中加入控制音乐播放的全局变量

App({
   onLaunch(){
      gIsPlayingMusic: false
   },
})

在post-detail.js中获取全局变量

const app = getApp()

在函数中尝试改变全局变量

   onMusicStart(event) {
      app.gIsPlayingMusic = true
   },

初始化时给isPlaying赋全局变量gIsPlayingMusic的值

   onLoad(options) {
      this.setData({
         isPlaying: app.gIsPlayingMusic
      })
   },

新问题:后台播放音乐时切换到其他文章仍然显示音乐正在播放

对全局变量做更改,用以标识ID,-1表示false

App({
   onLaunch(){
      // gIsPlayingMusic: false
      gIsPlayingMusic: -1
   },
})
   currentMusicIsPlaying() {
      if (app.gIsPlayingMusic != -1 && app.gIsPlayingMusic == this.data._pid) {
         return true
      }
      return false
   },
   onLoad(options) {

      this.setData({
         postData,
         collected,
         isPlaying: this.currentMusicIsPlaying()
      })
   },
   onMusicPause(event) {
      app.gIsPlayingMusic = -1
   },
   onMusicStart(event) {
      app.gIsPlayingMusic = this.data._pid
   },

tabBar选项卡

app.json:

   "tabBar": {
      "selectedColor": "#333333",
      "color": "#999999",
      "list": [{
            "pagePath": "pages/posts/posts",
            "text": "阅读",
            "iconPath": "images/tab/post.png",
            "selectedIconPath": "images/tab/[email protected]"
         },
         {
            "pagePath": "pages/movies/movies",
            "text": "电影",
            "iconPath": "images/tab/movie.png",
            "selectedIconPath": "images/tab/[email protected]"
         }
      ]
   },

如果要跳转到带有tabBar选项卡的页面:

   onTap: function (params) {
      wx.switchTab({
         url: '/pages/posts/posts',
      })
   }
Comments