magiccube-vue3
Version:
vue3-js版组件库
211 lines (181 loc) • 5.58 kB
JavaScript
import { ref, computed, provide, inject } from 'vue'
import * as utils from '../../utils/common'
const getSelectedData = (list = [], selected, key) => {
const arr = []
function mapList(_list = []) {
_list.map(item => {
if (selected.includes(item[key])) {
arr.push({
name: item.name,
[key]: item[key]
})
}
mapList(item.children || [])
})
}
mapList(list)
return arr
}
const initTreeData = (data, selected = []) => {
const _data = [...data]
function formatterTreeData(list = []) {
const arr = []
list.map(item => {
const obj = {
...item,
children: formatterTreeData(item.children || []),
isChecked: selected.includes(item.key)
}
obj.isExtend = obj.isExtend || obj.children.some(n => n.isChecked || n.isExtend)
arr.push(obj)
})
return arr
}
return formatterTreeData(_data)
}
const TreeNode = {
name: 'McTreeNode',
props: {
data: Array,
parentData: {
type: Object,
default: () => { }
},
multi: Boolean,
keyName: {
type: String,
default: 'value'
}
},
setup(props, { emit }) {
const parentRefresh = inject('parentRefresh', () => {})
const parentSingleSelect = inject('parentSingleSelect', () => {})
const parentMultiSelect = inject('parentMultiSelect', () => {})
const handleExtend = (e, item) => {
e.stopPropagation()
item.isExtend = !item.isExtend
parentRefresh()
}
const handleClick = (item) => {
if (props.multi) return
parentSingleSelect(item)
}
const handleCheck = (item) => {
parentMultiSelect(item)
}
const extendNode = (item) => (
<span class={{
'arrow-wrap': true,
'active': item.isExtend
}} onClick={(event) => handleExtend(event, item)}>
<i class="arrow"></i>
</span>
)
const singleNode = (item) => (
<span class={{
'name': true,
'enable-click': true,
'checked': item.isChecked
}} onClick={() => handleClick(item)}>{item.name}</span>
)
const multiNode = (item) => (
<>
<McCheckbox v-model={item.isChecked}
onChange={() => handleCheck(item)} />
<span class="name" style="margin-left:5px;">{item.name}</span>
</>
)
const itemNode = (item) => (
<TreeNode
data={item.children}
multi={props.multi}
parent-data={item}
key-name={props.keyName} />
)
const liNode = (item, idx) => (
<li key={idx}>
<div class="wrap">
{
item.children && item.children.length ? extendNode(item) : ''
}
{
props.multi ? multiNode(item) : singleNode(item)
}
</div>
{
item.isExtend && item.children && item.children.length ? itemNode(item) : ''
}
</li>
)
return () => (
<ul class="mc-tree">
{
props.data.map(liNode)
}
</ul>
)
}
}
const Tree = {
name: 'McTree',
props: {
modelValue: Array,
data: Array,
multi: Boolean,
keyName: {
type: String,
default: 'value'
},
},
setup(props, { emit }) {
const treeData = ref([])
const model = computed({
get() {
return props.modelValue || []
},
set(value) {
emit('update:modelValue', value)
emit('change', getSelectedData(props.data, value, props.keyName))
}
})
treeData.value = initTreeData(props.data, model.value)
const handleSingleSelected = (item) => {
model.value = [item[props.keyName]]
setTree()
}
const handleMultiSelected = (item) => {
const value = item[props.keyName]
const arr = model.value
const exist = arr.includes(value)
if (exist) {
arr.splice(arr.indexOf(value), 1)
} else {
arr.push(value)
}
model.value = arr
setTree()
}
const setTree = () => {
treeData.value = initTreeData(treeData.value, model.value)
}
const refresh = () => {
treeData.value = utils.deepCopy(treeData.value)
}
provide('parentRefresh', refresh)
provide('parentSingleSelect', handleSingleSelected)
provide('parentMultiSelect', handleMultiSelected)
return () => (
<div class="mc-tree">
<TreeNode
data={treeData.value}
multi={props.multi}
keyName={props.keyName} />
</div>
)
}
}
Tree.install = (app) => {
app.component(Tree.name, Tree)
}
const McTree = Tree
export { McTree, McTree as default }