实现原理:
- 方式一:通过
vue.extend
实现 - 方式二:通过
new Vue()
实现,本例采用该方法实现,比较简单,即新实例化一个vue对象,单独操作它。其实就是动态创建一个Vue实例对象。
代码实现
<!-- components/pop-share/pop-share.vue --> <template> <!-- 最外层需要一个透明遮罩,监听点击事件 --> <div class="mo-mask" :style="{ 'z-index': zIndex }" @click="handleClose"> <transition name="el-fade-in-linear"> <div class="pop-share" :style="style" @click.stop="handleClick"> <div data-value="select" class="pop-share__item"> <i class="el-icon-share"></i>选中分享 </div> <div data-value="all" class="pop-share__item"> <i class="el-icon-share"></i>全部分享 </div> <div data-value="work-weixin" class="pop-share__item"> <i class="el-icon-position"></i>发送到企业微信 </div> <div data-value="search" class="pop-share__item"> <i class="el-icon-search"></i>搜索 </div> </div> </transition> </div> </template> <script> // created at 2022-06-21 export default { name: 'pop-share', // 接收参数中可以定义需要接收的参数 props: { top: { type: Number | String, default: 0 }, left: { type: Number | String, default: 0 }, // 点击事件回调 onItemClick: { type: Function, default: null } }, components: {}, data() { return { zIndex: 0 }; }, computed: { style() { return { top: this.top + 'px', left: this.left + 'px' }; } }, methods: { async getData() {}, handleClick(e) { if (e.target.dataset.value) { if (this.onItemClick) { this.onItemClick({ value: e.target.dataset.value }); } this.handleClose(); } }, handleClose(e) { this.$parent.handleClose(); }, // js获取当前窗口最大z-index getMaxZIndex() { var elements = document.querySelectorAll('*'); let maxZindex = 0; for (var i = 0; i < elements.length; i++) { maxZindex = Math.max(maxZindex, elements[i].style.zIndex || 0); } return maxZindex; } }, mounted() { // console.log(this.getMaxZIndex() + 1); this.zIndex = this.getMaxZIndex() + 1; }, created() { this.getData(); } }; </script> <style lang="less"> // 遮罩层 .mo-mask { position: fixed; top: 0; bottom: 0; left: 0; right: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0); } .pop-share { position: fixed; background-color: #373737; color: #fff; display: flex; align-items: center; line-height: 1.5; border-radius: 6px; transform: translate(-50%, -50px); } .pop-share::after { content: ''; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-left: 8px solid transparent; border-right: 8px solid transparent; border-top: 8px solid #373737; } .pop-share__item { font-size: 12px; line-height: 32px; height: 32px; padding: 0 12px; box-sizing: border-box; color: #dfdfdf; position: relative; cursor: pointer; white-space: nowrap; } .pop-share__item:not(:last-child)::after { position: absolute; content: ''; width: 1px; height: 14px; line-height: 14px; padding: 0; box-sizing: border-box; background-color: #666; top: 50%; right: 0; transform: translateY(-50%); } </style> <style lang="less" scoped></style>
// components/pop-share/index.js import Vue from 'vue'; import PopShare from './pop-share.vue'; // 所有实例列表 let instances = []; // 显示 function show(props) { console.log('show'); // let PopShareVue = Vue.extend(PopShare); // 此处需要使用 propsData传递参数 // let instance = new PopShareVue({ // propsData: props // }); let instance = new Vue({ render(h) { return h(PopShare, { props }); }, methods: { handleClose() { close(instance); } } }); instance.$mount(); document.body.appendChild(instance.$el); instances.push(instance); } // 关闭 function close(instance) { console.log('close'); if (instance) { document.body.removeChild(instance.$el); } let index = instances.findIndex(item => item === instance); if (index > -1) { instances.splice(index, 1); } } function closeAll() { for (let instance of instances) { close(instance); } } export default { show, close, closeAll };
将其挂载到Vue实例
// main.js import Vue from 'vue'; import App from './App.vue'; import PopShare from './components/pop-share/index.js'; Vue.prototype.$popShare = PopShare; const app = new Vue({ render: h => h(App) }).$mount('#app');
调用弹出分享组件
<!-- App.vue --> <template> <div @mouseup="handleMouseUp" class="meeting-content" v-html="content"></div> </template> <script> // created at 2022-06-21 export default { name: '', data(){ return { content: "" } }, methods: { handleMouseUp(e) { // 将当前鼠标的坐标传入 this.$popShare.show({ top: e.clientY, left: e.clientX, // 点击回调 onItemClick: e => { console.log(e); } }); } }, created() { // this.getData(); } }; </script> <style lang="less"> .meeting-content { white-space: pre-wrap; line-height: 1.8; color: #222222; font-size: 14px; &::selection { background-color: #b0d4fc; } } </style> <style lang="less" scoped></style>
参考