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

调整wc编译;开始重构layer

old
宇天 2019-08-21 21:03:41 +08:00
parent e0697a53c0
commit 189253f2df
20 changed files with 994 additions and 494 deletions

View File

@ -86,11 +86,11 @@ function mkWCFile({ style, html, js }) {
}) })
js = fixImport(js) js = fixImport(js)
.replace(/class ([\w]+)/, function(s, m) { .replace(/class ([a-zA-Z0-9]+)/, function(s, m) {
name = m name = m
return `${s} extends HTMLElement ` return `${s} extends HTMLElement `
}) })
.replace(/constructor\([^)]?\)\s+\{/, 'constructor() {\n super();') .replace(/__init__\(\)\s+\{/, 'constructor() {\n super();')
.replace( .replace(
'/* render */', '/* render */',
` `

View File

@ -93,11 +93,11 @@ function mkWCFile({ style, html, js }) {
}) })
js = fixImport(js) js = fixImport(js)
.replace(/class ([\w]+)/, function(s, m) { .replace(/class ([a-zA-Z0-9]+)/, function(s, m) {
name = m name = m
return `${s} extends HTMLElement ` return `${s} extends HTMLElement `
}) })
.replace(/constructor\([^)]?\)\s+\{/, 'constructor() {\n super();') .replace(/__init__\(\)\s+\{/, 'constructor() {\n super();')
.replace( .replace(
'/* render */', '/* render */',
` `
@ -136,7 +136,9 @@ function mkWCFile({ style, html, js }) {
${res.code} ${res.code}
if(!customElements.get('wc-${name.toLowerCase()}')){
customElements.define('wc-${name.toLowerCase()}', ${name}) customElements.define('wc-${name.toLowerCase()}', ${name})
}
` `
} }

View File

@ -168,7 +168,7 @@ export default class Avatar {
fit: '' // 头像填充方式 fill, contain, cover, scale-down fit: '' // 头像填充方式 fill, contain, cover, scale-down
} }
constructor() { __init__() {
/* render */ /* render */
this.__IMG__ = this.root.lastElementChild this.__IMG__ = this.root.lastElementChild
var text = this.textContent.slice(0, 1) var text = this.textContent.slice(0, 1)

View File

@ -59,7 +59,7 @@ export default class Badge {
label: '' label: ''
} }
constructor() { __init__() {
/* render */ /* render */
this.__DOT__ = this.root.lastElementChild this.__DOT__ = this.root.lastElementChild
} }

View File

@ -1,6 +0,0 @@
## 更新日志
v1.0.0 (2017-09-11)
============
First Release.

View File

@ -1,469 +0,0 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2016-02-14 13:58:39
*
*/
'use strict'
import 'css/datepicker.scss'
/**************** 公共函数 *****************/
//计算日历数组
function getCalendarTable({ year, month, max, min }, last) {
let nums = getTotalDays(year, month)
let numsFixed = 1 - getFirstDay(year, month)
let isLimitYM = isLimited({ max, min }, { year, month })
let list = []
for (let i = numsFixed; i <= nums; i++) {
let day = {
weekend: !1,
day: i < 1 ? '' : i,
selected: !1,
disabled: !0
}
if (i > 0) {
let week = getFirstDay(year, month, i)
day.weekend = week === 0 || week === 6
day.selected = isSelected({ year, month, day: i }, last)
day.disabled = disabledDay({ max, min }, i, isLimitYM)
}
list.push(day)
}
return list
}
//判断当前年/月是否超出限制
function isLimited({ max, min }, { year, month }) {
let result = ''
if ((!max.year && !min.year) || (!max.month && !min.month) || !year) {
return false
}
if ((min.year && year < min.year) || (max.year && year > max.year)) {
return true
}
if (month) {
if (year === min.year) {
if (min.month && month < min.month) {
return true
}
if (month == min.month) {
result += '-'
}
}
if (year === max.year) {
if (max.month && month > max.month) {
return true
}
if (month == max.month) {
result += '+'
}
}
}
return result
}
//判断指定天数是否有效
function disabledDay({ max, min }, day, limitedYM) {
if (limitedYM === '-') {
return day < min.day
}
if (limitedYM === '+') {
return max.day && day > max.day
}
if (limitedYM === '-+') {
return day < min.day || (max.day && day > max.day)
}
return limitedYM
}
//判断指定天数是否被选中
function isSelected({ year, month, day }, last) {
return !(last.year !== year || last.month !== month || last.day !== day)
}
//修改当前选中日期的样式
function changeStyle(calendar, day) {
calendar.list.forEach(function(item) {
if (item.day != day) {
item.selected = !1
} else {
item.selected = !0
}
})
}
//获取今年的年份/月份,返回的是数组
function getThisYearMonth() {
var oDate = new Date()
return [oDate.getFullYear(), oDate.getMonth() + 1]
}
//根据年份获取指定月份天数
function getTotalDays(year, month) {
return new Date(year, month, 0).getDate()
}
//判断指定年月第一天是星期几
function getFirstDay(year, month, day) {
return new Date(year, month - 1, day || 1).getDay()
}
Anot.ui.datepicker = '1.0.0'
export default Anot.component('datepicker', {
__init__: function(props, state, next) {
this.classList.add('do-datepicker')
this.classList.add('do-fn-noselect')
this.classList.add(props.size || 'mini')
this.setAttribute(
':css',
"{width: props.width, height: props.height, 'line-height': props.height + 'px'}"
)
this.setAttribute(':click', 'cancelBubble')
// 日期格式化, 不显示时间时, 默认会调用过滤器的格式'Y-m-d H:i:s'
if (!props.showTime && !props.format) {
props.format = 'Y-m-d'
}
//获取初始值
let defVal = state.value || null
if (props.minDate) {
if (!Date.isDate(props.minDate)) {
props.minDate = new Date(props.minDate)
}
}
if (props.maxDate) {
if (!Date.isDate(props.maxDate)) {
props.maxDate = new Date(props.maxDate)
}
}
if (defVal) {
// 修正默认值, 如果不是Date对象, 则转为Date对象
if (!Date.isDate(defVal)) {
defVal = new Date(defVal)
}
} else {
defVal = new Date()
if (props.minDate && defVal < props.minDate) {
defVal = props.minDate
}
if (props.maxDate && defVal > props.maxDate) {
defVal = props.maxDate
}
}
state.min.year = props.minDate.getFullYear()
state.min.month = props.minDate.getMonth() + 1
state.min.day = props.minDate.getDate()
state.max.year = props.maxDate.getFullYear()
state.max.month = props.maxDate.getMonth() + 1
state.max.day = props.maxDate.getDate()
state.last = {
year: defVal.getFullYear(),
month: defVal.getMonth() + 1,
day: defVal.getDate()
}
state.value = defVal.format(props.format)
state.calendar = {
list: [1],
year: defVal.getFullYear(),
month: defVal.getMonth() + 1,
day: defVal.getDate(),
hour: defVal.getHours(),
minute: defVal.getMinutes(),
second: defVal.getSeconds()
}
state.disabled = !!props.disabled
//移除部分属性
delete props.minDate
delete props.maxDate
delete props.hostPush
delete props.disabled
next()
},
render: function() {
return `
<label class="date-input">
<input
class="input"
type="text"
readonly
:duplex="value"
:focus="onFocus"
:css="{'border-radius': props.radius}"
:attr-placeholder="props.placeholder || '请选择日期'"
:attr-disabled="disabled">
<i class="do-icon-calendar icon"></i>
</label>
<dl
class="calendar-box"
:css="{top: top, left: left}"
:if="showCalendar">
<dt class="contrl">
<a class="do-icon-dbl-left" :click="turn(1, -1)"></a>
<a class="do-icon-left prev-month" :click="turn(0, -1)"></a>
<a class="do-icon-right next-month" :click="turn(0, 1)"></a>
<a class="do-icon-dbl-right next-year" :click="turn(1, 1)"></a>
<span
title="双击回到今天"
:dblclick="back2today"
:text="calendar.year + '-' + numberFormat(calendar.month)"></span>
</dt>
<dd class="table">
<section class="thead">
<span class="td"></span>
<span class="td"></span>
<span class="td"></span>
<span class="td"></span>
<span class="td"></span>
<span class="td"></span>
<span class="td"></span>
</section>
<section class="tr do-fn-cl" :click="pick">
<span class="td"
:class="{weekend:el.weekend, disabled: el.disabled, selected: el.selected}"
:for="calendar.list"
:data-idx="$index"
:text="el.day"></span>
</section>
</dd>
<dd class="time" :if="props.showTime">
<label>
<input type="text" :duplex-number="calendar.hour">
</label>
<label>
<input type="text" :duplex-number="calendar.minute">
</label>
<label>
<input type="text" :duplex-number="calendar.second">
</label>
<a href="javascript:;" class="now" :click="now">现在</a>
</dd>
<dt class="confirm" :if="props.showTime">
<a :click="close" class="cancel">取消</a>
<a :click="confirmPick" class="ok">确定</a>
</dt>
<dd class="tips" :if="tips" :text="tips"></dd>
</dl>`
},
componentWillMount: function() {
this.resetCalendarTable()
this.$fire('value', this.value)
},
componentDidMount: function() {
if (typeof this.props.created === 'function') {
this.props.created(this)
}
Anot(document).bind('click', () => {
this.close()
})
},
state: {
showCalendar: false, //显示日历对话框
disabled: false, //是否禁用
last: { year: 0, month: 0, day: 1 },
tips: '',
timer: null,
value: '', // 用于显示在输入框里的日期变量
max: { year: 0, month: 0, day: 1 },
min: { year: 0, month: 0, day: 1 },
top: 0,
left: 0,
calendar: {
// list: [1],
// year: '',
// month: '',
// day: '',
// hour: '',
// minute: '',
// second: ''
}
},
props: {
showTime: false, //对话框上显示时间
radius: 3,
height: null,
width: null,
size: 'mini', //默认规格,mini, medium, large
format: '', // 日期显示格式
created: Anot.PropsTypes.isFunction(),
datePicked: Anot.PropsTypes.isFunction()
},
skip: ['max', 'min', 'last', 'timer'],
watch: {
tips: function(val) {
if (!val) {
return
}
this.timer = setTimeout(() => {
clearTimeout(this.timer)
this.tips = ''
}, 1500)
},
'calendar.hour': function(val) {
if (val > 23) {
val = 23
}
this.calendar.hour = val
},
'calendar.minute': function(val) {
if (val > 59) {
val = 59
}
this.calendar.minute = val
},
'calendar.second': function(val) {
if (val > 59) {
val = 59
}
this.calendar.second = val
}
},
methods: {
// 重置日历表格
resetCalendarTable: function() {
let {
max,
min,
calendar: { year, month },
last
} = this
this.calendar.day = 0
this.calendar.list.clear()
this.calendar.list.pushArray(
getCalendarTable({ max, min, year, month }, last)
)
},
// 数字前面加0
numberFormat: function(num) {
num += ''
if (num.length > 1) {
return num
}
while (num.length < 2) {
num = '0' + num
}
return num
},
// 输入框获取焦点时,显示日历
onFocus: function(ev) {
let { top, left } = Anot(ev.target).offset()
this.top = top + 30
this.left = left
this.showCalendar = !0
},
back2today: function() {
let today = new Date()
this.calendar.year = today.getFullYear()
this.calendar.month = today.getMonth() + 1
this.resetCalendarTable()
},
// 切换上/下 年/月
turn: function(isYear, step) {
let {
calendar: { year, month },
max,
min
} = this
if (isYear === 1) {
year += step
} else {
month += step
if (month < 1) {
month = 12
year--
}
if (month > 12) {
month = 1
year++
}
}
if (isLimited({ max, min }, { year, month }) === true) {
this.tips = '日期超出限制'
return
}
this.calendar.year = year
this.calendar.month = month
this.resetCalendarTable()
},
pick: function(ev) {
if (ev.target === ev.currentTarget) {
return
}
let item = this.calendar.list[ev.target.dataset.idx]
if (item.disabled) {
return
}
this.calendar.day = item.day
changeStyle(this.calendar, item.day)
if (!this.props.showTime) {
this.confirmPick()
}
},
updateTime: function() {
let { year, month, day, hour, minute, second } = this.calendar
// day 小于1, 说明切换年/月之后, 没有选择具体日期
if (day < 1) {
return
}
this.last = { year, month, day }
if (!this.props.showTime) {
hour = 0
minute = 0
second = 0
}
this.last.pick = new Date(year, month - 1, day, hour, minute, second)
this.value = this.last.pick.format(this.props.format)
},
now: function() {
let now = new Date()
this.calendar.hour = now.getHours()
this.calendar.minute = now.getMinutes()
this.calendar.second = now.getSeconds()
},
cancelBubble: function(ev) {
;(ev.stopPropagation && ev.stopPropagation()) || (ev.cancelBubble = true)
},
close: function() {
this.showCalendar = false
},
confirmPick: function() {
this.updateTime()
this.close()
if (
this.calendar.day > 0 &&
typeof this.props.datePicked === 'function'
) {
// 返回一个格式化后的值和一个Date对象
this.props.datePicked(this.value, this.last.pick, this.$elem)
}
}
}
})

17
src/drag/core.js Normal file
View File

@ -0,0 +1,17 @@
/**
* 拖拽插件
* @author yutent<yutent@doui.cc>
* @date 2019/08/21 17:28:40
*/
"use strict";
export default Drag {
constructor(elem){
this.$elem = elem
}
by(node){
}
}

View File

@ -244,7 +244,7 @@ export default class Button {
disabled: false disabled: false
} }
constructor() { __init__() {
/* render */ /* render */
// 圆形按钮不允许文字 // 圆形按钮不允许文字

View File

@ -259,7 +259,7 @@ export default class Select {
disabled: false disabled: false
} }
constructor() { __init__() {
/* render */ /* render */
this.__OUTER__ = this.root.children[1] this.__OUTER__ = this.root.children[1]

View File

@ -144,7 +144,7 @@ export default class Checkbox {
checked: false, checked: false,
disabled: false disabled: false
} }
constructor() { __init__() {
/* render */ /* render */
this.__SWITCH__ = this.root.lastElementChild this.__SWITCH__ = this.root.lastElementChild

View File

@ -243,7 +243,7 @@ export default class Input {
disabled: false disabled: false
} }
constructor() { __init__() {
var type = this.getAttribute('type') var type = this.getAttribute('type')
var input = '' var input = ''
if (type !== 'textarea') { if (type !== 'textarea') {

View File

@ -67,7 +67,7 @@ export default class Progress {
max: 1 max: 1
} }
constructor() { __init__() {
/* render */ /* render */
this.__THUMB__ = this.root.children[1].lastElementChild this.__THUMB__ = this.root.children[1].lastElementChild
} }

View File

@ -159,7 +159,7 @@ export default class Radio {
checked: false, checked: false,
disabled: false disabled: false
} }
constructor() { __init__() {
/* render */ /* render */
this.__SWITCH__ = this.root.lastElementChild this.__SWITCH__ = this.root.lastElementChild

View File

@ -262,7 +262,7 @@ export default class Select {
disabled: false disabled: false
} }
constructor() { __init__() {
/* render */ /* render */
this.__OUTER__ = this.root.children[1] this.__OUTER__ = this.root.children[1]

View File

@ -103,7 +103,7 @@ export default class Switch {
checked: false, checked: false,
disabled: false disabled: false
} }
constructor() { __init__() {
/* render */ /* render */
this.__SWITCH__ = this.root.lastElementChild this.__SWITCH__ = this.root.lastElementChild

View File

@ -100,7 +100,7 @@ export default class Icon {
is: '' is: ''
} }
constructor() { __init__() {
/* render */ /* render */
this.__ICO__ = this.root.lastElementChild this.__ICO__ = this.root.lastElementChild

956
src/layer/next.wc Normal file
View File

@ -0,0 +1,956 @@
<template>
<div class="layer">
<div class="layer__title noselect"></div>
<div class="layer__content"><slot></slot></div>
<div class="layer__ctrl noselect"></div>
</div>
</template>
<style lang="scss">
:host {
display: flex;
justify-content: center;
align-items: center;
width: auto;
height: auto;
}
.noselect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
img,
a {
-webkit-user-drag: none;
}
}
.layer {
flex: 0 auto;
position: absolute;
z-index: 65535;
padding: 15px 10px;
border-radius: 3px;
color: #666;
font-size: 14px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
// opacity: 0;
&.shift {
transition: all 0.5s ease-out;
}
&.scale {
transform: scale(1.02);
transition: transform 0.1s linear;
}
&:active {
z-index: 65536;
}
/* 弹层样式 */
&__title {
width: 100%;
height: 43px;
padding: 0 10px;
line-height: 43px;
font-size: 16px;
color: nth($cd, 2);
}
&__content {
position: relative;
width: 100%;
height: auto;
min-height: 50px;
word-break: break-all;
word-wrap: break-word;
}
&__ctrl {
width: 100%;
height: 40px;
padding: 5px 0;
line-height: 30px;
font-size: 14px;
color: #454545;
text-align: right;
}
}
:host([mask]) {
position: fixed;
z-index: 65534;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(5px);
&.shift {
transition: all 0.5s ease-out;
}
&.inner {
position: absolute;
}
}
:host([type='alert']),
:host([type='confirm']),
:host([type='prompt']) {
.layer {
max-width: 600px;
min-width: 300px;
background: #fff;
&__content {
padding: 10px;
}
}
}
</style>
<script>
import '../drag/index'
import { nextTick, bind, unbind, clickOutside } from '../utils'
const LANGUAGES = {
en: {
TITLE: 'Dialog',
YES_BTN: 'OK',
NO_BTN: 'Cancel',
ERROR: 'The layer instance is not exists',
NEED_CONTAINER: 'layer "tips" require a DOM object as container'
},
zh: {
TITLE: '提示',
YES_BTN: '确定',
NO_BTN: '取消',
ERROR: '要关闭的layer实例不存在',
NEED_CONTAINER: 'tips类型需要指定一个元素节点作为容器'
}
}
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 = {
type: 1, // 弹窗类型
background: '#fff',
mask: true, // 遮罩
maskClose: false, // 遮罩点击关闭弹窗
maskColor: null, // 遮罩背景色
radius: '0px', // 弹窗圆角半径
area: ['auto', 'auto'],
title: lang.TITLE, // 弹窗主标题(在工具栏上的)
menubar: true, // 是否显示菜单栏
content: '', // 弹窗的内容
fixed: false, // 是否固定不可拖拽
shift: {}, // 弹窗出来的初始位置,用于出场动画
offset: {}, // 弹窗出来后的坐标, 为数组,可有4个值,依次是 上右下左
btns: [lang.YES_BTN, lang.NO_BTN] // 弹窗的2个按钮的文字
}
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 fixOffset = function(offset) {
for (let i in offset) {
if (offset[i] === 'auto' || (!offset[i] && offset[i] !== 0)) {
delete offset[i]
} else {
if (isFinite(offset[i])) {
offset[i] += 'px'
}
}
}
return offset
}
/* type: { // 弹窗类型对应的id值
1: 'alert',
2: 'confirm',
3: 'prompt',
4: 'iframe',
5: 'tips',
6: 'loading',
7: 'msg',
} */
class __layer__ {
get dot() {
//loading的子元素数量
return {
1: 1,
2: 5,
3: 5,
4: 9
}
}
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
}
// 真正的初始化弹层配置
__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)
}
}
}
// 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 += `<i class="arrow"></i>`
}
layBox.innerHTML = `
${this.mkMenubar()}
<div
class="layer-content do-fn-cl"
style="${boxcss}"
${!state.wrap && state.type !== 6 ? ':html="content"' : ''}>
${state.type === 6 ? this.mkLoading(state.load) : ''}
</div>
${this.mkCtrl()}
${arrow}
`
delete state.wrap
outerBox.appendChild(layBox)
return [outerBox, layBox]
}
// 创建loading元素
mkLoading(style) {
return `
<div class="loading style-${style}">
<span class="dot-box">
${(style === 1 ? '<i class="do-icon-loading"></i>' : '<i></i>').repeat(
this.dot[style]
)}
</span>
</div>
`
}
// 创建窗口导航条
mkMenubar() {
let { menubar, fixed } = this.init.state
let html = ''
if (menubar) {
html = `
<div class="layer-title do-fn-noselect"
:text="title"
${!fixed ? ':drag="layer-box" data-limit="window"' : ''}>
</div>
`
}
return html
}
// 创建窗口按钮
mkCtrl() {
let { type } = this.init.state
if (type > 3) {
return ''
} else {
let html = ''
let btns = `
<a class="action-yes"
:on-click="handleConfirm"
tabindex="-1"
:text="btns[0]"
></a>
`
if (type > 1) {
btns =
`
<a class="action-no"
:on-click="handleCancel"
:text="btns[1]"
></a>
` + btns
}
html = `
<div class="layer-ctrl do-fn-noselect">
${btns}
</div>
`
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)
}
}
}
}
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 = '<p>ffdfdffd</p>'
document.body.appendChild(l)
return _layer.open(opt)
},
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)
},
frame(url, extra = {}) {
let opt = {
content: `<iframe ref="frame" class="frame-box" src="${url}"></iframe>`,
menubar: false,
maskClose: true,
type: 4,
...extra
}
return _layer.open(opt)
},
toast(txt, type = 'info', timeout = 2500) {
if (typeof type === 'number') {
timeout = type
type = 'info'
}
switch (type) {
case 'info':
break
case 'warn':
break
case 'error':
type = 'deny'
break
default:
type = 'info'
}
let opt = {
content: `
<mark class="toast-box style-${type}">
<i class="do-icon-${type}"></i>
${txt}
</mark>`,
menubar: false,
mask: false,
type: 7,
shift: { top: 0 },
timeout,
offset: { top: 50 },
fixed: true,
toast: true // toast模式
}
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(
'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
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 new __layer__(opt).init.$id
}
},
version: Anot.ui.layer
}
/* 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)
})
}
}
}) */
window.layer = _layer
export default class Layer {
props = {
type: 'msg',
title: ''
}
__init__() {
/* render */
this.__TITLE__ = this.root.children[1].firstElementChild
this.__BODY__ = this.root.children[1].children[1]
this.__CTRL__ = this.root.children[1].lastElementChild
}
set title(val) {
this.__TITLE__.textContent = val || lang.TITLE
}
}
</script>

View File

@ -135,7 +135,7 @@ export default class Pager {
pagesize: 20, pagesize: 20,
simple: false simple: false
} }
constructor() { __init__() {
/* render */ /* render */
this.__LAYOUT__ = this.root.children[1] this.__LAYOUT__ = this.root.children[1]

View File

@ -346,7 +346,7 @@ export default class DatePicker {
disabled: false disabled: false
} }
constructor() { __init__() {
/* render */ /* render */
this.__INPUT__ = this.root.children[1] this.__INPUT__ = this.root.children[1]

View File

@ -83,7 +83,7 @@ const IS_FF = !!window.sidebar
/* */ /* */
export default class Scroll { export default class Scroll {
props = {} props = {}
constructor() { __init__() {
/* render */ /* render */
this.__BOX__ = this.root.children[1] this.__BOX__ = this.root.children[1]
this.__X__ = this.root.children[2].children[0] this.__X__ = this.root.children[2].children[0]