一、用户登录

官网事件使用使用


1. 绑定事件 和 获取数据

bindinput :当输入框有变化时,触发事件。

  handleInput(event){// let type=event.currentTarget.id; // 1. 通过设置的id 传值let type=event.currentTarget.dataset.type; // 2. 通过data-type 传值this.setData({[type]:event.detail.value; // [type]: value})},

结果:

2. 前端验证

wx.showToast(Object object) 提示信息

<button class="confirm-btn" bindtap="login">登录</button>

关键代码:

// 正则表达式验证号码是否正确
let {phone,password}=this.data;
let phoneReg=/^1(3|4|5|6|7|8|9)\d{9}$/;
if(!phoneReg.test(phone)){// 提醒用户wx.showToast({title:"手机号格式错误!!",icon:"none"});return;
}

全部代码:

  //登录的回调login(){// 1. 收集表单项的数据let {phone,password}=this.data;// 2. 前端验证 : 不能为空,号码正确if(!phone){// 提醒用户wx.showToast({title:"用户名不能为空!",icon:"none"});return;}// 正则表达式:号码正确let phoneReg=/^1(3|4|5|6|7|8|9)\d{9}$/;if(!phoneReg.test(phone)){// 提醒用户wx.showToast({title:"手机号格式错误!!",icon:"none"});return;}// 验证密码if(!password){// 提醒用户wx.showToast({title:"密码不能为空!!",icon:"none"});return;}// 提醒用户wx.showToast({title:"前端验证通过!",icon:"none"});},

3. 后端验证

首先还是先启动本地的服务器!

// 3. 后端验证let result = await request("/login/cellphone",{phone,password});if(result.code === 200){ // 成功wx.showToast({title: "登录成功!"});}else if(result.code === 400){wx.showToast({title: "手机号错误 !",icon: "none"});}else if(result.code === 502) {wx.showToast({title: "密码错误 !",icon: "none"});}else{wx.showToast({title: "登录失败,请重新登陆 !",icon: "none"});}

二、本地存储(个人中心与登录界面的交互)

页面跳转 :


页面跳转使用 reLaunch(login --> personal页面)

在页面跳转的时候,数据很难交互,这里使用本地缓存

数据存储 官方API

展示本地数据:

获取存储数据:

  // 个人中心页面跳转 登录界面toLogin(){wx.navigateTo({url:"/pages/login/login"}),onLoad: function (options) {// 读取本地存储的用户信息let userInfo = wx.getStorageSync("userInfo");if(userInfo){this.setData({userInfo:JSON.parse(userInfo)});}
},

存储数据:

    // 3. 后端验证let result = await request("/login/cellphone",{phone,password});if(result.code === 200){ // 登录成功wx.showToast({title: "登录成功!"});// 将用户信息存储到本地// * JSON.stringify()的作用是将 JavaScript 对象转换为 JSON 字符串,而JSON.parse()可以将JSON字符串转为一个对象。wx.setStorageSync("userInfo",JSON.stringify(result.profile));// 跳转个人中心wx.reLaunch({url:"/pages/personal/personal"});}

三、获取用户的播放纪录

服务器接口:

页面:

 <view class="recentPlayContainer"><text class="title">最近播放</text><!-- 最近播放记录 --><scroll-view wx:if="{{recentPlayList.length}}" scroll-x class="recentScroll" enable-flex><view class="recentItem" wx:for="{{recentPlayList}}" wx:key="id"><image src="{{item.song.al.picUrl}}"></image></view></scroll-view><view wx:else>暂无播放记录</view></view>

样式:

/* 最近播放纪录的样式*/
.recentScroll{display: flex;height: 200rpx;
}.recentItem{margin-right: 20rpx;
}.recentScroll image{width: 200rpx;height: 200rpx;border-radius: 10rpx;
}

获取播放记录的js代码:

  // 获取用户的播放纪录async getUserRecentPalyList(userId) {let recentPalyListData = await request("/user/record", {uid: userId, type: 0});// 由于每一项没有一个key 可以标识,这里使用map进行加工一下let index = 0;let recentPlayList = recentPalyListData.allData.slice(0,10).map(item=>{ // recentPlayList 就是加工后的数据item.id=index++;return item;})this.setData({recentPlayList:recentPlayList})},

四、视频播放

1. 导航数据动态显示

知识点:1.标签动态添加 class属性值

<view class="navContent {{navId === item.id ? 'active':''}}" bindtap="changeNav" id="{{item.id}}">

界面:

<!--  导航区域  -->
<scroll-view scroll-x class="navScroll" enable-flex><view class="navItem" wx:for="{{videoGroupList}}" wx:key="id"><view class="navContent {{navId === item.id ? 'active':''}}" bindtap="changeNav" id="{{item.id}}">{{item.name}}</view></view>
</scroll-view>

js代码:

  data: {videoGroupList:[], // 导航标签数据navId:"", // 导航的标识,标记哪个被选中},// 获取导航数据async getVideoGroupListData() {let videoGroupListData = await request("/video/group/list");this.setData({videoGroupList: videoGroupListData.data.slice(0, 14),navId:videoGroupListData.data[0].id})},//点击切换导航的回调changeNav(event){let navId = event.currentTarget.id;this.setData({navId:navId * 1 // 这里乘以一个 1 为了将字符串转换成 int类型})},

2. 通过 cookie 获取视频数据


2.1 存储cookie:

下面对request进行了修改,由于获取视频数据需要携带 cookie,登录时添加了isLogin参数来标识是否是登录操作,如果是登录操作:成功后需要将cookie存储到本地。

// 登录:::: let result = await request("/login/cellphone",{phone,password,isLogin:true});

存储 cookie

根据cookie是否有值来来设置是否携带cookie(使用三元表达式)

header:{// 这里使用三元操作 ,为了保证 cookie有值,不然会报错cookie:wx.getStorageSync("cookies") ? wx.getStorageSync("cookies").find(item => item.indexOf("MUSIC_U") !== -1) : ""
},
export default(url , data={}, method="GET")=>{return new Promise((resolve,reject)=>{// 1. new Promise 初始化promise 实例的状态pendingwx.request({url:config.host + url,data,method,header:{// 这里使用三元操作 ,为了保证 cookie有值,不然会报错cookie:wx.getStorageSync("cookies") ? wx.getStorageSync("cookies").find(item => item.indexOf("MUSIC_U") !== -1) : ""},success:(res)=>{// 获取后台数据成功if(data.isLogin){ // 如果是登录请求,需要将cookie存入本地wx.setStorage({key:"cookies",data:res.cookies})}// console.log("获取后台数据成功",res);resolve(res.data); // resolve 修改promise的状体为成功状态 resolved},fail:(err)=>{// 获取后台数据失败// console.log("获取后台数据失败",err);reject(err); //reject 修改promise的状态为失败状态 为 rejected}})})
}

2.2 请求获取视频数据

  // 获取导航数据async getVideoGroupListData() {let videoGroupListData = await request("/video/group/list");this.setData({videoGroupList: videoGroupListData.data.slice(0, 14),navId:videoGroupListData.data[0].id});this.getVideoList(this.data.navId); // 获取视频列表数据 navId 是当前选择的 标签ID},// 获取视频列表数据async getVideoList(navId) {let videoListData = await request("/video/group", {id: navId});// 为了wx:key 有唯一值,所以这里加工一下let index =0 ;let videoList = videoListData.datas.map(item =>{item.id = index++;return item;})this.setData({videoList:videoList})},

3. 视频展示

页面:

<!--  视频的列表区域  -->
<scroll-view scroll-y class="videoScroll"><view class="videoItem" wx:for="{{videoList}}" wx:key="id"><video src="{{item.data.urlInfo.url}}"></video><view class="content">{{item.data.title}}</view><view class="footer"><image class="avatar" src="{{item.data.creator.avatarUrl}}"></image><text class="nickName">{{item.data.creator.nickname}}</text><view class="comments_praised"><text class="item"><text class="iconfont icon-buoumaotubiao15"></text><text class="count">{{item.data.praisedCount}}</text></text><text class="item"><text class="iconfont icon-pinglun1"></text><text class="count">{{item.data.commentCount}}</text></text><button open-type="share" class="item btn"><text class="iconfont icon-gengduo"></text></button></view></view></view>
</scroll-view>

样式:

/*  视频列表的样式  */
.videoScroll{padding-top: 10rpx;
}.videoItem{padding: 0 3%;
}.videoItem video{width: 100%;height: 360rpx;border-radius: 10rpx;
}.videoItem .content {font-size: 26rpx;height:80rpx;line-height: 80rpx;max-width: 500rpx;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;
}/* footer */
.footer {border-top: 1rpx solid #eee;padding: 20rpx 0;
}
.footer .avatar {width: 60rpx;height: 60rpx;border-radius: 50%;vertical-align: middle;
}.footer  .nickName {font-size: 26rpx;vertical-align: middle;margin-left: 20rpx;
}.footer .comments_praised {float: right;
}.comments_praised .btn {display: inline;padding: 0;background-color: transparent;border-color: transparent;
}.comments_praised .btn:after {border: none;
}.comments_praised .item {margin-left: 50rpx;position: relative;
}.comments_praised .item .count {position: absolute;top: -20rpx;font-size: 20rpx;
}

4. 导航切换视频

通过导航栏切换视频时,获取服务器的数据要消耗一定的时间,为了给用户比较好的体验,当加载数据的时候显示加载提示,使用wx.showLoading函数。

wx.showLoading(Object object)

显示 loading 提示框。需主动调用 wx.hideLoading 才能关闭提示框

点击导航时,通过navId来获取不同的视频数据。

this.getVideoList(this.data.navId);

注意点::

  1. 加载新的视频页时,清除旧的视频数据;
  2. 在得到数据前显示“正在加载”提示;
  3. 获取数据成功后,关闭提示;
// 获取视频列表数据async getVideoList(navId) {this.setData({videoList:[], // 加载新的视频页时 将原来的视频数据清空});wx.showLoading({title:"正在加载"});let videoListData = await request("/video/group", {id: navId});wx.hideLoading(); // 关闭提示框// 为了wx:key 有唯一值,所以这里加工一下let index =0 ;let videoList = videoListData.datas.map(item =>{item.id = index++;return item;})this.setData({videoList:videoList})},

设置点击导航,当前的项滚动到第一位置!

scroll-view

<!--  导航区域  -->
<scroll-view scroll-into-view="{{'nzs'+navId}}" scroll-with-animation="true" scroll-x class="navScroll" enable-flex><view id="{{'nzs'+item.id}}" class="navItem" wx:for="{{videoGroupList}}" wx:key="id"><view class="navContent {{navId === item.id ? 'active':''}}" bindtap="changeNav" id="{{item.id}}">{{item.name}}</view></view>
</scroll-view>

5. 决解同时播放多个视频问题

当点击新的视频的时候,需要关闭上次点击的视频!

思想:单用例,好比,一个瓶子只能装一个球,需要将旧的球先倒出,然后将新的球放入!(关闭上一次的视频,播放新的视频)

Video组件


VideoContext API

<video id="{{item.data.vid}}" bindplay="handlePlay" src="{{item.data.urlInfo.url}}"></video>
// 点击播放| 继续播放 触发事件handlePlay(event){/* 问题:决解多个视频同时播放的问题需求:1. 在点击播放的事件中需要找到上一个播放的视频2. 在播放新的视频之前需要关闭上一个正在播放的视频关键:1. 如何获取上一个视频的实例对象?2. 如风确认点击播放的视频和正在播放的视频不是同一个视频单例模式:1. 需要创建多个对象的场景下,通过一个变量接收,始终保持只有一个对象,2. 好处:节约内存空间* */let vid = event.currentTarget.id;this.vid!==vid && this.videoContext && this.videoContext.stop(); // 关闭上一个播放的视频this.vid = vid;// 1. 创建一个可以控制 video标签的实例对象this.videoContext = wx.createVideoContext(vid);},

6. image 代替 video 性能优化


<!--  视频的列表区域  -->
<scroll-view scroll-y class="videoScroll"><view class="videoItem" wx:for="{{videoList}}" wx:key="id"><videoid="{{item.data.vid}}"bindplay="handlePlay"src="{{item.data.urlInfo.url}}"poster="{{item.data.coverUrl}}"wx:if="{{videoId === item.data.vid}}"object-fit="cover"></video><!--     性能优化:使用iamge标签代替video标签       --><image wx:else bindtap="handlePlay" id="{{item.data.vid}}" src="{{item.data.coverUrl}}"></image>
</scroll-view>
  // 点击播放| 继续播放 触发事件handlePlay(event){let vid = event.currentTarget.id;// 更新data中的videoId的状态数据this.setData({videoId:vid // 当前播放的videoID})// 1. 创建一个可以控制 video标签的实例对象this.videoContext = wx.createVideoContext(vid);this.videoContext.play()},

7. 实现视频播放跳转☞指定的位置

VideoContext.seek()

1.播放进度变化时事件,实现跳转:

2.视频播放结束,需要将纪录在videoUpdateTime数组里面删除纪录:

<videoid="{{item.data.vid}}"bindplay="handlePlay"src="{{item.data.urlInfo.url}}"poster="{{item.data.coverUrl}}"wx:if="{{videoId === item.data.vid}}"object-fit="cover"bindtimeupdate="handleTimeUadate"bindended="handleEnded"
>
</video>

保存纪录:

  //  监听视频播放的事件handleTimeUadate(event){let videoTimeObj = {vid:event.currentTarget.id,currentTime:event.detail.currentTime}; // 整合一个对象,标记视频的播放时长let {videoUpdateTime} = this.data;// 判断纪录播放时长的videoUatateTime数组中是否存在当前的视频的播放记录let videoItem = videoUpdateTime.find(item => item.vid === videoTimeObj.vid);if(videoItem){ // 已存在videoItem.currentTime =  videoTimeObj.currentTime;} else{ // 数组里面的没有纪录videoUpdateTime.push(videoTimeObj);}this.setData({videoUpdateTime:videoUpdateTime})},

删除纪录:

  // 视频播放结束的回调函数handleEnded(event){console.log("播放结束");// 移除纪录时长数组中当前视频的纪录let {videoUpdateTime} = this.data;videoUpdateTime.splice(videoUpdateTime.findIndex(item => item.vid === event.currentTarget.id),1);this.setData({videoUpdateTime:videoUpdateTime})},

再次播放跳转到上次离开的位置纪录:

    // 1. 创建一个可以控制 video标签的实例对象this.videoContext = wx.createVideoContext(vid);// 判断当前的视频是否有播放纪录:如果有,跳转☞指定的位置let {videoUpdateTime} = this.data;let videoItem = videoUpdateTime.find(item => item.vid === vid);if(videoItem){ // 跳转this.videoContext.seek(videoItem.currentTime);}this.videoContext.play()

五、列表滑动功能

scroll-view

从上面一个效果演示可以看出,当界面下滑动时,上面的搜索框和标签栏都会跟着动,为了将其固定,实现列表滑动的效果,我们需要将 scrool-view 组件的高度设置一下,使其占据除了搜索框和标签栏和tabBar以外的高度。

/*  视频列表的样式  */
.videoScroll{padding-top: 10rpx;/*  calc:可以动态计算css的宽高 注意:计算数的两边必须加空格,不然计算失效 *//*  视口单位:vh vw 1vh = 1% 的视口高度, 1vw = 1% 的视口宽度  */height: calc(100vh - 152rpx);
}

六、 Scroll-view 下拉刷新、上拉加载

Scroll-view

下拉刷新:


上拉加载:

<!--  视频的列表区域  -->
<scroll-viewscroll-yclass="videoScroll"refresher-enabled="true"bindrefresherrefresh="handleRefresh"refresher-triggered="{{isTriggered}}"bindscrolltolower="handleToLower"
>
  //  1.自定义下拉刷新的回调 :scroll-viewhandleRefresh(event){// 1.发请求,获取最新的视频数据// 2. 关闭下拉,在getVideoGroupListData函数中进行this.getVideoList(this.data.navId);},// 收回下拉状态this.setData({isTriggered:false})// 2.自定义上拉触底你的回调:scrool-viewhandleToLower(event){console.log("下拉加载新的数据")// 数据分页:1. 后端分页 2. 前端分页// 模拟数据let newVideoList = this.data.videoList;let videoList = this.data.videoList;// 更新数据videoList.push(...newVideoList);this.setData({videoList:videoList});},

注意:Page也有下拉和上拉的刷新事件

微信小程序【网易云音乐实战】(第四篇 用户登录、本地存储、视频播放、上拉下拉刷新)相关推荐

  1. 微信小程序网易云音乐播放界面

    微信小程序网易云 效果图 HTML JS CSS 效果图 HTML <view class="box"><!-- 毛玻璃 --><view class ...

  2. SSM+微信小程序网易云音乐设计与实现 毕业设计-附源码261620

    基于SSM微信小程序的网易云音乐 摘  要 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,微信小程序 ...

  3. SSM+mysql+微信小程序网易云音乐设计与实现 毕业设计-附源码261620

    基于SSM微信小程序的网易云音乐 摘  要 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,微信小程序 ...

  4. (附源码 )SSM+mysql+微信小程序网易云音乐设计与实现 毕业设计261620

    基于SSM微信小程序的网易云音乐 摘 要 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,微信小程序的 ...

  5. 微信小程序网易云音乐设计与实现 毕业设计-附源码261620

    基于SSM微信小程序的网易云音乐 摘 要 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,微信小程序的 ...

  6. (附源码)SSM+mysql+微信小程序网易云音乐设计与实现 毕业设计261620

    基于SSM微信小程序的网易云音乐 摘 要 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,微信小程序的 ...

  7. WeChat微信小程序网易云音乐播放链接方法

  8. 微信小程序网易云音乐轮播图右侧留白

    效果图 这个效果需要用到swiper里面的一个方法next-margin 使用如下: <swiper class="topListSwiper" next-margin='5 ...

  9. 微信小程序网易云音乐视频播放切换的功能的实现

    需要使用bindplay事件 <video src="{{item.data.urlInfo.url}}" object-fit="cover" bind ...

  10. 微信小程序 | 网易云+ChatGPT实现一个智能音乐推荐小程序

    文章目录 * 效果预览 ** 分析用户的输入产生推荐 ** 分析用户的选择标签进行推荐 一.需求背景 二.项目原理及架构 2.1 实现原理 (1) 基于用户的喜欢歌手推荐 (2)基于用户的兴趣标签推荐 ...

最新文章

  1. Android消息机制学习笔记
  2. LCS最长公共子序列和LIS最长上升子序列——例题剖析
  3. 带你开发类似 Pokemon Go 的 AR 游戏
  4. python运行的原理_Python运行机制(转)
  5. php根据位置获取经纬度(百度地图)
  6. JPA 2.1实体图–第1部分:命名实体图
  7. solr4 mysql自动更新_(solr系列:五) solr定时实时重建索引和增量更新
  8. 重磅发布:阿里云云安全中心一键防勒索功能上线!
  9. 4t硬盘实际容量是多少_SMR硬盘到底能用不?点进来看看避免踩雷
  10. 使用强大的 Mockito 来测试你的代码
  11. Data truncation: Data too long for column错误分析
  12. 3.7.3 - Basic String Operations
  13. zookeeper的zxid
  14. win10系统下安装基于虚拟机的32位XP系统
  15. threeJS鼠标单击模型边缘高亮
  16. 惠普战66键盘win10亮度调节快捷键失灵的解决办法
  17. 男人就要对自己狠一点
  18. 粉笔公考——判断推理
  19. CANopen DS402 驱动电机运动控制模式
  20. 取消参考文献自动编号_word文档参考文献如何自动编号

热门文章

  1. Object.defineProperty与proxy进行对比
  2. 支付宝沙箱支付可能遇见的问题
  3. 计算机技术与软件专业资格(水平)考试 报考指南
  4. Powershell知识点1:开启脚本限制 报错:无法加载文件,因为在此系统中禁止执行脚本
  5. vue实现网页端企业微信扫码登录功能(前端部分)
  6. 一维数据二维化的办法汇总(二)
  7. 如何查询本人医保就医明细
  8. 蓝桥杯-方格计数(java)
  9. ADATE320介绍
  10. MyBatis联合主键结果集与SQL查询结果不一致的问题