微信小程序【网易云音乐实战】(第三篇 自定义组件、排行榜的制作、内网穿透、tabBar、个人中心)

一、自定义组件

官方文档 自定义组件

1. 制作自定义组件

可以发现
上面这个部分将在项目中重复使用,所有将其作为一个组件。

在这里插入图片描述
首先将index页面文件夹里面的 wxml和wxss里面关于header的代码片段和样式复制到新建的conponent组件相应的文件里。

在这里插入图片描述
在这里插入图片描述

2. 使用自定义组件

  1. 在page里面需要注册(在index.json文件的usingComponents添加注册)
    在这里插入图片描述

在这里插入图片描述

由于前面设置的滚动条太高了,所有需要设置一下这个容器的高度!

/* 推荐歌曲样式设置 */
.commmendContainer{
    
    
  padding: 20rpx;
  height: 400rpx;
}

完成组件的复用:
在这里插入图片描述

3. 组件动态数据

需要根据不同的需要改变组件的显示内容

参考官方文档!

Navheader.wxml

<!--	头部	-->
<view class="header">
    <text class="title">{
   
   {title}}</text>
    <view>
        <text>{
   
   {nav}}</text>
        <text class="more">查看更多</text>
    </view>
</view>

NavHeader.js

  properties: {
    
    
    title:{
    
    
      type:String,
      value:"title的默认值"
    },
    nav:{
    
    
      type:String,
      value:"nav的默认值"
    }
  },

index.wxml 里面的使用

	<!--	头部	-->
	<NavHeader title="推荐歌曲" nav="为你精心推荐"></NavHeader>
	<!--		头部区域-->
	<NavHeader title="排行榜" nav="热歌风向标"></NavHeader>

在这里插入图片描述


二、排行榜的制作

1. 静态搭建

在这里插入图片描述

	<!--	排行榜区域-->
	<view class="topList">
		<!--		头部区域-->
		<NavHeader title="排行榜" nav="热歌风向标"></NavHeader>
		<!--		内容区域  采用轮播图的形式 -->
		<swiper class="topListSwiper" next-margin="50rpx" previous-margin="50rpx">
		
			<swiper-item>
				<view class="swiperItem">
					<view class="title">云音乐热歌榜</view>
					<view class="musicItem">
						<image src="/static/images/nvsheng.jpg"></image>
						<text class="count">1</text>
						<text class="musicName">光辉岁月</text>
					</view>
					<view class="musicItem">
						<image src="/static/images/nvsheng.jpg"></image>
						<text class="count">2</text>
						<text class="musicName">海阔天空</text>
					</view>
					<view class="musicItem">
						<image src="/static/images/nvsheng.jpg"></image>
						<text class="count">3</text>
						<text class="musicName">真的爱你</text>
					</view>
				</view>
			</swiper-item>

			<swiper-item>
				<view class="swiperItem">
					<view class="title">云音乐热歌榜</view>
					<view class="musicItem">
						<image src="/static/images/nvsheng.jpg"></image>
						<text class="count">1</text>
						<text class="musicName">光辉岁月</text>
					</view>
					<view class="musicItem">
						<image src="/static/images/nvsheng.jpg"></image>
						<text class="count">2</text>
						<text class="musicName">海阔天空</text>
					</view>
					<view class="musicItem">
						<image src="/static/images/nvsheng.jpg"></image>
						<text class="count">3</text>
						<text class="musicName">真的爱你</text>
					</view>
				</view>
			</swiper-item>
			
		</swiper>
	</view>
/* 排行榜的 样式*/

.topList{
    
    
  padding: 20rpx;
}

.topListSwiper{
    
    
  height: 400rpx;
}

.swiperItem{
    
    
  width: 96%;
  background: #FBFBFB;
}

.swiperItem .title{
    
    
  font-size: 30rpx;
  line-height: 80rpx;
}

.musicItem{
    
    
  /*  当一个元素设置为flex,其子元素会自动成为block元素  */
  display: flex;
  padding-bottom: 20rpx;
}

.musicItem image{
    
    
  width: 100rpx;
  height: 100rpx;
  border-radius: 6rpx;
}

.musicItem .count{
    
    
  width: 100rpx;
  height: 100rpx;
  text-align: center;
  line-height: 100rpx;
}

.musicItem .musicName{
    
    
  height: 100rpx;
  line-height: 100rpx;
  /* 歌曲名过长 时隐藏 */
  max-width: 400rpx;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

2. 获取排行榜动态数据

直接for循环

	<!--	排行榜区域-->
	<view class="topList">
		<!--		头部区域-->
		<NavHeader title="排行榜" nav="热歌风向标"></NavHeader>
		<!--		内容区域  采用轮播图的形式 -->
		<swiper class="topListSwiper" next-margin="50rpx" previous-margin="50rpx">
			<swiper-item wx:for="{
     
     {topListData}}" wx:key="name" >
				<view class="swiperItem">
					<view class="title">{
   
   {item.name}}</view>
					<view class="musicItem"  wx:for="{
     
     {item.tracks}}" wx:key="id" wx:for-item="musicItem">
						<image src="{
     
     {musicItem.al.picUrl}}"></image>
						<text class="count">{
   
   {index+1}}</text>
						<text class="musicName">{
   
   {musicItem.name}}</text>
					</view>
				</view>
			</swiper-item>
		</swiper>
	</view>
 // 3. 获取排行榜的数据
      /* 需求分析
        1. 需要根据idx的值获取对应的数据
        2. idx的取值范围是 0-20 ,我们只需要 0-4
        3. 所以需要发送5次请求来获取数据
      * */
    // 3.1 组装数据
    let index = 0;// 标识idx
    let resultArr=[];
    while (index<5){
    
    
      let topListData = await request("/top/list",{
    
    idx:index++});
      // 数组的截取:splice(会修改原数组) slice(不会修改原数组)
      let topListItem={
    
    name:topListData.playlist.name,tracks:topListData.playlist.tracks.slice(0,3)};
      resultArr.push(topListItem);
	  // 3.2 更新数据
	  this.setData({
    
    
	      topListData:resultArr
	  });
    }

在这里插入图片描述


三、内网穿透(真机体验)

使用工具 https://u.tools/

由于服务器在自己的本机上,我们的手机localhost是访问不到的,所以我们需要借助工具 uTool.
下载:
在这里插入图片描述
下载插件:内网穿透
在这里插入图片描述

在这里插入图片描述
将生成的域名链接替换原来的 localhost
在这里插入图片描述

最后进行真机调试:
在这里插入图片描述


四、tabBar(底部栏) 的使用

官方文档 tabBar的使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
使用:

在app.json里面添加tabBar,list最少需要两个

  "tabBar": {
    
    
    "color":"#333",
    "selectedColor": "#d43c33",
    "backgroundColor": "#FFF",
    "list": [
      {
    
    
      "pagePath": "pages/index/index",
      "text": "主页",
      "iconPath": "/static/images/tabs/tab-home.png",
      "selectedIconPath": "static/images/tabs/tab-home-current.png"
      },
      {
    
    
        "pagePath": "pages/video/video",
        "text": "视频",
        "iconPath": "/static/images/tabs/select.png",
        "selectedIconPath": "static/images/tabs/selected.png"
      },
      {
    
    
        "pagePath": "pages/personal/personal",
        "text": "个人中心",
        "iconPath": "/static/images/tabs/tab-my.png",
        "selectedIconPath": "static/images/tabs/tab-my-current.png"
      }
    ]
  }

在这里插入图片描述
可设置为顶部位置:
在这里插入图片描述

在这里插入图片描述


五、个人中心页面

在这里插入图片描述

关键点介绍:
在这里插入图片描述

    <view
            class="cover-container"
            bindtouchstart="handleTouchStart"
            bindtouchmove="handleTouchMove"
            bindtouchend="handleTouchEnd"
            style="transform: {
       
       {
       
       coverTransform}}; transition:{
       
       {
       
       coverTransition}}"
    >
// pages/personal/personal.js
let startY=0; // 手指开始的坐标
let moveY=0; // 手指移动的坐标
let moveDistance=0; // 手指移动的距离

Page({
    
    
  data: {
    
    
    coverTransform:"translateY(0rpx)", // 移动距离数据
    coverTransition:"" // 缓动效果
  },

  // 1. 开始
  handleTouchStart(event){
    
    
    // 获取起始坐标
   startY=event.touches[0].clientY; // touches[0]取第一次点击,因为屏幕可能有多个位置被点击
  },

   // 2.移动
  handleTouchMove(event){
    
    
    // 获取手指移动的坐标
    moveY = event.touches[0].clientY;
    moveDistance=moveY-startY; // 手指往下移动为正,往下为负数
    // 更新移动的距离
    if(moveDistance <=0){
    
    
      return;
    }
    if(moveDistance >= 80){
    
    
      moveDistance = 80;
    }
    this.setData({
    
    
      coverTransform:`translateY(${
      
      moveDistance}rpx)`,
      coverTransition:""
    })
  },
  // 3.结束
  handleTouchEnd(event){
    
    
    this.setData({
    
    
      coverTransform:`translateY(0rpx)`,
      coverTransition:"transform 1s linear"
    })
  },
})

界面和样式下载 https://download.csdn.net/download/qq_45021180/14921902

界面的搭建代码如下:

<view class="personalContainer">
    <view class="user-section">
        <image class="bg" src="/static/images/personal/bgImg2.jpg"></image>
        <view class="user-info-box">
            <view class="portrait-box">
                <image class="portrait" src='/static/images/personal/missing-face.png'></image>
            </view>
            <view class="info-box">
                <text class="username">游客</text>
            </view>
        </view>

        <view class="vip-card-box">
            <image class="card-bg" src="/static/images/personal/vip-card-bg.png" mode=""></image>
            <view class="b-btn">
                立即开通
            </view>
            <view class="tit">
                <!-- 会员图标-->
                <text class="iconfont icon-huiyuan-"></text>
                硅谷会员
            </view>
            <text class="e-m">atguigu Union</text>
            <text class="e-b">开通会员听歌, 撸代码</text>
        </view>
    </view>


    <view
            class="cover-container"
            bindtouchstart="handleTouchStart"
            bindtouchmove="handleTouchMove"
            bindtouchend="handleTouchEnd"
            style="transform: {
       
       {
       
       coverTransform}}; transition:{
       
       {
       
       coverTransition}}"
    >
        <image class="arc" src="/static/images/personal/arc.png"></image>
        <!-- 个人中心导航 -->
        <view class="nav-section">
            <view class="nav-item"  hover-class="common-hover"  hover-stay-time="50">
                <text class="iconfont icon-xiaoxi"></text>
                <text>我的消息</text>
            </view>
            <view class="nav-item"   hover-class="common-hover" hover-stay-time="50">
                <text class="iconfont icon-myRecommender"></text>
                <text>我的好友</text>
            </view>
            <view class="nav-item"  hover-class="common-hover"  hover-stay-time="50">
                <text class="iconfont icon-gerenzhuye"></text>
                <text>个人主页</text>
            </view>
            <view class="nav-item" hover-class="common-hover"  hover-stay-time="50">
                <text class="iconfont icon-gexingzhuangban"></text>
                <text>个性装扮</text>
            </view>
        </view>

        <!-- 个人中心列表 -->
        <view class="personalContent">
            <view class="recentPlayContainer">
                <text class="title">最近播放</text>
                <!-- 最近播放记录 -->
            </view>

            <view class="cardList">
                <view class="card-item">
                    <text class="title">我的音乐</text>
                    <text class="more"> > </text>
                </view>
                <view class="card-item">
                    <text class="title">我的收藏</text>
                    <text class="more"> > </text>
                </view>
                <view class="card-item">
                    <text class="title">我的电台</text>
                    <text class="more"> > </text>
                </view>
            </view>
        </view>
    </view>

</view>

样式:

/* pages/personal/personal.wxss */
.personalContainer {
    
    
    width: 100%;
    height: 100%;

}

.personalContainer .user-section {
    
    
    height: 520rpx;
    position: relative;
    padding: 100rpx 30rpx 0;
}
.user-section .bg {
    
    
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    opacity: 0.7;
    filter: blur(1px);
}


.user-info-box{
    
    
    height: 180rpx;
    display:flex;
    align-items:center;
    position:relative;
    z-index: 1;

}

.user-info-box .portrait{
    
    
    width: 130rpx;
    height: 130rpx;
    border:5rpx solid #fff;
    border-radius: 50%;
}
.user-info-box .username{
    
    
    font-size: 24;
    color: #303133;
    margin-left: 20rpx;
}


/* vip-box */
.vip-card-box {
    
    
    position: relative;
    display: flex;
    flex-direction: column;
// background: linear-gradient(left, red, black);
    background: rgba(0, 0, 0, .7);
    height: 240rpx;
    color: #f7d680;
    border-radius: 16rpx 16rpx 0 0;
    padding: 20rpx 24rpx;
}


.vip-card-box .card-bg{
    
    
    position:absolute;
    top: 20rpx;
    right: 0;
    width: 380rpx;
    height: 260rpx;
}

.vip-card-box .b-btn{
    
    
    position: absolute;
    right: 20rpx;
    top: 16rpx;
    width: 132rpx;
    height: 40rpx;
    text-align: center;
    line-height: 40rpx;
    font-size: 22rpx;
    color: #36343c;
    border-radius: 20px;
    background: #f9e6af;
    z-index: 1;
}

.vip-card-box .b-btn{
    
    
    position: absolute;
    right: 20rpx;
    top: 16rpx;
    width: 132rpx;
    height: 40rpx;
    text-align: center;
    line-height: 40rpx;
    font-size: 22rpx;
    color: #36343c;
    border-radius: 20px;
    /*background: linear-gradient(left, #f9e6af, #ffd465);*/ /*渐变不生效*/
    background: #f9e6af;
    z-index: 1;
}

.vip-card-box .tit {
    
    
    font-size: 22rpx;
    color: #f7d680;
    margin-bottom: 28rpx;
}
.vip-card-box .tit .iconfont{
    
    
    color: #f6e5a3;
    margin-right: 16rpx;
}




.vip-card-box .e-m{
    
    
    font-size: 34rpx;
    margin-top: 10rpx;
}
.vip-card-box .e-b{
    
    
    font-size: 24rpx;
    color: #d8cba9;
    margin-top: 10rpx;
}


.cover-container{
    
    
    margin-top: -150rpx;
    padding: 0 30rpx;
    position:relative;
    background: #f5f5f5;
    padding-bottom: 20rpx;
}

.cover-container .arc{
    
    
    position:absolute;
    left: 0;
    top: -34rpx;
    width: 100%;
    height: 36rpx;
}


/* 导航部分 */
.cover-container .nav-section {
    
    
    display: flex;
    background: #fff;
    padding: 20rpx 0;
    border-radius: 15rpx;
}


.nav-section .nav-item {
    
    
    width: 25%;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.nav-section .nav-item .iconfont {
    
    
    font-size: 50rpx;
    color: #d43c33;
    line-height: 70rpx;
}

.nav-section .nav-item text:last-child {
    
    
    font-size: 22rpx;

}


/* 个人中心列表 */
.personalContent {
    
    
    background: #fff;
    margin-top: 20rpx;
}

/* 最近播放 */
.personalContent .scrollView {
    
    
    display: flex;
    height: 160rpx;
}
.personalContent .recentPlay {
    
    
    display: flex;
}

.recentPlayContainer .title {
    
    
    padding-left: 20rpx;
    font-size: 26rpx;
    color: #333;
    line-height: 80rpx;
}

.personalContent .recentPlay image {
    
    
    width: 160rpx;
    height: 160rpx;
    margin-left: 20rpx;
    border-radius: 20rpx;
}


.cardList {
    
    
    margin-top: 20rpx;

}
.cardList .card-item{
    
    
    border-top: 1rpx solid #eee;
    height: 80rpx;
    line-height: 80rpx;
    padding: 10rpx;
    font-size: 26rpx;
    color: #333;
}
.cardList .card-item .more {
    
    
    float: right;
}

猜你喜欢

转载自blog.csdn.net/qq_45021180/article/details/112986534
今日推荐