vue实现点击出现操作弹出框的示例


Posted in Javascript onNovember 05, 2020

vue实现点击出现操作弹出框的示例

如上图所示,这次要实现一个点击出现操作弹框的效果;并将这个功能封装成一个函数,便于在项目的多个地方使用。

具体思路是:

封装一个组件,组件保护一个插槽,我们可以根据不同的场景,利用插槽随意在这个弹框里插入任何元素,这个弹框显示时根据我鼠标的点击位置,定位弹窗的位置,并在组件里面监听鼠标抬起事件,触发事件时将弹窗隐藏;

接着在函数中利用createElement和appendChild方法将弹出框创建并插入到页面中;

   本次实现基于vuecli3

接下来,具体实现:

     首先,我们先写一个demo组件

   在点击出现弹出框的元素上把事件对象数据传递一下,以便获取点击时鼠标的数据,以此确定弹出框的位置

// 文件路径参考: src > views > demo> index.vue
<template>
 <div class="demo-wrapper">
  <div class="demo-div">
   <span>更多功能</span>
   <i class="xk-icon xk-ellipsis" @click.stop='showMenu($event)'></i> // 为了获取鼠标位置,这里把事件对象数据传递一下
  </div>
 </div>
</template>

<script lang="ts">
 import { Vue, Component, Prop, Watch} from "vue-property-decorator";
 @Component({

 })
 export default class articleView extends Vue {
  showMenu($event:any){
   // 点击时出现弹出框
  }
 };
</script>

     接着,我们把弹出框里面的组件也写一下

     组件随便命名为ActionList,组件里面把把列表数据及点击事件都基于父组件传递的值而定,由于只是小demo,所以我们传递的menu数据数组只是简单的字符串数组

// 文件路径参考: src > components > ActionList > index.vue<template>
 <ul class="menu-wrapper">
  <li
   class="menu-item"
   v-for="item in menu"
   :key="item"
   @click="handleClick(item)"
  >
   {{ item }}
  </li>
 </ul>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
@Component
export default class ActionList extends Vue {
 @Prop() menu: string[];
 handleClick(str: string) {
  this.$emit('click', str);
 }
}
</script>

    接着,开始着手写弹框组件

  1、弹框组件的显示隐藏用v-show控制,为什么不用v-if ?因为这里我监听了mouseup事件来让弹框隐藏,如果在插槽里的元素绑定事件,比如点击事件,用v-if 的话,点击插槽里的元素时,弹框先消失,插槽里的点击事件就不会生效了。

     2、handleOpen事件里我们根据鼠标点击位置定位弹框位置。

// 文件路径参考: src > components > PublicModel > index.vue<template>
 <div class="dropdown-menu" :style="style" v-show='showModel'>
  <slot></slot>
 </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
interface IStyle {
 left?: string;
 right?: string;
 top?: string;
 bottom?: string;
}
@Component
export default class PublicModel extends Vue {
 showModel:boolean = false;
 style:IStyle = {};

 // 组件显示时
 handleOpen($event:any){
  const { clientWidth, clientHeight, scrollWidth, scrollHeight } = document.body || document.documentElement;
  const { pageX, pageY, clientX, clientY } = $event;
  let style:IStyle = {} 
  if(clientX > (clientWidth * 2)/3 ){
   style.right = scrollWidth - pageX + 10 + 'px';
  }else{
   style.left = pageX+10+'px'
  }
  if(clientY > (clientHeight * 2) / 3 ){
   style.bottom = scrollHeight - pageY + 10 + 'px';
  }else{
   style.top = pageY + 10 + "px"
  }
  this.style = style;
  this.showModel = true;
  document.addEventListener('mouseup',this.closeModel)
 }

 // 隐藏关闭此组件
 closeModel(){
  this.showModel = false;
  document.removeEventListener('mouseup', this.closeModel);
 }

 // 组件销毁生命周期
 destroyed(){
  document.removeEventListener('mouseup', this.closeModel);
 }
}
</script>

    接着,重点来了,书写公用封装函数

  我们要在demo组件点击时触发这个函数,即在demo组件里的showMenu事件触发函数,这个函数要利用createElement和appendChild方法将弹出框创建并插入到页面中。

  因为是点击时创建并插入元素,所以为了性能优化,避免有恶意疯狂点击,不断创建和插入元素,我们利用throttle-debounce插件做一个节流。

  先直接看代码,其他注释写在了代码里,函数名随意取:ModelFun

// 文件路径参考: src > components > PublicModel > index.ts
import Vue from 'vue';
import PublicModel from './index.vue'; // 导入上面所写的弹框组件
const throttleDebounce = require('throttle-debounce'); // throttle-debounce插件
const debounce = throttleDebounce.debounce;
const PublicModelConstructor = Vue.extend(PublicModel);
let instance:any;
const initInstance = () => {
 instance = new PublicModelConstructor({
  el: document.createElement('div'),
 });
 document.body.appendChild(instance.$el);
}
const insertInstanceSlot = (slotVNode:any, $event:any) => { // 这里两个参数一个是弹框里插槽的组件,还有就是点击的事件对象(方便定位弹框位置)
 if(!instance){
  initInstance()
 }
 instance.$slots.default = [slotVNode]; // 将传递过来的插槽组件插入弹框组件中
 instance.handleOpen($event) // 触发弹框组件(见上一段代码)的弹框获取定位信息并显示的事件
}
const ModelFun = debounce(200, false, insertInstanceSlot) // 使用throttle-debounce里的debounce保证在一系列调用时间中回调函数只执行一次,这里是200毫秒               // 第二个参数为false时,在点击时会在200毫秒后再执行callback(即insertInstanceSlot),但为true时,会立即先执行一次;
export default ModelFun

    接着,重点来了,书写公用封装函数

  我们要在demo组件点击时触发这个函数,即在demo组件里的showMenu事件触发函数,这个函数要利用createElement和appendChild方法将弹出框创建并插入到页面中。

  因为是点击时创建并插入元素,所以为了性能优化,避免有恶意疯狂点击,不断创建和插入元素,我们利用throttle-debounce插件做一个节流。

  先直接看代码,其他注释写在了代码里,函数名随意取:ModelFun

// 文件路径参考: src > components > PublicModel > index.tsimport Vue from 'vue';
import PublicModel from './index.vue'; // 导入上面所写的弹框组件
const throttleDebounce = require('throttle-debounce'); // throttle-debounce插件
const debounce = throttleDebounce.debounce;
const PublicModelConstructor = Vue.extend(PublicModel);
let instance:any;
const initInstance = () => {
 instance = new PublicModelConstructor({
  el: document.createElement('div'),
 });
 document.body.appendChild(instance.$el);
}
const insertInstanceSlot = (slotVNode:any, $event:any) => { // 这里两个参数一个是弹框里插槽的组件,还有就是点击的事件对象(方便定位弹框位置)
 if(!instance){
  initInstance()
 }
 instance.$slots.default = [slotVNode]; // 将传递过来的插槽组件插入弹框组件中
 instance.handleOpen($event) // 触发弹框组件(见上一段代码)的弹框获取定位信息并显示的事件
}
const ModelFun = debounce(200, false, insertInstanceSlot) // 使用throttle-debounce里的debounce保证在一系列调用时间中回调函数只执行一次,这里是200毫秒               // 第二个参数为false时,在点击时会在200毫秒后再执行callback(即insertInstanceSlot),但为true时,会立即先执行一次;export default ModelFun

    最后,我们回过头来完善一下demo组件

     利用vue的 $createElement 将ActionList组件插入弹框中,并将数据和事件传递给ActionList组件,这里我们传递的事件是简单的弹出我们点击的数据

// 文件路径参考: src > views > demo> index.vue<template>
 <div class="demo-wrapper">
  <div class="demo-div">
   <span>更多功能</span>
   <i class="xk-icon xk-ellipsis" @click.stop='showMenu($event)'></i>
  </div>
 </div>
</template>

<script lang="ts">
 import { Vue, Component, Prop, Watch} from "vue-property-decorator";
 import ActionList from "@/components/ActionList/index.vue";
 import modelFun from "@/components/PublicModel/index";
 @Component({

 })
 export default class articleView extends Vue {
  menuList: string[] = ['菜单1','菜单2','菜单3'];
  menuClick(name:string){ // 弹框里插槽的点击事件
   this.$message({message:name,type:'success'})
  }
  showMenu($event:any){
   modelFun(
    this.$createElement(
     ActionList,
     {
      props: { menu:this.menuList },
      on:{
       click: this.menuClick,
      }
     }
    ),
    $event
   )
  }
 };
</script>

  至此,效果如下

vue实现点击出现操作弹出框的示例

最后,我们利用element ui 的 tree 组件结合我们封装的弹框看一下效果
代码:

<template>
 <div class="demo-wrapper">
  <el-tree
    :data="data"
   node-key="id"
    :default-expand-all="true"
   :expand-on-click-node="false"
   show-checkbox
   >
    <div class="custom-tree-node tree-item" iv slot-scope="{ node }">
     <span>{{ node.label }}</span>
     <span
      class="action"
      @click.stop="showMenu($event)"
     >
      <i class="el-icon-more"></i>
     </span>
    </div>
   </el-tree>
 </div>
</template>

<script lang="ts">
 import { Vue, Component, Prop, Watch} from "vue-property-decorator";
 import ActionList from "@/components/ActionList/index.vue";
 import modelFun from "@/components/PublicModel/index";
 @Component({

 })
 export default class articleView extends Vue {
  menuList: string[] = ['菜单1','菜单2','菜单3'];
  data:any[] = [{
  id: 1,
  label: '一级 1',
  children: [{
   id: 4,
   label: '二级 1-1',
   children: [{
   id: 9,
   label: '三级 1-1-1'
   }, {
   id: 10,
   label: '三级 1-1-2'
   }]
  }]
  }, {
  id: 2,
  label: '一级 2',
  children: [{
   id: 5,
   label: '二级 2-1'
  }, {
   id: 6,
   label: '二级 2-2'
  }]
  }, {
  id: 3,
  label: '一级 3',
  children: [{
   id: 7,
   label: '二级 3-1'
  }, {
   id: 8,
   label: '二级 3-2'
  }]
  }];
  menuClick(name:string){
   console.log(name)
   this.$message({message:name,type:'success'})
  }
  showMenu($event:any){
   modelFun(
    this.$createElement(
     ActionList,
     {
      props: { menu:this.menuList },
      on:{
       click: this.menuClick,
      }
     }
    ),
    $event
   )
  }
 };
</script>

效果:

vue实现点击出现操作弹出框的示例

以上就是vue实现点击出现操作弹出框的示例的详细内容,更多关于vue 弹出框的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
获取DOM对象的几种扩展及简写
Oct 09 Javascript
JavaScript导出Excel实例详解
Nov 25 Javascript
JS实现网页滚动条感应鼠标变色的方法
Feb 26 Javascript
DOM事件阶段以及事件捕获与事件冒泡先后执行顺序(图文详解)
Aug 18 Javascript
创建基于Bootstrap的下拉菜单的DropDownList的JQuery插件
Jun 02 Javascript
js实现获取两个日期之间所有日期的方法
Jun 17 Javascript
微信小程序 实现拖拽事件监听实例详解
Nov 16 Javascript
IntelliJ IDEA 安装vue开发插件的方法
Nov 21 Javascript
vue-cli扩展多模块打包的示例代码
Apr 09 Javascript
vue实现word,pdf文件的导出功能
Jul 31 Javascript
JavaScript JSON数据处理全集(小结)
Aug 15 Javascript
JS this关键字在ajax中使用出现问题解决方案
Jul 17 Javascript
nuxt 自定义 auth 中间件实现令牌的持久化操作
Nov 05 #Javascript
Vant 在vue-cli 4.x中按需加载操作
Nov 05 #Javascript
前端vue如何使用高德地图
Nov 05 #Javascript
解决vue项目中遇到 Cannot find module ‘chalk‘ 报错的问题
Nov 05 #Javascript
vue 全局封装loading加载教程(全局监听)
Nov 05 #Javascript
vant组件中 dialog的确认按钮的回调事件操作
Nov 04 #Javascript
Array.filter中如何正确使用Async
Nov 04 #Javascript
You might like
PHP的开合式多级菜单程序
2006/10/09 PHP
nginx下安装php7+php5
2016/07/31 PHP
浅谈PHP命令执行php文件需要注意的问题
2016/12/16 PHP
PHP中实现中文字串截取无乱码的解决方法
2018/05/29 PHP
php微信开发之音乐回复功能
2018/06/14 PHP
JavaScript 中的日期和时间及表示标准介绍
2013/08/21 Javascript
jQuery实现将页面上HTML标签换成另外标签的方法
2015/06/09 Javascript
js中对函数设置默认参数值的3种方法
2015/10/23 Javascript
JS实现设置ff与ie元素绝对位置的方法
2016/03/08 Javascript
JS面试题---关于算法台阶的问题
2016/07/26 Javascript
JSON格式的时间/Date(2367828670431)/格式转为正常的年-月-日 格式的代码
2016/07/27 Javascript
Google 地图获取API Key详细教程
2016/08/06 Javascript
JS实现身份证输入框的输入效果
2017/08/21 Javascript
基于casperjs和resemble.js实现一个像素对比服务详解
2018/01/10 Javascript
Vue将页面导出为图片或者PDF
2020/08/17 Javascript
layui操作列按钮个数和文字颜色的判断实例
2019/09/11 Javascript
webpack 最佳配置指北(推荐)
2020/01/07 Javascript
jQuery+css实现的点击图片放大缩小预览功能示例【图片预览 查看大图】
2020/05/29 jQuery
vue 中this.$set 动态绑定数据的案例讲解
2021/01/29 Vue.js
python求斐波那契数列示例分享
2014/02/14 Python
Python提示[Errno 32]Broken pipe导致线程crash错误解决方法
2014/11/19 Python
python构建指数平滑预测模型示例
2019/11/21 Python
详解字符串在Python内部是如何省内存的
2020/02/03 Python
tensorflow保持每次训练结果一致的简单实现
2020/02/17 Python
Python requests.post方法中data与json参数区别详解
2020/04/30 Python
如何基于Python爬虫爬取美团酒店信息
2020/11/03 Python
利用CSS3动画实现圆圈由小变大向外扩散的效果实例
2018/09/10 HTML / CSS
h5页面背景图很长要有滚动条滑动效果的实现
2021/01/27 HTML / CSS
电子专业毕业生自我鉴定
2014/01/22 职场文书
小学生暑假感言
2014/02/06 职场文书
代领学位证书毕业证书委托书
2014/09/30 职场文书
2015年三万活动总结
2015/03/25 职场文书
2015年农村党员公开承诺事项
2015/04/28 职场文书
2016干部作风整顿心得体会
2016/01/22 职场文书
pytorch 两个GPU同时训练的解决方案
2021/06/01 Python
解决Vue+SpringBoot+Shiro跨域问题
2021/06/09 Vue.js