最近写了一个开源项目,有些地方需要二次封装,需要透传一些数据,需要注意的是ref
,我这里使用俩种方式间接传递ref
,具体如下:
使用:
import VideoPlayer from './index.js'
Vue.use(VideoPlayer)
index.js
:因为是Vue 2.7 老项目,所以这里用Vue.extend
构造函数构造组件这里和 Vue3
不太一样,Vue3
要用 defineComponent
创建组件支持hook
式和选项式,废弃了Vue.extend()
,这里属性继承用$attrs
, 事件用 $listeners
(Vue3
不需要,在attrs
里面),插槽这里固定指定了一个ocr
作用域插槽,refs
后面说
import Player from "video-player"
import OcrResult from "@/components/ocrResult"
import Vue from "vue"
let P = Vue.extend({
data() {
return {
isEnableOcr: true, // 是否启用ocr
isEnableWaterMarker: true, // 是否启动水印
waterMarkerContent: '水印' // 水印内容
}
},
template: `
<Player
ref="player"
v-bind="$attrs"
v-on="$listeners"
:isEnableOcr="isEnableOcr"
:isEnableWaterMarker="isEnableWaterMarker"
:waterMarkerContent="waterMarkerContent">
<template v-if="isEnableOcr" #ocr="{ show_ocr, curPlayTime, cancel }">
<ocrResult
v-model="show_ocr"
:curPlayTime="curPlayTime * 1000"
@cancel="cancel"/>
</template>
</Player >`,
})
export default {
install(Vue) {
Vue.component('VideoPlayer', VideoPlayer)
}
}
这里如果涉及到多个slot
插槽,利用#[name]
动态插槽,scope
返回作用域插槽数据:
<template v-for="(_, name) in $slots" #[name]="scope">
<slot :name="name" v-bind="scope"></slot>
</template>
这里涉及到 refs
,因为 refs``Vue
没有做处理,不想 react
有 forwardRef
,我的处理方式,提前已知组件暴露出什么数据,遍历获取,反之全部遍历获取:
// 透传ref属性,这里劫持下,不然会报错
let attributes = ['_register_emits', 'current', 'duration']
attributes.forEach(key => {
Object.defineProperty(this, key, {
get() {
return Reflect.get(this.$refs.player, key, this)
},
set(v) {
throw new Error('Not Allow!')
}
})
})
// for (let key in this.$refs.player) {
// this[key] = this.$refs.player[key]
// }
还有一种方式,利用render
函数渲染 vnode
,这样做少去了编译过程,Vue
拿到节点compire
为 AST
,进而打标记最后生成render
函数,render
函数渲染时当前利用Vue.extend()
生成的组件实例会自动绑定this
,而template
不会这么做
render(h) {
let scopedSlots = {}
if (this.isEnableOcr) {
scopedSlots.ocr = ({ show_ocr, curPlayTime, cancel }) => {
return h(ocrResult, {
props: {
value: show_ocr,
curPlayTime: curPlayTime * 1000
},
on: {
input: (val) => { show_ocr = val; },
cancel
}
});
};
}
return h(Player, {
attrs: this.$attrs,
on: this.$listeners, // 添加 $listeners
props: {
isEnableOcr: this.isEnableOcr,
isEnableWaterMarker: this.isEnableWaterMarker,
waterMarkerContent: this.waterMarkerContent
},
scopedSlots
})
}