05月26, 2021

Vue实战(八)-- 组件之间的通信

八、组件之间的通信

父组件向子组件传递值:通过props属性,具体参看

Vue实战(四)-- Vue 组件

子组件向父组件传递值:通过this.$emit("事件名","值")事件传值

示例:将子组件中的频道id(channelId)传递到父组件中

Channels组件

<template>
  <div> 
    <el-menu
      :default-active="activeIndex"
      class="el-menu-demo"
      mode="horizontal"
      @select="handleSelect"
    >
      <el-menu-item :index="i.toString()
      " v-for="(item,i) in showChannels" :key="item.channelId"
      @click="changeChannel(item.channelId)"
      >{{item.name}}</el-menu-item>
      <el-menu-item><a @click="handleFold()">{{isFold?"折叠":"展开"}}</a></el-menu-item>
    </el-menu>
  </div>
</template>

<script>
import {getNewsChannels} from '../services/NewsService'
export default {
  data() {
    return {
      chooseId:"",
      activeIndex:"0",
      isFold:false,
      channels:[],
    };
  },
  methods: {
    handleFold(){
      this.isFold = !this.isFold;
    },
    handleSelect(key, keyPath) {
      console.log(key, keyPath);
    },
    changeChannel(channelId){
      console.log("子组件页面---->" + channelId);
      this.chooseId = channelId;
      //给组件注册change事件,并传递this.chooseId
      this.$emit("change",this.chooseId);
    }
  },
  computed:{
    showChannels(){
      if(this.isFold){ //如果没有折叠显示全部数据
        return this.channels;
      }
      else{ //如果折叠显示6条新闻频道数据
        return this.channels.slice(0,6);
      }

    },
  },
  async created() {
    let resp = await getNewsChannels();
    console.log("axios获取的远程数据格式--->" + resp);
    this.channels = resp;
    //调用changeChannel方法,目的是页面出现就传递ChannelId
    this.changeChannel(this.chooseId);
  },
};
</script>

<style></style>

相对于之前的代码,这段代码主要下面的方法

changeChannel(channelId){
      console.log("子组件页面---->" + channelId);
      this.chooseId = channelId;
      //给组件注册change事件,并传递this.chooseId
      this.$emit("change",this.chooseId);
}

this.$emit("change",this.chooseId); 就是将change事件注册给子组件,那么父页面在调用子组件的时候,就需要调用@change事件

父组件App.vue

<template>
  <div id="app">
    <el-container>
      <el-header>

      </el-header>
      <el-main>
        <!-- 调用子组件,并且调用子组件的change事件 -->
        <Channels @change="handleChange"></Channels>
      </el-main>
    </el-container>
  </div>
</template>

<script>
import Channels from "./components/Channels";
export default {
  name: "App",
  methods: {
    handleChange(chooseId){
      console.log("主页面---->" + chooseId);
    }
  },  
  components: { Channels },
};
</script>

<style>
.el-header,
.el-footer {
  color: #333;
  text-align: center;
  line-height: 60px;
}

.el-aside {
  color: #333;
  text-align: center;
  line-height: 200px;
}

.el-main {
  color: #333;
  text-align: center;
}
</style>

相对于之前的代码,主要也是多了一个方法

handleChange(chooseId){
  console.log("主页面---->" + chooseId);
}

这个方法主要用于子组件事件的调用

<Header @change="handleChange"></Header>

handleChange方法里面的参数chooseId,会由子组件传递过来

显示新闻列表

父组件中已经获取了频道id,那么,我们可以通过这个频道id,获取这个频道下所有的新闻列表

当然,先做好基本的测试,写好service获取远程API数据

可以到阿里云中先观察必须的API,然后封装我们自己的方法 https://market.aliyun.com/products/57126001/cmapi011150.html?spm=5176.2020520132.101.1.ee2e1a46tkPOsZ#sku=yuncode515000003

获取新闻列表的Service方法

export async function getNewsList(channelId,page=1,limit=10){
    let resp = await axios.get("http://ali-news.showapi.com/newsList",{
        headers:{
            Authorization:`APPCODE 176eadd6b4654cd5a9328c74a9025c37`
        },
        params:{
            channelId,
            page,
            maxResult:limit,
            needAllList:false,
            needContent:1
        }
    });
    return resp.data.showapi_res_body.pagebean;
}

创建显示新闻列表的组件NewList

<template>
<div>
  <div class="news-item-normal" v-for="(item) in news" :key="item.id">
    <div class="words">
      <h1 class="title">
        <a :href="item.link">{{item.title}}</a>
      </h1>
      <div class="aside">
        <span>{{item.channelName}}</span>
        <span>{{item.source}}</span>
        <span>{{item.pubDate}}</span>
      </div>
      <div class="content">
        {{item.content}}
      </div>
    </div>
  </div>
</div>
</template>

<script>
import {getNewsChannels,getNewsList} from '@/services/NewsService'


export default {
  data() {
    return {
      news:[],
    }
  },
  async created() {
    var resp = await getNewsList("5572a108b3cdc86cf39001cd");
    console.log(resp.contentlist);
    this.news = resp.contentlist;
  },
}
</script>

<style scoped>
.news-item-normal {
  border-bottom: 1px solid #ccc;
  overflow: hidden;
  padding: 20px 0;
}
.image {
  width: 150px;
  height: 150px;
  border: 1px solid #ccc;
  border-radius: 4px;
  float: left;
  margin-right: 20px;
}
.image img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.title {
  font-size: 1.5em;
}
.aside {
  font-size: 14px;
  color: #888;
}
.aside span {
  margin-right: 15px;
}

.content {
  max-height: 100px;
  overflow: hidden;
  line-height: 2;
}
</style>

当然,接下来就需要在App.vue中加入NewList.vue组件即可

<template>
  <div id="app">
    <el-container>
      <el-header>
        <!-- 调用子组件,并且调用子组件的change事件 -->
        <Header @change="handleChange"></Header>
      </el-header>
      <el-main>
        <NewList></NewList>
      </el-main>
    </el-container>
  </div>
</template>

<script>
import Header from "./components/Header";
import NewList from "./components/NewList";

export default {
  name: "App",
  methods: {
    handleChange(chooseId){
      console.log("主页面---->" + chooseId);
    }
  },  
  components: { Header,NewList },

};
</script>

<style>
...省略
</style>

传递频道id

上面的新闻列表组件写了一个固定的频道id,现在需要点哪个频道,就显示哪个频道的新闻列表,需要将频道id传递过来,改写新闻列表页面,传递频道id,当然,也能在父页面直接获取频道列表,然后直接传递频道列表数组过来

修改App.vue

<template>
  <div id="app">
    <el-container>
      <el-header>
        <!-- 调用子组件,并且调用子组件的change事件 -->
        <Header @change="handleChange"></Header>
      </el-header>
      <el-main>
        <!-- 调用子组件,传递新闻列表数组 -->
        <NewList :news="news"></NewList>
      </el-main>
    </el-container>
  </div>
</template>

<script>
import Header from "./components/Header";
import NewList from "./components/NewList";
import { getNewsList } from './services/NewsService';

export default {
  name: "App",
  components: { Header,NewList },
  data(){
    return {
      chooseId:0,
      news:[],
    } 
  },
  methods: {
    async handleChange(chooseId){ //切换频道的时候传递频道id并调用远程数据
      this.chooseId = chooseId;
      console.log("主页面---->" + chooseId);
      let resp = await getNewsList(this.chooseId);
      this.news = resp.contentlist;
    }
  },  
};
</script>

<style>
...省略
</style>

修改NewList.vue页面

<template>
...省略
</template>

<script>
export default {
  props:{
    news:{
      type:Array,
      default:function(){return [];}
    }
  }
}
</script>

<style scoped>
...省略
</style>

当然现在这个样子,必须界面要点击新闻频道的名字,才会显示下面的新闻列表,并没有一开始就直接显示新闻列表。这是因为我们只是和点击事件绑定了channelId的传递,还应该在一开是created() Channels组件的时候,就应该传递channelId Channels.vue

...省略其他代码
async created() {
    let resp = await getNewsChannels();
    this.channels = resp;
    //调用changeChannel方法,目的是页面出现就传递ChannelId
    this.changeChannel(this.chooseId);
},

本文链接:http://www.yanhongzhi.com/post/VueInAction-8.html

-- EOF --

Comments