背景
在前端开发中,组件封装已经成为工作当中不可或缺的一部分,但是很多时候,我们封装好的组件只能满足在某一特定框架下使用,一旦有别的框架想要接入使用我们封装好的组件,我们通常需要重新写一套可以适配的组件提供出去。那么如何才能更大程度的利用我们已有的组件,也是一个值得大家讨论的问题。
已有解决方式
1、iframe
iframe的优缺点很明显,其中最重要的就是跨域cookie同步问题,有需要的可以参考iframe内页面cookie同步解决方案。
2、web-components
web-components是谷歌公司近几年推出的原生组件解决方案,其最大的问题在于浏览器兼容性问题。
3、vuera等工具
vuera等一定程度上可以满足我们的需求,但是其种类繁多,且各个框架有各自的工具,使用成本较高。
通过挂载的方式解决
例如我们想开发以下这样一个时钟组件,并要求其可以在react框架以外也可以使用:
step1: 正常开发组件
import {Button} from "antd";
import moment from 'moment';
import PropTypes from "prop-types";
// 正常开发组件
class MoreComp extends React.Component {
constructor(props) {
super(props);
this.interId = null
this.state = {
time: null
}
}
static propTypes = {
lable: PropTypes.string
};
static defaultProps = {
lable: "当前时间为"
}
componentDidMount() {
this.interId = setInterval(() => {
this.setState({
time: moment().format('YYYY-MM-DD h:mm:ss')
})
}, 1000)
}
handleCancel() {
this.interId && clearInterval(this.interId);
}
render() {
const {lable} = this.props;
const {time} = this.state;
return (
<div>
{time && <span>{`${lable}: ${time}`}</span>}
<Button onClick={() => this.handleCancel()} type="primary">停止</Button>
</div>
);
}
}
export default MoreComp;
step2: 测试没有问题以后,对组件进行改造
import { Button } from "antd";
import moment from "moment";
import PropTypes from "prop-types";
// 正常开发组件
class MoreComp extends React.Component {
constructor(props) {
super(props);
this.interId = null;
this.state = {
time: null,
};
}
static propTypes = {
lable: PropTypes.string,
};
static defaultProps = {
lable: "当前时间为",
};
componentDidMount() {
this.interId = setInterval(() => {
this.setState({
time: moment().format("YYYY-MM-DD h:mm:ss"),
});
}, 1000);
}
handleCancel() {
this.interId && clearInterval(this.interId);
this.props.handleCancel();
}
render() {
const { lable } = this.props;
const { time } = this.state;
return (
<div>
{time && <span>{`${lable}: ${time}`}</span>}
<Button onClick={() => this.handleCancel()} type="primary">
停止
</Button>
</div>
);
}
}
window.moreComp = function (domId, props) {
let dom = document.getElementById(domId);
if (dom) {
ReactDOM.render(<MoreComp {...props} />, dom);
}
}
// export default MoreComp;
step3: 打包组件
step4: 在VUE项目中使用组件
// 使用方式
<template>
<div class="wrapper">
<div class="tips">this is a demo for using React component in VUE </div>
<div id="moreComp"></div>
</div>
</template>
<script>
import renderComp from "./renderComp.js"
export default {
data() {
return {};
},
mounted() {
console.log(this.handleCancel)
renderComp("moreComp", "http://localhost:4000/more-comp/cdn/index.js", {lable: "this is a clock that could be stoped", handleCancel: this.handleCancel});
},
methods: {
handleCancel(){
console.log(this)
}
}
};
</script>
<style scoped>
.wrapper {
margin: 0 auto;
}
.tips {
height: 100px;
line-height: 100px;
font-weight: bold;
font-size: 22px
}
#moreComp {
height: 100px;
width: 500px;
text-align: "center";
border: solid 1px #eee;
line-height: 100px;
padding-left: 10px;
}
</style>
// renderComp.js
function renderComp(id, src, props) {
let script = document.createElement("script");
script.type = "text/javascript";
script.src = src;
script.onload = script.onreadystatechange = function() {
if (script.ready) {
return false;
}
if (
!script.readyState ||
script.readyState == "loaded" ||
script.readyState == "complete"
) {
console.log(id, props);
moreComp(id, props)
}
};
document.body.appendChild(script);
}
export default renderComp;
总结:
用类似的方式可以实现该组件在HTML文件、React项目、Angular项目中使用组件。另外,为了不影响打包后的组件在React项目中的正常使用,还应该在设计的时候更加精细,且调用方法过于繁琐,可以考虑封装成独立的方法,用来简化使用流程。