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