文章目录
1. 实现效果
2. 实现功能-流程
- 在故障上报页面点击
故障位置
进入选择故障位置
(调用接口渲染list), - 支持连续下钻选择,选择完成点击
确认
返回故障上报页面 - 支持面包屑路径进行点击跳转,
- 支持默认值数据回显
3. 实现代码
3.1 【故障上报页面】故障位置选择页面代码
这个页面其他部分太多,只贴了一部分相关的代码
通过点击clickLoaction()
事件进行跳转到故障位置选择页面
<view class="box-line boeder-bottom">
<u-form-item label-width="150" label="故障位置" :border-bottom="false">
<u-input type="select" v-model="formParams.locationName" input-align="right"
:placeholder="'请选择'" disabled @click="clickLoaction()"/>
</u-form-item>
</view>
data 数据,存储故障位置name,故障位置id,(
formParams
用于提交故障上报的完整数据)
formParams: {
locationName: '', // 故障位置Name
locationId: '', // 故障位置ID
.....// 其他参数
},
点击进行跳转至故障位置选择页面,传入
locationId
参数
如果传了locationId
就是默认选中 该位置
// 选择 位置
clickLoaction(){
let url = `/fault/conditionFilter/treeList?locationId=${this.formParams.locationId}`
this.navigate(url)
},
// 设置 位置,通过故障位置选择页面选择完成后返回的值,并渲染到formParams对象中
setSelectLocationData(data){
let locationObj = JSON.parse(data);
if(!locationObj.length) return
this.formParams.locationName = locationObj[0].locationName
this.formParams.locationId = locationObj[0].locationId
},
3.2 【故障位置选择】
支持连续下钻选择,选择完成点击
确认
返回故障上报页面,完整代码breadcrumbs
组件就是list 无线级树型结构,面包屑导航的组件 。getCurrentPages
实现两个页面传值
<template>
<view class="container container-bg" :style="{height:(height)+'px'}">
<!-- #ifdef MP-WEIXIN -->
<u-navbar title="选择故障位置" title-size="36" back-icon-size="36" title-color="#333" back-icon-color="#333" height="48"
:border-bottom="false"></u-navbar>
<!-- #endif -->
<view class="white-bg flex-column flex-center" style="padding:0 30rpx;" :style="{height:searchHeight+'px'}">
<u-search placeholder="请输入" clearabled="true" shape="square" :show-action="false" v-model="keyword"
@input="refreshData">
</u-search>
</view>
<view class="white-bg color-9 font28 font-family fontW-500" :style="{height:elseHeight+'px'}">
<breadcrumbs :treeNone="list" :isCheck='true' :checkList="checkList" :props="props" :keyValue="keyValue" @sendValue="sendValue">
</breadcrumbs>
</view>
</view>
</template>
<script>
import {
config,
post
} from '@/utils/network.js';
import publicController from '@/common/publicController'
export default {
data() {
return {
height: this.windowHeightT(),
navH: this.navHeight,
searchHeight: uni.upx2px(102),
elseHeight: uni.upx2px(67),
jianju: uni.upx2px(20),
publicController: new publicController(),
keyword: '',
keyValue: "locationId",
props: {
label: "locationName",
children: "children",
multiple: false,
nodes: false
},//list 数据obj映射。
locationId:"",//设置的默认值
list: [],
selectedId: '',
checkList:[],
}
},
// 获取传入的位置id,如果存在,设置checkList值,默认选中
onLoad(option) {
this.locationId = option.locationId
if(this.locationId){
this.checkList.push({"locationId":this.locationId})
}
this.init()
},
methods: {
// 初始化
async init() {
// 调用接口
this.queryLocationTreeByID();
},
// 查询所有维修方式
async queryLocationTreeByID() {
this.list = await this.publicController.queryLocationTreeByID({});
},
refreshData(){
setTimeout(() => {
this.init()
}, 200)
},
// 点击确认按钮,子组件传入的data数据,值为选择的list的item值,
// 通过getCurrentPages返回到上一个页面,通过 prevPage.$vm.setSelectLocationData 方法传入选择的值
sendValue(data) {
let pages = getCurrentPages();
let prevPage = pages[pages.length - 2];
prevPage.$vm.setSelectLocationData(JSON.stringify(data))
uni.navigateBack({
delta: 1
})
}
}
}
</script>
<style lang='scss' scoped>
// ...... 省略
</style>
3.3 【breadcrumbs】组件完整代码
<template>
<view>
<view class="header">
<view class="title">
<scroll-view scroll-x style="width: 100%;white-space: nowrap;" :scroll-left="scrollLeft">
<view class="flex-row flex-item-center">
<block v-for="(item,index) in tree_stack" :key="index">
<view class="font28 font-family fontW-500"
:class="index==tree_stack.length-1?'color-9':'colorBlue'" v-if="index==0"
@click="backTree(item,-1)">全部</view>
<view class="flex-row flex-item-center" @click="backTree(item,index)" v-if="index!=0">
<i class="iconfont font24 next-icon"></i>
<view class="font28 font-family fontW-500"
:class="index==tree_stack.length-1?'color-9':'colorBlue'">
{{item[props.label]}}
</view>
</view>
</block>
</view>
</scroll-view>
</view>
</view>
<view>
<view class="container-list">
<view class="common" v-for="(item, index) in tree" :key="index" @click="handleClick(item,index)">
<label class="content">
<view class="list-item" v-show="isCheck" @click.stop="handleClick(item,-1)">
<view v-if="radioSelect(item)" class="iconfont font34 colorBlue"></view>
<view v-else class="iconfont font34 color-c"></view>
</view>
<view class="lable-text ellipsis">{{item[props.label]}}</view>
<view class="right"><i v-if="!item.isChild&&item.children.length>0"
class="iconfont"></i>
</view>
</label>
</view>
</view>
</view>
<view class="bottom-container width-max">
<uni-button :bottomHeight="bottomHeight" location='bottom' :texts="buttonTexts"
@uniButtonClick="backConfirm">
</uni-button>
</view>
</view>
</template>
<script>
export default {
props: {
// list数组值
treeNone: {
type: Array,
default: () => {
return []
}
},
//是否开启选中
isCheck: {
type: Boolean,
default: () => {
return false
}
},
checkList: {
type: Array,
default: () => []
},
parentList: {
type: Array,
default: () => []
},
// 匹配id
keyValue: {
type: String,
default: 'id',
},
props: {
type: Object,
default: () => {
return {
label: 'name',
children: 'children',
multiple: false,
nodes: false
}
}
}
},
watch: {
treeNone(val) {
this.tree = val;
this.catchTreeNone = [...val];
},
checkList(val){
this.newCheckList = val
}
},
computed: {
isSelect() {
return (item) => {
const checkList = this.newCheckList
if (checkList.length == 0) {
this.props.checkStrictly ? (item.bx = 0, item.qx = 0) : ''
return false
}
const i = checkList.findIndex(e => {
return item[this.keyCode] == e[this.keyCode]
}) > -1
return i && !item.qx
}
},
radioSelect() {
const list = this.newCheckList
return (item) => {
return list.length > 0 && item[this.keyCode] == list[0][this.keyCode]
}
},
keyCode() {
return this.keyValue
}
},
data() {
return {
height: this.windowHeightT(),
navHeight: this.navHeight,
bottomHeight: uni.upx2px(146),
buttonTexts: [{
text: '确认',
bgClass: 'uni-button-submit'
}],
isre: false,
tree: Object.freeze(this.treeNone),
newNum: 0,
oldNum: 0,
catchTreeNone: [...this.treeNone],
tree_stack: [1],
searchResult: [],
newCheckList: this.checkList,
scrollLeft: 999,
nodePathArray: []
}
},
created() {
this.Init()
},
methods: {
// 初始化
Init() {
if (this.newCheckList.length !== 0) {
let {
tree_stack,
props,
catchTreeNone,
newCheckList
} = this
this.getNodeRoute(catchTreeNone, newCheckList[0][this.keyCode])
let arr = this.nodePathArray.reverse()
if (arr.length == 0) return
this.tree_stack = tree_stack.concat(arr);
this.tree = this.tree_stack[this.tree_stack.length - 1].children;
}
},
// 点击项目处理
handleClick(item, index) {
let children = item[this.props.children]
if (index > -1 && children && children.length > 0) {
this.toChildren(item)
} else {
this.checkbox(item, index)
}
},
// 获取路径
getPath() {
const {
keyCode,
tree_stack,
props
} = this
const path = [...tree_stack].map(e => {
const item = Object.assign({}, e)
delete item[props.children]
return item
})
return path.slice(1, path.length) || []
},
// 关联下一级,选中
chooseChild(arr, path) {
let that = this;
const oldPath = [...path]
for (var i = 0, len = arr.length; i < len; i++) {
let item = arr[i];
if (item.isChild) {
that.newCheckList.push({
...item,
path: oldPath
})
} else {
const newItem = {
...item
}
delete newItem[that.props.children]
const newPath = [...oldPath, newItem]
that.chooseChild(item.children, newPath)
}
}
},
// (tree为目标树,targetId为目标节点id)
getNodeRoute(tree, targetId) {
for (let index = 0; index < tree.length; index++) {
if (tree[index].children) {
let endRecursiveLoop = this.getNodeRoute(tree[index].children, targetId)
if (endRecursiveLoop) {
this.nodePathArray.push(tree[index])
return true
}
}
if (tree[index][this.keyCode] === targetId) {
return true
}
}
},
//单选
checkbox(item, index) {
const path = this.getPath()
this.$set(this, 'newCheckList', [{
...item,
path
}])
},
//到下一级
toChildren(item) {
if (item.isChild) return
var that = this;
uni.showLoading({
title: '加载中'
})
let children = that.props.children;
if (!item.isChild && item[children].length > 0 && !(that.tree_stack[0][this.keyCode] == item[this
.keyCode])) {
that.tree = item[children];
that.tree_stack.push(item);
}
this.$nextTick(() => {
uni.hideLoading()
this.scrollLeft += 200;
})
if (this.props.checkStrictly) this.checkAllChoose();
},
checkAllChoose() {
let o = false,
t = true;
this.tree.forEach((e, i) => {
if (!e.isChild) {
e.qx = o;
e.bx = o;
this.computAllNumber(e.children);
if (this.newNum != 0 && this.oldNum != 0) {
if (this.newNum == this.oldNum) {
e.qx = t;
e.bx = o;
} else {
e.qx = o;
e.bx = t;
}
}
if (this.newNum != 0 && this.oldNum == 0) {
this.$set(this.tree[i], 'bx', o);
this.$set(this.tree[i], 'qx', o);
}
this.$forceUpdate()
this.newNum = 0
this.oldNum = 0
}
})
},
computAllNumber(arr) {
for (let j = 0; j < arr.length; j++) {
var e = arr[j];
this.checkSum(e[this.keyCode])
if (e.isChild) {
this.newNum++;
} else {
this.computAllNumber(e.children)
}
}
},
checkSum(id) {
for (let i = 0; i < this.newCheckList.length; i++) {
if (id == this.newCheckList[i][this.keyCode]) {
this.oldNum++;
break
}
}
},
//返回其它层
backTree(item, index) {
let that = this,
tree_stack = that.tree_stack,
max = 10000;
if (index === -1) {
that.tree = that.catchTreeNone
that.tree_stack.splice(1, max)
that.isre = false
} else {
if (tree_stack.length - index > 2) {
tree_stack.forEach((item, i) => {
if (i > index) {
that.tree_stack.splice(i, max)
}
})
} else if (index !== tree_stack.length - 1) {
that.tree_stack.splice(tree_stack.length - 1, 1)
}
that.tree = item[that.props.children]
}
if (this.props.checkStrictly) this.checkAllChoose();
this.$forceUpdate()
},
// $emit 传入选中的数据
backConfirm() {
this.$emit('sendValue', this.newCheckList, 'back')
}
},
}
</script>
</script>
<style lang="scss" scoped>
.flex_between_center {
display: flex;
justify-content: space-between;
align-items: center;
}
.checkBorder {
border: 1px solid #ecdee4;
}
.header {
// width: 100%;
// position: fixed;
// background-color: #fff;
// z-index: 9999;
padding: 10rpx 30rpx;
.title {
// height: 90rpx;
// padding: 0 32rpx;
// line-height: 90rpx;
// font-size: 30rpx;
color: #999;
}
}
.iconclass {
display: inline-block;
margin: 0 12rpx;
color: #D0D4DB;
font-size: 28rpx;
}
.container-list {
overflow-y: scroll;
overflow-x: hidden;
margin-top: 20rpx;
// padding-bottom: 160rpx;
// padding-top: 200rpx;
.common {
background-color: #fff;
border-bottom: 1rpx solid #f4f4f4;
// padding-left: 10rpx;
.content {
display: flex;
align-items: center;
height: 96rpx;
padding: 0 30rpx;
.lable-text{
margin-left: 45rpx;
font-size: 30rpx;
color: #333;
width: 500rpx;
}
.right {
position: absolute;
right: 30rpx;
color: #babdc3;
font-size: 32rpx;
}
}
}
}
.active {
color: #4297ED !important;
}
.none {
color: #666666;
}
.icon-selected{
color: #0095F2!important;
font-size: 40rpx!important;
}
.icons{
color: #0095F2!important;
font-size: 40rpx!important;
}
.next-icon{
margin: 0 34rpx;
}
.content-item{
display: flex;
position: relative;
align-items: center;
}
.box_sizing {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.bottom-container {
position: fixed;
bottom: 0;
left: 0;
}
</style>