vue3 動態將組件當作dom插入到3d模型指定的位置下!!!


這個近期做three.js  項目有這種需求,需要將一個組件插入到 css2dobject 生產的 2d標簽下實現自定義標簽的效果。

 

 大概就是這種效果。

 

最終尋求到的方案有兩種:

// method 1


** mount.js **
import { createVNode, render } from 'vue'

export const mount = (component, { props, children, element, app } = {}) => {
    let el = element

    let vNode = createVNode(component, props, children)
    if (app && app._context) vNode.appContext = app._context
    if (el) render(vNode, el)
    else if (typeof document !== 'undefined' ) render(vNode, el = document.createElement('div'))

    const destroy = () => {
        if (el) render(null, el)
        el = null
        vNode = null
    }

    return { vNode, destroy, el }
}

** useage **
/**+
tagDiv:  待插入的組件
div: 帶插入的組件的目標div
root: 當前頁面的 vue根組件實例
*/

    
const { el, vNode, destory } = mount(tagDiv, {
    props: { // 傳入到組件中的props
        resData: tableData.value 
    },
    element: div,
    app: root
});

// 結果是 可以將組件插入到div中,但是有局限性,就是插入的組件內無法識別對象和響應式數據

,如圖,會被直接當成文本,搞不懂, 將只有純文本的組件插入顯示是ok的,插值表達式,插槽props object  都不會被識別。。。

 

//method 2

/**

*/
// renderComponent.js
import { createApp } from 'vue'

export default function renderComponent({ el, component, props, appContext }) {
  let app = createApp(component, props)
  Object.assign(app._context, appContext) // must use Object.assign on _context
  app.mount(el)

  return () => {
    // destroy app/component
    app?.unmount()
    app = undefined
  }
}

// usage
<script setup>
import { ref, onUnmounted, getCurrentInstance } from 'vue'
import renderComponent from '@/data/renderCom.js'

const { appContext } = getCurrentInstance() // 這個appContext 是當前根組件上下文?  官網沒找到說明
const container = ref()
let counter = 1
let destroyComp = null

onUnmounted(() => destroyComp?.())

const insert = async () => {
  destroyComp?.()
  destroyComp = renderComponent({
    el: container.value, //  組件要插入的那個dom
    component: (await import('@/components/HelloWorld.vue')).default, // 要插入的組件
    props: { // 傳入 props
      key: counter,
      msg: 'Message ' + counter++,
      test: [{name: 'testpropsaaa'}]
    },
    appContext, // 獲取組件實例的 
  })
}
</script>

<template>
  <button @click="insert">Insert component</button>
  <div ref="container"></div>
</template>

 這種方式 插入的組件都是 ok的  nice!!!

附上效果圖:

 

這里是以 div 承載 el-table 結合 three.js  實現的效果

 

2022年3月7日16:14:02 補充

由於客戶需求是這里的數據是實時的,這里就需要重新發請求后,先刪除之前的組件,在重復上述的動態添加。 這里之所以不去組件中發請求是因為每個table組件中的數據都是通過 props傳過去的,如果要在table組件中發送請求,需要做一些額外的處理,比如數據過濾啥的,雖然不麻煩,加上這個實時功能做好了,補充這個博文才想到如何在組件中發請求,就還是在外面發了。

 

 

如何去動態刪除上面動態添加的組件:

// renderComponent.js
import { createApp } from 'vue'

export default function renderComponent({ el, component, props, appContext }) {
  let app = createApp(component, props)
  Object.assign(app._context, appContext) // must use Object.assign on _context
  app.mount(el)

  return () => { 
     app?.unmount();
app = undefined
}
}
//  可以看到renderComponent 這里返回的一個方法, 可以看到 明顯是移除掛載的意思,所以就好辦了
// destroy 

  

let destroyComp = ref([]); //定義數組 接收renderComponent 返回值,至於要定義為數組是因為不只一個table組件,要全部移除的話就需要每個table組件的實例都執行這個方法

    destroyComp.value.push( // vue3 寫法,將每個table 組件實例所對應的unmount方法存入數組
      renderComponent({
        // renderComponent 返回一個函數,調用這個函數可以移除動態添加的組件!!!
        el: div,
        component: (await import("@/components/tagDiv.vue")).default,
        props: {
          resData: [v],
        },
        appContext,
      })
    );



// 遍歷destroyComp ,執行unmount方法
    destroyComp.value.forEach((v) => {
      v();
      destroyComp.value.unshift(); // 執行一次就推出一個
    });

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM