在开发中经常遇到关于子父组件之间传值和方法调用的问题,因此将上述两种方式结合作为例子记录下来。
功能需求:
通过切换左侧侧边栏(以下简称left),右侧对应显示相关内容(以下简称right)
?实现效果:
实现思路:
将left和right分别封装为自定义组件,left切换时调用change事件,将id值传回父页面,再由父页面调用right中获取列表的方法
代码片段:
left.vue
<template>
<div class="left-content">
<ul :class="{nesting: nesting}">
<li v-for="item in list" :key="item.id" :class="{active: item.id === activeId}" @click="changeTab(item.id)">
{{item.name}}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'left',
props: ['nesting'],
data(){
return{
list: [
{name: '文章', id: 1},
{name: '海报', id: 2},
{name: '视频', id: 3},
{name: '早报', id: 4},
{name: '素材', id: 5},
{name: '宣传册', id: 6},
{name: '文件', id: 7},
],
activeId: 1
}
},
methods: {
//切换侧边栏
changeTab(id){
this.activeId = id
//将值返回父页面,父页面中@func为自定义方法
this.$emit('func',this.activeId)
}
}
}
</script>
<style lang="scss" scoped>
ul{
padding: 0;
margin: 0;
height: 100vh;
overflow: auto;
&.nesting{
height: calc(100vh - 0.5rem);
}
li{
list-style: none;
padding: 0.1rem;
text-align: center;
font-size: 0.14rem;
position: relative;
&:before{
content: '';
display: inline-block;
width: 0.04rem;
height: 0.16rem;
border-radius: 0.02rem;
position: absolute;
top: 0.1rem;
left: 0.04rem;
}
&.active{
color: $main;
&:before{
background-color: $main;
}
}
}
}
</style>
index.vue
<template>
<div class="marking">
<div class="left">
<left v-bind="$attrs" @func="getContentType"></left>
</div>
<div class="right">
<right v-bind="$attrs" ref="rightDiv"></right>
</div>
</div>
</template>
<script>
import left from './module/left'
import right from './module/right'
export default ({
name: 'Marketing',
data(){
return{
contentType: 1
}
},
methods:{
getContentType(data){
this.contentType = data
this.$refs.rightDiv.parentHandleclick(this.contentType);
}
},
components: {
left,
right
},
created(){
}
})
</script>
<style lang="scss" scoped>
.marking{
display: flex;
.left{
width: 0.8rem;
overflow: auto;
border-right: 0.01rem solid $borderColor;
}
.right{
flex: 1;
widows: calc(100vh - 0.8rem);
overflow: auto;
}
}
</style>
right.vue
<template>
<div class="right-content">
<div class="top flex itemsCenter justifyBetween">
<span class="title">企业文库</span>
<el-input placeholder="请输入内容" v-model="searchText" class="input-with-select">
<el-button slot="append" icon="el-icon-search" @click="searchFun"></el-button>
</el-input>
</div>
<div :class="['content-list', {nesting: nesting}]">
<div class="item" v-for="(item, index) in dataList" :key="index">
<div class="flex itemsCenter justifyBetween" v-if="item.type === 2">
<video class="video" preload="auto" controls src="http://account.tanmarket.cn/fdfsServer/group1/M00/1D/49.mp4"></video>
</div>
<div class="flex itemsCenter justifyBetween" v-else>
<img src="" alt="">
<div class="info">
<div class="item-title two-line">{{item.contentName}}</div>
<div class="time">{{item.createTime}}</div>
</div>
</div>
<div class="btns flex itemsCenter justifyBetween">
<el-button @click="detailPop = true">查看详情</el-button>
<el-button>分享链接</el-button>
</div>
</div>
</div>
<detail-pop :detailPop.sync="detailPop"></detail-pop>
</div>
</template>
<script>
import DetailPop from './DetailPop'
import {getMarketContentList} from '@/api/marketing'
export default {
name: 'right',
props: ['nesting'],
data(){
return{
contentType:1,
siteID: 1,
dataList:[],
searchText: '',
detailPop: false
}
},
components: {
DetailPop
},
created () {
this.getMarketContentList()
},
methods: {
parentHandleclick(val) {
//父页面调用子组件方法
this.contentType = val
this.getMarketContentList()
},
getMarketContentList(){
getMarketContentList({
siteID: this.siteID,
contentType: this.contentType,
pageNo: 1,
pageSize: 5,
}).then(res => {
this.dataList = res.data.datas
})
},
searchFun(){
}
}
}
</script>
<style lang="scss" scoped>
.right-content{
.top{
padding: 0.1rem;
box-shadow: 0 0.03rem 0.03rem $borderColor;
.el-input{
width: 1.8rem
}
}
.title{
display: inline-block;
padding-right: 0.2rem;
white-space: nowrap;
}
}
.content-list{
height: calc(100vh - 0.5rem);
overflow: auto;
padding: 0 0.1rem 0.1rem 0.1rem;
box-sizing: border-box;
&.nesting{
height: calc(100vh - 1rem);
}
.item{
border: 0.01rem solid $borderColor;
padding: 0.1rem;
margin-top: 0.1rem;
border-radius: 0.04rem;
box-shadow: 0 0 0.05rem $borderColor;
img{
width: 0.5rem;
height: 0.5rem;
margin-right: 0.1rem;
}
.info{
width: 2rem;
}
.item-title{
font-size: 0.14rem;
}
.time{
margin-top: 0.04rem;
font-size: 0.12rem;
color: $gray;
}
.btns{
margin-top: 0.1rem;
}
}
.video{
background-color: $borderColor;
border-radius: 0.04rem;
width: 100%;
height: 1rem;
object-fit: contain;
}
}
</style>
|