element-ui 的 Switch 组件封装异步实现

需求场景

近期需求中,要做一个列表。列表中每项数据会有一个快捷启用禁用入口。
clipboard.png

目前,项目使用的是 element-ui,里边有 Switch 组件,画界面是非常容易的。

问题

大概的逻辑是:用户点击这个 Switch 组件后,会发送一个请求。请求获得正确结果后,再切换 Switch 组件的状态。
其中一种场景:用户会快速连续点击这个 Switch 组件,这样请求就会连续被发送。
还一种场景:请求结果是异常的,状态不应该被改变。

思考和方案

第一个问题处理方式可以是:发送一个请求的时候,吧这个请求缓存起来,如果请求发送成功,再把这个缓存值清空。每次发请求之前都检查这个缓存值是否为空。如果缓存值存在,就取消上一次的请求。
还一种方法:添加一个disable的状态,发送请求前把 Switch 组件变成 disable 状态,请求发送有结果后,再把组件变成正常状态。
第二个问题:element-ui 中其实要变更当前 Switch 按钮状态就是改变绑定值就可以了。但是我们再一个数据条数不确定的列表中,并不合适去手动设定一个可控的绑定值。所以需要有一个作用域来控制变更单个 Switch 组件的状态。所以想到了再次封装 Switch 组件。

实现与编码

首先,确认我们组件要传入:

  • val: 当前状态
  • reqUrl: 改变状态 接口url
  • id: 标识这个状态的id 要传数据的 值
  • idName: 改变状态要传的数据字段名

其次,我们再组建中创建一个变量,来绑定改组件的值。在创建这个组件的时候,把传进来的状态赋值给组件内的变量值。这样就实现了局部控制。同时,用了一个 isDisabled 变量来控制组件的可用状态。
当然,用了禁用方案,就不会怕用户连续发送变更组件状态了,所以检测请求重复就取消上一个请求的操作是多余的。不过这里既然讲了,就再组件中写了实现的方法。
封装后的组件源码如下:

<template>
  <div>
    <el-switch
            :value="value"
            @change="changeStatus"
            active-color="#13ce66" :disabled="isDisabled"
            inactive-color="#ff4949">
    </el-switch>
  </div>
</template>

<script>
  /**
   * val: 当前状态
   * reqUrl: 改变状态 接口url
   * id: 标识这个状态的id 要传数据的 值
   * idName: 改变状态要传的数据字段名
   * */
  export default {
    name:'switchItem',
    props:[
      'val',
      'reqUrl',
      'id',
      'idName',
    ],
    data() {
      return {
        value:false,
        setStatusHttp: null,
        isDisabled: false,
      }
    },
    created() {
      let self = this;
      self.value = self.val
    },
    methods:{
      changeStatus(){
        let self = this;
        self.isDisabled=true
        self.setStatus()
      },
      // setStatus
      setStatus(){
        let self = this;
        if (!self.setStatusHttp) {    // 判断是否已经有请求正在发送
          self.setStatusHttpReq();
        } else {
          // abort 正在发送的请求 然后再次发送请求
          self.setStatusHttpReq();
        }
      },
      setStatusHttpReq(){
        let self = this;
        let CancelToken = self.$http.CancelToken
        let postData = {}
        postData[self.idName] = self.id
        self.$http.post(self.reqUrl,postData,{
          cancelToken: new CancelToken(function executor(c) {
            // An executor function receives a cancel function as a parameter
            self.setStatusHttp = c;
          })
        }).then(res => {
          if(res.data.error_code == '00000'){
            self.$message({
              type: 'success',
              message: '操作成功!'
            });
            self.value = !self.value
          }else{
            self.$message({
              type: 'error',
              message: res.data.message
            });
          }
          self.isDisabled=false
        })
      },
    }
  }
</script>

总结

当一个列表中,某个组件需要一个局部作用域来操作或者控制一些状态的的时候,可以对该组件再次进行封装,这样就会有一个组件的作用域,再这个作用域里边,我们就可以做一些骚操作来实现特殊场景的需求了。

阅读 2.1k

推荐阅读
79px
用户专栏

前端开发

6 人关注
21 篇文章
专栏主页