Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于Vue自定义组件实现 #31

Closed
unsad opened this issue May 14, 2019 · 10 comments
Closed

关于Vue自定义组件实现 #31

unsad opened this issue May 14, 2019 · 10 comments

Comments

@unsad
Copy link

unsad commented May 14, 2019

#20 因为在这个issue中看到Vue自定义组件正在开发中,我希望能将这套方案用到Vue项目中,请问下实现方案是用Vue重写了核心机制还是有一套Vue转React组件的实现呢?

@2betop
Copy link
Collaborator

2betop commented May 14, 2019

应该是这样的方式, React 还是底层,Vue 组件在 React 的 didMount 中实例化出来,并打通通信。

@2betop
Copy link
Collaborator

2betop commented May 14, 2019

@RickCole21 可以来详细说一下

@RickCole21
Copy link
Contributor

RickCole21 commented May 16, 2019

新的自定义组件核心还是React组件,可以参考以下的思路:

1. 在 React 中创建 Vue 的实例

import * as Vue from 'vue/dist/vue';  // 注意这里要引同时包含编译器和运行时的完整版本
import {Renderer} from '../factory' //  根据自定义组件的需求自行选择渲染器,Renderer、FormItem或者OptionsControl

@Renderer({
    test: /(^|\/)hello\-vue$/
})
class VueComponent extends React.PureComponent<any>{
    vm: any;

    constructor(props: any) {
        super(props);
        this.domRef = React.createRef();
    }

    componentDidMount() {

        // DidMount的时候实例化Vue
        this.vm = new Vue({
            el: '#dom',
            template: '<div>Hello {{name}}</div>',
            data() {
                return {
                    name: 'Vue'
                };
            }
        });
        this.domRef.current.appendChild(this.vm.$mount().$el);
    }

    componentWillUnmount() {
        this.vm.$destroy();
    }

    render() {
        return (
            <div ref={this.domRef}></div>
        );
    }
}

2. 打通和 amis 的通信

大部分情况应该是会编写基于FormItem或者OptionsControl的表单组件,那么amisVue之间的通信不可避免,分两个方向

vue -> amis

在实例化Vue后,通过$on监听当前实例上的自定义事件,例如:

// 这里的this.props.onChange是amis暴露出来的方法,可以修改表单项的值
this.vm.$on('change', (value: any) => this.props.onChange(value));

监听之后在Vue实例中就可以这样使用

 this.$emit('change', '新的value');

amis -> vue

有时候amis数据的变化,也需要通知到Vue组件中,例如给OptionsControl配置source动态拉取数据时,拉取到options需要通知给Vue组件进行更新

但是由于Vue的限制,你需要在实例化的时候声明所有响应式属性,所以在实例化Vue组件之前,将 amispropsVue组件的 data merge一下,方便后续的通信,例如:

let amisData = {};
Object.keys(this.props).forEach(key => {
    const value = this.props[key];
    typeof value !== 'function' && (amisData[key] = value);
});
this.vm = new Vue({
    data() {
        return Object.assign(amisData, {
            name: 'Vue'
        });
    }
});

之后在componentDidUpdate,直接通过this.vm更新数据就可以了

componentDidUpdate() {
    Object.keys(this.props).forEach(key =>
        // 过滤掉function
        typeof this.props[key] !== 'function' && (this.vm[key] = this.props[key]);
    );
}

@qdsang
Copy link

qdsang commented Aug 7, 2019

@2betop 不考虑直接出个全vue版本吗?

@2betop
Copy link
Collaborator

2betop commented Aug 7, 2019

不考虑,这成本得多大!!

@qdsang
Copy link

qdsang commented Aug 7, 2019

https://elemefe.github.io/element-react/
他们家怎么做到了?

现在新业务很少会选 React 做后台了吧,基本都是Webpack+Vue做基础

@2betop
Copy link
Collaborator

2betop commented Aug 7, 2019

这是json renderer 不是 ui 库,用什么底层无所谓

@Niqian
Copy link

Niqian commented Aug 29, 2022

关于vue组件的问题,能不出一个完整的demo,从自定义组件的开发打包到实际在vue项目中运用,对于前端基础差的同学们真的是很有必要的,谢谢了

@guanyue-leo
Copy link
Contributor

我的方法:

import Vue from 'vue'
import VueComponent from './VueComponent '
let React = amisRequire('react')
let amisLib = amisRequire('amis')

function CustomComponent(props) {
  let dom = React.useRef(null)
  React.useEffect(function () {
    const vm = new Vue({...VueComponent , propsData: props})
    dom.current.appendChild(vm.$mount().$el)
  })
  return React.createElement('div', {
    ref: dom
  })
}

// 注意test为组件名
amisLib.Renderer({
  test: /(^|\/)vue-component/
})(CustomComponent)

@jwxhhxx
Copy link

jwxhhxx commented Mar 8, 2023

我的方法:

import Vue from 'vue'
import VueComponent from './VueComponent '
let React = amisRequire('react')
let amisLib = amisRequire('amis')

function CustomComponent(props) {
  let dom = React.useRef(null)
  React.useEffect(function () {
    const vm = new Vue({...VueComponent , propsData: props})
    dom.current.appendChild(vm.$mount().$el)
  })
  return React.createElement('div', {
    ref: dom
  })
}

// 注意test为组件名
amisLib.Renderer({
  test: /(^|\/)vue-component/
})(CustomComponent)

请问这个amis怎传数据给vue组件呢

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants