昨日回顾
网易云案例
开发前端服务需要接口- 用的nodejs服务-先启动该服务
看一个nodejs服务或者前端服务启动命令,要看package.json中的scripts
- start nodejs项目 或者react
serve vue项目
dev vue项目 react项目
- start nodejs项目 或者react
nodejs服务的地址和前端服务形成了跨域
nodejs服务开放了cors
新建vue项目-初始化-选择了路由-安装了axios-vant-babel-plugin-import
- 需求分析-Layout(布局组件)- Home(首页)-Search(搜索页)- 播放页
路由关系
layout- 布局<br /> -首页<br /> - 搜索页<br /> play - 同级
新建组件 layout- tabbar组件- navbar组件
- 封装axios ```javascript import axios from ‘axios’
const instance = axios.create({ baseURL: ‘’, timeout: 5000 }) // 请求拦截器 成功的回调函数。失败的回调函数 instance.interceptors.request.use(function(config) { // url headers cookie params. data return config // 会用这个config去请求 }, function (error) { return Promise.reject(error) // 抛出错误 })
// 响应拦截器 instance.interceptors.response.use(function(response) { // response就是响应的数据- 处理一些解构的问题 return response.data
}, function (error) { // 经常在这个位置判断 http的状态码 // 401- 表示token失效或者没传 // 如果是401- 删除token 重新登录
return Promise.reject(error) // 抛出错误 })
export default instance
8. 封装请求模块 api/home.js-好处是复用性
```javascript
import request from '@/utils/request
export function getResult(params) {
return request({
url,
params
})
}
- 首页获取
先定义一个静态结构
- 定义data数据接收
- created获取数据- methods方法- created调用该方法
- v-for循环生成静态结构
- 搜索页
出现代码一定是代码出现了问题-只能看代码
一定要敢改代码-下笔
不管多么微小的想法,一定要落实到代码上
- 点击热搜时-获取数据-watch
- 热搜修改时-获取数据-watch
- 上拉加载时-获取数据
1. 解决获取数据的重复问题
现在的问题是:数据一直在追加,势必造成id重复
- 什么情况下要追加,什么情况下不能追加
- 上拉加载的时候追加- 加载下一页
- watch监听-关键字发生了变化-重新加载数据-赋值
因为值改变和上拉加载公用了一个方法,给这个方法加了一个参数 isAppend
async getSearchResult(keywords, isAppend = false) {
const { data: { result: { songs } } } = await getSearchResult({ keywords, limit: 20, offset: (this.page - 1) * 20 })
if(isAppend) {
// 追加的情况放到后面
this.searchList.push(...songs)
}else {
this.searchList = songs // 不追加就赋值
}
},
调用时- 上拉加载传true,值改变的时候不用传值
async onLoad() {
this.page++
await this.getSearchResult(this.keyWord, true)
// 此时认为执行完毕
this.loading = false
}
2. 当输入框的值为空的时候,有报错
keyWord 是空的,是查不出东西来的
- 意味着当关键字清空的时候,之前的数据重置设置为空
重置原来的数据 分页属性page 1 loading(false) finished(false), 不再发出请求
watch: { keyWord(newValue) { // 当输入框的值为空的时候 重置数据 if (!newValue) { this.searchList = [] this.page = 1 this.loading = false this.finished = false return } // 要去搜索 this.getSearchResult(newValue) } },
3. 当输入框的值发生变化-页码和数据问题
当输入框的值发生变化,意味着重新搜索
重新从第一页开始搜索
- 搜一首歌曲 海底- 200条记录- 滑到底了之后,finished 应该为true, 再去搜一个歌曲 起风了
重新设置finished loading也要重新设置
watch: { keyWord(newValue) { // 当输入框的值为空的时候 重置数据 this.page = 1 this.loading = false this.finished = false if (!newValue) { this.searchList = [] return } // 要去搜索 this.getSearchResult(newValue) } },
4. 当搜索不到内容时的报错问题
当关键字搜索搜索不到数据的时候,由于我们直接用了解构赋值
当搜索不到内容时-判断接口返回的数据 code为200 并且 songCount大于0的时候 才可以赋值
否则- finished 设置为true
async getSearchResult(keywords, isAppend = false) {
const { data } = await getSearchResult({ keywords, limit: 20, offset: (this.page - 1) * 20 })
const { code, result } = data // code为状态码200 表示加载成功- 获取result中的songCount > 0
if (code === 200 && result.songCount > 0) {
if (isAppend) {
// 追加的情况放到后面
this.searchList.push(...result.songs)
} else {
this.searchList = result.songs // 不追加就赋值
}
}else {
// 此时意味着搜索不到数据 或者数据已经搜索完毕
this.finished = true // 意味着获取数据已经结束
}
},
5. 搜索防抖的实现
watch监听了变量的更新
- 防抖函数可以执行单位时间之内的最后一次
watch: { keyWord(newValue) { // 当输入框的值为空的时候 重置数据 this.page = 1 this.loading = false this.finished = false if (!newValue) { this.searchList = [] return } clearTimeout(this.timer) // 清空上一次的定时器 this.timer = setTimeout(() => this.getSearchResult(newValue),300) // 要去搜索 } },
6. 首页的布局问题
- 先调整navbar组件的fixed属性,固定在顶部
- 用div.main 包裹路由容器
<template> <div> <van-nav-bar fixed :title="$route.meta.title"></van-nav-bar> <div class="main"> <router-view></router-view> </div> <van-tabbar route> <van-tabbar-item replace to="/layout/home" icon="home-o">首页</van-tabbar-item> <van-tabbar-item replace to="/layout/search" icon="search">搜索</van-tabbar-item> </van-tabbar> </div> </template>
7. 封装统一的音乐的选项组件 SongItem
- 可以封装一个统一的组件SongItem
- 公共的组件- components-SongItem
```vue
2. 替换原来的结构
```html
<van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
<!-- <van-cell center v-for="item in searchList" :key="item.id" :title="item.name" :label="item.ar[0].name">
<template #right-icon>
<van-icon name="play-circle-o" size="0.6rem" />
</template>
</van-cell> -->
<song-item v-for="item in searchList" :key="item.id" :item="item"></song-item>
</van-list>
8.播放音乐的实现
- 准备了play组件
```html
{{ songInfo.name }}-{{ songInfo && songInfo.ar && songInfo.ar[0].name }}
{{ curLyric }}
需要在SongItem中跳转到播放页面
```vue
<template>
<van-cell center :title="item.name" :label="item.name">
<!-- 具名插槽 -->
<template #right-icon>
<van-icon name="play-circle-o" size="0.6rem" @click="toPlay" />
</template>
</van-cell>
</template>
<script>
export default {
name: 'SongItem',
props: {
item: {
type: Object,
default: () => ({}) // eslint要求 default必须是一个函数
}
},
methods: {
toPlay() {
this.$router.push({
path: '/play',
query: {
id: this.item.id
}
})
}
}
}
</script>
<style>
</style>