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 相关文章推荐
图片onload事件触发问题解决方法
Jul 31 Javascript
jQuery prototype冲突的2种解决方法(附demo示例下载)
Jan 21 Javascript
JavaScript、jQuery与Ajax的关系
Jan 24 Javascript
工作中比较实用的JavaScript验证和数据处理的干货(经典)
Aug 03 Javascript
第一次动手实现bootstrap table分页效果
Sep 22 Javascript
jQuery post数据至ashx实例详解
Nov 18 Javascript
Javascript基础回顾之(二) js作用域
Jan 31 Javascript
微信小程序 两种为对象属性赋值的方式详解
Feb 23 Javascript
vue-cli扩展多模块打包的示例代码
Apr 09 Javascript
在vue项目中引入highcharts图表的方法
Jan 21 Javascript
解决layer弹出层中表单不起作用的问题
Sep 09 Javascript
js 计算月/周的第一天和最后一天代码
Feb 01 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 生成唯一id的几种解决方法
2013/03/08 PHP
使用php验证复选框有效性的示例
2013/11/13 PHP
Laravel 5.3 学习笔记之 配置
2016/08/28 PHP
Laravel的throttle中间件失效问题解决方法
2016/10/09 PHP
php的laravel框架快速集成微信登录的方法
2016/12/12 PHP
PHP笛卡尔积实现原理及代码实例
2020/12/09 PHP
prototype1.4中文手册
2006/09/22 Javascript
lib.utf.js
2007/08/21 Javascript
setInterval 和 setTimeout会产生内存溢出
2008/02/15 Javascript
JavaScript 原型链学习总结
2010/10/29 Javascript
ExtJS中设置下拉列表框不可编辑的方法
2014/05/07 Javascript
jquery实现点击页面计算点击次数
2015/01/23 Javascript
详解AngularJS中的filter过滤器用法
2016/01/04 Javascript
Bootstrap实现圆角、圆形头像和响应式图片
2016/12/14 Javascript
JavaScript实现两个select下拉框选项左移右移
2017/03/09 Javascript
让微信小程序支持ES6中Promise特性的方法详解
2017/06/13 Javascript
vue绑定的点击事件阻止冒泡的实例
2018/02/08 Javascript
解决修复npm安装全局模块权限的问题
2018/05/17 Javascript
vue实践---vue不依赖外部资源实现简单多语操作
2020/09/21 Javascript
[01:32]2016国际邀请赛中国区预选赛CDEC战队教练采访
2016/06/26 DOTA
python 实现归并排序算法
2012/06/05 Python
Python使用Srapy框架爬虫模拟登陆并抓取知乎内容
2016/07/02 Python
Python算法输出1-9数组形成的结果为100的所有运算式
2017/11/03 Python
Python连接Mssql基础教程之Python库pymssql
2018/09/16 Python
python实现浪漫的烟花秀
2019/01/30 Python
Python时间和字符串转换操作实例分析
2019/03/16 Python
Python判断变量是否是None写法代码实例
2020/10/09 Python
阿提哈德航空官方网站:Etihad Airways
2017/01/06 全球购物
英国汽车零件购物网站:GSF Car Parts
2019/05/23 全球购物
C#笔试题和英文面试题
2013/02/07 面试题
外贸业务员工作职责
2014/01/06 职场文书
办公室秘书自我鉴定
2014/01/18 职场文书
生物学专业求职信
2014/07/23 职场文书
项目建议书
2015/02/04 职场文书
收入证明怎么写
2015/06/12 职场文书
开学第一周总结
2015/07/16 职场文书