web端平常开发常常会遇到各类弹层需求,弹层内容千奇百怪。根据咱们平常的组件化开发经验,咱们会把弹层分为2个组件vue
蒙版
, 展现隐藏
逻辑import CitySelect from './components/CitySelect'; import modal from '@/components/modal'; ... openCitySelect() { modal.popup({ content: CitySelect, props: { data, onSave: () => {...} } }); } ...
这种用法的好处是显而易见的react
调用方
与CitySelect
都不须要维护一个visible
变量调用方
与CitySelect
模块分离更加清晰,调用方
只须要触发一次openCitySelect
,以后就和弹层再无关系,CitySelect
只关心自身逻辑不须要关心弹层的状态。下面来看此api在vue
和react
上面的实现web
vue下面实现此api
的方法较多,可使用dom操做
, 动态组件
, render函数
来实现。咱们以动态组件
为例:api
<template> <div class="container" v-show="visible"> <div class="mask"></div> <component :is="currentView" v-if="currentView" ref="comp" :v-bind="propsData"></component> </div> </template> <script> const Popup = { props: { title: { type: String, default: '提示' }, propsData: { type: Object }, currentView: { type: Object }, }, data () { return { visible: false } }, mounted () { // 建立后直接打开 this.$nextTick(this.open) }, methods: { open () { this.visible = true; }, close () { this.visible = false; // 移除元素 if (this.$el.parentNode) { this.$el.parentNode.removeChild(this.$el) } } } } export default { popup({ content, title, props }) { let Comp = Vue.extend(Popup); let instance = new Comp({ propsData: { propsData: props, currentView: content, title } }).$mount(); document.appendChild(instance.$el); } }; </script>
React实现须要配合react-dom
,rn的话能够在app入口加一个常驻弹窗容器来实现,原理大体相同。
这里仍是以web端为例,代码直接从ant
抄过来的。app
// 弹窗组件 class Popup extends Component { componentDidMount() { } render() { const { close, props = {}, visible = false, } = this.props; if (!visible) { return null; } const DlgContent = content; return ( <Router> <Provider {...store}> <div className={styles.container}> <div className="mask"></div> <DlgContent close={close} {...props} /> </div> </Provider> </Router> ) } } // 方法 const popup = function(config) { const div = document.createElement('div'); document.body.appendChild(div); let currentConfig = { ...config, visible: true, close }; function close(...args) { currentConfig = { ...currentConfig, visible: false }; render(currentConfig); setTimeout(destroy, 100); } function destroy() { const unmountResult = ReactDOM.unmountComponentAtNode(div); if (unmountResult && div.parentNode) { div.parentNode.removeChild(div); } } function render(config) { ReactDOM.render(<Popup {...config} />, div); } render(currentConfig); return { destroy: close }; }; const modal = { popup } ; export default modal;
因为弹窗是咱们手动new
出来的,并无包含在入口的jsx引用中,因此相似router
,store
,locale
这些Provider
须要手动从新包装下,这样才能像页面同样使用相关功能dom