用过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])