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-09-04 18:12:41 +08:00
parent 823e17e5ba
commit 33111851db
3 changed files with 116 additions and 267 deletions

View File

@ -1,30 +0,0 @@
v1.0.0-base / 2017-09-20
==================
+ 统一字体图标
+ 精简动画类型
+ 优化样式
v0.0.4-base / 2017-04-20
==================
+ 优化offset的处理
+ 优化样式
v0.0.3-base / 2017-04-15
==================
+ 重构wrap方式创建弹窗实例的实现
v0.0.2-base / 2017-04-13
==================
+ 修复:layer方式创建实例时,漏掉自身的bug;
+ 修复layer.open()方法打开已有实例时不返回id的bug;
+ 修复layer.close()方法关闭实例时,未修改实例状态的bug;
+ 修改特殊模式下的实例的最小宽度为10px;
+ 优化:layer方式创建实例的逻辑处理;
+ 优化layer.alert()方法参数的处理;
v0.0.1-base / 2017-04-06
==================
+ 完成layer base版移植

View File

@ -1,147 +0,0 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2016-09-21 01:36:29
*
*/
'use strict'
import layer from './core'
const log = console.log
/* Anot.directive('layer', {
priority: 8090,
init: function(binding) {
// 去掉:layer属性,避免二次扫描
binding.element.removeAttribute(binding.name)
if (!binding.param || binding.param !== 'tips') {
binding.param = '' // 去掉param,保证之后的逻辑处理正常
binding.element.style.display = 'none'
}
},
update: function(val) {
if (!val) {
return console.error(
`SyntaxError: Unexpected [${this.name}=${this.expr}]`
)
}
let state = Object.assign({ type: 7, wrap: true }, this.element.dataset)
if (!this.param) {
let init = { $id: 'layerwrap-' + val, state, props: {} }
if (state.hasOwnProperty('area')) {
state.area = state.area.split(',')
}
if (state.hasOwnProperty('shift')) {
state.shift = fixOffset(new Function(`return ${state.shift}`)())
}
if (state.hasOwnProperty('offset')) {
state.offset = fixOffset(new Function(`return ${state.offset}`)())
}
if (state.hasOwnProperty('btns')) {
state.btns = state.btns.split(',')
}
if (!state.hasOwnProperty('menubar')) {
state.menubar = false
}
let tmp = new __layer__().__init__(init)
//去掉data-*属性
for (let i in this.element.dataset) {
delete this.element.dataset[i]
}
layerObj[tmp.init.$id] = {
obj: tmp,
parentElem: this.element.parentNode,
wrap: this.element,
show: false
}
layerDom[tmp.init.$id] = tmp.create()
} else if (this.param === 'tips') {
let tips = document.createElement('div')
let cont = document.createElement('span')
let arrow = document.createElement('i')
let $container = Anot(this.element)
let { position } = getComputedStyle(this.element)
tips.className = 'do-layer__tips'
cont.className = 'layer-content'
arrow.className = 'arrow'
cont.textContent = val
tips.appendChild(cont)
tips.appendChild(arrow)
if (position === 'static') {
this.element.style.position = 'relative'
}
this.element.appendChild(tips)
let style = {}
if (state.color) {
style.color = state.color
}
if (state.color) {
style.background = state.background
}
let cw = $container.innerWidth()
let ch = $container.innerHeight()
let arrowOffset = ['top']
// log(tips, layw, layh)
Anot(tips).css(style)
$container.bind('mouseenter', ev => {
let tmpStyle = { visibility: 'visible' }
let layw = tips.clientWidth
let layh = tips.clientHeight
let { left, top } = $container.offset()
let ol = left - $doc.scrollLeft()
let ot = top - $doc.scrollTop()
// 判断位置是以确定出现 在上还是在下
if (ot < layh + 8) {
arrowOffset[0] = 'bottom'
arrow.style.borderBottomColor = state.background
tmpStyle.bottom = ''
tmpStyle.top = ch + 8
} else {
arrow.style.borderTopColor = state.background
tmpStyle.top = ''
tmpStyle.bottom = ch + 8
}
if (ol + cw * 0.7 + layw > window.innerWidth) {
tmpStyle.left = cw * 0.3 - layw
arrowOffset[1] = 'left'
} else {
tmpStyle.left = cw * 0.7
}
arrow.classList.add('offset-' + arrowOffset.join('-'))
Anot(tips).css(tmpStyle)
})
$container.bind('mouseleave', () => {
setTimeout(() => {
arrow.classList.remove('offset-' + arrowOffset.join('-'))
arrowOffset = ['top']
arrow.style.borderBottomColor = ''
arrow.style.borderTopColor = ''
tips.style.visibility = 'hidden'
}, 100)
})
}
}
}) */
export default layer

View File

@ -7,12 +7,22 @@
</template> </template>
<style lang="scss"> <style lang="scss">
:host { :host {
display: flex; display: none;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
width: auto; width: auto;
height: auto; height: auto;
} }
:host([alert]),
:host([confirm]),
:host([prompt]),
:host([frame]),
:host([toast]),
:host([notify]),
:host([common]) {
display: flex;
}
.noselect { .noselect {
-webkit-touch-callout: none; -webkit-touch-callout: none;
-webkit-user-select: none; -webkit-user-select: none;
@ -187,9 +197,9 @@
backdrop-filter: blur(5px); backdrop-filter: blur(5px);
} }
:host([type='alert']), :host([alert]),
:host([type='confirm']), :host([confirm]),
:host([type='prompt']) { :host([prompt]) {
.layer { .layer {
max-width: 600px; max-width: 600px;
min-width: 300px; min-width: 300px;
@ -200,7 +210,7 @@
} }
} }
} }
:host([type='notify']) { :host([notify]) {
.layer { .layer {
width: 300px; width: 300px;
height: 120px; height: 120px;
@ -210,7 +220,7 @@
} }
} }
} }
:host([type='toast']) { :host([toast]) {
.layer { .layer {
box-shadow: none; box-shadow: none;
@ -230,13 +240,11 @@ import { nextTick, bind, unbind, clickOutside } from '../utils'
const LANGUAGES = { const LANGUAGES = {
en: { en: {
TITLE: 'Dialog', TITLE: 'Dialog',
BTNS: ['Cancel', 'OK'], BTNS: ['Cancel', 'OK']
ERROR: 'The layer instance is not exists'
}, },
zh: { zh: {
TITLE: '提示', TITLE: '提示',
BTNS: ['取消', '确定'], BTNS: ['取消', '确定']
ERROR: '要关闭的layer实例不存在'
} }
} }
LANGUAGES['zh-CN'] = LANGUAGES.zh LANGUAGES['zh-CN'] = LANGUAGES.zh
@ -260,9 +268,20 @@ function renderBtns(list) {
class Layer { class Layer {
props = { props = {
left: 'auto',
right: 'auto',
top: 'auto',
bottom: 'auto',
from: Object.create(null),
to: Object.create(null),
btns: [], btns: [],
type: '', type: '',
title: '', title: '',
blur: false,
background: null,
mask: false,
'mask-close': false,
'mask-color': null,
fixed: false //是否固定位置 fixed: false //是否固定位置
} }
@ -282,7 +301,14 @@ class Layer {
set title(val) { set title(val) {
this.props.title = val this.props.title = val
if (val) { if (val) {
this.__TITLE__.textContent = val if (this.__TITLE__.firstElementChild) {
this.__TITLE__.insertBefore(
document.createTextNode(val),
this.__TITLE__.firstElementChild
)
} else {
this.__TITLE__.textContent = val
}
this.__TITLE__.style.display = '' this.__TITLE__.style.display = ''
} else { } else {
this.__TITLE__.style.display = 'none' this.__TITLE__.style.display = 'none'
@ -292,7 +318,7 @@ class Layer {
set type(val) { set type(val) {
var { btns } = this.props var { btns } = this.props
if (this._handleBtnClick) { if (!val || this._handleBtnClick) {
return return
} }
@ -330,7 +356,7 @@ class Layer {
this.__CTRL__.style.display = 'none' this.__CTRL__.style.display = 'none'
} }
this.setAttribute('type', val) this.setAttribute(val, '')
} }
set fixed(val) { set fixed(val) {
@ -375,32 +401,46 @@ class Layer {
} }
close(force) { close(force) {
if (this._dragIns) { if (this.wrapped === false) {
this._dragIns.destroy() if (this._dragIns) {
} this._dragIns.destroy()
if (UNIQUE_TYPES.includes(this.props.type)) {
uniqueInstance = null
}
delete this.promise
unbind(this.__CTRL__, 'click', this._handleBtnClick)
// 离场动画
if (this.props.from && !force) {
let _style = 'opacity:0;'
for (let k in this.props.from) {
_style += `${k}:${this.props.from[k]};`
} }
this.root.children[1].style.cssText += _style if (UNIQUE_TYPES.includes(this.props.type)) {
this.timer = setTimeout(() => { uniqueInstance = null
}
delete this.promise
unbind(this.__CTRL__, 'click', this._handleBtnClick)
// 离场动画
if (this.props.from && !force) {
let _style = 'opacity:0;'
for (let k in this.props.from) {
_style += `${k}:${this.props.from[k]};`
}
this.root.children[1].style.cssText += _style
this.timer = setTimeout(() => {
this.parentNode.removeChild(this)
}, 200)
} else {
clearTimeout(this.timer)
this.parentNode.removeChild(this) this.parentNode.removeChild(this)
}, 200) }
} else { } else {
clearTimeout(this.timer) this.removeAttribute('common')
this.parentNode.removeChild(this)
} }
} }
show() {
if (this.wrapped === false) {
return
}
this.setAttribute('common', '')
}
mounted() { mounted() {
this.type = this.props.type
this.title = this.props.title
this._handleBtnClick = 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
@ -437,6 +477,10 @@ class Layer {
}) })
} }
if (this.props.mask) {
this.setAttribute('mask', '')
}
this._updateFixedStat() this._updateFixedStat()
/* ------------------------ */ /* ------------------------ */
@ -444,8 +488,10 @@ class Layer {
/* ------------------------ */ /* ------------------------ */
if (this.props.mask) { if (this.props.mask) {
this._handlMask = clickOutside(this.root.children[1], ev => { this._handlMask = clickOutside(this.root.children[1], ev => {
if (this.props.maskClose) { if (this.props['mask-close']) {
this.reject(null) if (this.wrapped === false) {
this.reject(null)
}
this.close() this.close()
} else { } else {
if (UNIQUE_TYPES.includes(this.props.type)) { if (UNIQUE_TYPES.includes(this.props.type)) {
@ -457,8 +503,8 @@ class Layer {
} }
}) })
if (this.props.maskColor) { if (this.props['mask-color']) {
this.style.backgroundColor = this.props.maskColor this.style.backgroundColor = this.props['mask-color']
} }
} }
@ -524,8 +570,25 @@ class Layer {
switch (name) { switch (name) {
case 'title': case 'title':
case 'type': case 'type':
if (val !== this.props[name]) { this[name] = val
this[name] = val break
case 'mask-color':
case 'background':
this.props[name] = val
break
case 'mask':
case 'mask-close':
case 'blur':
this.props[name] = true
break
case 'left':
case 'right':
case 'top':
case 'bottom':
if (val !== null) {
this.props.from[name] = val
this.props.to = this.props.from
this.removeAttribute(name)
} }
break break
case 'fixed': case 'fixed':
@ -535,7 +598,7 @@ class Layer {
} }
} }
function createLayer(opt) { function _layer(opt) {
var layDom = document.createElement('wc-layer') var layDom = document.createElement('wc-layer')
if (opt.type === 'toast') { if (opt.type === 'toast') {
@ -554,9 +617,7 @@ function createLayer(opt) {
} }
toastInstance = layDom toastInstance = layDom
} else { } else {
if (opt.mask) { layDom.props.mask = opt.mask
layDom.setAttribute('mask', '')
}
if (opt.btns === false) { if (opt.btns === false) {
layDom.props.btns = [] layDom.props.btns = []
@ -571,14 +632,14 @@ function createLayer(opt) {
} }
layDom.props.mask = opt.mask layDom.props.mask = opt.mask
layDom.props.maskClose = opt.maskClose layDom.props['mask-close'] = opt['mask-close']
if (opt.hasOwnProperty('overflow')) { if (opt.hasOwnProperty('overflow')) {
layDom.props.overflow = opt.overflow layDom.props.overflow = opt.overflow
} }
/* 额外样式 */ /* 额外样式 */
layDom.props.maskColor = opt.maskColor layDom.props['mask-color'] = opt['mask-color']
layDom.props.blur = opt.blur layDom.props.blur = opt.blur
@ -607,55 +668,20 @@ function createLayer(opt) {
} }
} }
layDom.title = opt.title layDom.props.type = opt.type
layDom.type = opt.type layDom.props.fixed = opt.fixed
layDom.fixed = opt.fixed layDom.props.title = opt.title
layDom.innerHTML = opt.content layDom.innerHTML = opt.content
layDom.wrapped = false // 用于区分是API创建的还是包裹现有的节点
document.body.appendChild(layDom) document.body.appendChild(layDom)
return layDom.promise return layDom.promise
} }
const _layer = function(opt) {
if (typeof opt === 'string') {
opt = 'layerwrap-' + opt
if (!layerObj[opt]) {
throw new Error(lang.ERROR)
} else {
//只能显示一个实例
if (layerObj[opt].show) {
return opt
}
layerObj[opt].show = true
layerObj[opt].parentElem.appendChild(layerDom[opt][0])
layerDom[opt][0]
.querySelector('.layer-content')
.appendChild(layerObj[opt].wrap)
layerObj[opt].wrap.style.display = ''
if (!Anot.vmodels[opt]) {
Anot(layerObj[opt].obj.init)
}
layerObj[opt].obj.show()
return opt
}
} else {
return createLayer(opt)
}
}
Object.defineProperty(_layer, '__map__', {
value: {},
writable: true,
enumerable: false,
configurable: true
})
Object.assign(_layer, { Object.assign(_layer, {
alert(content, title = lang.TITLE) { alert(content, title = lang.TITLE) {
return createLayer({ return this({
type: 'alert', type: 'alert',
title, title,
content, content,
@ -668,7 +694,7 @@ Object.assign(_layer, {
intercept = title intercept = title
title = lang.TITLE title = lang.TITLE
} }
return createLayer({ return this({
type: 'confirm', type: 'confirm',
title, title,
content, content,
@ -678,7 +704,7 @@ Object.assign(_layer, {
}) })
}, },
prompt(title = lang.TITLE, intercept) { prompt(title = lang.TITLE, intercept) {
return createLayer({ return this({
type: 'prompt', type: 'prompt',
title, title,
content: `<wc-input autofocus class="layer__content__input"></wc-input>`, content: `<wc-input autofocus class="layer__content__input"></wc-input>`,
@ -688,17 +714,17 @@ Object.assign(_layer, {
}) })
}, },
frame(url, extra = {}) { frame(url, extra = {}) {
return createLayer({ return this({
...extra, ...extra,
type: 'frame', type: 'frame',
content: `<iframe class="layer__content__frame" src="${url}"></iframe>`, content: `<iframe class="layer__content__frame" src="${url}"></iframe>`,
fixed: true, fixed: true,
mask: true, mask: true,
maskClose: true 'mask-close': true
}) })
}, },
notify(content) { notify(content) {
return createLayer({ return this({
type: 'notify', type: 'notify',
title: '通知', title: '通知',
content, content,
@ -718,7 +744,7 @@ Object.assign(_layer, {
type = 'info' type = 'info'
} }
return createLayer({ return this({
content: ` content: `
<div class="layer__content__toast style-${type}"> <div class="layer__content__toast style-${type}">
<wc-icon size="mini" is="${type}"></wc-icon> <wc-icon size="mini" is="${type}"></wc-icon>