小程序项目学习--第五章:项目实战一

news2024/11/20 9:30:51

第五章:项目实战一、

01_(了解)音乐小程序的项目介绍

坑关于Vant Weapp中组件引入未找到的解决方案

[ pages/main-music/main-music.json 文件内容错误] pages/main-music/main-music.json: [“usingComponents”][“van-search”]: “@vant/weapp/search/index” 未找到

小程序构建npm问题:https://blog.csdn.net/weixin_46587302/article/details/118681069

关于Vant Weapp中组件引入未找到的解决方案
npm install

npm i @vant/weapp -S --production

构建npm

 "setting": {
     ...
	"packNpmManually": true,
    "packNpmRelationList": [
      {
        "packageJsonPath": "./package.json",
        "miniprogramNpmDistDir": "./"
      }
    ],
    ...
 }
    

02_(掌握)项目结构搭建和TabBar的页面配置

1.初始化项目结构

image-20230121171151812

2.创建对应文件夹-components–services-assets

image-20230121171409705

3.创建底部tabBar页面–main-muisic 和main-video

image-20230121172317127

3.1自定义页面标题

image-20230124102809321

03_(掌握)视频页面-请求MV列表数据和基本展示

1.做视频页面,需要数据获取列表,数据就需要发送网络请求–封装网络请求–展示页面

之前做过网络封装,这里直接复用之前使用个的网络请求封装,这里使用类封装的请求方法

// 封装成类 -> 实例
import { baseURL } from "./config"

class HYRequest {
  constructor(baseURL) {
    this.baseURL = baseURL
  }
  request(options) {
    const { url } = options
    return new Promise((resolve, reject) => {
      wx.request({
        ...options,
        url: this.baseURL + url,
        success: (res) => {
          resolve(res.data)
        },
        fail: (err) => {
          console.log("err:", err);
        }
      })
    })
  }
  get(options) {
    return this.request({ ...options, method: "get" })
  }
  post(options) {
    return this.request({ ...options, method: "post" })
  }
}

export const hyRequest = new HYRequest("http://codercba.com:9002")

2.发送对应的网络请求

  1. 首先需要存储数据的空数组用来保存数据,显示到页面上
data: {
    // 1.首先需要存储数据的空数组用来保存数据             
    videoList: [],
  }
  1. 引入封装的实例请求方法
// pages/main-video/main-video.js
import { hyRequest } from "../../services/index"
  1. 需要在对应的生命周期中调用实例(onLoad())发送网络请求,使用promise获取请求,将数据放入到data里面
onLoad(){
    // .需要在对应的生命周期中调用实例(onLoad())发送网络请求,使用promise获取请求,将数据放入到data里面
    hyRequest.get({
      url:"/top/mv",
      data:{
        limit:20,
        offset:0
      }
    }).then(res=>{
      // console.log(res);
      this.setData({videoList:res.data})
    })
  }

​ 3.1可以通过调试器中的AppData检验

image-20230124110808691

  1. 对数据遍历(wx:for)进行展示,key需要根据不同的情况进行思考,如果是深层次的key,可以写mustache语法{{}}–
<!--pages/main-video/main-video.wxml-->
<view class="video-list">
  <block wx:for="{{videoList}}" wx:key="id">
      <view>
          <image src="{{item.cover}}"/>
          <view>{{item.name}}</view>
      </view>
  </block>
</view>


  1. 对展示的数据进行布局

2.1,调整每次进入的页面

方式一,通过app.js配置

方式二:更改页面的编译模式–更改启动页面

2.2网络请求时–点击->详情->本地设置->不校验合法域名

04_(掌握)视频页面-网络请求代码的重构和封装

0.对数据发给网络请求,获取数据,对数据进行展示,

1.对应网络请求的数据非常多,每个页面都来管理自己页面的url和参数,如果当前对应的url发生改变,如果写到的书对应页面里面,是不好寻找的,

所以我们会在services文件夹进行模块划分,对请求进行抽取,对网络请求的url地址和参数进行封装,对于页面来说我们只需要发送什么样的请求就行,

里面会对地址和参数进行拼接好,在外部只需要调用对应的方法就行

2.网络分层架构

对应请求视频相关的所有页面我们在services中新建video.js,对应经常变化的参数,让页面传递进来

services->video.js

import { hyRequest } from "./index"

export function getTopMV(offset = 0, limit = 20) {
  return hyRequest.get({
    url: "/top/mv",
    data: {
      limit,
      offset
    }
  })
}

main-video.js

// pages/main-video/main-video.js
// 2.引入封装的实例请求方法
import { getTopMV } from "../../services/video"

Page({
  data: {
    // 1.首先需要存储数据的空数组用来保存数据             
    videoList: [],
  },
  onLoad(){
    // 3.需要在对应的生命周期中调用实例(onLoad())发送网络请求,使用promise获取请求,将数据放入到data里面
   getTopMV().then(res=>{
      // console.log(res);
      this.setData({videoList:res.data})
    })
  }
})

3.我们发送网络请求的代码写在onLoad里面,但是我们不希望我们的代码是promise情况,我们希望是async 和await,但是如果是async 和await是同步,会阻塞直到前面代码执行,才会继续执行,会操成后续代码不会执行,如果我们对代码进行封装,也会方便后续对代码的复用

使用我们并不会将完全请求的代码放到onLoad里面,而是封装一个函数,然后再onLoad中调用封装的方法

// pages/main-video/main-video.js
// 2.引入封装的实例请求方法
import { getTopMV } from "../../services/video"

Page({
  data: {
    // 1.首先需要存储数据的空数组用来保存数据             
    videoList: [],
  },
  onLoad(){
    // 发送网络请求
    this.fetchTopMV()
  },
  async fetchTopMV(){
    // 老方法promise
    // getTopMV().then(res=>{
    // this.setData({videoList:res.data})
    // })
    const res = await getTopMV()
    this.setData({videoList:res.data})
  }
})

05_(掌握)视频页面-VideoItem的具体展示过程

image-20230125110959046

1.VideoItem是独立的组件,对组件进行封装,然后进行wx:for循环,给组件传入数据,以列表的形式展示组件

1.1封装组件VideoItem进行封装,和通过properties接收数据

<view>
  <image src="{{itemData.cover}}"></image>
  <view>{{itemData.name}}</view>
</view>


// components/video-item/video-item.js
Component({
//  组件的属性列表
  properties: {
    itemData:{
      type:Object,
      value:{}
    }
  },
})

1.2向组件传递数据 {{item}}

<view class="video-list">
  <block wx:for="{{videoList}}" wx:key="id">
    <video-item   itemData="{{item}}"></video-item>
  </block>
</view>

1.3使用组件需要进行注册

 "usingComponents": {
    "video-item": "/components/video-item/video-item"
  }

2.对组件进行结构和布局

pages/main-video

/* pages/main-video/main-video.wxss */
.video-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
  padding: 0 10rpx;
}

.video-list .item {
  width: 48%;
}

<!--pages/main-video/main-video.wxml-->
<view class="video-list">
  <block wx:for="{{videoList}}" wx:key="id">
    <video-item 
      class="item" 
      itemData="{{item}}"
      bindtap="onVideoItemTap"
      data-item="{{item}}"
    />
  </block>
</view>

video-item

<!--components/video-item/video-item.wxml-->
<wxs src="/utils/format.wxs" module="fmt"></wxs>
<view class="item" bindtap="onItemTap">
  <view class="album">
    <image class="image" mode="widthFix" src="{{itemData.cover}}"></image>
    <view class="info">
      <view class="count">{{fmt.formatCount(itemData.playCount)}}</view>
      <view class="duration">{{fmt.formatTime(itemData.mv.videos[0].duration)}}</view>
    </view>
  </view>
  <view class="content">{{itemData.name}} - {{itemData.artistName}}</view>
</view>

样式省略... 

3.细节处理–对数字进行格式化(封装–通过utils–》wxs)

format.wxs -->在wxml中使用 wxs

// 对count进行格式化
function formatCount(count) {
  count = Number(count)
  if (count >= 100000000) {
    return (count / 100000000).toFixed(1) + "亿"
  } else if (count >= 10000) {
    return (count / 10000).toFixed(1) + "万"
  } else {
    return count
  }
}

// 2 -> 02
// 24 -> 24
function padLeft(time) {
  time = time + ""
  return ("00" + time).slice(time.length)
}

// 对time进行格式化
// 100 -> 01:40
function formatTime(time) {
  // 0.将毫秒转成秒
  time = time / 1000

  // 1.获取时间
  var minute = Math.floor(time / 60)
  var second = Math.floor(time) % 60

  // 2.拼接字符串
  return padLeft(minute) + ":" + padLeft(second)
}

// 必须导出后, 才能被其他地方调用: 必须使用CommonJS导出
module.exports = {
  formatCount: formatCount,
  formatTime: formatTime
}

06_(掌握)视频页面-上拉加载更多的功能实现

目前的局限->展示数据只能展示20条数据,我们需要实现上拉加载更多

逻辑分析: 我们需要记录之前的数据偏移了多少,在请求偏移的最新的20条数据

我们通过在data中offset记录偏移,再次发送网络请求的时候对offset进行修改,并且将新的数据追加到原来数据的后面

但是我们的数据可能请求完,我们可以通过hasMore变量来记录是否还有更多数据

// pages/main-video/main-video.js
// 2.引入封装的实例请求方法
import { getTopMV } from "../../services/video"

Page({
  data: {
    videoList: [],
    offset: 0,
    hasMore: true
  },

  onLoad() {
    // 发送网络请求 
    this.fetchTopMV()
  },

  // =================  发送网络请求的方法 =================  
  async fetchTopMV() {
    // getTopMV().then(res => {
    //   this.setData({ videoList: res.data })
    // })
    // 1.获取数据
    const res = await getTopMV(this.data.offset)

    // 2.将新的数据追加到原来数据的后面
    const newVideoList = [...this.data.videoList, ...res.data]

    // 3.设置全新的数据
    this.setData({ videoList: newVideoList })
    this.data.offset = this.data.videoList.length
    this.data.hasMore = res.hasMore
  },

  // =================  监听上拉和下拉功能  =================  
  onReachBottom() {
    // 1.判断是否有更多的数据
    if (!this.data.hasMore) return

    // 2.如果有更多的数据, 再请求新的数据
    this.fetchTopMV()
  },
  
})

07_(掌握)视频页面-下拉刷新数据的功能实现

1.开启下拉刷新–默认页面没有开启下拉刷新功能 看不见需要在app.json中改变样式

  "enablePullDownRefresh": true,
      
  "window": {
      ...
    "backgroundTextStyle": "dark",
  }

2.监听 清空之前数据 ,重新请求新的数据,停止下拉刷新

方式一:promise方式

在fetchTopMV重新请求到数据的时候通过promise停止下拉刷新

image-20230125125051301

方式二:async/await方式

image-20230125125119596

  async onPullDownRefresh() {
    // 1.清空之前的数据
    this.setData({ videoList: [] })
    this.data.offset = 0
    this.data.hasMore = true

    // 2.重新请求新的数据
    await this.fetchTopMV()

    // 3.停止下拉刷新
    wx.stopPullDownRefresh()
  },

08_(掌握)视频页面-点击Item跳转到详情的方式–detail-video

1.首先创建detail-video页面 ,我们可以通过onLoad中options参数通过 options.id 获取id options就是通过模板字符串中穿过来的值

<text>{{id}}</text>


// pages/detail-video/detail-video.js
Page({
  data: {
    id: 0
  },
  onLoad(options) {
    const id = options.id
    console.log(options);
    this.setData({
      id
    })
  }

})

2.跳转到详情的

方式一:组件的监听点击

通过在组件上 bindtap监听整个组件点击和给组件添加自定义属性用来判断用户点击的是哪个组件

 <video-item 
      class="item" 
      itemData="{{item}}"
      bindtap="onVideoItemTap"
      data-item="{{item}}"
    />
          
  // =================  界面事件监听的方法 =================  
  onVideoItemTap(event) {
    // const item = event.currentTarget.dataset.item
    // wx.navigateTo({
    //   url: `/pages/detail-video/detail-video?id=${item.id}`,
    // })
  }          

方式二:组件内部的监听

在item组件内部根元素,通过bindtap绑定点击事件,在这里跳转不用传参数,可以通过this.properties.itemData

<view class="item" bindtap="onIt emTap">
    
    
  methods: {
    onItemTap() {
      const item = this.properties.itemData
      wx.navigateTo({
        url: `/pages/detail-video/detail-video?id=${item.id}`,
      })
    }
  }

09_(掌握)视频页面-请求视频地址和视频播放

1.请求视频地址和视频播放网络–方法封装

export function getMVUrl(id) {
  return hyRequest.get({
    url: "/mv/url",
 //id 就是options中的id
    data: {
      id
    }
  })
}


2.引入方法和调用请求视频地址数据

// pages/detail-video/detail-video.js
import { getMVUrl } from "../../services/video"

Page({
  data: {
    id: 0,
    mvUrl: "",
  },
  onLoad(options) {
     // 1.获取id
    const id = options.id
    this.setData({id})
     // 2.请求数据
    this.fetchMVUrl()
  },
  async fetchMVUrl() {
    const res = await getMVUrl(this.data.id)
    this.setData({ mvUrl: res.data.url })
  },

})

3.展示数据和设置样式

<!--pages/detail-video/detail-video.wxml-->
<video 
  class="video" 
  src="{{mvUrl}}" 
  danmu-list="{{danmuList}}"
  autoplay />
           

4.弹幕

data: {
  danmuList: [
      { text: "哈哈哈, 真好听", color: "#ff0000", time: 3 },
      { text: "呵呵呵, 不错哦", color: "#ffff00", time: 10 },
      { text: "嘿嘿嘿, 好喜欢", color: "#0000ff", time: 15 },
    ]
}  

10_(掌握)视频页面-请求视频详情和视频推荐的数据

1.请求新数据就需要封装新接口

export function getMVInfo(mvid) {
  return hyRequest.get({
    url: "/mv/detail",
    data: {
      mvid
    }
  })
}

export function getMVRelated(id) {
  return hyRequest.get({
    url: "/related/allvideo",
    data: {
      id
    }
  })
}

2.引入方法和调用请求

import { getMVInfo, getMVRelated } from "../../services/video"
 data: {
	mvInfo: {},
    relatedVideo: [],
 }

  onLoad(options) {
    // 1.获取id
    const id = options.id
    this.setData({ id })

    // 2.请求数据
    this.fetchMVInfo()
    this.fetchMVRelated()
  },
      
async fetchMVInfo() {
    const res = await getMVInfo(this.data.id)
    this.setData({ mvInfo: res.data })
  },
  async fetchMVRelated() {
    const res = await getMVRelated(this.data.id)
    this.setData({ relatedVideo: res.data })
  }
      

3.展示数据和设置样式

<scroll-view class="content" scroll-y>
  <view class="info">
    <view>{{ mvInfo.artistName }}</view>
  </view>

  <view class="related-video">
    <block wx:for="{{relatedVideo}}" wx:key="vid">
      <view class="item">
        <image src="{{item.coverUrl}}" mode="widthFix"></image>
        <view>{{item.title}}</view>
      </view>
    </block>
  </view>
</scroll-view>

/* pages/detail-video/detail-video.wxss */
page {
  height: 100vh;
}

.video {
  width: 100%;
  /* position: fixed;
  top: 0;
  left: 0; */
}

.content {
  /* margin-top: 225px; */
  /* height: 300px; */
  height: calc(100% - 225px);
}

11_(掌握)视频页面-内容的滚动方案实现和对比

方案一:通过样式调整

/* pages/detail-video/detail-video.wxss */

.video {
  width: 100%;
  /* 会脱离标准流,跑到上面去 */
  /* position: fixed;
  top: 0;
  left: 0; */
}

.content {
  /* margin-top: 225px; */
  /* height: 300px; */
  height: calc(100% - 225px);
}

方案二:使用组件scroll-view

<scroll-view class="content" scroll-y>
  <view class="info">
    <view>{{ mvInfo.artistName }}</view>
  </view>

  <view class="related-video">
    <block wx:for="{{relatedVideo}}" wx:key="vid">
      <view class="item">
        <image src="{{item.coverUrl}}" mode="widthFix"></image>
        <view>{{item.title}}</view>
      </view>
    </block>
  </view>
</scroll-view>  
/* pages/detail-video/detail-video.wxss */
page {
  height: 100vh;
}

.video {
  width: 100%;
  /* 会脱离标准流,跑到上面去 */
  /* position: fixed;
  top: 0;
  left: 0; */
}

.content {
  /* margin-top: 225px; */
  /* height: 300px; */
  height: calc(100% - 225px);
}

第五章:音乐界面

12_(掌握)音乐页面-Vant库的安装和使用过程

音乐页面从上到下-

搜索框–第三方组件–vant https://vant-contrib.gitee.io/vant-weapp/#/home

1.安装

小程序新建终端

npm i @vant/weapp

会自动生成package-lock.json 和package.json文件 node_modules

如果没有生成,我们通过命令npm init -y之后在重新安装 npm i @vant/weapp

npm init -y

安装完还是不可以直接使用,因为不是node环境也不是webpack环境,而是小程序自己的环境

我们选择使用npm环境-》工具-》构建npm(每次通过npm下载,都需要重新构建一下)

本质是将安装在node_modules里面的东西构建在miniprogram_npm下面,因为你下载的node_modules里面的东西默认不会从中寻找,而是从miniprogram_npm下面寻找

image-20230126104023995

2.注册

在使用的页面中的json文件中

 "usingComponents": {
    "van-search": "@vant/weapp/search/index",
 }

3.使用

在使用的页面wxml中使用

<van-search
  value="{{ searchValue }}"
  shape="round"
  background="#fafafa"
  placeholder="请输入搜索关键词"
  bind:click-input="onSearchClick"
/>

image-20230126105046902

13_(掌握)音乐页面-搜索框搭建和点击搜索框的跳转

1.

1.引入组件

  "usingComponents": {
    "van-search": "@vant/weapp/search/index",
  }

2.设置样式

"navigationBarBackgroundColor": "#fafafa",

<van-search
  value="{{ searchValue }}"
  shape="round" 
  background="#fafafa"
  placeholder="请输入搜索关键词"
  bind:click-input="onSearchClick"
/>    
    
page {
  --search-background-color: #fff;
  --search-padding: 10px 0;

  box-sizing: border-box;
  padding: 0 24rpx;
  background-color: #fafafa;
}

2.

覆盖元素背景样式的方法

image-20230126160031083

方式一 获取class,重写

/* .van-search__content {
  background-color: #fff !important;
} */

方式二:修改变量

--search-background-color: #fff;

3.

vant 2.18.1之后出现的警告,不是错误

image-20230126160223341

解决

方式一:修改源码

方式二: 使用低版本的基础库(但是新功能使用不了,但是适配能力越强)

使用2.18.0在 project.config.json 修改

 "libVersion": "2.18.0",

4.点击搜索框进入搜索页面

创建页面detail-search

<!--pages/detail-search/detail-search.wxml-->
<text>pages/detail-search/detail-search.wxml</text>

绑定点击事件

<!--pages/main-music/main-music.wxml-->
<van-search
  value="{{ searchValue }}"
  shape="round" 
  background="#fafafa"
  placeholder="请输入搜索关键词"
  bind:click-input="onSearchClick"
/>    

书写方法

// pages/main-music/main-music.js
Page({
  data: {
    searchValue: "",
  },
  
  // 界面的事件监听方法
  onSearchClick() {
    wx.navigateTo({url: '/pages/detail-search/detail-search'})
  },
})

14_(掌握)音乐页面-请求轮播图数据和效果展示

轮播图的实现步骤

从服务器中获取数据 -》将数据放到data里面-》通过for循环进行展示

1.请求对应数据->创建对应文件-》封装请求方法

music.js

import { hyRequest } from "./index"


export function getMusicBanner(type = 0) {
  return hyRequest.get({
    url: "/banner",
    data: {
      type
    }
  })
}

2.对应请求逻辑

import { getMusicBanner } from "../../services/music"

data:{  
  banners: [],
}onLoad() {
    this.fetchMusicBanner()
}   
// 网络请求的方法封装
async fetchMusicBanner() {
    const res = await getMusicBanner()
    this.setData({ banners: res.banners })
 },  

3.轮播图的展示

<!-- 2.轮播图的展示 -->
<swiper 
  class="banner"
  circular
  indicator-dots
  style="height: {{bannerHeight}}px;"
  wx:if="{{banners.length}}"
>
  <block wx:for="{{banners}}" wx:key="targetId">
    <swiper-item class="item">
      <image 
        class="banner-image" 
        src="{{item.imageUrl}}" 
        mode="widthFix"
        bindload="onBannerImageLoad"
      />
    </swiper-item>
  </block>
</swiper>

15_(掌握)音乐页面-页面内边距和轮播图的基本样式

给整个页面设置内边距=》针对于不需要设置内边距的地方,我们撑开就行

/* pages/main-music/main-music.wxss */
page {
  --search-background-color: #fff;
  --search-padding: 10px 0;

  box-sizing: border-box;
  padding: 0 24rpx;
  background-color: #fafafa;
}

/* .van-search__content {
  background-color: #fff !important;
} */

/* 轮播图的样式 */
.banner {
  border-radius: 12rpx;
  overflow: hidden;
  /* height: 260rpx; */
}

.banner-image {
  width: 100%;
}

16_(掌握)音乐页面-轮播图的高度计算和节流函数

轮播图默认高度(150px)有问题,我们的目标是轮播图的高度和图片的高度保持一致,

所以我们需要监听图片什么时候加载完毕,加载完获取组件高度,把image组件的高度设置为swiper高度

获取image组件高度需要一个新的api,我们需要进行封装到工具里面,通过promise进行回调,获取结果

但是发现执行的太频繁,所以我们使用节流函数进行优化

1.动态设置高度

mode=“widthFix” 会导致图标在下面,设置固定高度,其他机型又会出现问题,其他模式也有各种问题

如何设置动态高度呢,通过插值语法,根据图片的高度动态设置

<swiper 
  class="banner"
  circular
  indicator-dots
  style="height: {{bannerHeight}}px;"
  wx:if="{{banners.length}}"
>
  <block wx:for="{{banners}}" wx:key="targetId">
    <swiper-item class="item">
      <image 
        class="banner-image" 
        src="{{item.imageUrl}}" 
        mode="widthFix"
        bindload="onBannerImageLoad"
      />
    </swiper-item>
  </block>
</swiper>


import querySelect from "../../utils/query-select"
            
 bannerHeight: 0,
     
  onBannerImageLoad(event) {
    querySelect(".banner-image").then(res => {
      this.setData({ bannerHeight: res[0].height })
    })
  },     

image里面有bindload事件,图片加载完成会执行该事件,在事件中获取Image组件的高度(对这个方法进行封装)

export default function querySelect(selector) {
  return new Promise(resolve => {
    const query = wx.createSelectorQuery()
    query.select(selector).boundingClientRect()
    query.exec((res) => {
      resolve(res)
    })
  })
}

2.节流

但是会调用八次,这里我们使用节流来进行优化

0.封装

export default function hythrottle(fn, interval = 200, { leading = true, trailing = false } = {}) {
  let startTime = 0
  let timer = null

  const _throttle = function(...args) {
    return new Promise((resolve, reject) => {
      try {
         // 1.获取当前时间
        const nowTime = new Date().getTime()

        // 对立即执行进行控制
        if (!leading && startTime === 0) {
          startTime = nowTime
        }

        // 2.计算需要等待的时间执行函数
        const waitTime = interval - (nowTime - startTime)
        if (waitTime <= 0) {
          // console.log("执行操作fn")
          if (timer) clearTimeout(timer)
          const res = fn.apply(this, args)
          resolve(res)
          startTime = nowTime
          timer = null
          return
        } 

        // 3.判断是否需要执行尾部
        if (trailing && !timer) {
          timer = setTimeout(() => {
            // console.log("执行timer")
            const res = fn.apply(this, args)
            resolve(res)
            startTime = new Date().getTime()
            timer = null
          }, waitTime);
        }
      } catch (error) {
        reject(error)
      }
    })
  }

  _throttle.cancel = function() {
    if (timer) clearTimeout(timer)
    startTime = 0
    timer = null
  }

  return _throttle
}

1.引入

import throttle  from '../../utils/throttle'

2.使用

const querySelectThrottle = throttle(querySelect, 100)

 // 图片加载完毕调用函数,设置高度
  onBannerImageLoad(event) {
    querySelectThrottle(".banner-image").then(res => {
      this.setData({ bannerHeight: res[0].height })
    })
  },  

17_(掌握)音乐页面-underscore库中节流函数使用

1.安装

npm install underscore

2.构建

工具-》构建npm

3.使用

import {throttle}  from 'underscore'

const querySelectThrottle = throttle(querySelect, 100)

18_(掌握)音乐页面-区域头部area-header的封装

自定义area-header头部组件

1.创建组件页面

2.注册、使用

 "usingComponents": { 
"area-header": "/components/area-header/area-header",
 }

<!-- 3.推荐歌曲的展示 -->
<view class="recommend">
  <area-header title="推荐歌曲" bind:moreclick="onRecommendMoreClick"/>
</view>


接收子组件传过来的点击事件进行处理
onRecommendMoreClick() {
   console.log(111)
  },

3.组件封装

// components/area-header/area-header.js
Component({
  properties: {
    title: {
      type: String,
      value: "默认标题"
    },
    hasMore: {
      type: Boolean,
      value: true
    }
  },
  methods: {
    onMoreTap() {
      // 将更多的点击事件传递出去
      this.triggerEvent("moreclick")
    }
  }
})

{
  "component": true,
  "usingComponents": {
    "van-icon": "@vant/weapp/icon/index"
  }
}

<!--components/area-header/area-header.wxml-->
<view class="header">
  <view class="title">{{title}}</view>
  <view class="more" wx:if="{{hasMore}}" bindtap="onMoreTap">
    <text class="text">更多</text>
    <van-icon name="arrow" />
  </view>
</view>

/* components/area-header/area-header.wxss */
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 32rpx 0;
}

.header .title {
  font-size: 36rpx;
  font-weight: 700;
  color: #000;
}

.header .more {
  display: flex;
  align-items: center;
  font-size: 36rpx;
  color: #888;
}

.header .more .text {
  font-size: 28rpx;
}

19_(理解)内容回顾和作业布置

第五章:内容回顾

一. 项目的搭建

1.1. 创建一个新项目

1.2. 创建项目目录结构

1.3. 搭建tabBar页面

二. 视频页面

2.1. 请求基本数据和展示

  • 网络请求进行分层结构
  • Promise -> await/async

2.2. 上拉加载更多功能

  • 监听滚到到底部
  • 加载更多的数据
    • offset
    • […this.data.videoList, …res.data]
    • hasMore

2.3. 下拉刷新的功能

  • 开启下拉刷新
  • 监听下拉刷新
  • 重置变量
    • offset = 0
    • videoList = []
    • hasMore = true
  • 请求结束后, 结束下拉刷新

三. 视频详情

3.1. 点击Item跳转到详情

  • video-item组件的监听点击
    • data-
  • video-item组件的内部监听
    • this.properties.itemData

3.2. 获取播放地址Video

  • 获取播放地址
  • 使用video组件播放

3.3. 获取详情的其他数据

  • MV详情
  • MV关联推荐视频

3.4. 滚动的页面展示

  • page滚动
  • scroll-view滚动

四. 音乐页面

4.1. 搜索框的展示

  • 安装vant

    • npm install @vant/weapp
    • 构建npm
  • 演练vant的使用

  • 搭建搜索框

    • 设置属性
    • 监听点击, 跳转搜索页面
  • 重要: 覆盖vant样式

    • CSS属性
    • CSS变量

4.2. 轮播图的展示

4.2.1. 请求轮播数据和基本展示

4.2.2. 轮播图的基本样式调整

  • 页面的内边距
  • 轮播图的圆角

DFS

4.2.3. 轮播图的动态计算

  • 根据加载出来的图片, 计算轮播图的高度
  • querySelect
  • 对方法调用进行节流操作

4.3. area-header的封装

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/194474.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里云们扎堆集结,数据库黄金时代到了?

配图来自Canva可画 作为全球数一数二的信息产业大国&#xff0c;我国在信息技术软硬件底层标准、架构、产品以及生态体系方面&#xff0c;长期被外商“卡脖子”&#xff0c;其中数据库市场更是长期被甲骨文等外商公司所占据。 近年来伴随着信创产业的高速发展&#xff0c;国内…

第七章 idea集成git本地库操作

第一节 配置忽略文件 1、哪些文件需要忽略&#xff1f; 对于git来说可以忽略的文件 Eclipse工程特定文件 IDEA工IDEA工程特定文件 编译产生的二进制文件&#xff08;对于Maven工程来说就是target目录&#xff09; 2、为什么要忽略这些文件&#xff1f; 与项目的实际功能无…

巧用Golang泛型,简化代码编写

作者 | 百度小程序团队 导读 本文整理了很多的泛型应用技巧&#xff0c;结合具体的实际代码示例&#xff0c;特别是很多直接对Go语言内置的类库的实现进行改造&#xff0c;再通过两者在使用上直观对比&#xff0c;帮助大家对泛型使用思考上提供了更多思路&#xff0c;定会帮助大…

【教程】Python:IDLE开发环境安装与配置保姆级教学

【教程】Python&#xff1a;IDLE开发环境安装与配置保姆级教学下载地址安装步骤编写你的Python程序IDLE交互界面&#xff08;交互式运行&#xff09;IDLE编辑器&#xff08;文件式运行&#xff09;下载地址 请访问官网&#xff1a;python解释器安装 安装步骤 若安装最新版本…

FPGA的ADC信号采集ADS52J90-JESD204B接口

jesd204b实战操作笔记 本篇的内容是基于博主设计的jesd204b接口的ADC和FPGA的硬件板卡&#xff0c;通过调用jesd204b ip核来一步步在FPGA内部实现高速ADC数据采集&#xff0c;jesd204b协议和xilinx 的jesd204 IP核相关基本知识已在前面多篇文章中详细介绍&#xff0c;这里不再…

设计师们都在用的5款有限元分析软件推荐

最好的有限元分析软件可以让您测试物体如何受到外部因素的影响。例如&#xff0c;一家公司可以使用 FEA 软件来测试更新后的产品&#xff0c;看看它是否受到振动、热量和其他因素的影响。前 5 名有限元分析软件ANSYS - 具有基于任务的界面OpenFOAM - 可选择插值SimScale - 在线…

QT打包成windows软件

在QTCreator中将Debug模式切换到Release模式&#xff0c;进行编译在项目文件中找到Release模式构建的文件夹进入里面的有一个release的文件&#xff0c;这个文件里就是我们需要的东西进入里面&#xff0c;会有一个.exe的启动程序&#xff0c;但现在是启动不了的&#xff0c;需要…

常用不等式

整理自一个知乎大佬的回答Cauchy-Schwarz积分不等式在上可积,有:取等号的充要条件是存在常数,使得Hlder 积分不等式Minkowski 积分不等式Chebyshev 积分不等式设在上是连续函数,并且在上单调递增,则Kantorovich 积分不等式设函数均在区间上可积,且在上满足,则Jensen 积分不等式…

ES6迭代器 Iterator 详细介绍

文章目录前言一、Iterator二、迭代过程三、可迭代的数据结构3.1 Array3.2 String3.3 Map3.4 Set3.5 arguments总结前言 迭代器&#xff0c;是 ES6 引入的一种新的遍历机制&#xff0c;主要讲解的是 Iterator 、迭代过程、可迭代的数据结构。 一、Iterator Iterator 是 ES6 引…

MAC泛洪攻击-ARPDOS攻击-ARP Middleman攻击-IP地址欺骗-ICMP DOS 攻击

项目二 目录 文章目录一、搭建实验环境&#xff1a;1. 网络环境架构2. 实验环境与工具:3. 搭建两侧的局域网4. 搭建路由二、MAC泛洪攻击1. 实验环境2. 实验过程3. 实验分析&#xff1a;三、ARP DOS攻击1. 实验环境2. 实验过程3. 实验分析&#xff1a;四、ARP Middleman 攻击1. …

《SQL基础》08. 多表查询

SQL - 多表查询多表查询多表关系一对多多对多一对一多表查询概述分类内连接外连接自连接联合查询子查询分类标量子查询列子查询行子查询表子查询案例多表查询 多表关系 项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#…

使用MySQL数据库,实现你的第一个JDBC程序

熟悉了JDBC的编程步骤后&#xff0c;接下来通过一个案例并依照上一小节所讲解的步骤来演示JDBC的使用。此案例会从tb_user表中读取数据&#xff0c;并将结果打印在控制台。需要说明的是&#xff0c;Java中的JDBC是用来连接数据库从而执行相关数据相关操作的&#xff0c;因此在使…

双面电子会议桌牌

产品特征&#xff1a; 超低功耗&#xff0c;3-5年电池寿命电子纸墨水屏幕&#xff0c;视角接近180多种电子桌牌显示颜色可选 3色&#xff08;黑&#xff0c;白&#xff0c;红&#xff09; 4色&#xff08;黑&#xff0c;白&#xff0c;红&#xff0c;黄&#xff09; 7色&…

营销大数据如何帮助企业深入了解客户—镭速

随着互联网的进一步发展&#xff0c;大门向您的企业敞开大门&#xff0c;让您在如何使用数据为客户提供他们所寻求的个性化&#xff0c;令人兴奋和引人入胜的体验方面更具创造性和创新性。大数据是了解客户究竟是谁以及如何与他们互动的关键部分。 行动中的见解 随着智能手机…

听劝,不要试图以编程为基础去学习网络安全

目录一、网络安全学习的误区1.不要试图以编程为基础去学习网络安全2.不要刚开始就深度学习网络安全3.收集适当的学习资料4.适当的报班学习二、学习网络安全的些许准备1.硬件选择2.软件选择3.外语能力三、网络安全学习路线第一阶段&#xff1a;基础操作入门第二阶段&#xff1a;…

什么是基站定位?

基站与信号塔首先&#xff0c;我们先介绍一下基站。基站包括移动、联通和电信基站&#xff0c;当手机开机、关机、切换基站时都会向最近最优基站赋权。其主要功能是负责用户手机端信号传出工作&#xff0c;包括语音通话、网络访问等各项业务。这里我们特别强调一个误区&#xf…

不离不弃生死相依

男孩儿&#xff1a;“对不起……” 女孩儿&#xff1a;“无所谓&#xff0c;你没什么对不起我的。” 键盘敲出最后这句话&#xff0c;女孩儿失声痛哭。 爱上他是女孩儿没有想到的事情&#xff0c;她以为自己不会爱上任何人。 可最后还是敌不过男孩儿的温柔&#xff0c;陷了进去…

OpenMMLab AI实战课笔记

1. 第一节课 1.1 计算机视觉任务 计算机视觉主要实现以下目标&#xff1a; 分类目标检测分割&#xff1a;语义分割、实例分割 (对像素进行精确分类, 像素粒度或细粒度)关键点检测 1.2 OpenMMLab框架 框架选择&#xff1a;PyTorchOpenMMLab是基于PyTorch开发的code base, …

linux_信号

文章目录1、信号的实现机制2、发送信号2.1、发送信号的原因2.2、发送信号的机制kill 函数3、接收信号3.1、处理信号signal 函数sigaction 函数3.2、信号阻塞 | 解除sigset_t 信号集合sigpending 函数sigprocmask 函数sigsuspend 函数4、定时器4.1、睡眠函数sleep 函数pause 函数…

STM32 学习笔记_1前言;软件安装

前言 学习自江科大自动协 b站课程。 呜呼&#xff01;今朝有坑今朝开&#xff0c;管他明朝埋不埋&#xff01;开新坑的过程是最爽的。 STM32 是 ST 公司基于 ARM CORE-M 芯片&#xff08;类似 CPU&#xff09;开发的32位的单片机&#xff0c;相比8位的51单片机性能更强。&am…