@@ -5,6 +5,8 @@ import applyReactInVue from './applyReactInVue'
5
5
import vueRootInfo from './vueRootInfo'
6
6
import { reactRouterInfo , setReactRouterInVue , updateReactRouterInVue } from './applyReactRouterInVue'
7
7
import globalOptions , { setOptions } from './options'
8
+ import ReactDOM from "react-dom" ;
9
+ import { MountingPortal } from 'portal-vue'
8
10
9
11
const unsafePrefix = parseFloat ( version ) >= 17 ? 'UNSAFE_' : ''
10
12
const optionsName = 'vuereact-combined-options'
@@ -82,9 +84,9 @@ class VueComponentLoader extends React.Component {
82
84
this . vueComponentContainer = this . createVueComponentContainer ( )
83
85
}
84
86
85
- pushPortal ( portal ) {
87
+ pushReactPortal ( reactPortal ) {
86
88
const { portals } = this . state
87
- portals . push ( portal )
89
+ portals . push ( reactPortal )
88
90
this . setState ( { portals } )
89
91
}
90
92
@@ -128,6 +130,13 @@ class VueComponentLoader extends React.Component {
128
130
}
129
131
130
132
componentWillUnmount ( ) {
133
+ // 删除portal
134
+ if ( this . vuePortal ) {
135
+ const { portals } = this . parentVueWrapperRef
136
+ const index = portals . indexOf ( this . vuePortal )
137
+ portals . splice ( index , 1 )
138
+ return
139
+ }
131
140
this . vueInstance . $destroy ( )
132
141
}
133
142
@@ -228,14 +237,25 @@ class VueComponentLoader extends React.Component {
228
237
}
229
238
return scopedSlots
230
239
}
240
+
241
+ function setVueInstance ( instance ) {
242
+ if ( ! this . vueInstance ) {
243
+ this . vueInstance = instance
244
+ }
245
+ }
246
+ setVueInstance = setVueInstance . bind ( this )
231
247
// 将vue组件的inheritAttrs设置为false,以便组件可以顺利拿到任何类型的attrs
232
248
// 这一步不确定是否多余,但是vue默认是true,导致属性如果是函数,又不在props中,会出警告,正常都需要在组件内部自己去设置false
233
249
// component.inheritAttrs = false
234
- // 创建vue实例
235
- this . vueInstance = new Vue ( {
250
+ const vueOptionsData = { ... this . doSync ( this . doVModel ( props ) ) , 'data-passed-props' : __passedProps }
251
+ const vueOptions = {
236
252
...vueRootInfo ,
237
- el : targetElement ,
238
- data : { ...this . doSync ( this . doVModel ( props ) ) , 'data-passed-props' : __passedProps } ,
253
+ data ( ) {
254
+ return vueOptionsData
255
+ } ,
256
+ created ( ) {
257
+ setVueInstance ( this )
258
+ } ,
239
259
methods : {
240
260
// 获取具名插槽
241
261
// 将react组件传入的$slots属性逐个转成vue组件,但是透传的插槽不做处理
@@ -397,23 +417,58 @@ class VueComponentLoader extends React.Component {
397
417
// 这一步有点繁琐,但是又必须得处理
398
418
const attrs = filterAttrs ( { ...lastProps } )
399
419
return createElement (
400
- 'use_vue_wrapper' ,
401
- {
402
- props : lastProps ,
403
- on : lastOn ,
404
- nativeOn,
405
- attrs,
406
- 'class' : className ,
407
- style,
408
- scopedSlots : { ...scopedSlots }
409
- } ,
410
- lastSlots
420
+ 'use_vue_wrapper' ,
421
+ {
422
+ props : lastProps ,
423
+ on : lastOn ,
424
+ nativeOn,
425
+ attrs,
426
+ 'class' : className ,
427
+ style,
428
+ scopedSlots : { ...scopedSlots }
429
+ } ,
430
+ lastSlots
411
431
)
412
432
} ,
413
433
components : {
414
434
'use_vue_wrapper' : component
415
435
}
436
+ }
437
+
438
+ if ( ! targetElement ) return
439
+
440
+ Vue . nextTick ( ( ) => {
441
+ const targetId = '__vue_wrapper_container_' + ( Math . random ( ) + '' ) . substr ( 2 )
442
+ targetElement . id = targetId
443
+ let parentInstance = this . _reactInternals . return
444
+ let vueWrapperRef
445
+ // 向上查找react包囊层
446
+ while ( parentInstance ) {
447
+ if ( parentInstance . stateNode ?. parentVueWrapperRef ) {
448
+ vueWrapperRef = parentInstance . stateNode . parentVueWrapperRef
449
+ break
450
+ }
451
+ if ( parentInstance . stateNode ?. vueWrapperRef ) {
452
+ vueWrapperRef = parentInstance . stateNode . vueWrapperRef
453
+ break
454
+ }
455
+ parentInstance = parentInstance . return
456
+ }
457
+ // 如果存在包囊层,则激活portal
458
+ if ( vueWrapperRef ) {
459
+ // 存储包囊层引用
460
+ this . parentVueWrapperRef = vueWrapperRef
461
+ // 存储portal引用
462
+ this . vuePortal = ( createElement , key ) => createElement ( MountingPortal , { props : { mountTo : '#' + targetId , slim :true , targetSlim : true } , key} , [ createElement ( vueOptions ) ] )
463
+ vueWrapperRef . pushVuePortal ( this . vuePortal )
464
+ return
465
+ }
466
+
467
+
468
+ // 创建vue实例
469
+ this . vueInstance = new Vue ( { ...vueOptions , el : targetElement } )
416
470
} )
471
+
417
472
}
418
473
419
474
updateVueComponent ( nextComponent ) {
0 commit comments