This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
bytedo
/
wcui
Archived
1
0
Fork 0

重构layer

old
宇天 2019-08-28 19:06:13 +08:00
parent 13665be881
commit 5c82a42bb4
1 changed files with 167 additions and 82 deletions

View File

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