svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer

  • svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer已关闭评论
  • 188 次浏览
  • A+
所属分类:Web前端
摘要

基于Svelte3.x 开发pc网页版 自定义弹窗组件svelteLayer。 svelte-layer:基于svelte.js 轻量级多功能pc桌面端 对话框组件。支持多种弹窗类型、30+参数随意组合配置,整合了拖拽/四周缩放/最大化/记忆弹窗位置/全屏/自定义层级 等功能。

基于Svelte3.x开发pc网页版自定义弹窗组件svelteLayer

svelte-layer:基于svelte.js轻量级多功能pc桌面端对话框组件。支持多种弹窗类型、30+参数随意组合配置,整合了拖拽/四周缩放/最大化/记忆弹窗位置/全屏/自定义层级等功能。

svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer

svelteLayer功能效果上有些类似layer.js插件。

◆ 快速引入

在需要使用组件功能的页面,引入组件。

import Layer, {svLayer} from '$lib/Layer'

svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer

svelteLayer支持标签式+函数式两种调用方式。

  • 标签式调用
<!-- 询问框 --> <Layer bind:open={showConfirm} shadeClose="false" title="警告信息" xclose zIndex="2001" lockScroll={false} resize dragOut     content="<div style='color:#00e0a1;padding:20px 40px;'>这里是确认框提示信息</div>"     btns={[         {text: '取消', click: () => showConfirm=false},         {text: '确定', style: 'color:#e63d23;', click: handleInfo},     ]} />

  • 函数式调用
function handleInfo(e) {     let el = svLayer({         title: '标题',         content: `<div style="padding:20px;">             <p>函数式调用:<em style="color:#999;">svLayer({...})</em></p>         </div>`,         resize: true,         btns: [             {                 text: '取消',                 click: () => {                     // 关闭弹窗                     el.$set({open: false})                 }             },             {                 text: '确认',                 style: 'color:#09f;',                 click: () => {                     svLayer({                         type: 'toast',                         icon: 'loading',                         content: '加载中...',                         opacity: .2,                         time: 2                     })                 }             },         ]     }) }

svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer

支持标签式和函数式混合搭配调用,还支持如上图动态加载外部组件。

svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer

svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer

svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer

svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer

svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer

svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer

◆ 参数配置

svelte-layer默认支持如下参数自定义配置。

<script context="module">     let index = 0 // 用于控制倒计时临时索引     let lockNum = 0 // 用于控制锁定屏幕临时索引 </script>  <script>     // 是否打开弹窗bind:open={showDialog}     export let open = false     // 弹窗标识     export let id = undefined     // 标题     export let title = ''     // 内容     export let content = ''     // 弹窗类型     export let type = ''     // 自定义样式     export let layerStyle = undefined     // 自定义类名     export let customClass = ''     // toast图标     export let icon = ''     // 是否显示遮罩层     export let shade = true     // 点击遮罩层关闭     export let shadeClose = true     // 锁定屏幕     export let lockScroll = true     // 遮罩层透明度     export let opacity = ''     // 是否显示关闭图标     export let xclose = false     // 关闭图标位置     export let xposition = 'right'     // 关闭图标颜色     export let xcolor = '#000'     // 弹窗动画     export let anim = 'scaleIn'     // 弹出位置(auto | ['100px','50px'] | t | r | b | l | lt | rt | lb | rb)     export let position = 'auto'     // 抽屉弹窗     export let drawer = ''     // 右键弹窗定位     export let follow = null     // 弹窗自动关闭时间     export let time = 0     // 弹窗层级     export let zIndex = 202204     // 置顶弹窗     export let topmost = false     // 弹窗大小     export let area = 'auto'     // 弹窗最大宽度     export let maxWidth = 375     // 弹窗是否最大化     export let maximize = false     // 弹窗是否全屏     export let fullscreen = false     // 是否固定     export let fixed = true     // 是否拖拽     export let drag = '.vlayer__wrap-tit'     // 是否拖拽屏幕外     export let dragOut = false     // 限制拖拽方向 vertical|horizontal     export let dragDir = ''     // 拖拽结束回调 {width: 120, height: 120, x: 100, y: 100}     export let dragEnd = undefined     // 是否缩放     export let resize = false      // 弹窗按钮事件     export let btns = null     /*export let btns = [         {text: '取消', style: 'color:red', disabled: true, click: null},         {text: '确定', style: 'color:blue', click: null}     ]*/      // 函数式打开|关闭回调     export let onOpen = undefined     export let onClose = undefined     export let beforeClose = undefined      // 接收函数移除指令     export let remove = undefined      import { onMount, afterUpdate, createEventDispatcher, tick } from 'svelte'     const dispatch = createEventDispatcher()          // ... </script>

弹窗模板及核心逻辑处理。

<div class="vui__layer" class:opened class:vui__layer-closed={closeCls} id={id} bind:this={el}>     <!-- 遮罩层 -->     {#if bool(shade)}<div class="vlayer__overlay" on:click={shadeClicked} style:opacity></div>{/if}     <!-- 主体 -->     <div class="vlayer__wrap {type&&'popui__'+type} anim-{anim}" style="{layerStyle}">         {#if title}<div class="vlayer__wrap-tit">{@html title}</div>{/if}         {#if icon&&type=='toast'}<div class="vlayer__toast-icon vlayer__toast-{icon}">{@html toastIcon[icon]}</div>{/if}         <div class="vlayer__wrap-cntbox">             <!-- 判断content插槽是否存在 -->             {#if $$slots.content}                 <div class="vlayer__wrap-cnt"><slot name="content" /></div>             {:else}                 {#if content}                     <!-- iframe -->                     {#if type=='iframe'}                     <div class="vlayer__wrap-iframe">                         <iframe scrolling="auto" allowtransparency="true" frameborder="0" src={content}></iframe>                     </div>                     <!-- message|notify|popover -->                     {:else if type=='message' || type=='notify' || type=='popover'}                     <div class="vlayer__wrap-cnt">                         {#if icon}<i class="vlayer-msg__icon {icon}">{@html messageIcon[icon]}</i>{/if}                         <div class="vlayer-msg__group">                             {#if title}<div class="vlayer-msg__title">{@html title}</div>{/if}                             <div class="vlayer-msg__content">{@html content}</div>                         </div>                     </div>                     <!-- 加载动态组件 -->                     {:else if type == 'component'}                     <svelte:component this={content}/>                     {:else}                     <div class="vlayer__wrap-cnt">{@html content}</div>                     {/if}                 {/if}             {/if}             <slot />         </div>          <!-- 按钮组 -->         {#if btns}         <div class="vlayer__wrap-btns">             {#each btns as btn,index}                 <span class="btn" class:btn-disabled={btn.disabled} style="{btn.style}">{@html btn.text}</span>             {/each}         </div>         {/if}          {#if xclose}         <span class="vlayer__xclose" style="color: {xcolor}" on:click={hide}></span>         {/if}         {#if maximize}<span class="vlayer__maximize" on:click={maximizeClicked}></span>{/if}         <!-- 缩放 -->         {#if resize}         <span class="vlayer__groupresize">             <i class="vlayer__resize LT"></i>             <i class="vlayer__resize RT"></i>             <i class="vlayer__resize LB"></i>             <i class="vlayer__resize RB"></i>         </span>         {/if}     </div>     <!-- 优化拖拽卡顿 -->     <div class="vlayer__dragfix"></div> </div>  <script>     /**      * @Desc     Svelte.js桌面端对话框组件SvelteLayer      * @Time     andy by 2022-04      * @About    Q:282310962  wx:xy190310      */          // ...      onMount(() => {         console.log('监听弹窗开启')         window.addEventListener('resize', autopos, false)         return () => {             console.log('监听弹窗关闭')             window.removeEventListener('resize', autopos, false)         }     })      afterUpdate(() => {         console.log('监听弹窗更新')     })      // 动态监听开启/关闭     $: if(open) {         show()     }else {         hide()     }      /**      * 开启弹窗      */     async function show() {         if(opened) return         opened = true         dispatch('open')         typeof onOpen === 'function' && onOpen()          // 避免获取弹窗宽高不准确         await tick()          zIndex = util.getZIndex(zIndex) + 1          auto()     }      /**      * 关闭弹窗      */     function hide() {         // ...     }      // 弹窗位置     function auto() {         autopos()          // 全屏弹窗         if(fullscreen) {             full()         }          // 拖拽|缩放         move()     }      // 弹窗定位     function autopos() {         if(!opened) return         let ol, ot         let pos = position         let isfixed = bool(fixed)         let vlayero = el.querySelector('.vlayer__wrap')          if(!isfixed || follow) {             vlayero.style.position = 'absolute'         }          let area = [util.client('width'), util.client('height'), vlayero.offsetWidth, vlayero.offsetHeight]          ol = (area[0] - area[2]) / 2         ot = (area[1] - area[3]) / 2          if(follow) {             offset()         }else {             typeof pos === 'object' ? (                 ol = parseFloat(pos[0]) || 0, ot = parseFloat(pos[1]) || 0             ) : (                 pos == 't' ? ot = 0 :                  pos == 'r' ? ol = area[0] - area[2] :                  pos == 'b' ? ot = area[1] - area[3] :                  pos == 'l' ? ol = 0 :                  pos == 'lt' ? (ol = 0, ot = 0) :                  pos == 'rt' ? (ol = area[0] - area[2], ot = 0) :                  pos == 'lb' ? (ol = 0, ot = area[1] - area[3]) :                 pos == 'rb' ? (ol = area[0] - area[2], ot = area[1] - area[3]) :                  null             )              vlayero.style.left = parseFloat(isfixed ? ol : util.scroll('left') + ol) + 'px'             vlayero.style.top = parseFloat(isfixed ? ot : util.scroll('top') + ot) + 'px'         }     }      // 跟随定位     function offset() {         let ow, oh, ps         let vlayero = el.querySelector('.vlayer__wrap')          ow = vlayero.offsetWidth         oh = vlayero.offsetHeight         ps = util.getFollowRect(follow, ow, oh)         tipArrow = ps[2]          vlayero.style.left = ps[0] + 'px'         vlayero.style.top = ps[1] + 'px'     }      // 最大化弹窗     async function full() {         // ...     }      // 复位弹窗     async function restore() {         // ...     }      // 拖拽缩放     function move() {         let isfixed = bool(fixed)         let isdragOut = bool(dragOut)         let c = {}          let vlayero = el.querySelector('.vlayer__wrap')         let otit = el.querySelector('.vlayer__wrap-tit')         let ocnt = el.querySelector('.vlayer__wrap-cntbox')         let obtn = el.querySelector('.vlayer__wrap-btns')         let odrag = el.querySelector(drag)         let oresize = el.querySelectorAll('.vlayer__resize')         let ofix = el.querySelector('.vlayer__dragfix')          // 拖拽         if(odrag) {             odrag.style.cursor = util.isIE() ? 'move' : 'grab'             util.on(odrag, 'mousedown', function(e) {                 // ...             })         }          util.on(document, 'mousemove', function(e) {             if(c.dragTrigger) {                 let iL = e.clientX - c.pos[0] + c.area[0]                 let iT = e.clientY - c.pos[1] + c.area[1]                 let fixL = isfixed ? 0 : c.scroll[1]                 let fixT = isfixed ? 0 : c.scroll[2]                 let iMaxL = c.client[0] + fixL - c.area[2]                 let iMaxT = c.client[1] + fixT - c.area[3]                 let oMaxT = c.scroll[0] - c.area[3]                  // 边界检测                 if(isdragOut) {                     iT = iT < 0 ? 0 : iT                     iT = (iT > oMaxT) ? oMaxT : iT                 }else {                     iL = (iL < fixL) ? fixL : iL                     iL = (iL > iMaxL) ? iMaxL : iL                     iT = (iT < fixT) ? fixT : iT                     iT = (iT > iMaxT) ? iMaxT : iT                 }                  // 记录拖拽弹窗坐标                 c.dragPosition = {                     width: c.area[2],                     height: c.area[3],                     x: iL,                     y: iT                 }                  // 限制拖拽方向                 dragDir == 'horizontal' ? (vlayero.style.left = iL + 'px')                 :                 dragDir == 'vertical' ? (vlayero.style.top = iT + 'px')                 :                 (vlayero.style.left = iL + 'px', vlayero.style.top = iT + 'px')             }              // 边角缩放             if(c.resizeTrigger && c.elem) {                 // ...             }         })          util.on(document, 'mouseup', function() {             c.dragTrigger && (                 delete c.dragTrigger, ofix.style.display = 'none',                 typeof dragEnd === 'function' && dragEnd(dragPosition)             )             c.resizeTrigger && (                 delete c.resizeTrigger, ofix.style.display = 'none'             )             document.onmouseup = null         })     }      // 点击最大化按钮     function maximizeClicked(e) {         let o = e.target         if(o.classList.contains('maximized')) {             restore()         }else {             full()         }     }          //... </script>

svelte-layer还支持类型为 message | notify | popover 弹窗。

svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer

svLayer.message({}) svLayer.notify({}) svLayer.popover({})

调用方式如上,只支持函数式调用。

svelte-layer支持自定义拖拽区域 drag: '#header' ,是否拖拽到窗口外 dragOut: true 。还支持iframe弹窗类型 type: 'iframe' ,配置 topmost: true 即可让当前活动窗口保持置顶状态。

该组件还有一大亮点,就是支持动态引入外部组件。

import Counter from '$lib/Counter.svelte'  // 动态加载组件(函数式调用) function showComponentLayer() {     svLayer({         type: 'component',         title: '动态加载组件',         content: Counter,         resize: true,         xclose: true,         maximize: true,         area: ['360px', '250px']     }) }  <!-- 组件调用 --> <Layer bind:open={showComponent} content="这里是内容信息" resize drag=".vlayer__wrap-cnt"     btns={[         {text: '确认', style: 'color:#f60;', click: () => showComponent=false},     ]}     on:open={handleOpen} on:close={handleClose} >     <svelte:fragment slot="content">         <Counter />     </svelte:fragment> </Layer>

OK,基于Svelte.js开发pc端弹窗组件就分享到这里。希望对大家有一些帮助~ ?

最后附上一个svelte3+svelteKit聊天实例项目

svelte3.x+sass仿微信app聊天:https://www.cnblogs.com/xiaoyan2017/p/16110203.html

svelte组件:svelte3自定义桌面PC端对话框组件svelte-layer