win7 建设网站服务器,关键词网络推广,wordpress聚合文章,海口网络推广vue3vant 实现树状多选组件 需求描述效果图代码父组件引用selectTree组件 tree组件数据格式 需求描述 移动端需要复刻Pc端如上图的功能组件#xff0c;但vant无组件可用#xff0c;所以自己封装一个。 效果图 代码
父组件引用
import TreeSelect from /selectTree.vu… vue3vant 实现树状多选组件 需求描述效果图代码父组件引用selectTree组件 tree组件数据格式 需求描述 移动端需要复刻Pc端如上图的功能组件但vant无组件可用所以自己封装一个。 效果图 代码
父组件引用
import TreeSelect from /selectTree.vuetreeSelectreftreeSelectRefv-model:showshowAera:modelValuemodelValue:listDataoptions:multipletrueplaceholder请选择changeModelValuechangeModelValue/treeSelectselectTree组件
templatevan-popup v-model:showshowPicker round positionbottom click-overlayonClickOverlay div classtree-boxdiv classtree-containerdiv classtree-dataTreeSelectreftreeSelectRef:listdata.list:listObjdata.listObjconfirmonConfirm/TreeSelect/div/div/divdiv classtree-confirmvan-button typeprimary block clickhandleConfirm确定/van-button/div/van-popup
/templatescript setup
import { reactive, watch, ref, nextTick, onMounted } from vue;
import TreeSelect from ./tree.vue;
import { showLoadingToast, closeToast } from vant;const emits defineEmits([changeModelValue, update:show, confirm]);
const props defineProps({show: {type: Boolean,default: false,},// 绑定值modelValue: {type: Array,default() {return [];},},listData: {type: Array,default() {return [];},},
});watch(() props.show,() {showPicker.value props.show;initData(props.listData);}
);const showPicker ref(props.show);
const data reactive({list: props.listData, // 树数组listObj: {}, // 数组对象selectList: [], // 选中的数据canCheckList: [], // 能够选择的数据集合canCheckListFixed: [], // 固定的能够选择的数据集合
});const treeSelectRef ref(null);const init (type) {data.canCheckList [];data.canCheckListFixed [];
};
const initData (options) {if (options options.length) {options[0].firsttruedata.list options;init();data.listObj setListObj(options);}
};// 将树形数据转为扁平对象
const setListObj (list) {let listObj {};list.forEach((itm) {if(props.modelValueprops.modelValue.indexOf(itm.id)!-1){itm.checkedtrue}data.canCheckList.push(itm);data.canCheckListFixed.push(itm);listObj[itm.id] itm;if (itm.children itm.children.length) {listObj {...listObj,...setListObj(itm.children),};}});return listObj;
};const onClickOverlay () {emits(update:show, false);
};
// 确认
const handleConfirm () {emits(changeModelValue, data.selectList);emits(update:show, false);
};const onConfirm (e) {const showSelectList filterData(e);data.selectList showSelectList.map((itm) itm.id);
};// 过滤数据
const filterData (selectList) {// 过滤出展示中且打勾的数据const showSelectList selectList.filter((itm) {return !itm.isHide !itm.isShowChildren;});return showSelectList;
};const sendWordShow ref(false);defineExpose({init,setListObj,
});
/scriptstyle langless scoped
.tree-box {--van-search-content-background-color: #eeeeee;--van-search-content-background: #eeeeee;
}.tree-container {width: 100%;padding: 32px 32px 0;
}.tree-data {height: 60vh;overflow-y: auto;
}.tree-btns {width: 100%;margin-bottom: 24px;display: flex;align-items: center;
}.tree-confirm {width: 100%;padding: 12px 32px;
}
/styletree组件
templatediv classlistdiv classitem v-foritem in props.list :keyitem.key v-show!item.isHidediv classtitlediv classcheckbox-boxvan-checkbox icon-size16px shapesquare click.stopcheckChange(item) v-modelitem.checkedspan stylefont-size: 15px;{{ item.name}}/span/van-checkbox/divdiv click.stopitemClick(item) :classitem.first?arrow:arrowlastvan-icon v-ifitem.children item.children.length :nameitem.isShowChildren ? arrow-up : arrow-down //div/divdiv classtree v-showitem.first||item.isShowChildrentree :isLinkdata.isLinkv-ifitem.children item.children.length :listitem.children :listObjprops.listObj:isFirstFloorfalse :multipledata.multiple confirmonConfirm :defaultIddefaultId/tree/div/div/div
/template
script setup
import { reactive, watch } from vue
import tree from ./tree.vue
const emits defineEmits([change,confirm])
const props defineProps({// 是否是第一层isFirstFloor: {type: Boolean,default() {return true;},},// 树形结构list: {type: Array,default() {return [];},},// 树形扁平化数据listObj: {type: Object,default() {return {};},},// 单选默认值defaultId : String
})const data reactive({firstLoad: true,checkboxValue1: [],showList: [],isLink:true,multiple:true,isOutData: true, // 需要将数据抛出
})watch(() props.list, () {if (data.firstLoad) {outDataBuffer();data.firstLoad false;}// 判断 是第一层树 且 不是进行显示隐藏操作时进行数据的抛出if (props.isFirstFloor data.isOutData) {if(data.multiple){outCheckedData();}}
}, { deep: true })// 展开
const itemClick (item) {outDataBuffer();item.isShowChildren !item.isShowChildren}
// 数据抛出缓冲在list数据变化时不想抛出选择的数据时调用该方法
const outDataBuffer () {data.isOutData false;setTimeout(() {data.isOutData true;}, 500);
}
// 获取选中对象
const getCheckData (list) {let deptList [];list.forEach((itm) {if (itm.checked) {deptList.push(itm);}if (itm.children itm.children.length) {deptList deptList.concat(getCheckData(itm.children));}});return deptList;
}
// 单项checked改变
const checkChange (item) {// 多选if (data.multiple) {// item.checked !item.checkedif (data.isLink) {// 展开所有可以展开的节点if (item.checked) {expandAll(item);}// 判断父级是否需要勾选checkParent(item);// 勾选子级if (item.children item.children.length) {checkChidren(item.children, item.checked);outCheckedData();}}return}// 单选if(item.children item.children.length) returntoggleAllSelectData(props.list)outCheckedData();}// 获取全部可选择数据进行全选/取消
const toggleAllSelectData (list) {list.forEach((itm) {itm.checked falseif (itm.children itm.children.length) {toggleAllSelectData(itm.children)}});
}// 展开所有可以展开的节点
const expandAll (item) {if (item.children?.length) {item.isShowChildren trueitem.children.forEach(itm {expandAll(itm);})}
}
// 判断父级是否需要勾选
const checkParent (item) {// 父级不存在不再往下走if (!props.listObj[item[props.pidKey]]) {return;}let someDataCount 0; // 同级的相同父级数据量let checkedDataCount 0; // 同级已勾选的数据量for (const id in props.listObj) {const itm props.listObj[id];if (itm[props.pidKey] item[props.pidKey] !itm.isHide) {someDataCount;if (itm.checked) {checkedDataCount;}}}const isEqual someDataCount checkedDataCount;if (props.listObj[item[props.pidKey]].checked ! isEqual) {props.listObj[item[props.pidKey]].checked isEqualcheckParent(props.listObj[item[props.pidKey]]);}
}
// 根据父级统一取消勾选或勾选
const checkChidren (list, isChecked) {list.forEach((itm) {itm.checked isCheckedif (itm.children itm.children.length) {checkChidren(itm.children, isChecked);}});
}
// 抛出选中的数据
const outCheckedData () {const checkedList getCheckData(props.list);emits(change, checkedList);onConfirm(checkedList)
}const onConfirm (e) {emits(confirm, e);
}defineExpose({itemClick,outDataBuffer,getCheckData,checkChange,expandAll,checkParent,checkChidren,outCheckedData,})
/scriptstyle langless scoped.list {.item {margin-bottom: 10px;.title {display: flex;align-items: center;justify-content: space-between;margin-bottom: 10px;.checkbox-box {display: flex;align-items: center;cursor: pointer;padding: 10px 0;}.arrow{width: 80px;display: flex;justify-content: flex-end;}}.tree {margin-left: 50px;}}.arrow{display: none !important;}
}
/style数据格式
[{name: 1,key: 0,children: [{name: 2,key: 1,children: []},{name: 3,key: 1,children: [{name: 4,key: 3,children: []}]}]}
]