基于Vue.js+Nuxt开发自定义弹出层组件


Posted in Javascript onOctober 09, 2020

今天给大家分享VPopup 基于Vue.js构建的轻量级移动端弹出框组件,详情如下所示:

一款融合了Vant、NutUI等热门Vue组件库中的Popup弹层、Dialog对话框、Toast提示框、ActionSheet动作面板框、Notify通知框等功能。

基于Vue.js+Nuxt开发自定义弹出层组件

快速使用

在main.js中引入组件

// 引入弹窗Popup
import Popup from './components/popup'
Vue.use(Popup)

支持如下两种 组件式 及 函数式 调用插件。

组件式

<template>
 <view id="root">
 ...
 
 <!-- 弹窗模板 -->
 <v-popup 
  v-model="showDialog" 
  anim="scaleIn" 
  title="标题"
  content="这里显示弹出框内容!" 
  shadeClose="false" 
  xclose
  :btns="[
  {...},
  {...},
  ]"
 />
 </view>
</template>

函数式

<script>
 export default {
 ...
 methods: {
  handleShowDialog() {
  let $el = this.$vpopup({
   title: '标题',
   content: '这里显示弹出框内容!',
   anim: 'scaleIn',
   shadeClose: false,
   xclose: true,
   onClose: () => {
   console.log('vpopup is closed!')
   },
   btns: [
   {text: '关闭'},
   {
    text: '确定',
    style: 'color:#00e0a1',
    click: () => {
    $el.close()
    }
   }
   ]
  });
  }
 }
 }
</script>

在实际项目开发中,大家可根据需要自行选择调用。

基于Vue.js+Nuxt开发自定义弹出层组件

msg信息提示

基于Vue.js+Nuxt开发自定义弹出层组件

基于Vue.js+Nuxt开发自定义弹出层组件

基于Vue.js+Nuxt开发自定义弹出层组件

<script>
 export default {
 ...
 methods: {
  handleShowDialog() {
  let $el = this.$vpopup({
   title: '标题',
   content: '这里显示弹出框内容!',
   anim: 'scaleIn',
   shadeClose: false,
   xclose: true,
   onClose: () => {
   console.log('vpopup is closed!')
   },
   btns: [
   {text: '关闭'},
   {
    text: '确定',
    style: 'color:#00e0a1',
    click: () => {
    $el.close()
    }
   }
   ]
  });
  }
 }
 }
</script>

ActionSheet动作面板框

基于Vue.js+Nuxt开发自定义弹出层组件

基于Vue.js+Nuxt开发自定义弹出层组件

基于Vue.js+Nuxt开发自定义弹出层组件

<!-- ActionSheet底部弹出式菜单 -->
<v-popup v-model="showActionSheet" anim="footer" type="actionsheet" :z-index="1011"
 content="弹窗内容,告知当前状态、信息和解决方法,描述文字尽量控制在三行内"
 :btns="[
 {text: '拍照', style: 'color:#09f;', disabled: true, click: handleInfo},
 {text: '从手机相册选择', style: 'color:#00e0a1;', click: handleInfo},
 {text: '保存图片', style: 'color:#e63d23;', click: () => null},
 {text: '取消', click: () => showActionSheet=false},
 ]"
/>

IOS风格弹窗

基于Vue.js+Nuxt开发自定义弹出层组件

基于Vue.js+Nuxt开发自定义弹出层组件

<!-- Ios风格样式 -->
<v-popup v-model="showIos1" type="ios" shadeClose="false" title="标题内容" z-index="1990"
	content="弹窗内容,告知当前状态、信息和解决方法,描述文字尽量控制在三行内"
	:btns="[
		{text: '知道了', click: () => showIos1=false},
		{text: '确定', style: 'color:#00e0a1;', click: handleInfo},
	]"
>
</v-popup>

Toast加载提示框

基于Vue.js+Nuxt开发自定义弹出层组件

基于Vue.js+Nuxt开发自定义弹出层组件

基于Vue.js+Nuxt开发自定义弹出层组件

<!-- Toast弹窗 -->
<v-popup v-model="showToast" type="toast" icon="loading" time="5" content="加载中..." />
<v-popup v-model="showToast" type="toast" icon="success" shade="false" time="3" content="成功提示" />
<v-popup v-model="showToast" type="toast" icon="fail" shade="false" time="3" content="失败提示" />

emmm~~ 看了如上效果,是不是觉得还不错哟!那就继续往下看实现过程吧?

弹窗参数配置

弹窗支持如下参数配置,大家根据需要自行组合搭配使用。

@@Props
------------------------------------------
v-model 当前组件是否显示
title 标题
content 内容(支持自定义插槽内容)
type 弹窗类型(toast | footer | actionsheet | actionsheetPicker | android/ios)
popupStyle 自定义弹窗样式
icon toast图标(loading | success | fail)
shade 是否显示遮罩层
shadeClose 是否点击遮罩时关闭弹窗
opacity 遮罩层透明度
round 是否显示圆角
xclose 是否显示关闭图标
xposition 关闭图标位置(left | right | top | bottom)
xcolor 关闭图标颜色
anim 弹窗动画(scaleIn | fadeIn | footer | fadeInUp | fadeInDown)
position 弹出位置(top | right | bottom | left)
follow 长按/右键弹窗(坐标点)
time 弹窗自动关闭秒数(1、2、3)
zIndex 弹窗层叠(默认8080)
btns 弹窗按钮(参数:text|style|disabled|click)
 
@@$emit
------------------------------------------
open 打开弹出层时触发(@open="xxx")
close 关闭弹出层时触发(@close="xxx")
 
@@Event
------------------------------------------
onOpen 打开弹窗回调
onClose 关闭弹窗回调

弹窗template模板

<template>
 <div v-show="opened" class="nuxt__popup" :class="{'nuxt__popup-closed': closeCls}" :id="id">
 <div v-if="JSON.parse(shade)" class="nuxt__overlay" @click="shadeClicked" :style="{opacity}"></div>
 <div class="nuxt__wrap">
 <div class="nuxt__wrap-section">
 <div class="nuxt__wrap-child" :class="['anim-'+anim, type&&'popui__'+type, round&&'round', position]" :style="popupStyle">
  <div v-if="title" class="nuxt__wrap-tit" v-html="title"></div>
  <div v-if="type=='toast'&&icon" class="nuxt__toast-icon" :class="['nuxt__toast-'+icon]" v-html="toastIcon[icon]"></div>
  <template v-if="$slots.content"><div class="nuxt__wrap-cnt"><slot name="content" /></div></template>
  <template v-else><div v-if="content" class="nuxt__wrap-cnt" v-html="content"></div></template>
  <slot />
  <div v-if="btns" class="nuxt__wrap-btns">
  <span v-for="(btn,index) in btns" :key="index" class="btn" :style="btn.style" v-html="btn.text"></span>
  </div>
  <span v-if="xclose" class="nuxt__xclose" :class="xposition" :style="{'color': xcolor}" @click="close"></span>
 </div>
 </div>
 </div>
 </div>
</template>
/**
 * @Desc VueJs自定义弹窗组件VPopup
 * @Time andy by 2020-10-06
 * @About Q:282310962 wx:xy190310
 */
<script>
 let $index = 0, $lockCount = 0, $timer = {};
 export default {
 props: {
 ...
 },
 data() {
 return {
 opened: false,
 closeCls: '',
 toastIcon: {
  ...
 }
 }
 },
 watch: {
 value(val) {
 const type = val ? 'open' : 'close';
 this[type]();
 },
 },
 methods: {
 // 打开弹窗
 open() {
 if(this.opened) return;
 this.opened = true;
 this.$emit('open');
 typeof this.onOpen === 'function' && this.onOpen();
 
 if(JSON.parse(this.shade)) {
  if(!$lockCount) {
  document.body.classList.add('nt-overflow-hidden');
  }
  $lockCount++;
 }
 
 // 倒计时关闭
 if(this.time) {
  $index++;
  if($timer[$index] !== null) clearTimeout($timer[$index])
  $timer[$index] = setTimeout(() => {
  this.close();
  }, parseInt(this.time) * 1000);
 }
 
 if(this.follow) {
  this.$nextTick(() => {
  let obj = this.$el.querySelector('.nuxt__wrap-child');
  let oW, oH, winW, winH, pos;
 
  oW = obj.clientWidth;
  oH = obj.clientHeight;
  winW = window.innerWidth;
  winH = window.innerHeight;
  pos = this.getPos(this.follow[0], this.follow[1], oW, oH, winW, winH);
 
  obj.style.left = pos[0] + 'px';
  obj.style.top = pos[1] + 'px';
  });
 }
 },
 // 关闭弹窗
 close() {
 if(!this.opened) return;
 
 this.closeCls = true;
 setTimeout(() => {
  this.opened = false;
  this.closeCls = false;
  if(JSON.parse(this.shade)) {
  $lockCount--;
  if(!$lockCount) {
  document.body.classList.remove('nt-overflow-hidden');
  }
  }
  if(this.time) {
  $index--;
  }
  this.$emit('input', false);
  this.$emit('close');
  typeof this.onClose === 'function' && this.onClose();
 }, 200);
 },
 shadeClicked() {
 if(JSON.parse(this.shadeClose)) {
  this.close();
 }
 },
 btnClicked(e, index) {
 let btn = this.btns[index];
 if(!btn.disabled) {
  typeof btn.click === 'function' && btn.click(e)
 }
 },
 getZIndex() {
 for(var $idx = parseInt(this.zIndex), $el = document.getElementsByTagName('*'), i = 0, len = $el.length; i < len; i++)
  $idx = Math.max($idx, $el[i].style.zIndex)
 return $idx;
 },
 // 获取弹窗坐标点
 getPos(x, y, ow, oh, winW, winH) {
 let l = (x + ow) > winW ? x - ow : x;
 let t = (y + oh) > winH ? y - oh : y;
 return [l, t];
 }
 },
 }
</script>

通过监听组件传过来的v-model值调用open和close方法。

watch: {
	value(val) {
		const type = val ? 'open' : 'close';
		this[type]();
	},
},

基于Vue.js+Nuxt开发自定义弹出层组件

基于Vue.js+Nuxt开发自定义弹出层组件

基于Vue.js+Nuxt开发自定义弹出层组件

基于Vue.js+Nuxt开发自定义弹出层组件

另外还支持右键弹窗/长按弹窗自定义插槽内容。

基于Vue.js+Nuxt开发自定义弹出层组件

基于Vue.js+Nuxt开发自定义弹出层组件

<!-- 组件调用 -->
<v-popup v-model="showComponent" xclose xposition="bottom" :shadeClose="false" content="这里是内容信息"
 :btns="[
 {text: '确认', style: 'color:#f60;', click: () => showComponent=false},
 ]"
 @open="handleOpen" @close="handleClose"
>
 <template #content><b style="color:#00e0a1;">当 content 和 自定义插槽 内容同时存在,只显示插槽内容!!!</b></template>
 <!-- <div slot="content">显示自定义插槽内容!</div> -->
 <div style="padding:30px 15px;">
 <img src="https://img.yzcdn.cn/vant/apple-3.jpg" style="width:100%;" @click="handleContextPopup" />
 </div>
</v-popup>

如果想通过函数式调用组件,需要用到Vue.extend扩展构造器来实现。

import Vue from 'vue';
import VuePopup from './popup.vue';
 
let PopupConstructor = Vue.extend(VuePopup);
 
let $instance;
 
let VPopup = function(options = {}) {
 // 同一个页面中,id相同的Popup的DOM只会存在一个
 options.id = options.id || 'nuxt-popup-id';
 $instance = new PopupConstructor({
 propsData: options
 });
 $instance.vm = $instance.$mount();
 
 let popupDom = document.querySelector('#' + options.id);
 if(options.id && popupDom) {
 popupDom.parentNode.replaceChild($instance.$el, popupDom);
 } else {
 document.body.appendChild($instance.$el);
 }
 
 Vue.nextTick(() => {
 $instance.value = true;
 })
 
 return $instance;
}
 
VPopup.install = () => {
 Vue.prototype['$vpopup'] = VPopup;
 Vue.component('v-popup', VuePopup);
}
 
export default VPopup;

这样就实现了在Vue原型 prototype 上挂载 $vpopup 方法及注册 v-popup 组件。

设置圆角及关闭按钮

设置round、xclose即可,另外可以配置xposition来设置关闭按钮位置。

基于Vue.js+Nuxt开发自定义弹出层组件

设置按钮禁用状态

设置disabled: true 可禁用按钮事件。

基于Vue.js+Nuxt开发自定义弹出层组件

Okay,基于Vue.js+Nuxt开发自定义弹出层组件就介绍到这里。目前VPopup正在Nuxt新项目中使用,届时也会分享出来。

最后附上最近两个实例项目

到此这篇关于基于Vue.js+Nuxt开发自定义弹出层组件的文章就介绍到这了,更多相关Vue+Nuxt自定义弹窗内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
jQuery 页面载入进度条实现代码
Feb 08 Javascript
禁止ajax缓存获取程序最新数据的方法
Nov 19 Javascript
在线一元二次方程计算器实例(方程计算器在线计算)
Dec 22 Javascript
js验证输入是否为手机号码或电话号码示例
Dec 30 Javascript
js正则表达式验证表单【完整版】
Mar 06 Javascript
jQuery实现扑克正反面翻牌效果
Mar 10 Javascript
React通过父组件传递类名给子组件的实现方法
Nov 13 Javascript
微信小程序实现折叠面板
Jan 31 Javascript
Node.js上传文件功能之服务端如何获取文件上传进度
Feb 05 Javascript
详解jQuery中的easyui
Sep 02 jQuery
使用JS location实现搜索框历史记录功能
Dec 23 Javascript
使用Taro实现小程序商城的购物车功能模块的实例代码
Jun 05 Javascript
IDEA配置jQuery, $符号不再显示黄色波浪线的问题
Oct 09 #jQuery
vue中解决chrome浏览器自动播放音频和MP3语音打包到线上的实现方法
Oct 09 #Javascript
vue实现选中效果
Oct 07 #Javascript
electron踩坑之dialog中的callback解决
Oct 06 #Javascript
electron踩坑之remote of undefined的解决
Oct 06 #Javascript
9个JavaScript日常开发小技巧
Oct 06 #Javascript
详解ES6中class的实现原理
Oct 03 #Javascript
You might like
php中json_encode处理gbk与gb2312中文乱码问题的解决方法
2014/07/10 PHP
php实现微信公众平台账号自定义菜单类
2014/12/02 PHP
postfixadmin忘记密码后的修改密码方法详解
2016/07/20 PHP
php动态读取数据清除最右边距的方法
2017/04/12 PHP
javascript动画效果类封装代码
2007/08/28 Javascript
jsp网页搜索结果中实现选中一行使其高亮
2014/02/17 Javascript
jQuery插件分享之分页插件jqPagination
2014/06/06 Javascript
多个checkbox被选中时如何判断是否有自己想要的
2014/09/22 Javascript
基于jQuery的ajax方法封装
2016/07/14 Javascript
浅谈js-FCC算法Friendly Date Ranges(详解)
2017/04/10 Javascript
解决bootstrap中使用modal加载kindeditor时弹出层文本框不能输入的问题
2017/06/05 Javascript
浅析Visual Studio Code断点调试Vue
2018/02/27 Javascript
mpvue构建小程序的方法(步骤+地址)
2018/05/22 Javascript
JS数组求和的常用方法实例小结
2019/01/07 Javascript
JavaScript实现的联动菜单特效示例
2019/07/08 Javascript
在nodejs中创建child process的方法
2021/01/26 NodeJs
举例讲解Python中的Null模式与桥接模式编程
2016/02/02 Python
python if not in 多条件判断代码
2016/09/21 Python
python 将字符串中的数字相加求和的实现
2019/07/18 Python
解决python对齐错误的方法
2020/07/16 Python
Django xadmin安装及使用详解
2020/10/26 Python
CSS3 linear-gradient线性渐变生成加号和减号的方法
2017/11/21 HTML / CSS
英国领先的高街书籍专家:Waterstones
2018/02/01 全球购物
暑期社会实践学生的自我评价
2014/01/09 职场文书
大一学生职业生涯规划
2014/03/11 职场文书
汉语言文学专业自荐信
2014/06/11 职场文书
法学院毕业生求职信
2014/06/25 职场文书
优秀大专毕业生求职信
2014/08/04 职场文书
社区党员公开承诺书
2014/08/30 职场文书
教育实践活动对照检查材料
2014/09/23 职场文书
镇人大副主席民主生活会对照检查材料思想汇报
2014/10/01 职场文书
人事行政部各岗位职责说明书!
2019/07/15 职场文书
餐厅营销的秘密:为什么老顾客会流水?
2019/08/08 职场文书
Pytorch 实现变量类型转换
2021/05/17 Python
springboot中rabbitmq实现消息可靠性机制详解
2021/09/25 Java/Android
Nginx实现会话保持的两种方式
2022/03/18 Servers