diff --git a/examples/index.html b/examples/index.html index a66ccbb..34da4d0 100644 --- a/examples/index.html +++ b/examples/index.html @@ -370,13 +370,14 @@ new SmartTable({ selector: '#smartTable1', height: 320, - selection: 'radio', + selection: 'radio' }) new SmartTable({ selector: '#smartTable2', align: 'left', height: 320, size: 'middle', + align: 'center', selection: 'checkbox', selectionKey: 1, }) diff --git a/lib/core/core.js b/lib/core/core.js index 391983c..1e9b5cc 100644 --- a/lib/core/core.js +++ b/lib/core/core.js @@ -9,6 +9,7 @@ import { removeChild, createElement, querySelector, + insertBefore, querySelectorAll, offsetHeight, offsetWidth, @@ -19,6 +20,7 @@ import { throttle, debounce, getAttrNumber, + createCheckbox, refactorCell, replaceColGroup, createTableWrapper, @@ -67,6 +69,9 @@ export default function initMixin(Table) { hoverBgColor: options.hoverBgColor || '#EFF8FF' } vm.size = {} + vm.hasCheckbox = !options.expand && options.selection === 'checkbox' + + vm.hasCheckbox && appendCheckbox(vm) //初始化thead 并获取props initProps(vm) @@ -96,9 +101,23 @@ export default function initMixin(Table) { } } +function appendCheckbox(vm) { + const { $thead, $tbody } = vm; + let theadRow = querySelector($thead, "tr"); + let th = theadRow.querySelector("th"); + let selectionTh = createCheckbox("th", getAttrNumber(th, "rowspan", 1)); + hasAttribute(th, "fixed") && setAttribute(selectionTh, "fixed") + insertBefore(theadRow, selectionTh, th) + querySelectorAll($tbody, "tr").forEach(row => { + let td = row.querySelector("td") + insertBefore(row, createCheckbox("td", getAttrNumber(td, "rowspan", 1)), td) + }) +} + function layout(vm, table) { const { $root, $thead, $tbody, options } = vm; - const { height, selection } = options; + const { height } = options; + querySelectorAll($thead, "th").forEach(cell => refactorCell(cell)) querySelectorAll($tbody, "td").forEach(cell => refactorCell(cell)) @@ -152,7 +171,11 @@ function initColgroupData(vm) { totalWidth = 0; arr = arr.map((item, index) => { if (item === 0) { - item = min; + if (vm.hasCheckbox && index === 0) { + item = per > 55 ? per : 55; + } else { + item = min; + } lastZeroIndex = index; } totalWidth += item @@ -279,17 +302,68 @@ function bindScrollEvents(vm) { function bindRowEvents(vm) { const { selection, selectionKey } = vm.options; + const totalCheckbox = querySelector(vm.$fixedLeft || vm.$thead, "th>.stb_cell>label.std-checkbox"); [].concat(vm.data, vm.unsortData).forEach(row => { addHoverEvent(vm, row.$el, [row.$fixedLeftEl, row.$fixedRightEl]) row.$fixedLeftEl && addHoverEvent(vm, row.$fixedLeftEl, [row.$el, row.$fixedRightEl]) row.$fixedRightEl && addHoverEvent(vm, row.$fixedRightEl, [row.$el, row.$fixedLeftEl]) - if (selection === 'radio') { + if (selection) { let value = row['field-' + (selectionKey || 0)] - addRadioEvent(vm, row.$el, [row.$fixedLeftEl, row.$fixedRightEl], value) - row.$fixedLeftEl && addRadioEvent(vm, row.$fixedLeftEl, [row.$el, row.$fixedRightEl], value) - row.$fixedRightEl && addRadioEvent(vm, row.$fixedRightEl, [row.$el, row.$fixedLeftEl], value) + switch (selection) { + case 'radio': + addRadioEvent(vm, row.$el, [row.$fixedLeftEl, row.$fixedRightEl], value) + row.$fixedLeftEl && addRadioEvent(vm, row.$fixedLeftEl, [row.$el, row.$fixedRightEl], value) + row.$fixedRightEl && addRadioEvent(vm, row.$fixedRightEl, [row.$el, row.$fixedLeftEl], value) + break + case 'checkbox': + addCheckboxEvent(vm, row.$fixedLeftEl || row.$el, totalCheckbox, value) + break + } } }) + if (vm.hasCheckbox) { + addTotalCheckboxEvent(vm, totalCheckbox) + } +} + +function addCheckboxEvent(vm, row, totalCheckbox, value) { + const trigger = querySelector(row, "label.std-checkbox") + if (!trigger || !totalCheckbox) return; + trigger.addEventListener('click', () => { + let { selected } = vm; + selected = selected || []; + const target = !hasAttribute(trigger, "checked"); + target ? setAttribute(trigger, 'checked', true) : removeAttribute(trigger, 'checked') + target ? selected.push(value) : selected.splice(selected.indexOf(value), 1) + const len = selected.length; + len ? setAttribute(vm.$root, 'selected', selected) : removeAttribute(vm.$root, 'selected'); + if (len === (vm.data.length + vm.unsortData.length)) { + setAttribute(totalCheckbox, 'checked', true) + } else { + removeAttribute(totalCheckbox, 'checked') + } + vm.selected = selected; + }) + +} + +function addTotalCheckboxEvent(vm, totalCheckbox) { + if (!totalCheckbox) return; + const { selectionKey } = vm.options; + totalCheckbox.addEventListener('click', () => { + let { selected } = vm; + selected = []; + const target = !hasAttribute(totalCheckbox, "checked"); + target ? setAttribute(totalCheckbox, 'checked', true) : removeAttribute(totalCheckbox, 'checked'); + [].concat(vm.data, vm.unsortData).forEach(row => { + let trigger = querySelector(row.$fixedLeftEl || row.$el, "label.std-checkbox") + target ? setAttribute(trigger, 'checked', true) : removeAttribute(trigger, 'checked') + target && selected.push(row['field-' + (selectionKey || 0)]) + }) + const len = selected.length; + len ? setAttribute(vm.$root, 'selected', selected) : removeAttribute(vm.$root, 'selected'); + vm.selected = selected; + }) } function addRadioEvent(vm, trigger, relates, radioValue) { @@ -511,7 +585,7 @@ function initExpand(vm, tbody) { data.push(node) } if (hasParent) { - styled(querySelector(row, "td"), { paddingLeft: 25 * paddingLength + "px" }) + styled(querySelector(row, "td"), { paddingLeft: 35 * paddingLength + "px" }) styled(row, { display: expandAll ? '' : 'none' }) } }) diff --git a/lib/core/utils.js b/lib/core/utils.js index c3beb7f..f3f693b 100644 --- a/lib/core/utils.js +++ b/lib/core/utils.js @@ -18,6 +18,18 @@ export function refactorCell(cell) { appendChild(cell, wrapper) } +export function createCheckbox(parentTag, rowspan) { + if (!parentTag) return; + let td = createElement(parentTag) + setAttribute(td, "rowspan", rowspan) + let wrapper = createElement("label", "std-checkbox"); + let input = createElement("span", "std-checkbox_input"); + appendChild(input, createElement("span", "std-checkbox_inner")) + appendChild(wrapper, input) + appendChild(td, wrapper) + return td +} + export function createTableWrapper(className, vm, type, content) { let wrapper = createElement("div", className); let table = createElement("table", "stb_" + type); diff --git a/lib/core/vdom.js b/lib/core/vdom.js index a97e33c..ce8922f 100644 --- a/lib/core/vdom.js +++ b/lib/core/vdom.js @@ -1,3 +1,5 @@ +import { insertBefore } from './node-ops'; + export default function(vm, key, sortType, sortOrder) { if (!vm.data || vm.data.length < 1) return; //使用快速排序 @@ -28,16 +30,16 @@ function diff(oldVnode, vnode) { const lastNextVNode = vnode[i - 1]; const refNode = lastNextVNode.$el.nextSibling; - refNode.parentNode.insertBefore(prevVNode.$el, refNode); + insertBefore(refNode.parentNode, prevVNode.$el, refNode); if (lastNextVNode.$fixedLeftEl) { const refLeftNode = lastNextVNode.$fixedLeftEl.nextSibling; - refLeftNode.parentNode.insertBefore(prevVNode.$fixedLeftEl, refLeftNode); + insertBefore(refLeftNode.parentNode, prevVNode.$fixedLeftEl, refLeftNode); } if (lastNextVNode.$fixedRightEl) { const refRightNode = lastNextVNode.$fixedRightEl.nextSibling; - refRightNode.parentNode.insertBefore(prevVNode.$fixedRightEl, refRightNode); + insertBefore(refRightNode.parentNode, prevVNode.$fixedRightEl, refRightNode); } } else { lastIndex = j; diff --git a/lib/index.scss b/lib/index.scss index bddd83b..e6513f5 100644 --- a/lib/index.scss +++ b/lib/index.scss @@ -150,6 +150,59 @@ text-align: right; } } + .std-checkbox_inner { + display: inline-block; + position: relative; + border: 1px solid #dcdfe6; + border-radius: 2px; + box-sizing: border-box; + width: 14px; + height: 14px; + background-color: #fff; + z-index: 1; + transition: border-color .25s cubic-bezier(.71, -.46, .29, 1.46), background-color .25s cubic-bezier(.71, -.46, .29, 1.46); + &:after { + box-sizing: content-box; + content: ""; + border: 1px solid #fff; + border-left: 0; + border-top: 0; + height: 7px; + left: 4px; + position: absolute; + top: 1px; + transform: rotate(45deg) scaleY(0); + width: 3px; + transition: transform .15s ease-in .05s; + transform-origin: center; + } + } + .std-checkbox_input { + white-space: nowrap; + cursor: pointer; + outline: none; + display: inline-block; + line-height: 1; + position: relative; + vertical-align: middle; + } + .std-checkbox { + color: #606266; + font-weight: 500; + font-size: 14px; + position: relative; + cursor: pointer; + display: inline-block; + white-space: nowrap; + user-select: none; + &[checked]>.std-checkbox_input>.std-checkbox_inner { + background-color: #409eff; + border-color: #409eff; + &:after { + transform: rotate(45deg) scaleY(1); + } + } + } .stb_cell { overflow: hidden; text-overflow: ellipsis;