完成分页组件的迁移;优化button组件

master
yutent 2023-04-18 14:21:53 +08:00
parent 211e90e4f0
commit 1665e881fb
3 changed files with 341 additions and 12 deletions

View File

@ -42,7 +42,7 @@
- [x] `wc-markd`markdown 组件 - [x] `wc-markd`markdown 组件
- [ ] `wc-meditor`md 文本编辑器 - [ ] `wc-meditor`md 文本编辑器
- [ ] `wc-neditor`富文本编辑器 - [ ] `wc-neditor`富文本编辑器
- [ ] `wc-pager`分页组件 - [x] `wc-pager`分页组件
- [x] `wc-color`颜色选择器 - [x] `wc-color`颜色选择器
- [ ] `wc-datepicker`日期选择器 - [ ] `wc-datepicker`日期选择器
- [ ] `wc-timepicker`时间选择器 - [ ] `wc-timepicker`时间选择器

View File

@ -4,7 +4,7 @@
* @date 2023/03/06 15:17:25 * @date 2023/03/06 15:17:25
*/ */
import { css, html, Component, nextTick } from '@bd/core' import { css, html, Component, nextTick, styleMap } from '@bd/core'
import '../icon/index.js' import '../icon/index.js'
class Button extends Component { class Button extends Component {
@ -62,7 +62,7 @@ class Button extends Component {
outline: none; outline: none;
color: inherit; color: inherit;
cursor: inherit; cursor: inherit;
transition: background 0.15s linear; transition: background 0.15s linear, color 0.15s linear;
&::-moz-focus-inner { &::-moz-focus-inner {
border: none; border: none;
@ -70,8 +70,7 @@ class Button extends Component {
} }
.icon { .icon {
--size: var(--icon-size, 18px); --size: var(--icon-size, 14px);
margin-right: 4px;
} }
} }
:host(:focus-within) { :host(:focus-within) {
@ -121,7 +120,7 @@ class Button extends Component {
font-size: map.get($v, 'f'); font-size: map.get($v, 'f');
.icon { .icon {
--size: #{map.get($v, 'f')}; --size: var(--icon-size, #{map.get($v, 'f')});
} }
} }
:host([size='#{$s}'][circle]) { :host([size='#{$s}'][circle]) {
@ -161,18 +160,19 @@ class Button extends Component {
warning: 'orange', warning: 'orange',
danger: 'red', danger: 'red',
secondary: 'dark', secondary: 'dark',
help: 'grey' help: 'grey',
plain: 'plain'
); );
@loop $t, $c in $colors { @loop $t, $c in $colors {
:host([type='#{$t}']) { :host([type='#{$t}']) {
button { button {
color: var(--color-#{$c}-2); color: var(--color-#{$c}-2);
border-color: var(--color-#{$c}-2); border-color: var(--color-#{$c}-1);
&:hover { &:hover {
color: var(--color-#{$c}-1); color: var(--color-#{$c}-1);
border-color: var(--color-#{$c}-1); border-color: var(--color-#{$c}-2);
} }
&:active { &:active {
color: var(--color-#{$c}-3); color: var(--color-#{$c}-3);
@ -184,7 +184,11 @@ class Button extends Component {
&:host([solid]) button { &:host([solid]) button {
border: 0; border: 0;
color: #fff; @if $t == 'plain' {
color: var(--color-dark-1);
} @else {
color: #fff;
}
background: var(--color-#{$c}-2); background: var(--color-#{$c}-2);
&:hover { &:hover {
@ -215,6 +219,13 @@ class Button extends Component {
` `
] ]
#empty = true
fixStyle() {
this.#empty = this.$refs.cont?.assignedNodes().length === 0
this.$requestUpdate()
}
created() { created() {
this.stamp = 0 this.stamp = 0
@ -241,13 +252,15 @@ class Button extends Component {
if (this.autofocus) { if (this.autofocus) {
nextTick(_ => this.$refs.btn.focus()) nextTick(_ => this.$refs.btn.focus())
} }
nextTick(_ => this.fixStyle())
} }
render() { render() {
let style = styleMap({ 'margin-right': this.#empty ? 0 : '4px' })
return html` return html`
<button ref="btn" disabled=${this.disabled}> <button ref="btn" disabled=${this.disabled}>
<wc-icon class="icon" name=${this.icon}></wc-icon> <wc-icon class="icon" name=${this.icon} style=${style}></wc-icon>
<slot></slot> <slot ref="cont"></slot>
</button> </button>
` `
} }

316
src/pager/index.js Normal file
View File

@ -0,0 +1,316 @@
/**
* {}
* @author yutent<yutent.io@gmail.com>
* @date 2023/04/18 09:38:01
*/
import { css, html, Component, bind, styleMap } from '@bd/core'
import '../form/button.js'
const LAYOUT_DICT = {
home: e =>
html`<wc-button
solid
type="plain"
data-act="1"
disabled=${e}
class="item"
icon="dbl-left"
></wc-button>`,
end: e =>
html`<wc-button
solid
type="plain"
data-act="end"
disabled=${e}
class="item"
icon="dbl-right"
></wc-button>`,
prev: e =>
html`<wc-button
solid
type="plain"
data-act="prev"
disabled=${e}
class="item"
icon="left"
></wc-button>`,
next: e =>
html`<wc-button
solid
type="plain"
data-act="next"
disabled=${e}
class="item"
icon="right"
></wc-button>`,
curr: n => html`<span class="curr item">${n}</span>`,
info: (t, p) => html`<span class="item">共 ${t}条, ${p}页</span>`,
jump(n) {
return html`<section class="item jump">
<span>Go to</span>
<input ref="input" @keydown=${this.gotoPage} maxlength="6" value=${n} />
</section>`
}
}
// 计算页码
function calculate(curr, total) {
var arr = []
var fixed = 0
var half = curr < 3 ? 6 - curr : 2 // 中间页码
// 总页码小于2
if (total < 2) {
arr.push({ to: curr, txt: curr })
return arr
}
// 当前页面比半数多时, 前面的用省略号代替
if (curr - half > 1 && total > 5) {
var to = curr - 2 * half
to = to < 1 ? 1 : to
arr.push({ to, txt: '...' })
}
if (total - curr < half) {
fixed = half - total + curr
}
// 把页码拆成2部分来
for (var i = curr - half - fixed; i < curr + half + 1 && i <= total; i++) {
if (i > 0) {
arr.push({ to: i, txt: i })
}
}
// 总页码太多时, 以省略号代替
if (curr + half < total) {
var to = curr + 2 * half
to = to > total ? total : to
arr.push({ to, txt: '...' })
}
return arr
}
class Pager extends Component {
static props = {
layout: {
type: String,
default: 'home, prev, pages, next, end',
attribute: false
},
total: {
type: Number,
default: 0,
attribute: false,
observer(v) {
if (this.#mounted) {
this.totalpage = Math.ceil(v / this.pagesize)
}
}
},
totalpage: {
type: Number,
default: 1,
attribute: false,
observer(v) {
if (this.page > v) {
this.page = v
}
}
},
page: {
type: Number,
default: 1,
attribute: false,
observer(v) {
if (v > this.totalpage) {
this.page = this.totalpage
} else if (v < 1) {
this.page = 1
}
}
},
pagesize: {
type: Number,
default: 20,
attribute: false,
observer(v) {
if (this.total > 0) {
this.totalpage = Math.ceil(this.total / v)
}
}
}
}
static styles = [
css`
:host {
display: block;
line-height: 1;
font-size: 14px;
user-select: none;
-moz-user-select: none;
color: var(--color-dark-1);
.layout {
display: flex;
justify-content: center;
align-items: center;
margin: 10px auto;
}
.item {
min-width: 32px;
width: auto;
--padding: 0;
margin: 0 5px;
--icon-size: 12px;
border-radius: 4px;
&.curr {
display: inline-flex;
align-items: center;
justify-content: center;
height: 32px;
background: var(--color-teal-1);
color: #fff;
}
&.jump {
display: flex;
align-items: center;
}
&[size='l'] {
--icon-size: 12px;
}
}
input {
width: 48px;
height: 24px;
padding: 0 4px;
margin-left: 4px;
border: 1px solid var(--color-grey-2);
border-radius: 3px;
text-align: center;
outline: none;
transition: box-shadow 0.15s linear;
&:focus {
box-shadow: 0 0 0 2px var(--color-plain-a);
}
}
}
`,
css``
]
#mounted = false
handleBtnClick(ev) {
let elem = ev.target
if (elem.tagName === 'WC-BUTTON') {
let { page, totalpage } = this
let num = elem.dataset.act
if (elem.disabled) {
return
}
switch (num) {
case 'prev':
num = page - 1
break
case 'next':
console.log(num, page)
num = page + 1
break
case 'end':
num = totalpage
break
}
if (+num === page) {
return
}
this.page = num
this.$emit('page-changed', { data: num })
}
}
gotoPage(ev) {
if (ev.keyCode === 13) {
let n = +ev.target.value
if (n === n) {
this.page = n
this.$emit('page-changed', { data: this.page })
}
ev.target.value = this.page
}
}
mounted() {
this.#mounted = true
}
render() {
let layout = this.layout.split(',').map(s => s.trim())
let { page, total, totalpage } = this
return html`
<div class="layout" @click=${this.handleBtnClick}>
${layout.map(n => {
switch (n) {
case 'pages':
return calculate(page, totalpage).map(it =>
page === it.to
? LAYOUT_DICT.curr(page)
: html`<wc-button
type="plain"
solid
class="item"
data-act="${it.to}"
>${it.txt}</wc-button
>`
)
case 'home':
return LAYOUT_DICT.home(page === 1)
case 'prev':
return LAYOUT_DICT.prev(page === 1)
case 'next':
return LAYOUT_DICT.next(page >= totalpage)
case 'end':
return LAYOUT_DICT.end(page >= totalpage)
case 'curr':
return LAYOUT_DICT.curr(page)
case 'info':
return LAYOUT_DICT.info(total, totalpage)
case 'jump':
return LAYOUT_DICT.jump.call(this, page)
default:
return ''
}
})}
</div>
`
}
}
Pager.reg('pager')