影城项目 DAY02

目录

1.Vue的事件修饰符

   1.1在vue中,为标签绑定事件的方式:

   1.2  .native的作用

2.实现新增演员页面相关业务

3..实现导演模块相关页面功能

4.实现演员与导演的删除

5.Vue中自定义组件的自定义事件(子向父传参)

6.封装 Axios

7.Axios的封装的设计实现流程


1.Vue的事件修饰符

1.1在vue中,为标签绑定事件的方式:

<div id="bb" @click="clickbb">
    <div id="ez" @click="clickez"></div>
</div>
<input @keyup="">
<form @submit=""></form>

在上述事件的处理函数中,可能需要:阻止事件冒泡、阻止浏览器默认行为、获取按键键值等需求。这些需求都要在事件处理函数中依靠事件对象(event)来实现。

vue认为:事件处理函数内部应该更多的聚焦在业务功能的实现上,而不是这些琐碎的事件对象的处理。所以vue提供了很多事件修饰符来帮助简化这些代码:

<div id="bb" @click="clickbb">
    <div id="ez" @click.stop="clickez"></div>
</div>
<input @keyup.enter="">
<form @submit.prevent=""></form>

1.2 .native的作用

native事件修饰符的作用是:将当前绑定的事件当做是html原生事件来看待。

<input @keyup="">   keyup为dom原生事件:按键抬起时触发
<el-input @keyup=""> keyup将被理解为elinput的自定义事件,何时被触发由组件决定
    
<el-input @keyup.native="">  将keyup当做dom原生事件来看待

所以,以后为自定义组件绑定原生事件时,长个心眼,一般都会加一个.native修饰符来告诉vue,这是一个原生事件:

<el-input @keyup.native=""></el-input>
<el-button @click.native=""></el-button>
<el-input @blur.native=""></el-input>

2.实现新增演员页面相关业务

业务需求: 点击侧边栏菜单:新增演员,看到新增演员的表单。填写表单点击提交,将演员的数据添加到数据库,提示添加成功,重置表单即可。el-upload在element有现成代码可供使用。

实现步骤:

  1. 准备好ActorAdd.vue的静态表单页面。做好表单验证。

  2. 基于el-uploader组件实现头像的上传,上传成功后,将会获取服务端返回的头像访问地址,保存起来。

  3. 点击提交按钮后,收集表单的数据,做好验证,发送post请求,成功添加后提示消息。

  4. 做好表单验证。

    1. 焦点失去的表单验证。

    2. 点击提交时的表单验证。

   <!-- 表单 -->
  <el-form ref="form" :model="form" :rules="rules" label-width="100px" style="width:600px;">
    <el-form-item label="演员姓名" prop="actorName">
    <el-input v-model="form.actorName" placeholder="请输入姓名"/>
    </el-form-item>
    <el-form-item label="演员头像" prop="actorAvatar">
      <el-upload
  class="avatar-uploader"
  :action="`${UPLOADURL}/upload`"
  :show-file-list="false"
  :on-success="handleAvatarSuccess"
  :before-upload="beforeAvatarUpload">
  <img v-if="form.actorAvatar" :src="form.actorAvatar" class="avatar">
  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
   //上传成功后执行
      handleAvatarSuccess(res, file) {
        console.log('上传成功',res)
        this.form.actorAvatar = res.data
      },
      //上传之前执行:格式 大小的验证 该方法需要返回true 或者  fasle
      //ture:通过验证可以上传
      //false:验证不通过,不可上传
      beforeAvatarUpload(file) {
        const isJPG = file.type === 'image/jpeg';
        const isPNG = file.type === 'image/png';
        const isLt2M = file.size / 1024 / 1024 < 2;

        if (!isJPG & !isPNG) {
          this.$message.error('上传头像图片只能是 JPG / PNG格式!');
        }
        if (!isLt2M) {
          this.$message.error('上传头像图片大小不能超过 2MB!');
        }
        return (isJPG || isPNG) && isLt2M;
      }
    }

3.实现导演模块相关页面功能(抄演员模块)

  1. 实现导演列表页面

    与演员列表页面功能雷同。不一样的是需要访问不同的接口:

    加载导演列表: http://localhost:3010/movie-directors?page=1&pagesize=100

    模糊加载导演列表: http://localhost:3010/movie-directors/name?name=关键字

  2. 实现新增导演页面

    上传文件接口一样 http://localhost:9000/upload

    新增导演接口:http://localhost:3010/movie-director/add POST

实现步骤:

  1. 将ActorList.vue与ActorAdd.vue,复制到src/director目录下

    改名为:DirectorList.vue,DirectorAdd.vue。

  2. 把两个文件中的代码进行单词的替换:

    演员 --> 导演

    actor --> director

    Actor --> Director

  3. 配置嵌套路由即可。

4.实现演员与导演的删除

上图可说明,每次点击叉子时,都会触发事件,在Person组件中就需要执行删除业务;但是在Person中并不能确定发送删除演员请求,还是删除导演请求,在事件处理函数中将两种业务都实现也不现实。应该如何去做?

在子组件捕获到叉子被点击后,不应该直接发请求,而是把该事件抛出,抛给父组件执行后续业务。逻辑如下图所示:

 person.vue

<template>
  <div class="person">
    <img :src="avatar" width="100px" :title="name">
    <div>{{ name }}</div>
    <i @click="clickx" class="el-icon-circle-close"></i>
  </div>
</template>

<script>
  export default {
    methods: {
    
    clickx() {  // 点击叉子之后执行
      // 手动抛出一个自定义事件,通知父组件用户点了叉子
      },
    },

actorList.vue

 methods: {
    
      deleteActor(id,e){
          // console.log('捕获到用户点了叉子...', id)
      // 执行删除演员业务,发送删除请求
        this.$confirm('是否移除该演员?','提示',{
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type:'warning'
        }).then(res=>{
         
          httpApi.actorApi.delete({id}).then(res=>{
            if(res.data.code==200){
              console.log('删除',id)
              this.search()
            }
          })
        })

5.Vue中自定义组件的自定义事件(子向父传参)

实现细节如下:

父组件使用子组件时可以捕获子组件的自定义事件:

ActorList.vue

<person @delete="deleteEvent($event)"></person>
deleteEvent(e){
    // 当父组件捕获到person子组件抛出的delete事件后自动调用
    // 执行删除操作即可
    //e 就是子组件抛出来的参数
}

子组件在发现达到某些时间点时,主动抛出delete事件即可:

clickX(){
    // 主动抛出一个事件,让父组件捕获
    this.$emit('delete', {a:100, b:20})
}

同一个页面由很多组件组成,有些是父子组件;有些是爷孙组件;有些是兄弟组件;当这些组件之间需要共享数据时,就涉及到了组件间传参的问题。

  1. 父子组件传参

    1. 父向子传参 使用自定义属性。<person :name="参数">

    2. 子向父传参 使用自定义事件。 <person @delete="deletePerson($event)">

爷孙组件传参

  1. 可以使用provide与inject配套完成爷孙组件传参。

6.封装 Axios

当前业务中使用Axios发送请求时API的设计弊端:

每次发请求,都需要写url的前缀,写的还都一样。但是前缀应该分为两种:

测试环境下:
http://localhost:3010/     业务模块请求前缀
http://localhost:9000/     上传文件请求前缀
生产环境下:
https://web.codeboy.com/bmdapi/     	  业务模块请求前缀
https://web.codeboy.com/bmduploadapi/     上传文件请求前缀
  1. 测试环境下:
    http://localhost:3010/     业务模块请求前缀
    http://localhost:9000/     上传文件请求前缀
    生产环境下:
    https://web.codeboy.com/bmdapi/           业务模块请求前缀
    https://web.codeboy.com/bmduploadapi/     上传文件请求前缀

    现阶段的写法如果要切换生产环境与测试环境的url前缀时,非常麻烦。

  2. 如果在项目中有多个地方都需要发送相同类型的请求(例如:查询演员列表),那么每次发送请求时,都需要使用相应的url、请求参数发送(地址不好记,每次都得查接口文档),更恶心的是,如果领导修改了接口,那么所有使用该接口的地方都需要改一遍,非常麻烦。

  3.  

7.Axios的封装的设计实现流程

  1. 解决每次发请求都需要重复的写请求路径的问题。

    在src/http目录中新建一个index.js,将发送请求的方法写在里面并导出对象即可。

// src/http/index.js
import myaxios from "./MyAxios";

const httpApi = {  // 封装http接口

  /**
   * 根据关键字模糊查询演员列表
   * @param {Object} params  请求参数  {name:关键字}
   * @returns Promise
   */
  queryActorsByName(params){
    let url = "http://localhost:3010/movie-actors/name"
    return myaxios.post(url, params)
  },

  /** 查询所有演员 */
  queryAllActors(){  
    let url = "http://localhost:3010/movie-actors"
    return myaxios.get(url, {page:1, pagesize:100})
  }
}

export default httpApi;

 需要的使用,引入该index.js,调用导出对象中的方法即可。

listActorsByName(){ // 通过关键字查询演员列表
    httpApi.queryActorsByName({name:this.name}).then(res=>{
        this.actors = res.data.data
    })
}

listActors() {  // 加载默认的首页演员列表
    httpApi.queryAllActors().then(res=>{
        this.actors = res.data.data
    })
}

2.当解决了上述问题后,又发现了httpApi对象中需要定义所有的请求接口方法,导致httpApi对象臃肿不堪,方法繁杂,所有接口的访问方法阿都在这一个对象里。需要进一步封装:按照业务模块将API拆分开来,把相应Api方法放入单独的Api模块文件中:

httpApi.actorApi.queryAllActors()
httpApi.directorApi.add()
httpApi.cinemaApi.queryAll()

实现思路:

  1. 为每一个业务模块准备子接口模块文件:

    src/http/apis/ActorApi.js  存放所有演员模块相关的接口方法
    src/http/apis/DirectorApi.js    存放所有导演模块相关的接口方法
    src/http/apis/MovieApi.js    存放所有电影模块相关的接口方法
    ......

    2.在相应的子模块文件中声明相关接口:

    // src/http/apis/ActorApi.js
    import myaxios from "../MyAxios";
    
    const actorApi = {  // 封装http接口
      /**
       * 根据关键字模糊查询演员列表
       * @param {Object} params  请求参数  {name:关键字}
       * @returns Promise
       */
      queryActorsByName(params){
        let url = "http://localhost:3010/movie-actors/name"
        return myaxios.post(url, params)
      },
    
      /** 查询所有演员 */
      queryAllActors(){  
        let url = "http://localhost:3010/movie-actors"
        return myaxios.get(url, {page:1, pagesize:100})
      }
    }
    
    export default actorApi;

    3.重构index.js,index.js的功能将成为所有子模块的入口:

    // src/http/index.js
    import actorApi from "./apis/ActorApi";
    
    const httpApi = {  // 封装http接口
      actorApi
    }
    
    export default httpApi;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值