通过搜索框,或者其他跳转的搜索页面如上所示,
1、课程,文章问答的跳转框如下所示
<template>
<view class="tab-bar">
<view class="bar-view">
<view class="bar-item " :class="{current:index==value}" v-for="(item, index) in tabs" :key="index" @click="changeTab(index)">{{item.name}}</view>
</view>
</view>
</template>
<script>
export default {
props: {
tabs: {
type: Array,
default: () => [{
id: 1,
name: '课程'
},
{
id: 2,
name: '文章'
},
{
id: 3,
name: '问答'
},
]
},
value: { // vue 语法糖, v-model双向绑定:1. props声明value, 2. 修改它时触发input事件传递
type: Number,
default: 0
}
},
data() {
return {}
},
methods: {
changeTab(index) {
// 点击不同的标签才能改变值
if(this.value!=index){
// 2. 修改它时触发input事件传递数据
this.$emit('input',index)
}
}
}
}
</script>
<style lang="scss">
.tab-bar {
width: 100%;
height: 80rpx;
background-color: #FFFFFF;
border: 1px solid #efeff4;
.bar-view {
width: 100%;
text-align: center;
display: flex;
.bar-item {
flex: 1;
font-size: 30rpx;
line-height: 80rpx;
position: relative;
&:after {
position: absolute;
content: '';
height: 0;
width: 0;
border-bottom: 6rpx solid $mxg-text-color-blue;
border-radius: 20rpx;
left: 50%;
bottom: 6rpx;
transform: translateX(-50%); //向x轴左边偏移百分之五十
transition: 0.3s; //过渡的时长
}
}
.current {
color: $mxg-text-color-blue;
&:after {
width: 60rpx;
}
}
}
}
</style>
1、绑定点击的按钮样式
:class="{current:index==value}"
value在props中绑定
value: { // vue 语法糖, v-model双向绑定:1. props声明value, 2. 修改它时触发input事件传递
type: Number,
default: 0
}
点击触发changeTab方法,这个是与父组件双向绑定value值
changeTab(index) {
// 点击不同的标签才能改变值
if(this.value!=index){
// 2. 修改它时触发input事件传递数据
this.$emit('input',index)
}
}
父组件运用v-model双向绑定value,不能使用 :value 的方法,这种只能父组件向子组件传值,单向绑定
<tab-bar v-if="!searched" v-model="tabIndex"></tab-bar>
在data中绑定tabIndex
data() {
return {
tabIndex:0
}
},
2、综合排序,全部分类的编写
<template>
<view class="down-bar row sticky-box">
<!-- class="one"样式为flex=1表示平均分配 -->
<!-- 禁止滚动 @touchmove.stop.prevent="()=>{} -->
<view class="one" v-for="(item ,i) in downbarList" :key='i' @click="clickDownView(item)" @touchmove.stop.prevent="()=>{}">
<view class=" center" :class="{active:item.active||(item.id||item.id===0)||item.categoryId}">
<text>{{item.name}}</text>
<text class="iconfont icon-down1" v-show="!item.active"></text>
<text class="iconfont icon-Up" v-show="item.active"></text>
</view>
<view class="item-list" v-show="item.active">
<category v-if="item.isCategory" :value='item' @searchByLabel="searchByLabel"></category>
<view class="name" v-else :class="{active:info.name==item.name}" v-for="(info, index) in item.list" :key="index"
@click="changeInfo(item,info)">{{info.name}}</view>
</view>
<view class="cover" v-show="item.active"></view>
</view>
</view>
</template>
<script>
import category from '@/pages/category/category.vue'
export default {
props: {
param: {
type: Object,
default: null
},
downbar: {
type: Array,
default: () => [{
type: 'sort',
name: '综合排序',
active: false, //是否被选中
list: [{
id: null,
name: '综合排序'
},
{
id: 'new',
name: '最新排序'
},
{
id: 'hot',
name: '热门排序'
}
]
},
{
type: 'label',
name: '全部分类', // 放到最后一个元素
active: false,
isCategory: true // 分类
}
]
}
},
data() {
return {
downbarList: []
}
},
watch: {
param: {
handler(newValue) {
console.log("请求参数", newValue)
// 如果标签的名字不等于空,则下面进行
if (newValue.name) {
// 取downbarList最后一个元素
let obj = this.downbar[this.downbar.length - 1]
console.log(obj)
//将全部分类替换成标签信息
obj.name = newValue.name
obj.id = newValue.labelId
obj.activeIndex = newValue.activeIndex
return
}
},
immediate: true
}
},
components: {
category
},
// 因为小程序端不能直接更改props中父组件传过来的值,所以需要定义一个数据接收
created() {
this.downbarList = this.downbar
},
methods: {
clickDownView(item) {
console.log(item.name)
//对downbar数组遍历,对每一个item进行比对,如果不同,active则为一律为false,不同则取反
this.downbarList.forEach(
(i) => {
i.active = (item === i) ? !item.active : false
}
)
},
changeInfo(item, info) {
if (item.name === info.name) return
item.name = info.name
item.id = info.id
//向父组件发送查询数据
this.$emit('search', {
[item.type]: info.id
})
},
//分类的子组件调用这个方法,来查询更新的类和方法
searchByLabel(label) {
console.log("传递过来的", label)
this.$emit('search',{labelId:label.id,categoryId:label.categoryId})
}
}
}
</script>
<style lang="scss">
.down-bar {
z-index: 100;
background-color: #fff;
font-size: 30rpx;
line-height: 80rpx;
}
.item-list {
z-index: 100;
background-color: #FFFFFF;
position: absolute;
left: 0;
right: 0;
// border-radius: 20rpx;
// width: 100%;
// height: 300rpx;
.name {
padding-left: 80rpx;
border-bottom: 1rpx solid #efeff4;
margin-bottom: 5rpx;
}
.category {
height: 580rpx;
}
}
.active {
color: $mxg-text-color-blue;
}
// 蒙层
.cover {
z-index: 99; //置于顶层
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 160rpx;
width: 100%;
height: 100%;
background-color: black;
opacity: 0.2 !important; //透明度
}
// 粘顶的样式,页面滚动,顶部不动
.sticky-box {
position: -webkit-sticky;
/* safari 浏览器 */
position: sticky;
/* 其他浏览器 */
top: var(--window-top);
}
</style>
clickDownView
点击触发的方法,并对父组件传递过来的参数遍历,
对downbar数组遍历,对每一个item进行比对,如果不同,active则为一律为false,不同则取反
item.active为true则为蓝色选中状态
clickDownView(item) {
//对downbar数组遍历,对每一个item进行比对,如果不同,active则为一律为false,不同则取反
this.downbarList.forEach(
(i) => {
i.active = (item === i) ? !item.active : false
}
)
},
changeInfo方法
changeInfo左边点击时候触发的方法,将list中的子名称,赋值给他的父名称,这样就能点击展开页面后,显示出来
changeInfo(item, info) {
if (item.name === info.name) return
item.name = info.name
item.id = info.id
//向父组件发送查询数据
this.$emit('search', {
[item.type]: info.id
})
},
downbar: {
type: Array,
default: () => [{
type: 'sort',
name: '综合排序',
active: false, //是否被选中
list: [{
id: null,
name: '综合排序'
},
{
id: 'new',
name: '最新排序'
},
{
id: 'hot',
name: '热门排序'
}
]
},
{
type: 'label',
name: '全部分类', // 放到最后一个元素
active: false,
isCategory: true // 分类
}
]
}
searchByLabel方法是接收子组件,category的中传参的方法
searchByLabel(label) {
console.log("传递过来的", label)
this.$emit('search',{labelId:label.id,categoryId:label.categoryId})
}
子组件也就是分类页面,
添加“不限”和全部分类的按钮
<template>
<view class="category">
<scroll-view scroll-y="true" class="left noScorll">
<view class="title">
<!--@click.stop阻止冒泡点击,不会影响父元素点击 -->
<view v-for="(item, index) in categoryList" :class="{active:index==activeIndex}" :key="index" @click.stop="getLable(index,item)">{{item.name}}</view>
</view>
</scroll-view>
<scroll-view scroll-y="true" class="right">
<view class="tag">
<!-- @click.stop阻止冒泡点击 -->
<view v-for="(item,index) in labelList" :key="index" @click.stop="clicklabel(item)">{{item.name}}</view>
</view>
</scroll-view>
</view>
</template>
<script>
import api from '@/api/course.js'
export default {
props: {
//将搜索页当前的组件作为子组件,传递了对应的对象
value: {
type: Object,
default: () => {}
}
},
data() {
return {
categoryList: [], //左侧分类数据
labelList: [], //右侧分类数据
activeIndex: 0 //当前选中的下标
}
},
mounted() {
this.getList()
},
// 监听原生导航按钮
onNavigationBarButtonTap(e) {
console.log("-------")
// uni.navigateTo({
// url:'/pages/search/search'
// })
// this.navTo('/pages/search/search')
if (e.index == 0) {
this.navTo('/pages/search/search')
}
},
methods: {
async getList() {
const res = await api.getCategoryList()
this.categoryList = res.data
console.log("查询分类的标签", res.data)
//如果传递的数据不为空,则添加一个全部分类的按钮
if (this.value) {
//针对每一个分离下的标签列表,添加一个不限的按钮
this.categoryList.forEach((item) => {
// 添加不限按钮,并且把左边主列表的Id和name赋值给他
item.labelList.unshift({
id: null,
name: "不限",
cname: item.name,
categoryId: item.id
})
})
this.activeIndex = this.value.activeIndex > -1 ? this.value.activeIndex + 1 : this.activeIndex
this.categoryList.unshift({
id: null,
name: '全部分类'
})
}
// 获取当前的标签列表
this.getLable(this.activeIndex)
},
// 获取标签信息
// index分类的下标,item当前分类的信息
getLable(index, item) {
// 选中的样式
this.activeIndex = index;
// 判断点击的是不是全部分类
if (item && item.name === '全部分类') {
// 如果有,则是分类弹窗,直接关闭窗口,将数据传递给下拉筛选的标题处
this.searchPageChangeValue(item)
return
}
//点击获取分类对象
// 通过获取了分类对象,来获取标签列表
const activeCategory = this.categoryList[index];
// 通过分类对象获取标签列表
this.labelList = activeCategory.labelList
console.log(activeCategory.labelList)
},
// 点击标签跳转到搜索页面
clicklabel(item) {
// 如果有值就作为子组件
if (this.value) {
// 将点击的标签信息回显到搜索页进行搜索
this.searchPageChangeValue(item)
return
}
const param = {
labelId: item.id,
name: item.name,
activeIndex: this.activeIndex
}
this.navTo(`/pages/search/search?param=${JSON.stringify(param)}`)
},
// 弹框选择标签
searchPageChangeValue(item) {
// console.log(item)
// 将上一次点击的名称和这次点击的对比,如果相同则不重复执行
if (this.value.name !== item.name && this.value.name !== item.cname) {
// 如果这条数据中有cname则是不限,没有则是普通的name
this.value.name = item.cname || item.name
// 标签ID
this.value.id = item.id || null
//分类ID点击的是不限则取分类ID
this.value.categoryId = item.categoryId || null
this.$emit("searchByLabel", this.value)
}
this.value.active = false
}
}
}
</script>
<style lang="scss">
page {
height: 100%;
}
.category {
display: flex;
// flex-direction: row;
height: 100%;
.left {
background-color: #F8F9FB;
width: 260rpx;
border-radius: 0 25rpx 25rpx 0;
.title {
view {
// color: #005CC5;
// width: 100%;
// padding: 50rpx 20rpx;
// text-align: center;
// font-size: 30rpx;
// position: relative;
text-align: center;
font-size: 30rpx;
color: #888888;
width: 100%;
padding: 55rpx 30rpx;
position: relative;
&:before {
position: absolute;
content: '';
width: 0;
height: 0;
border-right: 6rpx solid $mxg-color-primary;
border-radius: 30rpx;
left: 0;
top: 50%;
transform: translateY(-50%);
transition: 0.3s;
}
}
.active {
color: $mxg-color-primary;
font-size: 33rpx;
font-weight: bold;
&:before {
height: 50rpx;
}
}
}
}
.right {
background-color: #FFFFFF;
padding-left: 20rpx;
margin: 0; //全屏铺满的效果
.tag {
display: flex; //指定flex布局
flex-wrap: wrap; //自动换行
padding-top: 35rpx;
padding-left: 10rpx;
view {
font-size: 25rpx;
line-height: 60rpx;
border: 1px solid #999;
border-radius: 30rpx;
min-width: 160rpx;
text-align: center;
padding: 0 5rpx;
margin: 15rpx 5rpx;
}
}
}
}
</style>
downBar页面引入的category 组件,绑定传入的数据,
<category v-if="item.isCategory" :value='item' @searchByLabel="searchByLabel"></category>
父传子,向子函数传入参数,
:value='item'
category 中异步请求数据的方法,如果父组件传递了参数,则每行添加一个“不限”按钮,添加一个“全部分类”的总标签
async getList() {
const res = await api.getCategoryList()
this.categoryList = res.data
console.log("查询分类的标签", res.data)
//如果传递的数据不为空,则添加一个全部分类的按钮
if (this.value) {
//针对每一个分离下的标签列表,添加一个不限的按钮
this.categoryList.forEach((item) => {
// 添加不限按钮,并且把左边主列表的Id和name赋值给他
item.labelList.unshift({
id: null,
name: "不限",
cname: item.name,
categoryId: item.id
})
})
this.activeIndex = this.value.activeIndex > -1 ? this.value.activeIndex + 1 : this.activeIndex
this.categoryList.unshift({
id: null,
name: '全部分类'
})
}
// 获取当前的标签列表
this.getLable(this.activeIndex)
},
searchPageChangeValue这个方法是判断点击的对比,并赋值,然后传递给父组件, @searchByLabel=“searchByLabel”
// 弹框选择标签
searchPageChangeValue(item) {
// console.log(item)
// 将上一次点击的名称和这次点击的对比,如果相同则不重复执行
if (this.value.name !== item.name && this.value.name !== item.cname) {
// 如果这条数据中有cname则是不限,没有则是普通的name
this.value.name = item.cname || item.name
// 标签ID
this.value.id = item.id || null
//分类ID点击的是不限则取分类ID
this.value.categoryId = item.categoryId || null
this.$emit("searchByLabel", this.value)
}
this.value.active = false
}