// 父组件 add-song.vue
// 添加歌曲模板
<template>
<transition name="slide">
<div class="add-song" v-show="showFlag" @click.stop>
<div class="header">
<h1 class="title">添加歌曲到列表</h1>
<div class="close" @click="hide">
<i class="icon-close"></i>
</div>
</div>
<div class="search-box-wrapper">
<search-box ref="searchBox"
@query="onQueryChange"
placeholder="搜索歌曲"
></search-box>
</div>
<div class="shortcut" v-show="!query">
<switches :switches="switches"
:currentIndex="currentIndex" @switch="switchItem"
></switches>
<div class="list-wrapper">
<scroll class="list-scroll"
ref="songList"
v-if="currentIndex===0"
:data="playHistory"
>
<div class="list-inner">
<song-list :songs="playHistory" @select="selectSong"></song-list>
</div>
</scroll>
<scroll class="list-scroll"
ref="searchList"
v-if="currentIndex===1"
:data="searchHistory"
>
<div class="list-inner">
<search-list :searches="searchHistory"
@select="addQuery"
@delete="deleteSearchHistory"
></search-list>
</div>
</scroll>
</div>
</div>
<div class="search-result" v-show="query">
<suggest :query="query"
:showSinger="showSinger"
@select="selectSuggest"
@listScroll="blurInput"
></suggest>
</div>
<top-tip ref="topTip">
<div class="tip-title">
<i class="icon-ok"></i>
<span class="text">1首歌曲已经添加到播放列表</span>
</div>
</top-tip>
</div>
</transition>
</template>
<script>
// 搜索框组件
import SearchBox from ‘base/search-box/search-box‘
// 切换组价
import Switches from ‘base/switches/switches‘
// 滚动组件
import Scroll from ‘base/scroll/scroll‘
// 歌单
import SongList from ‘base/song-list/song-list‘
import {mapGetters, mapActions} from ‘vuex‘
import Song from ‘common/js/song‘
import SearchList from ‘base/search-list/search-list‘
// 搜素结果模板
import Suggest from ‘components/suggest/suggest‘
import TopTip from ‘base/top-tip/top-tip‘
export default{
data() {
return {
showFlag: false,
currentIndex: 0,
switches: [
{name: ‘最近播放‘},
{name: ‘最近搜索‘}
],
query: ‘‘,
// 不显示歌手
showSinger: false
}
},
computed: {
...mapGetters([
‘playHistory‘,
‘searchHistory‘
])
},
methods: {
// 将search-box中的input给blur(失去焦点事件),隐藏输入框
blurInput() {
// 父组件通过$refs调用子组件searchBox的blur()方法
this.$refs.searchBox.blur()
},
// 保存搜索历史
saveSearch() {
// 通过mapActions调用saveSearchHistory()来对state进行修改,完成存储
this.saveSearchHistory(this.query)
},
// 选择搜索表中歌曲
selectSuggest() {
// 保存搜索历史
this.saveSearch()
// 提示框
this.$refs.topTip.show()
},
// 监听search-box中query变化,并将变化值传递给add-song然后发送给suggest并请求数据
onQueryChange(query) {
this.query = query
},
// 将搜索历史加入搜索框
addQuery(query) {
this.$refs.searchBox.setQuery(query)
},
selectSong(song, index) {
if (index !== 0) {
// 此处song是从缓存中读取出来的,不是对象需要实例化也就是new
this.insertSong(new Song(song))
this.$refs.topTip.show()
}
},
// 将索引传给currentIndex并传给子组件
switchItem(index) {
this.currentIndex = index
},
show() {
this.showFlag = true
// 点开页面时,刷新页面,scroll重新计算,然后就可以滚动了
if (this.currentIndex === 0) {
this.$refs.songList.refresh()
} else {
this.$refs.searchList.refresh()
}
},
hide() {
this.showFlag = false
},
...mapActions([
‘insertSong‘,
‘deleteSearchHistory‘,
‘saveSearchHistory‘
])
},
components: {
SearchBox,
Switches,
Scroll,
SongList,
SearchList,
Suggest,
TopTip
}
}
</script>
<style lang="scss" scoped>
@import "./add-song.scss";
</style>
// 子组件switches.vue
// 切换模块 <template> <ul class="switches"> <li class="switch-item" :class="{‘active‘ : currentIndex === index}" v-for="(item, index) in switches" @click="switchItem(index)" > <span>{{item.name}}</span> </li> </ul> </template> <script> export default{ props: { switches: { type: Array, default: [] }, currentIndex: { type: Number, default: 0 } }, methods: { switchItem(index) { // 将点击将索引发给父组件 this.$emit(‘switch‘, index) } } } </script> <style lang="scss" scoped> @import "./switches"; </style>
父传子:(本页数据存储一般放在data()中,接受的父组件的数据一般放在props)将data()中的switches数据通过数据绑定(左侧为绑定数据的名称):switches="switches”(右侧为绑定的数据)传给子组件switches,用props来接受数据(通过传来的数据名)
子传父:将点击开关模块对应的下角标传递给父组件,this.$emit(‘switch‘,index)通过emit发射switch事件,在父组件中通过(左侧为接受子组件发送过来的事件)@switch="switchItem"(右侧为父组件定义的方法名)
模块切换实现原理:
主要通过下角标来控制切换后的样式,事件
先将子组件要显示的switches数据通过绑定的方式传给子组件switches,v-for将数据渲染到页面并获得每个item的index,当点击每个item时,会获得当前点击item的下角标currentIndex,将currentIndex传给父组件,通过v-if ="currentIndex===0",v-if="currentIndex===1"来控制页面显示,将currentIndex通过数据绑定再传给子组件switches,通过class绑定的方法来控制样式的变化:class=“‘active’: currentIndex === index”(在样式scss中,先写好active样式)
// switches.scss样式
@import "~common/scss/variable";
.switches{
display: flex;
align-items: center;
width: 240px;
margin: 0 auto;
border: 1px solid $color-highlight-background;
border-radius: 5px;
.switch-item{
flex: 1;
padding: 8px;
text-align: center;
font-size: $font-size-medium;
color: $color-text-d;
&.active{
background: $color-highlight-background;
color: $color-text;
}
}
}