diff --git a/src/layer/next.wc b/src/layer/next.wc index c7a5775..bf44ef5 100644 --- a/src/layer/next.wc +++ b/src/layer/next.wc @@ -42,6 +42,9 @@ transform: scale(1.02); transition: transform 0.1s linear; } + &.blur { + backdrop-filter: blur(5px); + } &:active { z-index: 65536; @@ -178,8 +181,7 @@ const LANGUAGES = { LANGUAGES['zh-CN'] = LANGUAGES.zh const lang = LANGUAGES[window.__ENV_LANG__ || navigator.language] || LANGUAGES.en -let layerDom = {} -let layerObj = {} + let unique = null // 储存当前打开的1/2/3类型的弹窗 let lid = 0 let defconf = { @@ -195,46 +197,14 @@ let defconf = { content: '', // 弹窗的内容 fixed: false, // 是否固定不可拖拽 shift: {}, // 弹窗出来的初始位置,用于出场动画 - offset: {}, // 弹窗出来后的坐标, 为数组,可有4个值,依次是 上右下左 - btns: [lang.YES_BTN, lang.NO_BTN] // 弹窗的2个按钮的文字 + offset: {} // 弹窗出来后的坐标, 为数组,可有4个值,依次是 上右下左 } -const $doc = Anot(document) + const uuid = function() { return 'layer-' + lid++ } -const close = function(id) { - if (typeof id !== 'string' && typeof id !== 'number') { - return Anot.error(lang.ERROR) - } - if (/^layerwrap\-/.test(id) || layerObj['layerwrap-' + id]) { - try { - id = (layerObj['layerwrap-' + id] ? 'layerwrap-' : '') + id - //未显示过,忽略 - if (!layerObj[id].show) { - return - } - layerObj[id].parentElem.replaceChild(layerObj[id].wrap, layerDom[id][0]) - layerObj[id].wrap.style.display = 'none' - layerObj[id].show = false - } catch (err) {} - } else { - unique = null - if (layerDom[id]) { - layerDom[id][0].classList.add('shift') - layerDom[id][1].classList.add('shift') - layerDom[id][0].style.opacity = '' - layerDom[id][1].style.opacity = 0 - setTimeout(function() { - try { - layerDom[id][0].parentNode.removeChild(layerDom[id][0]) - delete layerDom[id] - delete Anot.vmodels[id] - } catch (err) {} - }, 200) - } - } - document.body.style.overflow = '' -} +// 要保证弹层唯一的类型 +const UNIQUE_TYPES = ['alert', 'confirm', 'prompt'] const fixOffset = function(offset) { for (let i in offset) { @@ -259,457 +229,51 @@ const fixOffset = function(offset) { 7: 'msg', } */ -class __layer__ { - get dot() { - //loading的子元素数量 - return { - 1: 1, - 2: 5, - 3: 5, - 4: 9 - } +function createLayer(opt) { + var layDom = document.createElement('wc-layer') + layDom.type = opt.type + if (opt.mask) { + layDom.setAttribute('mask', '') } - constructor(opt) { - if (opt) { - let { yes, no, success } = opt - delete opt.yes - delete opt.no - delete opt.success - - this.__init__({ - state: { ...opt }, - props: { yes, no, success } - }) - .append() - .show() - } - this.timeout = null + if (opt.title) { + layDom.title = opt.title } - // 真正的初始化弹层配置 - __init__(opt) { - let _id = opt.$id || uuid() - this.init = { - $id: _id, - state: { - ...defconf, - ...opt.state - }, - props: opt.props, - skip: [ - 'area', - 'shift', - 'offset', - 'mask', - 'maskClose', - 'container', - 'follow' - ], - methods: { - shake() { - this.$refs.layer.classList.add('scale') - setTimeout(() => { - this.$refs.layer.classList.remove('scale') - }, 100) - }, - onMaskClick: function(ev) { - if (ev.target === ev.currentTarget) { - if (this.type < 4 && !this.maskClose) { - this.shake() - } else { - this.maskClose && this.close() - } - } - }, - handleConfirm: function() { - if (this.type === 3) { - if (!this.prompt) { - return this.shake() - } - } - if (typeof this.props.yes === 'function') { - let cb = [this.$id] - if (this.type === 3) { - cb.unshift(this.prompt) - } - this.props.yes.apply(this, cb) - } else { - this.close() - } - }, - handleCancel: function() { - if (typeof this.props.no === 'function') { - this.props.no.call(this, this.$id) - } else { - this.close() - } - }, - close: function() { - close(this.$id) - } - // cancelBubble: function(ev) { - // ev.cancelBubble = true - // } - }, - mounted: function() { - if (typeof this.props.success === 'function') { - this.props.success.call(this) - } - } - } + layDom.innerHTML = opt.content + document.body.appendChild(layDom) - // iframe类型补一个自适应高度的方法 - if (this.init.state.type === 4) { - this.init.methods.autoSize = function() { - let { layer, frame } = this.$refs - frame.onload = function() { - try { - let $body = frame.contentWindow.document.body - let { clientWidth, clientHeight } = $body - - layer.style.cssText += `width: ${clientWidth}px;height: ${clientHeight}px;` - frame.style.cssText += `height: ${clientHeight}px;` - } catch (err) {} - } - } - } - return this - } - - // 创建弹层容器及骨架 - create() { - let { state, $id } = this.init - let outerBox = document.createElement('div') - let layBox = document.createElement('div') - - outerBox.setAttribute('anot', $id) - outerBox.setAttribute(':on-click', 'onMaskClick') - - outerBox.classList.add('do-layer') - if (state.mask) { - outerBox.classList.add('mask') - if (state.container && state.container !== document.body) { - outerBox.classList.add('inner') - } - } - if (state.maskColor) { - outerBox.style.background = state.maskColor - } - - layBox.classList.add('layer-box') - layBox.classList.add('skin-normal') - - if (state.extraClass) { - layBox.classList.add(state.extraClass) - delete state.extraClass - } - if (state.shift) { - fixOffset(state.shift) - for (let k in state.shift) { - let val = state.shift[k] - val += isFinite(val) ? 'px' : '' - layBox.style.cssText += `${k}: ${val};` - } - } - - if (state.toast) { - layBox.classList.add('type-toast') - } else { - layBox.classList.add('type-' + state.type) - } - - layBox.setAttribute('ref', 'layer') - // layBox.setAttribute(':on-click', 'cancelBubble') - - // 暂时隐藏,避免修正定位时,能看到闪一下 - layBox.style.cssText += 'border-radius:' + state.radius + 'px' - - // 没有菜单栏, 且未禁止拖拽,则加上可拖拽属性 - if (!state.menubar && !state.fixed) { - layBox.setAttribute(':drag', '') - layBox.setAttribute('data-limit', 'window') - } - - // size of layer-content - var boxcss = '' - if (state.area[0] !== 'auto') { - boxcss += 'width: ' + state.area[0] + ';' - } - if (state.area[1] !== 'auto') { - boxcss += 'height: ' + state.area[1] + ';' - } - let arrow = '' - if (state.type === 5) { - arrow += `` - } - - layBox.innerHTML = ` - ${this.mkMenubar()} -
- - ${state.type === 6 ? this.mkLoading(state.load) : ''} -
- ${this.mkCtrl()} - ${arrow} - ` - delete state.wrap - outerBox.appendChild(layBox) - return [outerBox, layBox] - } - - // 创建loading元素 - mkLoading(style) { - return ` -
- - ${(style === 1 ? '' : '').repeat( - this.dot[style] - )} - -
- ` - } - - // 创建窗口导航条 - mkMenubar() { - let { menubar, fixed } = this.init.state - let html = '' - if (menubar) { - html = ` -
-
- ` - } - return html - } - - // 创建窗口按钮 - mkCtrl() { - let { type } = this.init.state - if (type > 3) { - return '' - } else { - let html = '' - let btns = ` - - ` - if (type > 1) { - btns = - ` - - ` + btns - } - html = ` -
- ${btns} -
- ` - return html - } - } - - append() { - let { state, $id } = this.init - let container = state.container - - if (state.type < 4) { - // 如果有已经打开的弹窗,则关闭 - if (unique) { - close(unique) - } - unique = $id - } - - // 返回一个数组,第1个元素是容器,第2个是骨架 - layerDom[$id] = this.create() - - delete state.toast - this.toast = true - if (!container) { - container = document.body - } - - container.appendChild(layerDom[$id][0]) - this.vm = Anot(this.init) - return this - } - - show() { - let vm = this.vm - let { state, $id } = this.init - let container = state.container - - setTimeout(function() { - let style = { background: state.background } - - let $dom1 = Anot(layerDom[$id][1]) - - // tips类型, 弹层的定位要在指定的容器上 - if (state.type === 5) { - let css = getComputedStyle(layerDom[$id][1]) - // 只有tips类型可以定义 `color` - style.color = state.color - style.opacity = 1 - let $container = Anot(container) - let $arrow = $container[0].querySelector('.arrow') - let cw = $container.innerWidth() - let ch = $container.innerHeight() - let ol = $container.offset().left - $doc.scrollLeft() - let ot = $container.offset().top - $doc.scrollTop() - - let layw = parseInt(css.width) - let layh = parseInt(css.height) - let arrowOffset = ['top'] - - Anot(layerDom[$id][1]).css(style) - - $container.bind('mouseenter', ev => { - let tmpStyle = { visibility: 'visible' } - ol = $container.offset().left - $doc.scrollLeft() - ot = $container.offset().top - $doc.scrollTop() - - if (ot + 18 < layh) { - arrowOffset[0] = 'bottom' - $arrow.style.borderBottomColor = state.background - tmpStyle.top = ot + ch + 8 - } else { - $arrow.style.borderTopColor = state.background - tmpStyle.top = ot - layh - 8 - } - - if (ol + cw * 0.7 + layw > window.innerWidth) { - tmpStyle.left = ol + cw * 0.3 - layw - arrowOffset[1] = 'left' - } else { - tmpStyle.left = ol + cw * 0.7 - } - - $arrow.classList.add('offset-' + arrowOffset.join('-')) - $dom1.css(tmpStyle) - }) - $container.bind('mouseleave', () => { - setTimeout(() => { - $arrow.classList.remove('offset-' + arrowOffset.join('-')) - arrowOffset = ['top'] - $arrow.style.borderBottomColor = '' - $arrow.style.borderTopColor = '' - layerDom[$id][1].style.visibility = 'hidden' - }, 100) - }) - } else { - let offsetStyle = { opacity: 1 } - if (state.offset) { - fixOffset(state.offset) - - Object.assign(offsetStyle, state.offset) - } - $dom1.css(style) - setTimeout(() => { - document.body.style.overflow = 'hidden' - layerDom[$id][1].classList.add('shift') - setTimeout(_ => { - $dom1.css(offsetStyle) - if (vm && vm.$refs.input) { - vm.$refs.input.focus() - } - setTimeout(_ => { - try { - layerDom[$id][1].classList.remove('shift') - } catch (err) {} - }, 500) - }, 50) - }, 50) - } - }, 4) - - // loading类型,回调需要自动触发 - if (state.type > 3) { - //大于0自动触发超时关闭 - if (state.timeout > 0) { - clearTimeout(this.timeout) - this.timeout = setTimeout(() => { - clearTimeout(this.timeout) - close($id) - - // 为loading类型时,自动关闭同时触发回调 - if (state.type === 6) { - this.vm.props.yes.call(this.vm, $id) - } - }, state.timeout) - } else if (state.type === 6) { - // loading类型, 非自动关闭时, 主动触发回调 - this.vm.props.yes.call(this.vm, $id) - } - } - } + return layDom } const _layer = { - alert(content, title, cb) { - let opt = { content, fixed: true } - - if (typeof title === 'function') { - opt.yes = title - } else { - if (title) { - opt.title = title + '' - } - if (cb && typeof cb === 'function') { - opt.yes = cb - } - } - var l = document.createElement('wc-layer') - l.title = 'hello' - l.setAttribute('type', 'alert') - l.setAttribute('mask', '') - l.innerHTML = '

ffdfdffd

' - document.body.appendChild(l) - - return _layer.open(opt) + alert(content, title) { + return createLayer({ + type: 'alert', + title: title || 'Hello world!', + content: + content || '

blablablablsjkdjbskj fghjsdgfjs djfhjsdgf jhs jhj

', + fixed: true, + mask: true + }) }, - confirm(content, title, yescb, nocb) { - let opt = { content, fixed: true, type: 2 } - - if (typeof title === 'function') { - opt.yes = title - if (typeof yescb === 'function') { - opt.no = yescb - } - } else { - if (title) { - opt.title = title + '' - } - if (yescb && typeof yescb === 'function') { - opt.yes = yescb - } - if (nocb && typeof nocb === 'function') { - opt.no = nocb - } - } - return _layer.open(opt) + confirm(content, title) { + return createLayer({ + type: 'confirm', + title: title || 'Hello world!', + content: content || 'blablablablsjkdjbskj fghjsdgfjs djfhjsdgf jhs jhj', + fixed: true, + mask: true + }) }, frame(url, extra = {}) { - let opt = { + return createLayer({ + type: 'frame', content: ``, - menubar: false, - maskClose: true, - type: 4, - ...extra - } - return _layer.open(opt) + fixed: true, + mask: true, + maskClose: true + }) }, toast(txt, type = 'info', timeout = 2500) { if (typeof type === 'number') { @@ -746,53 +310,6 @@ const _layer = { return _layer.open(opt) }, - load(style, container, cb) { - style = style >>> 0 - style = style < 1 ? 1 : style > 4 ? 4 : style - - if (typeof container === 'function') { - cb = container - container = null - } else { - if (!(container instanceof HTMLElement)) { - container = null - } - if (typeof cb !== 'function') { - cb = Anot.noop - } - } - return _layer.open({ - container, - type: 6, - load: style, - yes: cb, - menubar: false, - background: 'none', - fixed: true - }) - }, - tips(content, container, opt = {}) { - if (!(container instanceof HTMLElement)) { - return Anot.error(lang.NEED_CONTAINER) - } - - if (!opt.background) { - opt.background = 'rgba(0,0,0,.5)' - } - if (!opt.color) { - opt.color = '#fff' - } - Object.assign(opt, { - container, - content, - type: 5, - fixed: true, - mask: false, - menubar: false, - timeout: 0 - }) - return _layer.open(opt) - }, prompt(title, yescb) { if (typeof yescb !== 'function') { return console.error( @@ -1008,6 +525,8 @@ export default class Layer { } set type(val) { + this.props.type = val + switch (val) { case 'alert': this.__CTRL__.innerHTML = renderBtns(['确定']) @@ -1018,12 +537,17 @@ export default class Layer { break case 'toast': break + case 'frame': + break default: + val = 'common' if (this.opt.btns) { this.__CTRL__.innerHTML = renderBtns(this.opt.btns) break } } + + this.setAttribute('type', val) } get fixed() { @@ -1033,24 +557,37 @@ export default class Layer { set fixed(val) { this.props.fixed = !!val + // 这3类弹层不允许拖拽 + if (UNIQUE_TYPES.includes(this.props.type)) { + return + } + if (this.props.fixed) { - this._dragIns = new Drag(this.root.children[1]).by(this.__TITLE__, { - overflow: false - }) - } else { if (this._dragIns) { this._dragIns.destroy() this._dragIns = null } + } else { + this._dragIns = new Drag(this.root.children[1]).by(this.__TITLE__, { + overflow: false + }) + this.removeAttribute('fixed') } } + close() { + if (this._dragIns) { + this._dragIns.destroy() + } + this.parentNode.removeChild(this) + } + mounted() { bind(this.__CTRL__, 'click', ev => { if (ev.target.tagName === 'BUTTON') { var idx = +ev.target.dataset.idx log(idx) - this.parentNode.removeChild(this) + this.close() } }) }