本文中省略很多开发说明,可能需有一定uniapp的实战基础的朋友才能看明白。
schema2code
生成的无限级分类页面只提供超简易版的功能,没有层级选择,只能自己填入父类ID,列表的时候也是全部显示,没有层级关系,无法根据分类逐层显示,或者树形显示。因此,我们需要在这个基础上进行修改,当然,我的原则是尽量少改一点。
默认模式没法用,层级层级没有,不知道在看什么
第一种:分层分页显示各级的方式
页面预览:
schema2code生成的分类修改后实现的功能
一、schema数据库结构设计
根据大意随便写一下,假设存在一个某某类别的数据表,其schema主要内容如下,其中授权、属性等在实际生产时再打磨。
{
"bsonType": "object",
"required": ["key","name"],
"permission": {
"read": true,
"create": "'admin' in auth.role",
"update": "'admin' in auth.role",
"delete": "'admin' in auth.role"
},
"properties": {
"_id": {
"description": "ID,系统自动生成"
},
"parent_id": {
"bsonType": "string",
"title": "上级",
"description": "父ID,用于多级分类",
"parentKey": "_id", // 指定父子关系为:如果数据库记录A的_id和数据库记录B的parent_id相等,则A是B的父级。
"enumType": "tree", // 默认表单控件将生成uni-data-picker
"enum": {
"collection": "test",
"orderby": "sort asc, value asc",
"field": "name as text, _id as value"
}
},
"name":{
"bsonType": "string",
"title": "名称",
"description": "分类名称",
"defaultValue": ""
},
"sort": {
"bsonType": "int",
"title": "排序",
"description": "类别排序,越大越靠后",
"defaultValue": 0
}
}
}
二、生成前端
- 选择
schema2code
生成前端,这时在uni-model
或者pages
目录下就应该会产生对应三个文件list.vue
、add.vue
、edit.vue
。 - 其中
list.vue
改动较多。 - 在本案例中将用到一个云对象
category
,此云对象主要就是将类目数据进行排序并进行层级嵌套或扁平化处理,输出的结果可以为扁平化单层结果也可以嵌套多层结果(子类都嵌套于children中)。
结果示例:
// 扁平化
[{
_id:'1',
parent_id:''
name:'a',
sort:'0'
},{
_id:'2',
parent_id:''
name:'b',
sort:'0'
},{
_id:'3',
parent_id:'1'
name:'c',
sort:'0'
},{
_id:'4',
parent_id:'3'
name:'d',
sort:'d'
},{
_id:'5',
parent_id:'2'
name:'e',
sort:'0'
}]
// 嵌套
[{
_id:'1',
parent_id:''
name:'a',
sort:'0',
children:[{
_id:'3',
parent_id:'1'
name:'c',
sort:'0',
children:[{
_id:'4',
parent_id:'3'
key:'d',
name:'d',
sort:'d'
}]
}]
},{
_id:'2',
parent_id:''
name:'b',
sort:'0',
children:[{
_id:'5',
parent_id:'2'
name:'e',
sort:'0'
}]
}]
三、修改list.vue
1. 增加基本配置
...
//导入云对象
const category = uniCloud.importObject('category')
...
// 增加两个变量
export default {
data() {
return {
parentId: '', // 当前父类id
navTree: [], // 导航栏树形数据
...
2. 增加路径导航、刷新和重置
// html
<view class="uni-header">
<view class="uni-group">
<view class="uni-title">
<uni-data-select v-model="parentId" :localdata="navTree" placeholder="当前位置" @change="navChange"></uni-data-select>
</view>
<view class="uni-sub-title">
<button class="uni-button" type="default" size="mini" @click="navigateTo('./list?parentId='+parentId)">刷新</button>
<button class="uni-button" type="default" size="mini" @click="navigateTo('./list?parentId=')">重置</button>
</view>
</view>
...
<view class="uni-group">
<button @click="navigateTo('./list?parentId='+item._id, false)" class="uni-button" size="mini" type="primary">下级</button>
...
// javascript
...
onLoad(e) {
...
// 获取父级id
this.parentId = (e.parentId) ? e.parentId : ''
// 修改数据库读取条件
this.where = 'parent_id == "' + this.parentId + '"'
// 创建db引用
// const db = uniCloud.database()
// 查询获得父节点路径,用于当前位置
db.collection(this.collectionList).field('_id, parent_id, name, sort').get({
getTreePath: {
"startWith": "_id=='" + this.parentId + "'"
}
})
.then((res) => {
//使用自建云对象category中的函数processTree对数据进行排序和符号标注,具体根据各自的对象函数要求操作
cateogry.processTree(res.result.data, {
isFlat: true,
sourceFlat: false,
spaceIcon: '・'
}).then(res => {
this.navTree = [
...this.navTree,
...res.result.map(item => ({
value: item._id,
text: item.__levelPrefix + item.name
}))
];
}).catch(e => {
console.log(e)
})
}).catch((err) => {
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
}).finally(() => {
uni.hideLoading()
// console.log("finally")
})
},
...
methods: {
// 导航位置下拉菜单选中后跳转页面同时传递一个parentId
navChange(e) {
uni.navigateTo({
url: './list?parentId=' + e
});
},
3. 修改新增按钮
在原来的新增按钮点击动作加一个参数parentId
,用来传递本层父类ID,这样点击新增按钮后打开的页面都将默认选中本层级的分类
<button class="uni-button" type="default" size="mini" @click="navigateTo('./add?parentId='+parentId)">新增</button>
这里有些人喜欢将新建子类
按钮放在每条数据后,这样可以直接在该条创建子类,而默认的新建按钮改名为新建一级分类
按钮。
本文实现的是点新建
按钮默认选中当前分类,可以随时重选。
四、修改add.vue
这里修改的代码比较简单,就是将传递的父类id赋值给表单parent_id
,这样父类picker默认就是当前父类,也可以自行重新选择。
...
onLoad(e) {
this.formData.parent_id = (e.parentId) ? e.parentId : ''
},
...
进化版的话就是不能选自己,不能选没有授权的。
五、修改edit.vue
主要就是根据选择的节点来修改picker选择器
的当前值,默认情况下该picker选择器
必须选中最后一层才有值,但实际上可能在中间某层就要选中,因此用选中节点事件 @nodeclick
来获取该节点的值的方法。
// html
...
<uni-forms-item name="parent_id" label="上级">
<uni-data-picker ... @nodeclick="onNodeClick_parentId"></uni-data-picker>
</uni-forms-item>
...
// javascript
...
methods: {
onNodeClick_parentId(e){
this.formData.parent_id = e.value
},
...
第二种:单页显示所有层级的方式
就是在一个页面上显示所有的层级,适用场景:层数较少,数据量较少,当然,也可以进化到每次只显示一层,点击后再加载其下的子类。
页面预览
与分页显示主要不同点就是:
一、数据扁平化处理后赋值给组件
将unicloud-db组件
获取的数据在onqueryload
方法中用自定义的云对象/云函数category
进行一次处理,输出带层级符号的数据列表,把这个数据列表赋值给this.$refs.udb.dataList
即可,该数据必须是扁平化的,这样页面仅需循环显示即可。
···
const category = uniCloud.importObject('category') //导入云对象
...
onqueryload(data) {
category.processTree(data, {
isFlat: true
}).then(res => {
this.$refs.udb.dataList = res.result
}).catch(e => {
this.$refs.udb.dataList = []
})
this.exportExcelData = data
},
...
二、页面增加前缀符号
扁平化处理后的数据主要内容如下,我们需要其生成的__levelPrefix
[
{
"_id": "66c721dec390b34a06875acb",
"name": "a",
"parent_id": "",
"__levelPrefix": "┬ "
},
{
"_id": "66c721f00b9a11185f5c531f",
"name": "c",
"parent_id": "66c721dec390b34a06875acb",
"__levelPrefix": "└┬ "
}
...
]
页面中名称的位置加上符号
// 空格需要转为 才能正常使用
<uni-td align="left">{{item.__levelPrefix ? item.__levelPrefix.replace(/ /g, ' ') : ''}}{{item.name}}</uni-td>
三、新增与修改
list.vue
右上方的新建按钮只能创造一级类;list.vue
每条数据增加一个创建子类
的按钮;add.vue
和edit.vue
和上一种方式类似,不再赘述
吐槽一下,其实add和edit这两个页面可以合并为一个,当_id不存在时就是add,存在就是edit,我原来的系统就是这么做的,这样的话,改动某一个组件只要动一个文件就行,现在就要动两个文件,增加了遗漏出错的可能。
参考:
uni-app开发日志:unicloud使用时遇到的问题解决汇总(不断补充)
制表符 制表符号大全
JQL语法
schema2code代码生成系统
组件名:uni-data-picker
uni-app之数据驱动的picker选择器( uni-data-picker)之可以选择到任意级别
unicloud项目中树形分类页面的快速开发(一)
unicloud项目中树形分类页面的快速开发(二)
unicloud项目中树形分类页面的快速开发(三)