基于vue组件传值实现电影榜单页

前言

组件传值

(1)父传子

  1. 在父组件中给子组件标签绑定属性,属性值为要传递的值。
  2. 在子组件中,通过props选项接收传递的属性,然后就可以直接使用了。

(2)子传父

子组件到父组件的通信,要借助Vue实例的$emit方法,也是需要分成两步:

  1. 在子组件中,需要$emit发送时间(.$emit(自定义事件名,参数,……))
  2. 父组件中,在子组件的标签上写监听,绑定它$emit的事件

(3)同级互传

  1. 在Vue的原型上新增一个属性 $bus,值为 新的Vue实例
  2. 在A组件中通过 this.$bus.$emit('自定义事件', 参数) 发射同级接收的电波
  3. 在B组件中通过 this.$bus.$on('事件名', 处理函数) 接收电波

实现过程

1.准备

(1)新建项目:vue create创建项目后在App.vue中引入MoviePage组件,再新建views文件夹存放电影页面,如下:

MoviePage组件中导入其余ListCom,MaskCom,PageCom,TabsCom组件,并使用对应组件标签。

(2)封装请求;新建request文件夹,存放http.js和index.js。http.js中是封装的axios请求,index.js是导入axios请求后,封装了getMovie和getDetail函数向后端发送请求。再导出两个函数。

2.导航栏

导航栏由三个按钮组成,如下图,要实现点击切换状态,需要在父组件MoviePage中先将type值传给子组件,再在按钮上绑定点击事件,并使用$emit将对应的type值传给父组件。在父组件中监听type值的变化,type变化向后台发送请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   <!-- 子组件部分代码
<button :class="{act:type=='in_theaters'}" @click='changeType("in_theaters")'>正在热映</button>
<button :class="{act:type=='coming_soon'}" @click='changeType("coming_soon")'>即将上映</button>
<button :class="{act:type=='top250'}" @click='changeType("top250")'>top250</button>
-->
// methods: {
// changeType(str){
// // 子传父
// console.log(str);
// this.$emit("update:type",str)
// }
// },
//父组件
<!-- <TabsCom :type.sync="type"></TabsCom> -->
//watch: {
// type: {
// immediate: true,
// handler() {
// console.log("type值变化了");
// this.getMovieLs();
// },
// },
//}

3.分页栏

分页栏包括页码和分页选择器。

(1)在父组件MoviePage中把分页参数page:{start:1,limit:10}页码总数total传到子组件PageCom中,再使用列表项渲染页码数据,使用v-model将page.limit绑定给分页器,因为传入的page参数是对象,所以子组件修改父组件传过来的值可以直接修改,不需要使用$emit也可以把更新后的数据同步到父组件中。

同时父组件中也对page设置监听,当页码改变时也会发送请求。

1
2
3
4
5
6
7
8
page:{
// 深度监听
deep:true,
handler(){
console.log('page值变化了');
this.getMovieLs();
}
}

(2)实现点击时给页码添加act类名,是在点击时将被点击到的页码的内容参数赋给start值,代表从第几页开始,当start值等于内容i的时候,就添加上act类名。

1
2
3
4
5
6
7
8
9
10
<ul class="page">
<li
v-for="i in total"
:key="i"
:class="{ act: page.start == i }"
@click="page.start = i"
>
{{ i }}
</li>
</ul>

4.列表项

列表项包括电影的图片和基本信息。

父组件MoviePage将movieList电影列表项的数据传递给子组件ListCom,子组件中使用v-for循环渲染列表项。给电影图片添加加载失败事件,图片加载不出时显示默认图片。

1
2
3
4
5
6
<!-- <img :src="item.medium" alt="" @error='loading'>
// methods: {
// loading(e){
// e.target.src='https://webilife.com/wp-content/uploads/2020/05/404.jpg'
// }
// },

5.遮罩层

实现点击电影列表,弹出电影简介遮罩层,需要在电影列表项中绑定点击事件,点击时将列表项的mId值传递给同级组件MaskCom

1
2
3
4
5
//<li @click="tellMask(item.mId)"> </li>
// // 通知遮罩层 - 同级传递
// tellMask(mId){
// this.$bus.$emit('open', mId)
// }

在遮罩层设置监听器,使用v-if将遮罩层设置为显示,并通过mId获取到电影列表项的简介渲染在页面上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   <!-- 
//只点击阴影部分才关闭遮罩
<div class="mask" v-show="isShow" @click.self="isShow = false">
<div class="mask-content">
<div class="loading" v-if="isLoading">loading ....</div>
<div v-else>
<p>名称:{{ info.title }}</p>
<p>简介:{{ info.summary }}</p>
</div>
</div>
</div>
-->
// mounted() {
// // 一进来就设定监听器,监听list的点击事件
// this.$bus.$on('open', mId => {
// this.isShow = true;
// this.isLoading = true;
// this.getInfo(mId)
// })
// },
//methods: {
// async getInfo(mId){
// let res = await getDetail(mId);
// this.isLoading = false;
// this.info = res.data;
// }
// },