123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- <template>
- <view class="gui-cascade-selection">
- <scroll-view scroll-x scroll-with-animation :scroll-into-view="scrollViewId"
- :style="{ backgroundColor: headerBgColor }" class="gui-bottom-line"
- :class="{ 'gui-btm-none': !headerLine }">
- <view class="gui-selection-header" :style="{ height: tabsHeight, backgroundColor: backgroundColor }">
- <block v-for="(item, iindex) in selectedArr" :key="iindex">
- <view class="gui-header-item" :class="{ 'gui-font-bold': iindex === currentTab && bold }"
- :style="{ color: iindex === currentTab ? activeColor : color, fontSize: size + 'rpx' }"
- :id="`id_${iindex}`" @tap.stop="swichNav" :data-current="iindex">
- {{ item.text }}
- <view class="gui-active-line" :style="{ backgroundColor: lineColor }"
- v-if="iindex === currentTab && showLine"></view>
- </view>
- </block>
- </view>
- </scroll-view>
- <swiper class="gui-selection-list" :current="currentTab" duration="300" @change="switchTab"
- :style="{ height: height, backgroundColor: backgroundColor }">
- <block v-for="(item, iindex) in selectedArr" :key="iindex">
- <swiper-item>
- <scroll-view scroll-y :scroll-into-view="item.scrollViewId" class="gui-selection-item"
- :style="{ height: height }">
- <view class="gui-first-item" :style="{ height: firstItemTop }"></view>
- <view class="gui-selection-cell" :style="{ padding: padding, backgroundColor: backgroundColor }"
- :id="`id_${subIndex}`" v-for="(subItem, subIndex) in item.list" :key="subIndex"
- @tap="change(iindex, subIndex, subItem)">
- <icon type="success_no_circle" v-if="item.index === subIndex" :color="checkMarkColor"
- :size="checkMarkSize" class="gui-icon-success"></icon>
- <image :src="subItem.src" v-if="subItem.src" class="gui-cell-img"
- :style="{ width: imgWidth, height: imgHeight, borderRadius: radius }"></image>
- <view class="gui-cell-title"
- :class="{ 'gui-font-bold': item.index === subIndex && textBold, 'gui-flex-shrink': nowrap }"
- :style="{ color: item.index === subIndex ? textActiveColor : textColor, fontSize: textSize + 'rpx' }">
- {{ subItem.text }}
- </view>
- <view class="gui-cell-sub_title"
- :style="{ color: subTextColor, fontSize: subTextSize + 'rpx' }" v-if="subItem.subText">
- {{ subItem.subText }}</view>
- </view>
- </scroll-view>
- </swiper-item>
- </block>
- </swiper>
- </view>
- </template>
- <script>
- export default {
- name: 'tuiCascadeSelection',
- props: {
- /**
- * 如果下一级是请求返回,则为第一级数据,否则所有数据
- * 数据格式
- [{
- src: "",
- text: "",
- subText: "",
- value: 0,
- children:[{
- text: "",
- subText: "",
- value: 0,
- children:[]
- }]
- }]
- * */
- itemList: {
- type: Array,
- default: () => {
- return [];
- }
- },
- /*
- 初始化默认选中数据
- [{
- text: "",//选中text
- subText: '',//选中subText
- value: '',//选中value
- src: '', //选中src,没有则传空或不传
- index: 0, //选中数据在当前layer索引
- list: [{src: "", text: "", subText: "", value: 101}] //所有layer数据集合
- }];
-
- */
- defaultItemList: {
- type: Array,
- value: []
- },
- //是否显示header底部细线
- headerLine: {
- type: Boolean,
- default: true
- },
- //header背景颜色
- headerBgColor: {
- type: String,
- default: '#FFFFFF'
- },
- //顶部标签栏高度
- tabsHeight: {
- type: String,
- default: '88rpx'
- },
- //默认显示文字
- text: {
- type: String,
- default: '请选择'
- },
- //tabs 文字大小
- size: {
- type: Number,
- default: 28
- },
- //tabs 文字颜色
- color: {
- type: String,
- default: '#555'
- },
- //选中颜色
- activeColor: {
- type: String,
- default: '#5677fc'
- },
- //选中后文字加粗
- bold: {
- type: Boolean,
- default: true
- },
- //选中后是否显示底部线条
- showLine: {
- type: Boolean,
- default: true
- },
- //线条颜色
- lineColor: {
- type: String,
- default: '#5677fc'
- },
- //icon 大小
- checkMarkSize: {
- type: Number,
- default: 15
- },
- //icon 颜色
- checkMarkColor: {
- type: String,
- default: '#5677fc'
- },
- //item 图片宽度
- imgWidth: {
- type: String,
- default: '40rpx'
- },
- //item 图片高度
- imgHeight: {
- type: String,
- default: '40rpx'
- },
- //图片圆角
- radius: {
- type: String,
- default: '50%'
- },
- //item text颜色
- textColor: {
- type: String,
- default: '#333'
- },
- textActiveColor: {
- type: String,
- default: '#333'
- },
- //选中后字体是否加粗
- textBold: {
- type: Boolean,
- default: true
- },
- //item text字体大小
- textSize: {
- type: Number,
- default: 28
- },
- //text 是否不换行
- nowrap: {
- type: Boolean,
- default: false
- },
- //item subText颜色
- subTextColor: {
- type: String,
- default: '#999'
- },
- //item subText字体大小
- subTextSize: {
- type: Number,
- default: 24
- },
- // item padding
- padding: {
- type: String,
- default: '20rpx 30rpx'
- },
- //占位高度,第一条数据距离顶部距离
- firstItemTop: {
- type: String,
- default: '20rpx'
- },
- //swiper 高度
- height: {
- type: String,
- default: '300px'
- },
- //item swiper 内容部分背景颜色
- backgroundColor: {
- type: String,
- default: '#FFFFFF'
- },
- //子集数据是否请求返回(默认false,一次性返回所有数据)
- request: {
- type: Boolean,
- default: false
- },
- //子级数据(当有改变时,默认当前选中项新增子级数据,request=true时生效)
- receiveData: {
- type: Array,
- default: () => {
- return [];
- }
- },
- //改变值则重置数据
- reset: {
- type: [Number, String],
- default: 0
- },
- joint: {
- type: "",
- default: " "
- }
- },
- watch: {
- itemList(val) {
- this.initData(val, -1);
- },
- receiveData(val) {
- this.subLevelData(val, this.currentTab);
- },
- reset() {
- this.initData(this.itemList, -1);
- }
- },
- created() {
- let defaultItemList = this.defaultItemList || [];
- if (defaultItemList.length > 0) {
- defaultItemList.map(item => {
- item.scrollViewId = `id_${item.index}`;
- });
- this.selectedArr = defaultItemList;
- this.currentTab = defaultItemList.length - 1;
- this.$nextTick(() => {
- this.checkCor();
- });
- } else {
- this.initData(this.itemList, -1);
- }
- },
- data() {
- return {
- currentTab: 0,
- //tab栏scrollview滚动的位置
- scrollViewId: 'id__1',
- selectedArr: []
- };
- },
- methods: {
- initData(data, layer) {
- if (!data || data.length === 0) return;
- if (this.request) {
- //第一级数据
- this.subLevelData(data, layer);
- } else {
- let selectedValue = this.selectedValue || {};
- if (selectedValue.type) {
- this.setDefaultData(selectedValue);
- } else {
- this.subLevelData(this.getItemList(layer, -1), layer);
- }
- }
- },
- removeChildren(data) {
- let list = data.map(item => {
- delete item['children'];
- return item;
- });
- return list;
- },
- getItemList(layer, index) {
- let list = [];
- let arr = JSON.parse(JSON.stringify(this.itemList));
- if (layer == -1) {
- list = this.removeChildren(arr);
- } else {
- let value = this.selectedArr[0].index;
- value = value == -1 ? index : value;
- list = arr[value].children || [];
- if (layer > 0) {
- for (let i = 1; i < layer + 1; i++) {
- let val = layer === i ? index : this.selectedArr[i].index;
- list = list[val].children || [];
- if (list.length === 0) break;
- }
- }
- list = this.removeChildren(list);
- }
- return list;
- },
- //滚动切换
- switchTab: function(e) {
- this.currentTab = e.detail.current;
- // console.log(this.selectedArr)
- this.checkCor();
- },
- //点击标题切换当
- swichNav: function(e) {
- // console.log("=====<", e)
- let cur = e.currentTarget.dataset.current;
- if (this.currentTab != cur) {
- this.currentTab = cur;
- }
- },
- checkCor: function() {
- let item = this.selectedArr[this.currentTab];
- item.scrollViewId = 'id__1';
- this.$nextTick(() => {
- setTimeout(() => {
- let val = item.index < 2 ? 0 : Number(item.index - 2);
- item.scrollViewId = `id_${val}`;
- }, 2);
- });
- if (this.currentTab > 1) {
- this.scrollViewId = `id_${this.currentTab - 1}`;
- } else {
- this.scrollViewId = `id_0`;
- }
- },
- change(index, subIndex, subItem) {
- let item = this.selectedArr[index];
- if (item.index == subIndex) {
- console.log('没有变化')
- console.log('cascadeChange:', index, subIndex, subItem)
- // return;
- }
- item.index = subIndex;
- item.text = subItem.text;
- item.value = subItem.value;
- item.subText = subItem.subText || '';
- item.src = subItem.src || '';
- if (!this.request) {
- let data = this.getItemList(index, subIndex);
- this.subLevelData(data, index);
- }
- let text = '';
- let value = '';
- let resultArr = JSON.parse(JSON.stringify(this.selectedArr));
- const result = resultArr.filter((item, i) => {
- return i <= index
- }).map(item => {
- text ? text += this.joint + item.text : text += item.text;
- value ? value += "," + item.value : value += item.value;
- delete item['list'];
- //delete item['index'];
- delete item['scrollViewId'];
- return item;
- });
- this.$emit('change', {
- result: result,
- layer: index,
- subIndex: subIndex,
- fullvalue: value,
- fulltext: text,
- ...subItem
- });
- },
- //新增子级数据时处理
- subLevelData(data, layer) {
- // console.log(data, layer)
- if (!data || data.length === 0) {
- if (layer == -1) return;
- //完成选择
- // console.log("====>", data, layer)
- this.selectedArr = this.selectedArr.slice(0, layer + 1);
- } else {
- //重置数据( >layer层级)
- let item = [{
- text: this.text,
- subText: '',
- value: '',
- src: '',
- index: -1,
- scrollViewId: 'id__1',
- list: data
- }];
- if (layer == -1) {
- this.selectedArr = item;
- } else {
- let retainArr = this.selectedArr.slice(0, layer + 1);
- this.selectedArr = retainArr.concat(item);
- }
- this.$nextTick(() => {
- this.currentTab = this.selectedArr.length - 1;
- });
- }
- let text = '';
- let value = "";
- const resultArr = JSON.parse(JSON.stringify(this.selectedArr));
- const result = resultArr.filter(item => {
- return item.index >= 0
- }).map(item => {
- text ? text += this.joint + item.text : text += item.text;
- value ? value += "," + item.value : value += item.value;
- delete item['list'];
- //delete item['index'];
- delete item['scrollViewId'];
- return item;
- });
- let lastItem = result[result.length - 1] || {};
- // console.log(lastItem)
- // this.$emit('change', {
- // layer: layer,
- // result: result,
- // value: lastItem.value,
- // text: text,
- // subText: lastItem.subText,
- // src: lastItem.src
- // });
- if (!data || data.length === 0) {
- this.$emit('complete', {
- result: result,
- value: lastItem.value,
- fullvalue: value,
- fulltext: text,
- text: lastItem.text,
- subText: lastItem.subText,
- src: lastItem.src
- });
- }
- }
- }
- };
- </script>
- <style scoped>
- .gui-cascade-selection {
- width: 100%;
- box-sizing: border-box;
- }
- .gui-selection-header {
- width: 100%;
- display: flex;
- align-items: center;
- position: relative;
- box-sizing: border-box;
- }
- .gui-bottom-line {
- position: relative;
- }
- .gui-bottom-line::after {
- width: 100%;
- content: '';
- position: absolute;
- border-bottom: 1rpx solid #eaeef1;
- -webkit-transform: scaleY(0.5) translateZ(0);
- transform: scaleY(0.5) translateZ(0);
- transform-origin: 0 100%;
- bottom: 0;
- right: 0;
- left: 0;
- }
- .gui-btm-none::after {
- border-bottom: 0 !important;
- }
- .gui-header-item {
- max-width: 240rpx;
- padding: 15rpx 30rpx;
- box-sizing: border-box;
- flex-shrink: 0;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- position: relative;
- }
- .gui-font-bold {
- font-weight: bold;
- }
- .gui-active-line {
- width: 60rpx;
- height: 6rpx;
- border-radius: 4rpx;
- position: absolute;
- bottom: 0;
- right: 0;
- left: 50%;
- transform: translateX(-50%);
- }
- .gui-selection-cell {
- width: 100%;
- box-sizing: border-box;
- display: flex;
- align-items: center;
- }
- .gui-icon-success {
- margin-right: 12rpx;
- }
- .gui-cell-img {
- margin-right: 12rpx;
- flex-shrink: 0;
- }
- .gui-cell-title {
- word-break: break-all;
- }
- .gui-flex-shrink {
- flex-shrink: 0;
- }
- .gui-font-bold {
- font-weight: bold;
- }
- .gui-cell-sub_title {
- margin-left: 20rpx;
- word-break: break-all;
- }
- .gui-first-item {
- width: 100%;
- }
- </style>
|