基于如下平常代码,我们可以发现,两个按钮逻辑中,有很多重复代码(开启loding,关闭loding),并且正式项目中会有很多按钮会发送请求   
< template> < el-button@click = " test" :loading = " loading" type = " primary" > </ el-button> < el-button@click = " test" :loading = " loading22" type = " primary" > </ el-button> </ template> < scriptsetup > 
import  {  ref }  from  "vue" ; 
const  loading1 =  ref ( false ) ; 
const  loading2 =  ref ( false ) ; 
function  test ( )  { 
  loading1. value =  true ; 
  try  { 
    fetch ( "http://localhost:8888/getUser?userName=''" ) 
      . then ( ( res )  =>  { 
        return  res. json ( ) ; 
      } ) 
      . then ( ( res )  =>  { 
        console. log ( res) ; 
      } ) ; 
  }  finally  { 
    loading1. value =  false ; 
  } 
} 
function  test ( )  { 
  loading2. value =  true ; 
  try  { 
    fetch ( "http://localhost:8888/getUser2?userName=" ) 
      . then ( ( res )  =>  { 
        return  res. json ( ) ; 
      } ) 
      . then ( ( res )  =>  { 
        console. log ( res) ; 
      } ) ; 
  }  finally  { 
    loading2. value =  false ; 
  } 
} 
 </ script>  
  
  
< template> < el-button:loading = " loading" v-bind = " $attrs" @click = " handleClick" > < slot> </ slot> </ el-button> </ template> < scriptsetup > 
import  {  ref,  useAttrs }  from  "vue" ; 
const  loading =  ref ( false ) ; 
const  attrs =  useAttrs ( ) ; 
const  {  onClick }  =  defineProps ( { 
  onClick:  Function, 
} ) ; 
async  function  handleClick ( )  { 
  console. log ( "click" ) ; 
  loading. value =  true ; 
  try  { 
    
    await  onClick?. ( ) ; 
  }  finally  { 
    loading. value =  false ; 
  } 
} 
 </ script> < template> < MyLoadingBtn@click = " test" type = " primary" > </ MyLoadingBtn> </ template> < scriptsetup > 
import  {  ref }  from  "vue" ; 
import  MyLoadingBtn from  "./components/MyLoadingBtn.vue" ; 
async  function  test ( )  { 
  await  fetch ( "http://localhost:8888/getUser?userName=" ) 
    . then ( ( res )  =>  { 
      return  res. json ( ) ; 
    } ) 
    . then ( ( res )  =>  { 
      console. log ( res) ; 
    } ) 
    . catch ( ( err )  =>  { 
      console. log ( err) ; 
    } ) ; 
} 
 </ script> 
 
 
 Vue2中和Vue3中逻辑基本一致,不过要稍微麻烦一点因为Vue2中父组件传递的所有方法,并不会一起放到$attrs中,而是会放到$listeners中 ,使用不了**在props中声明, 
       
        
         
         
           a 
          
         
           t 
          
         
           t 
          
         
           r 
          
         
           s 
          
         
           对象中不存在的特性 
          
         
           ∗ 
          
         
           ∗ 
          
         
           ,那么我们就需要对 
          
         
           ‘ 
          
         
        
          attrs对象中不存在的特性**,那么我们就需要对` 
         
        
       a tt rs 对象中不存在的特性 ∗ ∗ ,那么我们就需要对 ‘ 对象单独处理一下再绑定到v-on=“xxx”`中 如果不处理$listeners.click函数的话,那么父组件绑定的点击事件函数就会调用两遍!!   
< template> < el-button:loading = " loading" v-bind = " $attrs" v-on = " listeners" @click = " handleClick" > < slot> </ slot> </ el-button> </ template> < script> 
export  default  { 
  name:  "MyLoadingBtn" , 
  data ( )  { 
    return  { 
      loading:  false , 
    } ; 
  } , 
  computed:  { 
    
    listeners ( )  { 
      const  copy =  {  ... this . $listeners } ; 
      delete  copy. click; 
      return  copy; 
    } , 
  } , 
  methods:  { 
    async  handleClick ( )  { 
      console. log ( "click" ) ; 
      const  fun =  this . $listeners; 
      this . loading =  true ; 
      try  { 
        
        await  fun. click?. ( ) ; 
      }  finally  { 
        this . loading =  false ; 
      } 
    } , 
  } , 
} ; 
 </ script> < template> < divclass = " test1" > < MyLoadingBtntype = " primary" @click = " handleClick" > </ MyLoadingBtn> </ div> </ template> < script> 
import  MyLoadingBtn from  "@/components/MyLoadingBtn.vue" ; 
export  default  { 
  components:  { 
    MyLoadingBtn, 
  } , 
  methods:  { 
    async  handleClick ( )  { 
      await  fetch ( "http://localhost:8888/getUser?userName=" ) 
        . then ( ( res )  =>  { 
          return  res. json ( ) ; 
        } ) 
        . then ( ( res )  =>  { 
          console. log ( res) ; 
        } ) ; 
    } , 
  } , 
} ; 
 </ script>