一、搜索视觉稿
http://www.youbaobao.xyz/mpvue-design/preview/#artboard1
二、搜索页面组件结构图
三、标签组件
可交互的标签组件
组件名称 | 属性 | 参数 | 用途 | 默认值 |
---|---|---|---|---|
Tag | props | text | 标签文本 | (空) |
methods | onClick | 标签点击事件 | (空) |
1.新建src\components\base\Tag.vue
<template>
<div class="tag-wrapper" @click="onClick">
<div class="tag">{{text}}</div>
</div>
</template>
<script>
export default {
props: {
text: {
type: String,
default: ''
}
},
methods: {
onClick() {
this.$emit('onClick')
}
}
}
</script>
<style lang="scss" scoped>
.tag-wrapper {
display: flex;
justify-content: center;
background: #F7F7F9;
border-radius: 16px;
padding: 6px 17px;
.tag {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 14px;
color: #272E37;
}
}
</style>
2.新建src\pages\search\main.js
import Vue from 'vue'
import App from './search'
const app = new Vue(App)
app.$mount()
3.新建src\pages\search\search.vue
<template>
<div>
</div>
</template>
<script>
export default {
components: {
},
data() {
return {
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>
修改src\components\home\SearchBar.vue
的如下部分(添加点击事件):
<div class="search-bar-wrapper" @click="onSearchBarClick">
为src\pages\index\index.vue
的onSearchBarClick
事件添加路由跳转:
onSearchBarClick() {
this.$router.push('/pages/search/main')
},
4.新建src\pages\search\main.json
{
"navigationBarTitleText": "搜索"
}
四、标签分组组件
标签分组组件,包含一个标题和按钮,以及标签分组
组件名称 | 属性 | 参数 | 用途 | 默认值 |
---|---|---|---|---|
TagGroup | props | headerText | 标题文本 | (空) |
btnText | 按钮文本 | (空) | ||
value | 标签数据 | [] | ||
methods | onTagClick | 标签点击事件 | (空) | |
onBtnClick | 按钮点击事件 | (空) |
1.新建src\components\base\TagGroup.vue
<template>
<div class="tag-group-wrapper">
<div class="tag-group-header">
<div class="header-text">{{headerText}}</div>
<div class="header-btn" @click="onBtnClick">{{btnText}}</div>
</div>
<div class="tag-goup">
<div class="tag-group-inner" v-for="(text, index) in value" :key="index">
<Tag :text="text" @onClick="onTagClick(text, index)"/>
</div>
</div>
</div>
</template>
<script>
import Tag from './Tag'
export default {
components: {Tag},
props: {
headerText: String,
btnText: String,
value: Array
},
methods: {
onTagClick(text, index) {
this.$emit('onTagClick', text, index)
},
onBtnClick() {
this.$emit('onBtnClick')
}
}
}
</script>
<style lang="scss" scoped>
.tag-group-wrapper {
.tag-group-header {
display: flex;
justify-content: space-between;
padding: 0 16px;
font-size: 14px;
line-height: 20px;
.header-text {
color: #333333;
}
.header-btn {
color: #3696EF;
}
}
.tag-goup {
display: flex;
flex-flow: row wrap;
padding: 4px 10px 0 10px;
.tag-group-inner {
padding: 12px 6px 0 6px;
}
}
}
</style>
2.在src\pages\search\search.vue中引入TagGroup
<template>
<div>
<TagGroup
:value="tags"
header-text="热门搜索"
btn-text="换一批"
@onTagClick="onTagClick"
@onBtnClick="onBtnClick"
/>
</div>
</template>
<script>
import TagGroup from '../../components/base/TagGroup'
export default {
components: {
TagGroup
},
data() {
return {
tags: [
'aaaaaa',
'bbbbb',
'c',
'ddddddddddddddddd',
'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
'ffffffffff'
]
}
},
methods: {
onTagClick(text, index) {
console.log('tag...', text, index)
},
onBtnClick() {
console.log('btn...')
}
}
}
</script>
3.效果
五、搜索分类组件
搜索列表中的分类组件
组件名称 | 属性 | 参数 | 用途 | 默认值 |
---|---|---|---|---|
SearchItem | props | title | 标题文本 | (空) |
subTitle | 副标题文本 | (空) | ||
icon | 图标类型 | (空) | ||
methods | onClick | 分类点击事件 | (空) |
1.新建src\components\search\SearchItem.vue
<template>
<div class="search-item-wrapper" @click="onClick">
<div class="search-item-icon">
<div class="icon-wrapper">
<van-icon :name="icon" color="#777777" :style="{ width:'20px', height:'20px' }" />
</div>
</div>
<div class="search-item-info">
<div class="search-item-title">{{title}}</div>
<div class="search-item-sub-title">{{subTitle}}</div>
</div>
</div>
</template>
<script>
export default {
props: {
title: String,
subTitle: String,
icon: String
},
methods: {
onClick() {
this.$emit('onClick')
}
}
}
</script>
<style lang="scss" scoped>
.search-item-wrapper {
display: flex;
align-items: center;
padding: 15px;
height: 36.5px;
.search-item-icon {
.icon-wrapper {
display: flex;
justify-content: center;
align-items: center;
width: 32px;
height: 32px;
border-radius: 50%;
background: #F7F7F9;
}
}
.search-item-info {
margin-left: 10px;
.search-item-title {
color: #333333;
font-size: 14px;
line-height: 20px;
}
.search-item-sub-title {
color: #777777;
font-size: 12px;
line-height: 16.5px;
}
}
}
</style>
2.在src\pages\search\search.vue中引入
<SearchItem icon="apps-o" title="计算机科学" sub-title="类别"/>
六、搜索列表组件
搜索结果列表组件
组件名称 | 属性 | 参数 | 用途 | 默认值 |
---|---|---|---|---|
SearchTable | props | data | 列表数据 | [] |
methods | onClick | 图书点击事件 | (空) |
1.新建src\components\search\SearchTable.vue
<template>
<div class="search-table-wrapper">
<div class="search-table-inner">
<div class="search-table-book" v-for="(book, index) in data" :key="index" @click="onClick(book)">
<div class="book-img-wrapper">
<div class="book-img">
<ImageView :src="book.cover"/>
</div>
</div>
<div class="book-info-wrapper">
<div class="book-title">{{book.title}}</div>
<div class="book-author">{{book.author}}</div>
<div class="book-category">{{book.categoryText}}</div>
</div>
</div>
</div>
</div>
</template>
<script>
import ImageView from '../base/ImageView'
export default {
components: {ImageView},
props: {
data: Array
},
methods: {
onClick(book) {
this.$emit('onClick', book)
}
}
}
</script>
<style lang="scss" scoped>
.search-table-wrapper {
padding: 0 16px;
.search-table-inner {
.search-table-book {
margin: 14.5px 0;
display: flex;
align-items: center;
.book-img-wrapper {
.book-img {
width: 47px;
height: 68.5px;
}
}
.book-info-wrapper {
width: 80%;
margin-left: 15.5px;
.book-title {
color: #333333;
font-size: 16px;
line-height: 22.5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 500;
}
.book-author {
color: #999999;
font-size: 13px;
line-height: 18px;
margin-top: 5px;
}
.book-category {
color: #777777;
font-size: 13px;
line-height: 18px;
}
}
}
}
}
</style>
2.在src\pages\search\search.vue中引入
<SearchTable :data="list"/>
...
data() {
return {
...
list: [
{
'id': 225,
'fileName': '2016_Book_MicrofinanceEUStructuralFundsA',
'cover': 'https://www.youbaobao.xyz/book/res/img/Economics/2016_Book_MicrofinanceEUStructuralFundsA.jpeg',
'title': 'Microfinance, EU Structural Funds and Capacity Building for Managing Authorities',
'author': 'Giovanni Nicola Pes',
'publisher': 'Palgrave Macmillan',
'bookId': '2016_Book_MicrofinanceEUStructuralFundsA',
'category': 3,
'categoryText': 'Economics',
'language': 'en',
'rootFile': 'OEBPS/9781137536013.opf'
},
{
'id': 88,
'fileName': '2018_Book_BetweenMobilityAndMigration',
'cover': 'https://www.youbaobao.xyz/book/res/img/SocialSciences/978-3-319-77991-1_CoverFigure.jpg',
'title': 'Between Mobility and Migration',
'author': 'Peter Scholten',
'publisher': 'Springer International Publishing',
'bookId': '2018_Book_BetweenMobilityAndMigration',
'category': 2,
'categoryText': 'SocialSciences',
'language': 'en',
'rootFile': 'OEBPS/package.opf'
},
{
'id': 225,
'fileName': '2016_Book_MicrofinanceEUStructuralFundsA',
'cover': 'https://www.youbaobao.xyz/book/res/img/Economics/2016_Book_MicrofinanceEUStructuralFundsA.jpeg',
'title': 'Microfinance, EU Structural Funds and Capacity Building for Managing Authorities',
'author': 'Giovanni Nicola Pes',
'publisher': 'Palgrave Macmillan',
'bookId': '2016_Book_MicrofinanceEUStructuralFundsA',
'category': 3,
'categoryText': 'Economics',
'language': 'en',
'rootFile': 'OEBPS/9781137536013.opf'
},
{
'id': 88,
'fileName': '2018_Book_BetweenMobilityAndMigration',
'cover': 'https://www.youbaobao.xyz/book/res/img/SocialSciences/978-3-319-77991-1_CoverFigure.jpg',
'title': 'Between Mobility and Migration',
'author': 'Peter Scholten',
'publisher': 'Springer International Publishing',
'bookId': '2018_Book_BetweenMobilityAndMigration',
'category': 2,
'categoryText': 'SocialSciences',
'language': 'en',
'rootFile': 'OEBPS/package.opf'
},
{
'id': 225,
'fileName': '2016_Book_MicrofinanceEUStructuralFundsA',
'cover': 'https://www.youbaobao.xyz/book/res/img/Economics/2016_Book_MicrofinanceEUStructuralFundsA.jpeg',
'title': 'Microfinance, EU Structural Funds and Capacity Building for Managing Authorities',
'author': 'Giovanni Nicola Pes',
'publisher': 'Palgrave Macmillan',
'bookId': '2016_Book_MicrofinanceEUStructuralFundsA',
'category': 3,
'categoryText': 'Economics',
'language': 'en',
'rootFile': 'OEBPS/9781137536013.opf'
},
{
'id': 88,
'fileName': '2018_Book_BetweenMobilityAndMigration',
'cover': 'https://www.youbaobao.xyz/book/res/img/SocialSciences/978-3-319-77991-1_CoverFigure.jpg',
'title': 'Between Mobility and Migration',
'author': 'Peter Scholten',
'publisher': 'Springer International Publishing',
'bookId': '2018_Book_BetweenMobilityAndMigration',
'category': 2,
'categoryText': 'SocialSciences',
'language': 'en',
'rootFile': 'OEBPS/package.opf'
}
]
}
},
3.效果
七、综合搜索列表组件
包含分类和列表的综合搜索列表
组件名称 | 属性 | 参数 | 用途 | 默认值 |
---|---|---|---|---|
SearchList | props | data | 列表数据 | {} |
methods | showList | 展示分类点击后的列表 | (空) |
1. 新建src\components\search\SearchList.vue
<template>
<div class="search-list-wrapper">
<SearchTable :data="data"/>
<SearchItem icon="apps-o" title="计算机科学" sub-title="类别"/>
<SearchItem icon="apps-o" title="计算机科学" sub-title="类别"/>
<SearchItem icon="apps-o" title="计算机科学" sub-title="类别"/>
</div>
</template>
<script>
import SearchItem from './SearchItem'
import SearchTable from './SearchTable'
export default {
components: {SearchTable, SearchItem},
props: {
data: Object
},
methods: {
showList() {
},
}
}
</script>
<style lang="scss" scoped>
</style>
2.修改src\pages\search\search.vue
- data中新增:
item: [
{ icon: 'apps-o', title: 'Compute Science', subTitle: 'Category' },
{ icon: 'contact', title: 'Compute Science', subTitle: 'Author' },
{ icon: 'newspaper-o', title: 'Compute Science', subTitle: 'Publisher' }
],
- 通过computed将data整合为一个参数对象
computed: {
data() {
return {
item: this.item,
list: this.list
}
}
},
- 去掉SearchTable和SearchItem,替换为SearchList
<SearchList :data="data"/>
3.修改src\components\search\SearchList.vue
在src\components\search\SearchList.vue中使用计算属性动态拿到传过来的数据:
computed: {
categroy() {
return this.data.item[0]
},
author() {
return this.data.item[1]
},
publisher() {
return this.data.item[2]
}
},
- 在页面部分绑定数据:
<SearchItem
:icon="categroy.icon"
:title="categroy.title"
:sub-title="categroy.subTitle"
@onClick="showList(categroy.title, 'categroy')"
/>
<SearchItem
:icon="author.icon"
:title="author.title"
:sub-title="author.subTitle"
@onClick="showList(author.title, 'author')"
/>
<SearchItem
:icon="publisher.icon"
:title="publisher.title"
:sub-title="publisher.subTitle"
@onClick="showList(publisher.title, 'publisher')"
/>
<SearchTable :data="data.list" @onClick="onBookClick"/>
- 文件完整内容如下:
<template>
<div class="search-list-wrapper">
<SearchItem
:icon="categroy.icon"
:title="categroy.title"
:sub-title="categroy.subTitle"
@onClick="showList(categroy.title, 'categroy')"
/>
<SearchItem
:icon="author.icon"
:title="author.title"
:sub-title="author.subTitle"
@onClick="showList(author.title, 'author')"
/>
<SearchItem
:icon="publisher.icon"
:title="publisher.title"
:sub-title="publisher.subTitle"
@onClick="showList(publisher.title, 'publisher')"
/>
<SearchTable :data="data.list" @onClick="onBookClick"/>
</div>
</template>
<script>
import SearchItem from './SearchItem'
import SearchTable from './SearchTable'
export default {
components: {SearchTable, SearchItem},
props: {
data: Object
},
computed: {
categroy() {
return this.data.item[0]
},
author() {
return this.data.item[1]
},
publisher() {
return this.data.item[2]
}
},
methods: {
showList(text, key) {
console.log(text, key)
},
onBookClick(book) {
console.log(book)
}
}
}
</script>
<style lang="scss" scoped>
</style>