vue转发ref总结--自研

本文介绍了一种在Vue中实现高阶组件转发ref的方法,通过构造代理组件并使用自定义函数bindRef来实现对BaseComponent的真实引用转发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用过react都知道转发ref是一件很容易的事情
但是对于vue来说,封装高阶组件很难转发ref,官方并没有开放转发的api以及实现方法
下面是转换的方法

<script  type="text/jsx">
    import ElementUI from 'element-ui'

    /**
     * 此组件只为element-ui 的Upload组件作增强处理(默认了数据行为)
     * @param BaseComponent
     * @returns {{mounted(): void, render(*): *, props: *}|*}
     * @constructor
     */
    function XKUploadWapper(BaseComponent) {
      return {
          props: {
              ...BaseComponent.props,
              //appKey
              appKey: {
                  default: 'XKES',
                  type: String,
                  required: false
              },
              //上传路径
              action: {
                  default: process.env.UPLOAD_URL,
                  type: String,
                  required: false
              },
              //上传的路径
              packageName: {
                  default: '',
                  type: String,
                  required: false
              },
              //文件名称
              name: {
                  default: 'Fdata',
                  type: String,
                  required: false
              },
              //额外的参数
              data: {
                  default: function () {
                      return {}
                  },
                  type: Object | Array,
                  required: false
              }
          },
          mounted(){
              //挂载后再转发ref
              bindRef(this._self,this._self.$children[0])
          },
          //methods,
          render(h) {
              // 将 this.$slots 格式化为数组,因为 h 函数第三个参数是子节点,是一个数组
              const slots = Object.keys(this.$slots)
                  .reduce((arr, key) => arr.concat(this.$slots[key]), [])
                  // 手动更正 context
                  .map(vnode => {
                      vnode.context = this._self //绑定到高阶组件上(默认 子组件找的是父组件)
                      return vnode
                  })
              let $props = this.$props;
              //额外参数
              Object.assign($props.data, {packageName: $props.packageName})
              //请求头
              Object.assign($props.headers, {appkey: $props.appKey})

              return h(BaseComponent, {
                  on: this.$listeners,
                  attrs: this.$attrs,
                  props: $props,
                  // 透传 scopedSlots
                  scopedSlots: this.$scopedSlots,
              }, slots) // 将 slots 作为 h 函数的第三个参数;
          }
      }
    }

    /**
     * 为vue绑定真实的ref,转发ref到BaseComponent
     * @param target 当前高阶组件真实实例
     * @param componnet 转发到指定的组件
     */
    function bindRef(target,componnet) {
        let $refs = target.$parent.$refs;
        if ($refs){
            Object.keys($refs).forEach(key=>{
                if ($refs[key]===target){
                    $refs[key]=componnet
                }
            })
        }
    }

    export default XKUploadWapper(ElementUI.Upload)

</script>



经过包装后的组件返回的是porxy代理后的对象,获取源对象this._self即可,
父组件的$refs[ref名称]就是this._self,替换即可

 function bindRef(target,componnet) {
        let $refs = target.$parent.$refs;
        if ($refs){
            Object.keys($refs).forEach(key=>{
                if ($refs[key]===target){
                    $refs[key]=componnet
                }
            })
        }
    }
  //挂载后再转发ref
   bindRef(this._self,this._self.$children[0])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值