重构layer
parent
13665be881
commit
5c82a42bb4
|
@ -38,10 +38,7 @@
|
|||
&.shift {
|
||||
transition: all 0.5s ease-out;
|
||||
}
|
||||
&.scale {
|
||||
transform: scale(1.02);
|
||||
transition: transform 0.1s linear;
|
||||
}
|
||||
|
||||
&.blur {
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
@ -53,6 +50,7 @@
|
|||
/* 弹层样式 */
|
||||
|
||||
&__title {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
padding: 15px;
|
||||
|
@ -62,17 +60,33 @@
|
|||
}
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
min-height: 50px;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
|
||||
::slotted(&__input) {
|
||||
flex: 1;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
::slotted(&__frame) {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
resize: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__ctrl {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
padding: 15px;
|
||||
|
@ -156,6 +170,7 @@
|
|||
</style>
|
||||
|
||||
<script>
|
||||
import '../form/input'
|
||||
import Drag from '../drag/core'
|
||||
|
||||
import { nextTick, bind, unbind, clickOutside } from '../utils'
|
||||
|
@ -164,26 +179,20 @@ const LANGUAGES = {
|
|||
en: {
|
||||
TITLE: 'Dialog',
|
||||
BTNS: ['Cancel', 'OK'],
|
||||
YES_BTN: 'OK',
|
||||
NO_BTN: 'Cancel',
|
||||
ERROR: 'The layer instance is not exists',
|
||||
NEED_CONTAINER: 'layer "tips" require a DOM object as container'
|
||||
ERROR: 'The layer instance is not exists'
|
||||
},
|
||||
zh: {
|
||||
TITLE: '提示',
|
||||
BTNS: ['取消', '确定'],
|
||||
YES_BTN: '确定',
|
||||
NO_BTN: '取消',
|
||||
ERROR: '要关闭的layer实例不存在',
|
||||
NEED_CONTAINER: 'tips类型需要指定一个元素节点作为容器'
|
||||
ERROR: '要关闭的layer实例不存在'
|
||||
}
|
||||
}
|
||||
LANGUAGES['zh-CN'] = LANGUAGES.zh
|
||||
const lang =
|
||||
LANGUAGES[window.__ENV_LANG__ || navigator.language] || LANGUAGES.en
|
||||
|
||||
let unique = null // 储存当前打开的1/2/3类型的弹窗
|
||||
let lid = 0
|
||||
let unique = null // 储存当前打开的alert/confirm/prompt类型的弹窗
|
||||
|
||||
let defconf = {
|
||||
type: 1, // 弹窗类型
|
||||
background: '#fff',
|
||||
|
@ -200,9 +209,6 @@ let defconf = {
|
|||
offset: {} // 弹窗出来后的坐标, 为数组,可有4个值,依次是 上右下左
|
||||
}
|
||||
|
||||
const uuid = function() {
|
||||
return 'layer-' + lid++
|
||||
}
|
||||
// 要保证弹层唯一的类型
|
||||
const UNIQUE_TYPES = ['alert', 'confirm', 'prompt']
|
||||
|
||||
|
@ -219,57 +225,81 @@ const fixOffset = function(offset) {
|
|||
return offset
|
||||
}
|
||||
|
||||
/* type: { // 弹窗类型对应的id值
|
||||
1: 'alert',
|
||||
2: 'confirm',
|
||||
3: 'prompt',
|
||||
4: 'iframe',
|
||||
5: 'tips',
|
||||
6: 'loading',
|
||||
7: 'msg',
|
||||
} */
|
||||
|
||||
function createLayer(opt) {
|
||||
var layDom = document.createElement('wc-layer')
|
||||
layDom.type = opt.type
|
||||
if (opt.mask) {
|
||||
layDom.setAttribute('mask', '')
|
||||
}
|
||||
|
||||
if (opt.title) {
|
||||
layDom.title = opt.title
|
||||
if (opt.btns && opt.btns.length) {
|
||||
layDom.props.btns = opt.btns
|
||||
} else {
|
||||
layDom.props.btns = lang.BTNS.concat()
|
||||
}
|
||||
|
||||
if (opt.intercept && typeof opt.intercept === 'function') {
|
||||
layDom.props.intercept = opt.intercept
|
||||
}
|
||||
|
||||
layDom.props.background = opt.background
|
||||
layDom.props.mask = opt.mask
|
||||
layDom.props.maskClose = opt.maskClose
|
||||
layDom.props.maskColor = opt.maskColor
|
||||
|
||||
layDom.type = opt.type
|
||||
layDom.innerHTML = opt.content
|
||||
document.body.appendChild(layDom)
|
||||
|
||||
return layDom
|
||||
// 这3种类型, 只允许同时存在1个, 如果之前有弹出则关闭
|
||||
if (UNIQUE_TYPES.includes(opt.type)) {
|
||||
if (unique) {
|
||||
unique.close()
|
||||
}
|
||||
unique = layDom
|
||||
}
|
||||
return layDom.promise
|
||||
}
|
||||
|
||||
const _layer = {
|
||||
alert(content, title) {
|
||||
alert(content, title = lang.TITLE) {
|
||||
return createLayer({
|
||||
type: 'alert',
|
||||
title: title || 'Hello world!',
|
||||
content:
|
||||
content || '<p>blablablablsjkdjbskj fghjsdgfjs djfhjsdgf jhs jhj</p>',
|
||||
title,
|
||||
content,
|
||||
fixed: true,
|
||||
mask: true
|
||||
})
|
||||
},
|
||||
confirm(content, title) {
|
||||
confirm(content, title = lang.TITLE, intercept) {
|
||||
if (typeof title === 'function') {
|
||||
intercept = title
|
||||
title = lang.TITLE
|
||||
}
|
||||
return createLayer({
|
||||
type: 'confirm',
|
||||
title: title || 'Hello world!',
|
||||
content: content || 'blablablablsjkdjbskj fghjsdgfjs djfhjsdgf jhs jhj',
|
||||
title,
|
||||
content,
|
||||
fixed: true,
|
||||
mask: true
|
||||
mask: true,
|
||||
intercept
|
||||
})
|
||||
},
|
||||
prompt(title = lang.TITLE, intercept) {
|
||||
return createLayer({
|
||||
type: 'prompt',
|
||||
title,
|
||||
content: `<wc-input autofocus class="layer__content__input"></wc-input>`,
|
||||
fixed: true,
|
||||
mask: true,
|
||||
intercept
|
||||
})
|
||||
},
|
||||
frame(url, extra = {}) {
|
||||
return createLayer({
|
||||
...extra,
|
||||
type: 'frame',
|
||||
content: `<iframe ref="frame" class="frame-box" src="${url}"></iframe>`,
|
||||
content: `<iframe class="layer__content__frame" src="${url}"></iframe>`,
|
||||
fixed: true,
|
||||
mask: true,
|
||||
maskClose: true
|
||||
|
@ -310,25 +340,7 @@ const _layer = {
|
|||
|
||||
return _layer.open(opt)
|
||||
},
|
||||
prompt(title, yescb) {
|
||||
if (typeof yescb !== 'function') {
|
||||
return console.error(
|
||||
'argument [callback] requires a function, but ' +
|
||||
typeof yescb +
|
||||
' given'
|
||||
)
|
||||
}
|
||||
let opt = {
|
||||
type: 3,
|
||||
prompt: '',
|
||||
title,
|
||||
content: `<input class="prompt-value" ref="input" :class="{alert: !prompt}" :duplex="prompt" />`,
|
||||
fixed: true,
|
||||
yes: yescb
|
||||
}
|
||||
return _layer.open(opt)
|
||||
},
|
||||
close: close,
|
||||
|
||||
open(opt) {
|
||||
if (typeof opt === 'string') {
|
||||
opt = 'layerwrap-' + opt
|
||||
|
@ -356,8 +368,7 @@ const _layer = {
|
|||
} else {
|
||||
return new __layer__(opt).init.$id
|
||||
}
|
||||
},
|
||||
version: Anot.ui.layer
|
||||
}
|
||||
}
|
||||
|
||||
/* Anot.directive('layer', {
|
||||
|
@ -494,8 +505,6 @@ const _layer = {
|
|||
}
|
||||
}) */
|
||||
|
||||
window.layer = _layer
|
||||
|
||||
function renderBtns(list) {
|
||||
var html = ''
|
||||
list.forEach((t, i) => {
|
||||
|
@ -505,8 +514,9 @@ function renderBtns(list) {
|
|||
return html
|
||||
}
|
||||
|
||||
export default class Layer {
|
||||
class Layer {
|
||||
props = {
|
||||
btns: [],
|
||||
type: 'msg',
|
||||
title: '',
|
||||
fixed: false //是否固定位置
|
||||
|
@ -518,42 +528,56 @@ export default class Layer {
|
|||
this.__TITLE__ = this.root.children[1].firstElementChild
|
||||
this.__BODY__ = this.root.children[1].children[1]
|
||||
this.__CTRL__ = this.root.children[1].lastElementChild
|
||||
|
||||
this.promise = new Promise((resolve, reject) => {
|
||||
this.resolve = resolve
|
||||
this.reject = reject
|
||||
})
|
||||
}
|
||||
|
||||
set title(val) {
|
||||
this.__TITLE__.textContent = val || lang.TITLE
|
||||
if (val) {
|
||||
this.__TITLE__.textContent = val
|
||||
this.__TITLE__.style.display = ''
|
||||
} else {
|
||||
this.__TITLE__.style.display = 'none'
|
||||
}
|
||||
}
|
||||
|
||||
set type(val) {
|
||||
this.props.type = val
|
||||
var { btns } = this.props
|
||||
|
||||
switch (val) {
|
||||
case 'alert':
|
||||
this.__CTRL__.innerHTML = renderBtns(['确定'])
|
||||
while (btns.length > 1) {
|
||||
btns.splice(0, 1)
|
||||
}
|
||||
break
|
||||
case 'confirm':
|
||||
case 'prompt':
|
||||
this.__CTRL__.innerHTML = renderBtns(['取消', '确定'])
|
||||
while (btns.length > 2) {
|
||||
btns.splice(0, 1)
|
||||
}
|
||||
break
|
||||
case 'toast':
|
||||
break
|
||||
case 'frame':
|
||||
btns = []
|
||||
break
|
||||
default:
|
||||
val = 'common'
|
||||
if (this.opt.btns) {
|
||||
this.__CTRL__.innerHTML = renderBtns(this.opt.btns)
|
||||
break
|
||||
}
|
||||
this.props.type = val
|
||||
if (btns.length) {
|
||||
this.__CTRL__.innerHTML = renderBtns(btns)
|
||||
this.__CTRL__.style.display = ''
|
||||
} else {
|
||||
this.__CTRL__.style.display = 'none'
|
||||
}
|
||||
|
||||
this.setAttribute('type', val)
|
||||
}
|
||||
|
||||
get fixed() {
|
||||
return this.props.fixed
|
||||
}
|
||||
|
||||
set fixed(val) {
|
||||
this.props.fixed = !!val
|
||||
|
||||
|
@ -575,24 +599,81 @@ export default class Layer {
|
|||
}
|
||||
}
|
||||
|
||||
// 拦截 "确定"按钮的事件
|
||||
_intercept(input) {
|
||||
if (this.props.intercept) {
|
||||
this.props.intercept(input, _ => {
|
||||
delete this.props.intercept
|
||||
this.resolve(input)
|
||||
this.close()
|
||||
})
|
||||
} else {
|
||||
this.resolve(input)
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this._dragIns) {
|
||||
this._dragIns.destroy()
|
||||
}
|
||||
if (UNIQUE_TYPES.includes(this.props.type)) {
|
||||
unique = null
|
||||
}
|
||||
delete this.promise
|
||||
unbind(this.__CTRL__, 'click', this._handleBtnClick)
|
||||
this.parentNode.removeChild(this)
|
||||
}
|
||||
|
||||
mounted() {
|
||||
bind(this.__CTRL__, 'click', ev => {
|
||||
this._handleBtnClick = bind(this.__CTRL__, 'click', ev => {
|
||||
if (ev.target.tagName === 'BUTTON') {
|
||||
var idx = +ev.target.dataset.idx
|
||||
log(idx)
|
||||
var { intercept, type } = this.props
|
||||
|
||||
switch (type) {
|
||||
case 'alert':
|
||||
this.resolve()
|
||||
this.close()
|
||||
break
|
||||
case 'confirm':
|
||||
case 'prompt':
|
||||
if (idx === 0) {
|
||||
this.reject()
|
||||
this.close()
|
||||
} else {
|
||||
let inputValue = type === 'prompt' ? this.__INPUT__.value : null
|
||||
this._intercept(inputValue)
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
// 其他类型, 如有按钮, 直接返回按钮的索引, 不作任何拦截
|
||||
this.resolve(idx)
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (this.props.type === 'prompt') {
|
||||
this.__INPUT__ = this.__BODY__.firstElementChild.assignedNodes().pop()
|
||||
this._handleSubmit = bind(this.__INPUT__, 'submit', ev => {
|
||||
this._intercept(ev.detail)
|
||||
})
|
||||
}
|
||||
|
||||
if (this.props.mask) {
|
||||
this._handlMask = clickOutside(this.root.children[1], ev => {
|
||||
if (this.props.maskClose) {
|
||||
this.close()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
unmount() {}
|
||||
unmount() {
|
||||
unbind(document, 'mousedown', this._handlMask)
|
||||
}
|
||||
|
||||
watch() {
|
||||
switch (name) {
|
||||
|
@ -606,4 +687,8 @@ export default class Layer {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.layer = _layer
|
||||
|
||||
export default _layer
|
||||
</script>
|
||||
|
|
Reference in New Issue