Vue layer pop-up window based on Vue PC module

xiaoyan2017 2020-11-11 11:47:20
vue layer pop-up pop window


Introduce

vlayer A fusion Alert|Dialog|Modal|Message|Notify|Popover|Toast|ActionSheet And many other functions of the desktop pop-up box components . Design is at the beginning of development , Reference has been made to Layer Shell layer plug-in 、antd And iView And so on .


Quick start

stay main.js The pop-up window component is introduced in .

import VLayer from './components/vlayer';
Vue.use(VLayer);

Provides Tagging and Functional expression 2 Kind of Alternative call mode .

<v-layer
v-model="isConfirm"
title=" Title Content "
content="<div style='color:#06f;padding:15px;'> Pop up content information !</div>"
xclose
z-index="2002"
lockScroll="false"
resize
dragOut
:btns="[
{text: ' Cancel ', click: () => isConfirm=false},
{text: ' determine ', style: 'color:#f90;', click: handleFn},
]"
/>

because vlayer Mounted global functions , Support functional writing .

let $el = this.$vlayer({
title: ' Title Content ',
content: '<div style='color:#06f;padding:15px;'> Pop up content information !</div>',
xclose: true,
zIndex: 2002,
lockScroll: false,
resize: true,
dragOut: true,
btns: [
{text: ' Cancel ', click: () => { $el.close(); }},
{text: ' determine ', click: () => this.handleFn()},
]
});

Results the preview

image
image
image
image
image
image
image
image
image
image

Parameter configuration

vlayer Support up to 30+ Parameters can be configured arbitrarily .

@@ Default parameters
v-model Whether the current component displays
title title
content Content ( Support custom slot content )
type Pop up type (toast | footer | actionsheet | android/ios | contextmenu | drawer | iframe | message/notify/popover)
layerStyle Custom pop up style
icon toast Icon (loading | success | fail)
shade Show mask layer
shadeClose Whether to close the pop-up window when clicking mask
lockScroll Whether the pop-up window will appear body Roll lock
opacity Mask layer transparency
xclose Whether to show the close icon
xposition Turn off icon location (left | right | top | bottom)
xcolor Turn off icon color
anim Pop up animation (scaleIn | fadeIn | footer | fadeInUp | fadeInDown | fadeInLeft | fadeInRight)
position Pop up position (auto | ['100px','50px'] | t | r | b | l | lt | rt | lb | rb)
drawer Drawer pop-up window (top | right | bottom | left)
follow Follow the element to locate the pop-up window ( Support elements .kk #kk or [e.clientX, e.clientY])
time The pop-up window closes automatically for seconds (1、2、3)
zIndex Pop up windows ( Default 8080)
topmost Top the current window ( Default false)
area The pop-up window is wide and high ( Default auto) Set width area: '300px' Set height area:['', '200px'] Set width and height area:['350px', '150px']
maxWidth The maximum width of the pop-up window ( Only when area:'auto' when ,maxWidth Only the setting of )
maximize Whether to display the maximize button ( Default false)
fullscreen Full screen pop-up ( Default false)
fixed Is the pop-up window fixed
drag Drag and drop elements ( You can define selectors drag:'.xxx' | No dragging drag:false)
dragOut Whether drag to the window is allowed ( Default false)
resize Is tensile dimension allowed ( Default false)
btns Pop up button ( Parameters :text|style|disabled|click)
------------------------------------------
@@ Component events
open Trigger when pop-up layer is opened (@open="xxx")
close Trigger when pop-up layer is closed (@close="xxx")
------------------------------------------
@@ Functional events
onOpen Open the pop-up window to call back
onClose Close the pop-up call back 

vlayer Pop up templates

<template>
<div v-show="opened" class="vui__layer" :class="{'vui__layer-closed': closeCls}" :id="vlayerId">
<div v-if="JSON.parse(shade)" class="vlayer__overlay" @click="shadeClicked" :style="{opacity}"></div>
<div class="vlayer__wrap" :class="['anim-'+anim, type&&'popui__'+type, drawer&&'popui__drawer-'+drawer, xclose&&'vlayer-closable', tipArrow]" :style="layerStyle">
<div v-if="title" class="vlayer__wrap-tit" v-html="title"></div>
<div v-if="type=='toast'&&icon" class="vlayer__toast-icon" :class="['vlayer__toast-'+icon]" v-html="toastIcon[icon]"></div>
<div class="vlayer__wrap-cntbox">
<template v-if="$slots.content">
<div class="vlayer__wrap-cnt"><slot name="content" /></div>
</template>
<template v-else>
<template v-if="content">
<iframe v-if="type=='iframe'" scrolling="auto" allowtransparency="true" frameborder="0" :src="content"></iframe>
<!-- message|notify|popover -->
<div v-else-if="type=='message' || type=='notify' || type=='popover'" class="vlayer__wrap-cnt">
<i v-if="icon" class="vlayer-msg__icon" :class="icon" v-html="messageIcon[icon]"></i>
<div class="vlayer-msg__group"><div v-if="title" class="vlayer-msg__title" v-html="title"></div><div class="vlayer-msg__content" v-html="content"></div></div>
</div><div v-else class="vlayer__wrap-cnt" v-html="content"></div>
</template>
</template>
<slot />
</div>
<div v-if="btns" class="vlayer__wrap-btns">
<span v-for="(btn,index) in btns" :key="index" class="btn" :class="{'btn-disabled': btn.disabled}" :style="btn.style" v-html="btn.text"></span>
</div>
<span v-if="xclose" class="vlayer__xclose" :class="!maximize&&xposition" :style="{'color': xcolor}" @click="close"></span>
<span v-if="maximize" class="vlayer__maximize"></span>
<span v-if="resize" class="vlayer__resize"></span>
</div>
<!-- Fix drag and hold -->
<div class="vlayer__dragfix"></div>
</div>
</template>

What's posted below is js Main functions .

/**
* @Desc vue Custom dialog components VLayer
* @Time andy by 2020-10-28
* @About Q:282310962 wx:xy190310
*/
<script>
import domUtils from './utils/dom'
let $index = 0, $lockCount = 0, $timer = {};
let ie = !!window.ActiveXObject || "ActiveXObject" in window;
export default {
props: {
// ...
},
data() {
return {
opened: false,
closeCls: '',
toastIcon: {
// ...
},
messageIcon: {
// ...
},
vlayerOpts: {},
tipArrow: null,
}
},
mounted() {
window.addEventListener('resize', () => {
this.autopos();
})
},
computed: {
vlayerId() {
return this.id ? this.id : `vlayer-${domUtils.generateId()}`;
}
},
watch: {
value(val) {
const type = val ? 'open' : 'close';
this[type]();
},
},
methods: {
// Open the pop-up window
open() {
if(this.opened) return;
this.opened = true;
this.$emit('open');
typeof this.onOpen === 'function' && this.onOpen();
const dom = this.$el;
this.$nextTick(() => {
document.body.appendChild(dom);
this.auto();
})
this.callback();
},
// Close the pop-up window
close() {
if(!this.opened) return;
let dom = this.$el;
let vlayero = dom.querySelector('.vlayer__wrap');
let ocnt = dom.querySelector('.vlayer__wrap-cntbox');
let omax = dom.querySelector('.vlayer__maximize');
this.closeCls = true;
setTimeout(() => {
this.opened = false;
this.closeCls = false;
if(this.vlayerOpts.lockScroll) {
$lockCount--;
if(!$lockCount) {
document.body.style.paddingRight = '';
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);
},
// Pop up window position
auto() {
// ...
this.autopos();
// Full screen pop-up
if(this.fullscreen) {
this.full();
}
// Pop up window drag | The zoom
this.move();
},
autopos() {
if(!this.opened) return;
let oL, oT;
let pos = this.position;
let isFixed = JSON.parse(this.fixed);
let dom = this.$el;
let vlayero = dom.querySelector('.vlayer__wrap');
let area = [domUtils.client('width'), domUtils.client('height'), vlayero.offsetWidth, vlayero.offsetHeight]
oL = (area[0] - area[2]) / 2;
oT = (area[1] - area[3]) / 2;
if(this.follow) {
this.offset();
}else {
typeof pos === 'object' ? (
oL = parseFloat(pos[0]) || 0, oT = parseFloat(pos[1]) || 0
) : (
// ...
)
vlayero.style.left = parseFloat(isFixed ? oL : domUtils.scroll('left') + oL) + 'px';
vlayero.style.top = parseFloat(isFixed ? oT : domUtils.scroll('top') + oT) + 'px';
}
},
// Elements follow positioning
offset() {
let oW, oH, pS;
let dom = this.$el;
let vlayero = dom.querySelector('.vlayer__wrap');
oW = vlayero.offsetWidth;
oH = vlayero.offsetHeight;
pS = domUtils.getFollowRect(this.follow, oW, oH);
this.tipArrow = pS[2];
vlayero.style.left = pS[0] + 'px';
vlayero.style.top = pS[1] + 'px';
},
// Maximize the pop-up window
full() {
let timer;
let isFixed = JSON.parse(this.fixed);
let dom = this.$el;
let vlayero = dom.querySelector('.vlayer__wrap');
let otit = dom.querySelector('.vlayer__wrap-tit');
let ocnt = dom.querySelector('.vlayer__wrap-cntbox');
let obtn = dom.querySelector('.vlayer__wrap-btns');
let omax = dom.querySelector('.vlayer__maximize');
let t = otit ? otit.offsetHeight : 0;
let b = obtn ? obtn.offsetHeight : 0;
let rect = [
parseFloat(domUtils.getStyle(vlayero, 'left')), parseFloat(domUtils.getStyle(vlayero, 'top')),
parseFloat(domUtils.getStyle(vlayero, 'width')), parseFloat(domUtils.getStyle(vlayero, 'height'))||vlayero.offsetHeight
]
this.vlayerOpts.rect = rect;
clearTimeout(timer);
timer = setTimeout(() => {
vlayero.style.left = isFixed ? 0 : domUtils.scroll('left') + 'px';
vlayero.style.top = isFixed ? 0 : domUtils.scroll('top') + 'px';
vlayero.style.width = domUtils.client('width') + 'px';
vlayero.style.height = domUtils.client('height') + 'px';
ocnt.style.height = domUtils.client('height') - t - b + 'px';
}, 16);
},
// Restore the pop-up window
restore() {
let dom = this.$el;
let vlayero = dom.querySelector('.vlayer__wrap');
let otit = dom.querySelector('.vlayer__wrap-tit');
let ocnt = dom.querySelector('.vlayer__wrap-cntbox');
let obtn = dom.querySelector('.vlayer__wrap-btns');
let omax = dom.querySelector('.vlayer__maximize');
let t = otit ? otit.offsetHeight : 0;
let b = obtn ? obtn.offsetHeight : 0;
vlayero.style.left = parseFloat(this.vlayerOpts.rect[0]) + 'px';
vlayero.style.top = parseFloat(this.vlayerOpts.rect[1]) + 'px';
vlayero.style.width = parseFloat(this.vlayerOpts.rect[2]) + 'px';
vlayero.style.height = parseFloat(this.vlayerOpts.rect[3]) + 'px';
ocnt.style.height = parseFloat(this.vlayerOpts.rect[3]) - t - b + 'px';
},
// Drag the | Zoom the pop-up window
move() {
// ...
},
// Event handling
callback() {
// The countdown is off
if(this.time) {
$index++;
// Prevent repeated clicks
if($timer[$index] !== null) clearTimeout($timer[$index])
$timer[$index] = setTimeout(() => {
this.close();
}, parseInt(this.time) * 1000);
}
},
// Click the maximize button
maximizeClicked(e) {
let o = e.target;
if(o.classList.contains('maximized')) {
// recovery
this.restore();
} else {
// Maximize
this.full();
}
},
// Click on the mask layer
shadeClicked() {
if(JSON.parse(this.shadeClose)) {
this.close();
}
},
// Button event
btnClicked(e, index) {
let btn = this.btns[index];
if(!btn.disabled) {
typeof btn.click === 'function' && btn.click(e)
}
},
},
}
</script>

By default, the title area can be dragged , Of course, you can also customize drag and drop elements , Just set up drag: '#xxx'  Or set up drag: false To ban the pop-up window drag function .

When setting dragOut: true The form can be dragged outside the browser .

When using popover Popup , Need to follow: '#xxxx' Positioning elements .

let $follow = this.$vlayer.popover({
follow: '#popover',
icon: 'warning',
content: ' This is a paragraph. Are you sure you want to delete it ?',
time: null,
xclose: false,
btns: [
{text: 'no', click: () => { $follow.close(); }},
{text: 'yes', click: () => this.handleXXX()},
],
onClose: function() {
this.$vlayer.message({content: 'success closed', icon: 'success'})
}
});

In addition, it also supports custom pop-up window display position , The default is auto In the middle ['150px','100px'] | t | r | b | l | lt | rt | lb | rb

<!-- Custom pop up location -->
<v-layer v-model="showPosition" xclose maximize drag=".dragImg" :position="rb">
<img class="dragImg" src="xxx.jpg" />
</v-layer>

When you need to open the pop-up window, it's full screen , Just configure fullscreen:true that will do .
image

ok, be based on vue.js Develop desktop side pop-up box to share here . I hope you like it ~~

image

版权声明
本文为[xiaoyan2017]所创,转载请带上原文链接,感谢

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple