antvis / X6

🚀 JavaScript diagramming library that uses SVG and HTML for rendering.
https://x6.antv.antgroup.com
MIT License
5.7k stars 1.7k forks source link

关于vue2使用teleport解决i18n国际化的问题 #4310

Open fengxiaodong28 opened 5 months ago

fengxiaodong28 commented 5 months ago

问题描述

https://github.com/antvis/X6/issues/1864 中遇到同样的场景

但是vue2版本的,如何使用teleport解决问题?

重现链接

重现步骤

预期行为

vue2版本中可以正常使用i18n

平台

屏幕截图或视频(可选)

No response

补充说明(可选)

No response

x6-bot[bot] commented 5 months ago

👋 @fengxiaodong28

Thanks for opening your first issue here! If you're reporting a 🐞 bug, please make sure you include steps to reproduce it. To help make it easier for us to investigate your issue, please follow the contributing guidelines. We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can.

lloydzhou commented 5 months ago

使用 https://www.npmjs.com/package/vue2-teleport 改写一下 https://github.com/antvis/X6/blob/master/packages/x6-vue-shape/src/teleport.ts 或许可以

lloydzhou commented 5 months ago

如果觉得改写 x6-vue-shape有难度,可以参考https://github.com/lloydzhou/x6-html-shape写一个 vue2-teleport的版本,这个改起来比较简单。

fengxiaodong28 commented 4 months ago

@lloydzhou 我这里试着改了一下,但是Object.keys(items)拿到的总是个空数组

import { h, reactive, markRaw } from '@vue/composition-api';
import { Fragment } from 'vue-fragment';
import Teleport from 'vue2-teleport';
import type { Graph } from '@antv/x6';
import type { VueShape } from '@antv/x6-vue-shape';
import Vue, { type VueConstructor } from 'vue';

let active = false;
const items = reactive<{ [key: string]: VueConstructor<Vue> }>({});

export function connect(id: string, component: VueConstructor<Vue>, node: VueShape, graph: Graph) {
    if (active) {
        // eslint-disable-next-line vue/one-component-per-file
        const vm = Vue.extend({
            provide: () => ({
                getNode: () => node,
                getGraph: () => graph
            }),
            render: () =>
                h(
                    Teleport,
                    {
                        attrs: {
                            to: '#test-teleport' // 测试
                        }
                    },
                    [
                        h(component, {
                            props: {
                                node,
                                graph
                            }
                        })
                    ]
                )
        });
        items[id] = markRaw(vm);
    }
}

export function disconnect(id: string) {
    if (active) {
        delete items[id];
    }
}

export function isGraphActive() {
    return active;
}

function getVNodes(): Promise<VNode[]> {
    return new Promise(resolve => {
        const VNodes = Object.keys(items).map(id => h(items[id]));
        resolve(VNodes);
    });
}

export async function getTeleport(): Promise<VueConstructor<Vue>> {
    active = true;

    const VNodes = await getVNodes();

    return new Promise(resolve => {
        // eslint-disable-next-line vue/one-component-per-file
        const vm = Vue.extend({
            render: () => h(Fragment, {}, VNodes)
        });
        resolve(vm);
    });
}
fengxiaodong28 commented 4 months ago

@lloydzhou 另外这里好像不需要自己connet了,因为可以直接拿到shapeMaps ,值和items是一样的,不过在Object.kyes时也是个空的

import  { shapeMaps } from '@antv/x6-vue-shape'

export async function getTeleport(): Promise<VueConstructor<Vue>> {
    return new Promise(resolve => {
        const vm = Vue.extend({
            render: () => h(Fragment, {}, Object.keys(shapeMaps).map(id => h(shapeMaps[id])))
        });
        resolve(vm);
    });
}
lloydzhou commented 4 months ago

shapeMaps不是vue里面的reactive的变量,只是一个常量。所以在vue里面使用的时候,如果值变化了,组件并不会更新

fengxiaodong28 commented 4 months ago

@lloydzhou 嗯嗯,后面还是用的items,但是没啥效果,渲染不到teleport上

chenp1204 commented 2 months ago

@fengxiaodong28 楼主的问题解决了嘛 请问最终是怎么实现的 我也遇到同样的问题

chenp1204 commented 2 months ago

找到了个比较偏门的方法 可以把问题解决 大概如下

/* 此处手动将i18n挂载到_i18n上, 因为在antv x6的自定义vue节点组件上使用国际化无法获取到this.$i18n导致无法国际化, 通过vue-i18n的源码得知,this.$i18n通过Vue.defineProperty定义且仅定义了get访问器, 所以无法直接将i81n赋值给Vue.prototype.$i18n, 通过源码进一步得知this.$i18n在内部通过this._i18n获取国际化对象,所以直接将i18n赋值给_i18n, 此处暂时可解决antv x6自定义vue节点无法国际化问题

特别注意:此处使用了vue-i18n包的内部变量_i18n,防止升级i18n后废弃该变量导致问题 */ Vue.prototype._i18n = i18n;