开发树形组件使用slot插槽后展示在小程序有问题,最后把代码改成浏览器端非uniapp组件方式运行又能正常运行,怀疑是uniapp对vue3的支持问题还是我的代码bug,麻烦大佬看下,能否告诉我是我代码没对还是需要uniapp继续对vue3的slot特性支持,同时也附上改装普通版本的tree组件。
在小程序中表现
预期效果:节点的文字不应该随着展开关闭变动,应该始终都在
放一组list变量数据
[{
"id": 5,
"content": "test",
"state_dict_id": 5,
"children": [{
"id": 11,
"content": "sub1",
"state_dict_id": 5,
"parent_id": 5,
"children": []
}, {
"id": 12,
"content": "sb2",
"state_dict_id": 5,
"parent_id": 5,
"children": []
}]
}, {
"id": 6,
"content": "test21",
"desc": "",
"state_dict_id": 5,
"parent_id": null,
"children": []
}]
uniapp版
引用.vue页面
<template>
<rich-tree :data="list" :defaultProps="{label: 'content', children: 'children'}" @on-item-click="handleItemClick">
<template #prefix="{node}">{{node.content}} ---</template>
</rich-tree>
</template>
rich-tree.vue页面
<template>
<view class="rich-tree">
<treeNode v-for="(item, index) in data" :key="item[defaultProps.id]"
:defaultProps="defaultProps"
:item="item" :depth="depth" :render-content="renderContent">
<template #prefix="{node}">
<slot name="prefix" :node="node"></slot>
</template>
</treeNode>
</view>
</template>
<script setup>
import {ref, unref, provide} from 'vue'
import treeNode from './tree-node.vue'
let depth = ref(1)
const props = defineProps({
data: {
type: Array,
default: () => {
return []
}
},
defaultProps: {
type: Object,
default: () => {
return {
id: 'id',
children: 'children',
label : 'label'
}
}
},
renderContent: Function
})
provide('onItemClick', handleItemClick)
const emit = defineEmits(['on-collapse-click', 'on-item-click'])
function handleItemClick(data){
emit('on-item-click', data)
}
</script>
<style lang="scss">
</style>
tree-node.vue页面
<template>
<view class="tree-node" :style="{paddingLeft: depth>1?'12px':null}">
<view class="node-item">
<view @click="handleItemClick({item, $event})" class="item-left">
<slot name="prefix" :node="item">
{{item[defaultProps.label]}}
</slot>
</view>
<view v-if="item[defaultProps.children]&&item[defaultProps.children].length" @click="handleCollapseClick" class="collapse-btn">
<view class="divider"></view>
<uni-icons :type="node.isCollapsed?'bottom':'top'" size="15"></uni-icons>
</view>
</view>
<view v-if="item[defaultProps.children]&&!node.isCollapsed" class="node-children"> <!-- 加入展开时渲染 -->
<treeNode v-for="(item, index) in item[defaultProps.children]" :key="defaultProps.id" :item="item" :defaultProps="defaultProps"
:depth="depth+1" :renderContent="renderContent">
<template #prefix="{node}">
<slot name="prefix" :node="node"></slot>
</template>
</treeNode>
</view>
</view>
</template>
<script setup>
import {ref, unref, inject, useSlots} from 'vue'
import treeNode from './tree-node.vue'
const slots = useSlots()
const props = defineProps({
item: {
type: Object,
default: () => {
return {}
}
},
depth: {
type: Number,
},
defaultProps: {
type: Object,
default: () => {
return {
id: 'id',
children: 'children',
label : 'label'
}
}
},
renderContent: Function
})
console.log('slots is:', slots)
let node = ref({depth: props.depth, data: props.item, isCollapsed: false})
const emit = defineEmits(['on-collapse-click', 'on-item-click'])
const handleItemClick = inject('onItemClick')
// function handleItemClick(){
// emit('on-item-click', {item})
// }
function handleCollapseClick(){
console.log('handleCollapseClick...', unref(node).isCollapsed)
node.value.isCollapsed = !unref(node).isCollapsed
emit('on-collapse-click', {item: props.item})
}
</script>
<style lang="scss">
.tree-node{
background-color: #fff;
}
.node-item{
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
.item-left{
flex: 1;
display: flex;
padding: 12px 15px;
}
.collapse-btn{
position: relative;
padding: 12px 15px;
height: 100%;
padding-left: 12px;
.divider{
position: absolute;
left: 0;
top: 50%;
height: 60%;
margin-top: calc(-30%);
width: 1px;
border-left: 1px dashed $uni-border-color;
}
}
}
</style>
以上代码为uniapp版本的tree的代码,研究半天解决不了问题,用renderContent函数使用vue3的h无法渲染成组件方式,只能渲染成字符串(暂时放弃不考虑了),再附上普通vue3版本的改装tree组件,tree-node组件上下图标用的是iview组件(简单替换即可)