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

一波优化

old
宇天 2019-08-12 21:26:08 +08:00
parent 16a3c54f92
commit f2cb1beecf
6 changed files with 774 additions and 49 deletions

View File

@ -69,7 +69,7 @@ function mkWCFile({ style, html, js }) {
let name = '' let name = ''
let props = '' let props = ''
js = js.replace(/props = (\{[\w\W]*?\n\s{2}?\})/, function(s, m) { js = js.replace(/props = (\{\}|\{[\w\W]*?\n\s{2}?\})/, function(s, m) {
props = m props = m
var attr = new Function( var attr = new Function(
`try { `try {

View File

@ -81,7 +81,7 @@ function mkWCFile({ style, html, js }) {
let name = '' let name = ''
let props = '' let props = ''
js = js.replace(/props = (\{[\w\W]*?\n\s{2}?\})/, function(s, m) { js = js.replace(/props = (\{\}|\{[\w\W]*?\n\s{2}?\})/, function(s, m) {
props = m props = m
var attr = new Function( var attr = new Function(
`var props = ${m}, attr = []; for(var i in props){attr.push(i)}; return attr` `var props = ${m}, attr = []; for(var i in props){attr.push(i)}; return attr`

380
src/form/cascader.wc Normal file
View File

@ -0,0 +1,380 @@
<template>
<div class="label">
<slot class="prepend" name="prepend"></slot>
<input readonly />
<wc-icon class="arrow" is="left"></wc-icon>
<slot class="append" name="append"></slot>
<div class="opt-box"></div>
</div>
</template>
<style lang="scss">
ul,
li {
list-style: none;
}
:host {
overflow: hidden;
display: inline-block;
user-select: none;
-moz-user-select: none;
color: nth($cd, 2);
border-radius: 4px;
}
.label {
display: flex;
justify-content: center;
align-items: center;
min-width: 64px;
height: 32px;
font-size: 14px;
border: 1px solid nth($cp, 3);
border-radius: inherit;
background: #fff;
color: inherit;
cursor: text;
input {
flex: 1;
min-width: 0;
height: 100%;
padding: 0 5px;
border: 0;
border-radius: inherit;
color: inherit;
font-size: inherit;
background: none;
outline: none;
box-shadow: none;
cursor: inherit;
&::placeholder {
color: nth($cgr, 1);
}
}
.prepend,
.append {
display: none;
justify-content: center;
align-items: center;
width: auto;
height: 30px;
padding: 0 10px;
background: nth($cp, 1);
}
.prepend {
border-right: 1px solid nth($cp, 3);
border-radius: 4px 0 0 4px;
}
.append {
border-left: 1px solid nth($cp, 3);
border-radius: 0 4px 4px 0;
}
&[prepend] .prepend,
&[append] .append {
display: flex;
}
/* ----- */
.arrow {
padding: 0 5px;
--size: 14px;
color: #ddd;
transform: rotate(-90deg);
}
}
.opt-box {
display: none;
position: fixed;
z-index: 10240;
left: 0;
top: 0;
width: 200px;
height: auto;
max-height: 200px;
min-height: 46px;
padding: 8px 0;
border-radius: 4px;
background: #fff;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
.list {
width: 100%;
}
&::after {
position: absolute;
left: 30px;
top: -4px;
width: 8px;
height: 8px;
background: #fff;
box-shadow: -1px -1px 2px rgba(0, 0, 0, 0.1);
transform: rotate(45deg);
content: '';
}
&.show {
display: flex;
}
li {
overflow: hidden;
width: 100%;
height: 30px;
line-height: 30px;
padding: 0 8px;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
&:hover,
&[focus] {
background: nth($cp, 1);
}
}
}
/* --- */
:host([disabled]) .label {
background: nth($cp, 1);
cursor: not-allowed;
opacity: 0.6;
}
:host(:focus-within) {
box-shadow: 0 0 3px nth($ct, 1);
}
:host(:focus-within[readonly]) {
box-shadow: 0 0 3px nth($co, 1);
}
/* 额外样式 */
:host([round]) {
border-radius: 21px;
.prepend {
border-radius: 21px 0 0 21px;
}
.append {
border-radius: 0 21px 21px 0;
}
}
:host([size='large']) {
.label {
height: 42px;
font-size: 16px;
}
.prepend,
.append {
height: 40px;
}
}
:host([size='medium']) {
.label {
height: 36px;
}
.prepend,
.append {
height: 34px;
}
}
:host([size='mini']) {
.label {
height: 24px;
font-size: 12px;
}
.icon {
--size: 16px;
}
.prepend,
.append {
height: 18px;
}
}
</style>
<script>
import '../scroll/index'
import '../icon/index'
import { nextTick, ebind, bind, unbind } from '../utils'
function parseTree(list, key) {
var tmp = {}
var arr = []
list.sort(function(a, b) {
return a.parent === b.parent ? a.id - b.id : a.parent - b.parent
})
list.forEach(it => {
it.id = +it.id
it.parent = +it.parent
it.children = []
tmp[it.id] = it
let _p = tmp[it.parent]
if (_p) {
_p.children.push(it)
} else {
arr.push(it)
}
})
// key && (store.project[key] = tmp)
return arr
}
function parseOptions(list) {
// 最多只允许4级联动
var arr = Array(4)
.fill(null)
.map(_ => [])
var path = {}
for (let it of list) {
path[value] = value
arr[0].push({ label: it.label, value: it.value })
if (it.children && it.children.length) {
for (let s of it.children) {
path[s.value] = it.value
}
}
arr[1] = arr[1].concat(it.children || [])
}
for (let it of arr[1]) {
}
}
export default class Select {
props = {
label: '',
placeholder: '',
multi: '',
options: [],
mvidx: null, //下拉列表光标的索引ID
disabled: false
}
constructor() {
/* render */
this.__OUTER__ = this.root.children[1]
this.__PREPEND__ = this.__OUTER__.children[0]
this.__INPUT__ = this.__OUTER__.children[1]
this.__ICO__ = this.__OUTER__.children[2]
this.__APPEND__ = this.__OUTER__.children[3]
this.__OPTG__ = this.__OUTER__.children[4]
}
get disabled() {
return this.props.disabled
}
set disabled(val) {
var type = typeof val
if (val === this.props.disabled) {
return
}
if ((type === 'boolean' && val) || type !== 'boolean') {
this.props.disabled = true
this.setAttribute('disabled', '')
this.__INPUT__.setAttribute('disabled', '')
} else {
this.props.disabled = false
this.removeAttribute('disabled')
this.__INPUT__.removeAttribute('disabled')
}
}
get value() {
return this.__INPUT__.value
}
set value(val) {
this.__INPUT__.value = val
}
_mkOpt(list) {
var html = list
.map((it, i) => `<li data-idx="${i}">${it.value}</li>`)
.join('')
}
mounted() {
var prepend = this.__PREPEND__.assignedNodes()
var append = this.__APPEND__.assignedNodes()
// 相同插槽, 只允许1个
while (prepend.length > 1) {
this.removeChild(prepend.pop())
}
while (append.length > 1) {
this.removeChild(append.pop())
}
if (prepend.length && this.props.type !== 'textarea') {
this.__OUTER__.setAttribute('prepend', '')
}
if (append.length && this.props.type !== 'textarea') {
this.__OUTER__.setAttribute('append', '')
}
// 渲染建议列表
this._parseOptGroup = bind(this.__INPUT__, 'click', ev => {
var { options: list } = this.props
let { x, y, width } = this.getBoundingClientRect()
log(list, this.props)
if (list && list.length) {
var html = list
.map((it, i) => `<li data-idx="${i}">${it.value}</li>`)
.join('')
this.__OPTG__.innerHTML = html
this.__OPTG__.classList.toggle('show', true)
this.__OPTG__.style.cssText = `left:${x}px;top:${y +
50}px;width:${width}px;`
} else {
this.__OPTG__.classList.toggle('show', false)
}
})
this._bubbleFn = ebind(this, 'click')
}
watch(name, old, val) {
if (old === val) {
return
}
switch (name) {
// label和placeholder 功能相同
case 'label':
case 'placeholder':
this.__INPUT__.setAttribute('placeholder', val)
break
case 'options':
if (val) {
try {
this.props.options = JSON.parse(val)
} catch (err) {}
}
break
case 'value':
this.value = val
break
case 'readonly':
case 'disabled':
if (val === '') {
this[name] = true
}
break
}
}
}
</script>

View File

@ -1,31 +1,356 @@
<template> <template>
<div class="label"> <div class="label">
<slot class="prepend" name="prepend"></slot> <slot class="prepend" name="prepend"></slot>
${input} <input readonly />
<wc-icon class="icon"></wc-icon> <wc-icon class="arrow" is="left"></wc-icon>
<slot class="append" name="append"></slot> <slot class="append" name="append"></slot>
<div class="opt-box">
<div class="suggestion"> <wc-scroll>
<ul class="list"></ul> <dl class="list"></dl>
</wc-scroll>
</div> </div>
</div> </div>
</template> </template>
<style lang="scss"></style> <style lang="scss">
ul,
li {
list-style: none;
}
:host {
overflow: hidden;
display: inline-block;
user-select: none;
-moz-user-select: none;
color: nth($cd, 2);
border-radius: 4px;
}
.label {
display: flex;
justify-content: center;
align-items: center;
min-width: 64px;
height: 32px;
font-size: 14px;
border: 1px solid nth($cp, 3);
border-radius: inherit;
background: #fff;
color: inherit;
cursor: text;
input {
flex: 1;
min-width: 0;
height: 100%;
padding: 0 5px;
border: 0;
border-radius: inherit;
color: inherit;
font-size: inherit;
background: none;
outline: none;
box-shadow: none;
cursor: inherit;
&::placeholder {
color: nth($cgr, 1);
}
}
.prepend,
.append {
display: none;
justify-content: center;
align-items: center;
width: auto;
height: 30px;
padding: 0 10px;
background: nth($cp, 1);
}
.prepend {
border-right: 1px solid nth($cp, 3);
border-radius: 4px 0 0 4px;
}
.append {
border-left: 1px solid nth($cp, 3);
border-radius: 0 4px 4px 0;
}
&[prepend] .prepend,
&[append] .append {
display: flex;
}
/* ----- */
.arrow {
padding: 0 5px;
--size: 14px;
color: #ddd;
transform: rotate(-90deg);
}
}
.opt-box {
display: none;
position: fixed;
z-index: 10240;
left: 0;
top: 0;
width: 200px;
height: auto;
max-height: 200px;
min-height: 46px;
padding: 8px 0;
border-radius: 4px;
background: #fff;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
.list {
width: 100%;
}
&::after {
position: absolute;
left: 30px;
top: -4px;
width: 8px;
height: 8px;
background: #fff;
box-shadow: -1px -1px 2px rgba(0, 0, 0, 0.1);
transform: rotate(45deg);
content: '';
}
&.show {
display: flex;
}
dt,
dd {
overflow: hidden;
width: 100%;
height: 30px;
line-height: 30px;
padding: 0 8px;
text-overflow: ellipsis;
white-space: nowrap;
}
dt {
font-size: 12px;
color: nth($cgr, 1);
cursor: default;
}
dd {
cursor: pointer;
&:hover,
&[focus] {
background: nth($cp, 1);
}
&[sub] {
text-indent: 1em;
}
}
}
/* --- */
:host([disabled]) .label {
background: nth($cp, 1);
cursor: not-allowed;
opacity: 0.6;
}
:host(:focus-within) {
box-shadow: 0 0 3px nth($ct, 1);
}
:host(:focus-within[readonly]) {
box-shadow: 0 0 3px nth($co, 1);
}
/* 额外样式 */
:host([round]) {
border-radius: 21px;
.prepend {
border-radius: 21px 0 0 21px;
}
.append {
border-radius: 0 21px 21px 0;
}
}
:host([size='large']) {
.label {
height: 42px;
font-size: 16px;
}
.prepend,
.append {
height: 40px;
}
}
:host([size='medium']) {
.label {
height: 36px;
}
.prepend,
.append {
height: 34px;
}
}
:host([size='mini']) {
.label {
height: 24px;
font-size: 12px;
}
.icon {
--size: 16px;
}
.prepend,
.append {
height: 18px;
}
}
</style>
<script> <script>
export default Select { import '../scroll/index'
import '../icon/index'
import { nextTick, ebind, bind, unbind } from '../utils'
function parseOptions(list) {
let html = ''
for (let it of list) {
if (it.list) {
html += `<dt>${it.name}</dt>`
for (let _ of it.list) {
html += `<dd sub data-value="${_.value}">${_.label}</dd>`
}
} else {
html += `<dd data-value="${it.value}">${it.label}</dd>`
}
}
return html
}
export default class Select {
props = { props = {
label: '',
label: '', label: '',
placeholder: '', placeholder: '',
multi: '',
options: [],
mvidx: null, //下拉列表光标的索引ID mvidx: null, //下拉列表光标的索引ID
autofocus: false,
disabled: false disabled: false
} }
constructor() { constructor() {
/* render */ /* render */
this.__OUTER__ = this.root.children[1]
this.__PREPEND__ = this.__OUTER__.children[0]
this.__INPUT__ = this.__OUTER__.children[1]
this.__ICO__ = this.__OUTER__.children[2]
this.__APPEND__ = this.__OUTER__.children[3]
this.__OPTG__ = this.__OUTER__.children[4]
}
get disabled() {
return this.props.disabled
}
set disabled(val) {
var type = typeof val
if (val === this.props.disabled) {
return
}
if ((type === 'boolean' && val) || type !== 'boolean') {
this.props.disabled = true
this.setAttribute('disabled', '')
this.__INPUT__.setAttribute('disabled', '')
} else {
this.props.disabled = false
this.removeAttribute('disabled')
this.__INPUT__.removeAttribute('disabled')
}
}
get value() {
return this.__INPUT__.value
}
set value(val) {
this.__INPUT__.value = val
}
mounted() {
var prepend = this.__PREPEND__.assignedNodes()
var append = this.__APPEND__.assignedNodes()
// 相同插槽, 只允许1个
while (prepend.length > 1) {
this.removeChild(prepend.pop())
}
while (append.length > 1) {
this.removeChild(append.pop())
}
if (prepend.length && this.props.type !== 'textarea') {
this.__OUTER__.setAttribute('prepend', '')
}
if (append.length && this.props.type !== 'textarea') {
this.__OUTER__.setAttribute('append', '')
}
// 渲染建议列表
this._parseOptGroup = bind(this.__INPUT__, 'click', ev => {
var { options: list } = this.props
let { x, y, width } = this.getBoundingClientRect()
log(list, this.props)
if (list && list.length) {
this.__OPTG__.firstElementChild.firstElementChild.innerHTML = parseOptions(
list
)
this.__OPTG__.classList.toggle('show', true)
this.__OPTG__.style.cssText = `left:${x}px;top:${y +
50}px;width:${width}px;`
} else {
this.__OPTG__.classList.toggle('show', false)
}
})
this._bubbleFn = ebind(this, 'click')
}
watch(name, old, val) {
if (old === val) {
return
}
switch (name) {
// label和placeholder 功能相同
case 'label':
case 'placeholder':
this.__INPUT__.setAttribute('placeholder', val)
break
case 'options':
if (val) {
try {
this.props.options = JSON.parse(val)
} catch (err) {}
}
break
case 'value':
this.value = val
break
case 'readonly':
case 'disabled':
if (val === '') {
this[name] = true
}
break
}
} }
} }
</script> </script>

View File

@ -601,25 +601,15 @@ export default class DatePicker {
break break
case 'max-date': case 'max-date':
if (val) {
let tmp = new Date(val)
if (tmp.getFullYear()) {
this.props.max = {
year: tmp.getFullYear(),
month: tmp.getMonth(),
day: tmp.getDate()
}
this._renderCalendar()
}
}
this.removeAttribute('max-date')
break
case 'min-date': case 'min-date':
if (val) { if (val) {
let v = +val
if (v === v) {
val = v
}
let tmp = new Date(val) let tmp = new Date(val)
if (tmp.getFullYear()) { if (tmp.getFullYear()) {
this.props.min = { this.props[name.slice(0, 3)] = {
year: tmp.getFullYear(), year: tmp.getFullYear(),
month: tmp.getMonth(), month: tmp.getMonth(),
day: tmp.getDate() day: tmp.getDate()
@ -627,7 +617,7 @@ export default class DatePicker {
this._renderCalendar() this._renderCalendar()
} }
} }
this.removeAttribute('min-date') this.removeAttribute(name)
break break
case 'value': case 'value':

View File

@ -81,9 +81,7 @@ const IS_FF = !!window.sidebar
/* */ /* */
export default class Scroll { export default class Scroll {
props = { props = {}
v: ''
}
constructor() { constructor() {
/* render */ /* render */
this.__BOX__ = this.root.children[1] this.__BOX__ = this.root.children[1]
@ -91,6 +89,53 @@ export default class Scroll {
this.__Y__ = this.root.children[3].children[0] this.__Y__ = this.root.children[3].children[0]
} }
get scrollTop() {
return this.__BOX__.scrollTop
}
set scrollTop(n) {
// this.__BOX__.scrollTop
}
get scrollLeft() {
return this.__BOX__.scrollLeft
}
set scrollLeft(val) {
// this.__BOX__.scrollLeft
}
get scrollHeight() {
return this.__BOX__.scrollHeight
}
_fetchScrollX(moveX) {
var { sw, ow, xw, sh, oh, yh } = this.props
if (moveX < 0) {
moveX = 0
} else if (moveX > ow - xw) {
moveX = ow - xw
}
this.__BOX__.scrollLeft = (sw - ow) * (moveX / (ow - xw))
this.__X__.style.transform = `translateX(${moveX}px)`
return moveX
}
_fetchScrollY(moveY) {
var { sw, ow, xw, sh, oh, yh } = this.props
if (moveY < 0) {
moveY = 0
} else if (moveY > oh - yh) {
moveY = oh - yh
}
this.__BOX__.scrollTop = (sh - oh) * (moveY / (oh - yh))
this.__Y__.style.transform = `translateY(${moveY}px)`
return moveY
}
mounted() { mounted() {
// 初始化滚动条的位置和长度 // 初始化滚动条的位置和长度
this._initFn = ev => { this._initFn = ev => {
@ -187,28 +232,13 @@ export default class Scroll {
moveX, moveX,
moveY, moveY,
mousemoveFn = ev => { mousemoveFn = ev => {
var { sw, ow, xw, sh, oh, yh, thumbY, thumbX } = this.props var { thumbY, thumbX } = this.props
if (startX !== null) { if (startX !== null) {
moveX = thumbX + ev.pageX - startX moveX = this._fetchScrollX(thumbX + ev.pageX - startX)
if (moveX < 0) {
moveX = 0
} else if (moveX > ow - xw) {
moveX = ow - xw
}
this.__BOX__.scrollLeft = (sw - ow) * (moveX / (ow - xw))
this.__X__.style.transform = `translateX(${moveX}px)`
} }
if (startY !== null) { if (startY !== null) {
moveY = thumbY + ev.pageY - startY moveY = this._fetchScrollY(thumbY + ev.pageY - startY)
if (moveY < 0) {
moveY = 0
} else if (moveY > oh - yh) {
moveY = oh - yh
}
this.__BOX__.scrollTop = (sh - oh) * (moveY / (oh - yh))
this.__Y__.style.transform = `translateY(${moveY}px)`
} }
}, },
mouseupFn = ev => { mouseupFn = ev => {