起源
闲着无聊该干嘛, 当然是造轮子玩.
写代码的时候, 要时常归纳总结, 什么是合适的解决方式, 什么是通用的逻辑很重要. 在 Vue 里,弹窗这个功能一般由第三方的组件库实现,
通常来说, 要使用一个弹窗, 我们需要写出如下代码
<template>
<!-- antdv -->
<a-modal>
<div class="content"></div>
</a-modal>
</template>
基本上, 都需要在模板内定义好弹窗的内容, 用起来总是觉得不顺手,所以想着自己实现一个不需要在 template 定义的弹窗插件
需求
先讲需求,从使用者的角度思考,自己想要的到底是怎样的调用方式
import Content from './Content.vue';
export default {
mounted() {
this.popup({
component: Content,
props: {},
onclose: () => {},
})
}
}
导入弹窗的内容, 通过函数调用, 传入被弹出的内容组件, 组件的props参数, 以及关闭弹窗时的回调函数, 大致上这些功能可以满足大部分使用场景的需求 有了需求和调用形式, 就如同有了解题的突破口, 有些新手觉得前端难学, 其实就是难在边界情况, 新人很难掌摸清技术的边界, 不能确定哪些功能能做, 哪些功能不能做, 这也是一个熟能生巧的过程, 在经历大量代码编写后, 自然就不会再有这样的问题
切入点
- 调用时使用的是
this调用,显然需要挂载到Vue的原型下 - 为了渲染组件, 需要用到
Vue来构造一个组件, 并挂载到指定的dom下 - 为了不丢失上下文, 可将
this作为parent传入子组件 - 自定义一些
css样式, 让弹窗看上去确实像弹窗
const state = {
Vue: null,
store: null,
router: null
}
const plugin = {
popup(options) {
const { component } = options;
const div = document.createElement('div');
div.innerHTML = `<div class="popup-bg"></div><div class="popup-content"></div>`
div.className = 'popup';
const basicStyle = {
position: 'absolute',
width: '100%',
height: '100%',
left: 0,
top: 0
}
Object.assign(div.style, basicStyle, {
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
});
const bg = div.querySelector('.popup-bg')
Object.assign(bg.style, basicStyle, {
backgroundColor: 'rgba(0,0,0,0.2)'
});
document.body.appendChild(div);
if (options.props) {
options.props.parent = this;
} else {
options.props = {
parent: this
}
}
const content = div.querySelector('.popup-content')
new state.Vue({
store: state.store,
router: state.router,
render(h) {
return h(component, {
props: options.props,
})
}
}).$mount(content)
},
install (Vue, options = {}) {
state.Vue = Vue;
state.store = options.store;
state.router = options.router;
Vue.prototype.$popup = this.popup;
}
}
export default plugin
小结
上述示例代码只是一个极其基础的弹窗功能, 简陋到无法正常使用, 选择的vue版本也是已经过时了的Vue2, 但是一法通则万法通, 并且已经初具雏形, 可以根据自己的需求进行增删, 似乎又是一个没什么用的玩具