更新记录

1.0.1(2025-07-10) 下载此版本

修改默认样式内容不显示bug

1.0.0(2025-07-10) 下载此版本

1、树形结构插件,支持三种数据源:树形结构、列表结构(所有数据)、列表结构(懒加载)

2、支持单选、多选

3、支持自定义列表样式

4、支持自定义父项与子项缩进


平台兼容性

uni-app

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- - - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 快应用-华为 快应用-联盟
- - - - - - - - - -

uni-app x

Chrome Safari Android iOS 鸿蒙 微信小程序
5.0 12 -

其他

多语言 暗黑模式 宽屏模式
× ×

sjx-tree-perfect

该组件为uni_modules组件,下载导入后可以全局直接使用,无需在页面中引入、声明组件

在开发中,结合数据源及实际需求,该组件提供了三种数据源结构,支持懒加载、支持单选、多选。

更重要的是支持自定义每一项的样式,主要是为了解决实际开发中不同页面树样式不一样的问题。

Props

字段 类型 默认值 可选值 功能描述 更新时间
dataType Number 0 0|1|2 数据源类型:0--树形结构;1--列表结构(所有数据);2--列表结构(懒加载) 2025-07-10
isSelf Boolean false true|false 是否使用自定义样式 2025-07-10
treeData Array [] ~ 数据源 2025-07-10
id String 'id' ~ id字段名 2025-07-10
pid String 'pid' ~ pid字段名 2025-07-10
name String 'name' ~ name字段名 2025-07-10
childsField String ‘children ~ 当数据源是树形结构时,子项字段名 2025-07-10
paddingGap Number 15 ~ 父项与子项缩进距离 2025-07-10
hasChildField String ’hasChild ~ 懒加载时是否有子项或者是否是叶子项 2025-07-10
childData Array [] ~ 懒加载时子项列表 2025-07-10
choiceType Number 0 0|1|2 选择类型:0--不需要;1--单选;2--多选 2025-07-10

Events

事件名 默认值 功能描述 更新时间
nodeClick ~ 列表项点击事件 2025-07-10
singleSelectChange ~ 单选事件 2025-07-10
multiSelectChange ~ 多选事件 2025-07-10

代码演示

数据源是树形结构

<template>
    <view class="content">
        <sjx-tree-perfect :treeData="treeData" name="title" @nodeClick='nodeClick'>
        </sjx-tree-perfect>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                title: 'Hello',
                treeData: [{
                    id: 1,
                    pid: 0,
                    title: '测试1',
                    children: [{
                        id: 4,
                        pid: 1,
                        title: '测试1-1',
                        children: [{
                            id: 8,
                            pid: 4,
                            title: '测试1-1-1'
                        }]
                    }, {
                        id: 5,
                        pid: 1,
                        title: '测试1-2'
                    }]
                }, {
                    id: 2,
                    pid: 0,
                    title: '测试2',
                    children: [{
                        id: 6,
                        pid: 2,
                        title: '测试2-1'
                    }]
                }, {
                    id: 3,
                    pid: 0,
                    title: '测试3',
                    children: [{
                        id: 7,
                        pid: 3,
                        title: '测试3-1'
                    }]
                }]
            }
        },
        mounted() {

        },
        methods: {
            nodeClick(item) {
                console.log('当前点击项', item);
            }
        }
    }
</script>

<style lang="scss" scoped>
    .content {
        padding: 10px;
    }
</style>

数据源是列表(所有数据)

<template>
    <view class="content">
        <sjx-tree-perfect :dataType="1" :treeData="treeData" name="title" @nodeClick='nodeClick'>
        </sjx-tree-perfect>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                title: 'Hello',
                treeData: [{
                    id: 1,
                    pid: 0,
                    title: '测试1'
                }, {
                    id: 2,
                    pid: 0,
                    title: '测试2'
                }, {
                    id: 3,
                    pid: 0,
                    title: '测试3'
                }, {
                    id: 4,
                    pid: 1,
                    title: '测试1-1'
                }, {
                    id: 5,
                    pid: 1,
                    title: '测试1-2'
                }, {
                    id: 6,
                    pid: 2,
                    title: '测试2-1'
                }, {
                    id: 7,
                    pid: 3,
                    title: '测试3-1'
                }, {
                    id: 8,
                    pid: 4,
                    title: '测试1-1-1'
                }]
            }
        },
        mounted() {

        },
        methods: {
            nodeClick(item) {
                console.log('当前点击项', item);
            }
        }
    }
</script>

<style lang="scss" scoped>
    .content {
        padding: 10px;
    }
</style>

数据源是列表(懒加载)

<template>
    <view class="content">
        <sjx-tree-perfect :dataType="2" :treeData="treeData" name="title" @nodeClick='nodeClick' :childData="childData"
            hasChildField="haschild">
        </sjx-tree-perfect>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                title: 'Hello',
                treeData: [{
                    id: 1,
                    pid: 0,
                    title: '测试1',
                    haschild: true
                }, {
                    id: 2,
                    pid: 0,
                    title: '测试2',
                    haschild: true
                }, {
                    id: 3,
                    pid: 0,
                    title: '测试3',
                    haschild: true
                }],
                childData: []
            }
        },
        mounted() {

        },
        methods: {
            nodeClick(item) {
                console.log('当前点击项', item);
                this.getNextData(item)
            },
            getNextData(item) {
                if (!item.isLoad) {
                    setTimeout(() => {
                        this.childData = []
                        if (item.id == 1) {
                            this.childData.push({
                                id: 4,
                                pid: 1,
                                title: '测试1-1',
                                haschild: true
                            })
                            this.childData.push({
                                id: 5,
                                pid: 1,
                                title: '测试1-2',
                                haschild: false
                            })
                        }
                        if (item.id == 2) {
                            this.childData.push({
                                id: 6,
                                pid: 2,
                                title: '测试2-1',
                                haschild: false
                            })
                        }
                        if (item.id == 3) {
                            this.childData.push({
                                id: 7,
                                pid: 3,
                                title: '测试3-1',
                                haschild: false
                            })
                        }
                        if (item.id == 4) {
                            this.childData.push({
                                id: 8,
                                pid: 4,
                                title: '测试1-1-1',
                                haschild: false
                            })
                        }
                    }, 1000)
                }

            }
        }
    }
</script>

<style lang="scss" scoped>
    .content {
        padding: 10px;
    }
</style>

默认单选

<template>
    <view class="content">
        <sjx-tree-perfect :dataType="1" :treeData="treeData" name="title" @nodeClick='nodeClick' :choiceType="1"
            @singleSelectChange='radioChanges'>
        </sjx-tree-perfect>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                title: 'Hello',
                treeData: [{
                    id: 1,
                    pid: 0,
                    title: '测试1'
                }, {
                    id: 2,
                    pid: 0,
                    title: '测试2'
                }, {
                    id: 3,
                    pid: 0,
                    title: '测试3'
                }, {
                    id: 4,
                    pid: 1,
                    title: '测试1-1'
                }, {
                    id: 5,
                    pid: 1,
                    title: '测试1-2'
                }, {
                    id: 6,
                    pid: 2,
                    title: '测试2-1'
                }, {
                    id: 7,
                    pid: 3,
                    title: '测试3-1'
                }, {
                    id: 8,
                    pid: 4,
                    title: '测试1-1-1'
                }]
            }
        },
        mounted() {

        },
        methods: {
            nodeClick(item) {
                console.log('当前点击项', item);
            },
            /* 参数说明
            item:当前选中项
            */
            radioChanges(item) {
                console.log('组件单选选中的项', item);
            }
        }
    }
</script>

<style lang="scss" scoped>
    .content {
        padding: 10px;
    }
</style>

默认多选

<template>
    <view class="content">
        <sjx-tree-perfect :dataType="1" :treeData="treeData" name="title" @nodeClick='nodeClick' :choiceType="2"
            @multiSelectChange='checkBoxChange'>
        </sjx-tree-perfect>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                title: 'Hello',
                treeData: [{
                    id: 1,
                    pid: 0,
                    title: '测试1'
                }, {
                    id: 2,
                    pid: 0,
                    title: '测试2'
                }, {
                    id: 3,
                    pid: 0,
                    title: '测试3'
                }, {
                    id: 4,
                    pid: 1,
                    title: '测试1-1'
                }, {
                    id: 5,
                    pid: 1,
                    title: '测试1-2'
                }, {
                    id: 6,
                    pid: 2,
                    title: '测试2-1'
                }, {
                    id: 7,
                    pid: 3,
                    title: '测试3-1'
                }, {
                    id: 8,
                    pid: 4,
                    title: '测试1-1-1'
                }]
            }
        },
        mounted() {

        },
        methods: {
            nodeClick(item) {
                console.log('当前点击项', item);
            },
            /* 参数说明 
            ids:选中项id数组
            names:选中项name数组
            items:选中项数组
            */
            checkBoxChange(ids, names, items) {
                console.log('组件多选选中的项', ids.join(','), names.join(','), items);
            }
        }
    }
</script>

<style lang="scss" scoped>
    .content {
        padding: 10px;
    }
</style>

自定义单选

主要是使用插槽slot

<template>
    <view class="container">
        <sjx-tree-perfect ref="tree" :dataType="1" :treeData="treeData" name="title" :is-self="true"
            @singleSelectChange='radioChanges'>
            <template v-slot:default="{data}">
                <view>
                    <!-- 以下内容是自定义样式,你可以根据自己实际需求书写样式,这里使用了组件默认样式 -->
                    <view class="item" v-for="(item,index) in data" :key="index"
                        :style="{paddingLeft: item.level*15+'px' }">
                        <view class="choice">
                            <radio :value="JSON.stringify(item)" @click="myRadioChange(item)" :checked="item.radio">
                            </radio>
                        </view>
                        <view class="content" @click="myItemClick(item)">
                            <view class="switch">
                                <view :class="item.isLeaf?'':(item.isExpan?'switch-on':'switch-off')"></view>
                            </view>
                            <text class="name">{{item.title}}</text>
                        </view>
                    </view>
                </view>
            </template>
        </sjx-tree-perfect>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                title: 'Hello',
                treeData: [{
                    id: 1,
                    pid: 0,
                    title: '测试1'
                }, {
                    id: 2,
                    pid: 0,
                    title: '测试2'
                }, {
                    id: 3,
                    pid: 0,
                    title: '测试3'
                }, {
                    id: 4,
                    pid: 1,
                    title: '测试1-1'
                }, {
                    id: 5,
                    pid: 1,
                    title: '测试1-2'
                }, {
                    id: 6,
                    pid: 2,
                    title: '测试2-1'
                }, {
                    id: 7,
                    pid: 3,
                    title: '测试3-1'
                }, {
                    id: 8,
                    pid: 4,
                    title: '测试1-1-1'
                }]
            }
        },
        mounted() {

        },
        methods: {
            nodeClick(item) {
                console.log('当前点击项', item);
            },
            myItemClick(item) {
                this.$refs.tree.itemClick(item)
            },
            myRadioChange(item) {
                this.$refs.tree.radioChange(item)
            },
            radioChanges(item) {
                console.log('组件单选选中的项', item);
            }

        }
    }
</script>

<style lang="scss" scoped>
    .container {
        padding: 10px;
    }

    .item {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        padding: 5px 0;
        border-bottom: #f6f6f6 1px solid;
        box-sizing: border-box;

        .choice {

            radio,
            checkbox {
                transform: scale(0.7);
            }
        }

        .content {
            display: flex;
            justify-content: flex-start;
            align-items: center;

            .switch {
                display: flex;
                width: 30px;
                justify-content: center;
                align-items: center;
            }

            .name {
                flex: 1;
            }

            .switch-on {
                width: 0;
                height: 0;
                border: #666 8px solid;
                border-radius: 5px;
                border-color: black transparent transparent transparent;
                transform: translateY(25%);
            }

            .switch-off {
                width: 0;
                height: 0;
                border: #666 8px solid;
                border-radius: 5px;

                border-color: transparent transparent transparent black;
                transform: translateX(25%);
            }
        }
    }
</style>

自定义多选

<template>
    <view class="container">
        <sjx-tree-perfect ref="tree" :dataType="1" :treeData="treeData" name="title" @nodeClick='nodeClick'
            :is-self="true" @multiSelectChange='checkBoxChange'>
            <template v-slot:default="{data}">
                <view>
                     <!-- 以下内容是自定义样式,你可以根据自己实际需求书写样式,这里使用了组件默认样式 -->
                    <view class="item" v-for="(item,index) in data" :key="index"
                        :style="{paddingLeft: item.level*15+'px' }">
                        <view class="choice">
                            <checkbox :value="JSON.stringify(item)" @click="myCheckChange(item)" :checked="item.check">
                            </checkbox>
                        </view>
                        <view class="content" @click="myItemClick(item)">
                            <view class="switch">
                                <view :class="item.isLeaf?'':(item.isExpan?'switch-on':'switch-off')"></view>
                            </view>
                            <!-- 以下显示内容可以根据item对象随意修改 -->
                            <text class="name">{{item.title}}</text>
                        </view>
                    </view>
                </view>
            </template>
        </sjx-tree-perfect>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                title: 'Hello',
                treeData: [{
                    id: 1,
                    pid: 0,
                    title: '测试1'
                }, {
                    id: 2,
                    pid: 0,
                    title: '测试2'
                }, {
                    id: 3,
                    pid: 0,
                    title: '测试3'
                }, {
                    id: 4,
                    pid: 1,
                    title: '测试1-1'
                }, {
                    id: 5,
                    pid: 1,
                    title: '测试1-2'
                }, {
                    id: 6,
                    pid: 2,
                    title: '测试2-1'
                }, {
                    id: 7,
                    pid: 3,
                    title: '测试3-1'
                }, {
                    id: 8,
                    pid: 4,
                    title: '测试1-1-1'
                }]
            }
        },
        mounted() {

        },
        methods: {
            nodeClick(item) {
                console.log('当前点击项', item);
            },
            myItemClick(item) {
                this.$refs.tree.itemClick(item)
            },
            myCheckChange(item) {
                this.$refs.tree.checkBoxChange(item)
            },
            checkBoxChange(ids, names, items) {
                console.log('组件单选选中的项', ids.join(','), names.join(','), items);
            }
        }
    }
</script>

<style lang="scss" scoped>
    .container {
        padding: 10px;
    }

    .item {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        padding: 5px 0;
        border-bottom: #f6f6f6 1px solid;
        box-sizing: border-box;

        .choice {

            radio,
            checkbox {
                transform: scale(0.7);
            }
        }

        .content {
            display: flex;
            justify-content: flex-start;
            align-items: center;

            .switch {
                display: flex;
                width: 30px;
                justify-content: center;
                align-items: center;
            }

            .name {
                flex: 1;
            }

            .switch-on {
                width: 0;
                height: 0;
                border: #666 8px solid;
                border-radius: 5px;
                border-color: black transparent transparent transparent;
                transform: translateY(25%);
            }

            .switch-off {
                width: 0;
                height: 0;
                border: #666 8px solid;
                border-radius: 5px;

                border-color: transparent transparent transparent black;
                transform: translateX(25%);
            }
        }
    }
</style>

关于我

1、如有不足或不方便的地方,请指出,我尽快完善。

2、各位小伙伴如果需要其他插件的话,请留言,我会根据实际需求及自身能力完成插件或给出建议。

谢谢大家!

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问